diff --git a/AI/Nullkiller/AIGateway.cpp b/AI/Nullkiller/AIGateway.cpp index a4613db1b..501c61eeb 100644 --- a/AI/Nullkiller/AIGateway.cpp +++ b/AI/Nullkiller/AIGateway.cpp @@ -481,7 +481,7 @@ void AIGateway::objectPropertyChanged(const SetObjectProperty * sop) NET_EVENT_HANDLER; if(sop->what == ObjProperty::OWNER) { - auto relations = myCb->getPlayerRelations(playerID, (PlayerColor)sop->val); + auto relations = myCb->getPlayerRelations(playerID, sop->identifier.as()); auto obj = myCb->getObj(sop->id, false); if(!nullkiller) // crash protection @@ -1419,7 +1419,7 @@ void AIGateway::tryRealize(Goals::Trade & g) //trade //TODO trade only as much as needed if (toGive) //don't try to sell 0 resources { - cb->trade(m, EMarketMode::RESOURCE_RESOURCE, res, g.resID, toGive); + cb->trade(m, EMarketMode::RESOURCE_RESOURCE, res, GameResID(g.resID), toGive); accquiredResources = static_cast(toGet * (it->resVal / toGive)); logAi->debug("Traded %d of %s for %d of %s at %s", toGive, res, accquiredResources, g.resID, obj->getObjectName()); } diff --git a/AI/VCAI/VCAI.cpp b/AI/VCAI/VCAI.cpp index 19313633b..c3068c989 100644 --- a/AI/VCAI/VCAI.cpp +++ b/AI/VCAI/VCAI.cpp @@ -564,7 +564,7 @@ void VCAI::objectPropertyChanged(const SetObjectProperty * sop) NET_EVENT_HANDLER; if(sop->what == ObjProperty::OWNER) { - if(myCb->getPlayerRelations(playerID, (PlayerColor)sop->val) == PlayerRelations::ENEMIES) + if(myCb->getPlayerRelations(playerID, sop->identifier.as()) == PlayerRelations::ENEMIES) { //we want to visit objects owned by oppponents auto obj = myCb->getObj(sop->id, false); @@ -2160,7 +2160,7 @@ void VCAI::tryRealize(Goals::Trade & g) //trade //TODO trade only as much as needed if (toGive) //don't try to sell 0 resources { - cb->trade(m, EMarketMode::RESOURCE_RESOURCE, res, g.resID, toGive); + cb->trade(m, EMarketMode::RESOURCE_RESOURCE, res, GameResID(g.resID), toGive); accquiredResources = static_cast(toGet * (it->resVal / toGive)); logAi->debug("Traded %d of %s for %d of %s at %s", toGive, res, accquiredResources, g.resID, obj->getObjectName()); } diff --git a/CCallback.cpp b/CCallback.cpp index 78c8fe884..7b87bc913 100644 --- a/CCallback.cpp +++ b/CCallback.cpp @@ -237,12 +237,12 @@ void CCallback::buyArtifact(const CGHeroInstance *hero, ArtifactID aid) sendRequest(&pack); } -void CCallback::trade(const IMarket * market, EMarketMode mode, ui32 id1, ui32 id2, ui32 val1, const CGHeroInstance * hero) +void CCallback::trade(const IMarket * market, EMarketMode mode, TradeItemSell id1, TradeItemBuy id2, ui32 val1, const CGHeroInstance * hero) { - trade(market, mode, std::vector(1, id1), std::vector(1, id2), std::vector(1, val1), hero); + trade(market, mode, std::vector(1, id1), std::vector(1, id2), std::vector(1, val1), hero); } -void CCallback::trade(const IMarket * market, EMarketMode mode, const std::vector & id1, const std::vector & id2, const std::vector & val1, const CGHeroInstance * hero) +void CCallback::trade(const IMarket * market, EMarketMode mode, const std::vector & id1, const std::vector & id2, const std::vector & val1, const CGHeroInstance * hero) { TradeOnMarketplace pack; pack.marketId = dynamic_cast(market)->id; @@ -254,9 +254,9 @@ void CCallback::trade(const IMarket * market, EMarketMode mode, const std::vecto sendRequest(&pack); } -void CCallback::setFormation(const CGHeroInstance * hero, bool tight) +void CCallback::setFormation(const CGHeroInstance * hero, EArmyFormation mode) { - SetFormation pack(hero->id,tight); + SetFormation pack(hero->id, mode); sendRequest(&pack); } diff --git a/CCallback.h b/CCallback.h index d7af2e38c..068ac547b 100644 --- a/CCallback.h +++ b/CCallback.h @@ -12,6 +12,7 @@ #include "lib/CGameInfoCallback.h" #include "lib/battle/CPlayerBattleCallback.h" #include "lib/int3.h" // for int3 +#include "lib/networkPacks/TradeItem.h" VCMI_LIB_NAMESPACE_BEGIN @@ -78,8 +79,8 @@ public: virtual bool upgradeCreature(const CArmedInstance *obj, SlotID stackPos, CreatureID newID=CreatureID::NONE)=0; //if newID==-1 then best possible upgrade will be made virtual void swapGarrisonHero(const CGTownInstance *town)=0; - virtual void trade(const IMarket * market, EMarketMode mode, ui32 id1, ui32 id2, ui32 val1, const CGHeroInstance * hero = nullptr)=0; //mode==0: sell val1 units of id1 resource for id2 resiurce - virtual void trade(const IMarket * market, EMarketMode mode, const std::vector & id1, const std::vector & id2, const std::vector & val1, const CGHeroInstance * hero = nullptr)=0; + virtual void trade(const IMarket * market, EMarketMode mode, TradeItemSell id1, TradeItemBuy id2, ui32 val1, const CGHeroInstance * hero = nullptr)=0; //mode==0: sell val1 units of id1 resource for id2 resiurce + virtual void trade(const IMarket * market, EMarketMode mode, const std::vector & id1, const std::vector & id2, const std::vector & val1, const CGHeroInstance * hero = nullptr)=0; virtual int selectionMade(int selection, QueryID queryID) =0; virtual int sendQueryReply(std::optional reply, QueryID queryID) =0; @@ -94,7 +95,7 @@ public: virtual bool dismissCreature(const CArmedInstance *obj, SlotID stackPos)=0; virtual void endTurn()=0; virtual void buyArtifact(const CGHeroInstance *hero, ArtifactID aid)=0; //used to buy artifacts in towns (including spell book in the guild and war machines in blacksmith) - virtual void setFormation(const CGHeroInstance * hero, bool tight)=0; + virtual void setFormation(const CGHeroInstance * hero, EArmyFormation mode)=0; virtual void save(const std::string &fname) = 0; virtual void sendMessage(const std::string &mess, const CGObjectInstance * currentObject = nullptr) = 0; @@ -181,9 +182,9 @@ public: void endTurn() override; void swapGarrisonHero(const CGTownInstance *town) override; void buyArtifact(const CGHeroInstance *hero, ArtifactID aid) override; - void trade(const IMarket * market, EMarketMode mode, ui32 id1, ui32 id2, ui32 val1, const CGHeroInstance * hero = nullptr) override; - void trade(const IMarket * market, EMarketMode mode, const std::vector & id1, const std::vector & id2, const std::vector & val1, const CGHeroInstance * hero = nullptr) override; - void setFormation(const CGHeroInstance * hero, bool tight) override; + void trade(const IMarket * market, EMarketMode mode, TradeItemSell id1, TradeItemBuy id2, ui32 val1, const CGHeroInstance * hero = nullptr) override; + void trade(const IMarket * market, EMarketMode mode, const std::vector & id1, const std::vector & id2, const std::vector & val1, const CGHeroInstance * hero = nullptr) override; + void setFormation(const CGHeroInstance * hero, EArmyFormation mode) override; void recruitHero(const CGObjectInstance *townOrTavern, const CGHeroInstance *hero) override; void save(const std::string &fname) override; void sendMessage(const std::string &mess, const CGObjectInstance * currentObject = nullptr) override; diff --git a/client/Client.h b/client/Client.h index 2be88e55a..31516cb98 100644 --- a/client/Client.h +++ b/client/Client.h @@ -162,7 +162,7 @@ public: void changeSpells(const CGHeroInstance * hero, bool give, const std::set & spells) override {}; bool removeObject(const CGObjectInstance * obj, const PlayerColor & initiator) override {return false;}; - void createObject(const int3 & visitablePosition, const PlayerColor & initiator, Obj type, int32_t subtype ) override {}; + void createObject(const int3 & visitablePosition, const PlayerColor & initiator, MapObjectID type, MapObjectSubID subtype) override {}; void setOwner(const CGObjectInstance * obj, PlayerColor owner) override {}; void changePrimSkill(const CGHeroInstance * hero, PrimarySkill which, si64 val, bool abs = false) override {}; void changeSecSkill(const CGHeroInstance * hero, SecondarySkill which, int val, bool abs = false) override {}; @@ -212,7 +212,8 @@ public: void changeFogOfWar(int3 center, ui32 radius, PlayerColor player, ETileVisibility mode) override {} void changeFogOfWar(std::unordered_set & tiles, PlayerColor player, ETileVisibility mode) override {} - void setObjProperty(ObjectInstanceID objid, int prop, si64 val) override {} + void setObjPropertyValue(ObjectInstanceID objid, ObjProperty prop, int32_t value) override {}; + void setObjPropertyID(ObjectInstanceID objid, ObjProperty prop, ObjPropertyID identifier) override {}; void showInfoDialog(InfoWindow * iw) override {}; void showInfoDialog(const std::string & msg, PlayerColor player) override {}; diff --git a/client/NetPacksClient.cpp b/client/NetPacksClient.cpp index 0a7861a3f..746c5ec2d 100644 --- a/client/NetPacksClient.cpp +++ b/client/NetPacksClient.cpp @@ -350,15 +350,16 @@ void ApplyClientNetPackVisitor::visitGiveBonus(GiveBonus & pack) cl.invalidatePaths(); switch(pack.who) { - case GiveBonus::ETarget::HERO: + case GiveBonus::ETarget::OBJECT: { - const CGHeroInstance *h = gs.getHero(ObjectInstanceID(pack.id)); - callInterfaceIfPresent(cl, h->tempOwner, &IGameEventsReceiver::heroBonusChanged, h, pack.bonus, true); + const CGHeroInstance *h = gs.getHero(pack.id.as()); + if (h) + callInterfaceIfPresent(cl, h->tempOwner, &IGameEventsReceiver::heroBonusChanged, h, pack.bonus, true); } break; case GiveBonus::ETarget::PLAYER: { - callInterfaceIfPresent(cl, PlayerColor(pack.id), &IGameEventsReceiver::playerBonusChanged, pack.bonus, true); + callInterfaceIfPresent(cl, pack.id.as(), &IGameEventsReceiver::playerBonusChanged, pack.bonus, true); } break; } @@ -433,16 +434,17 @@ void ApplyClientNetPackVisitor::visitRemoveBonus(RemoveBonus & pack) cl.invalidatePaths(); switch(pack.who) { - case GiveBonus::ETarget::HERO: + case GiveBonus::ETarget::OBJECT: { - const CGHeroInstance *h = gs.getHero(ObjectInstanceID(pack.whoID)); - callInterfaceIfPresent(cl, h->tempOwner, &IGameEventsReceiver::heroBonusChanged, h, pack.bonus, false); + const CGHeroInstance *h = gs.getHero(pack.whoID.as()); + if (h) + callInterfaceIfPresent(cl, h->tempOwner, &IGameEventsReceiver::heroBonusChanged, h, pack.bonus, false); } break; case GiveBonus::ETarget::PLAYER: { //const PlayerState *p = gs.getPlayerState(pack.id); - callInterfaceIfPresent(cl, PlayerColor(pack.whoID), &IGameEventsReceiver::playerBonusChanged, pack.bonus, false); + callInterfaceIfPresent(cl, pack.whoID.as(), &IGameEventsReceiver::playerBonusChanged, pack.bonus, false); } break; } diff --git a/client/widgets/CAltar.cpp b/client/widgets/CAltar.cpp index ba76f47d3..a21766618 100644 --- a/client/widgets/CAltar.cpp +++ b/client/widgets/CAltar.cpp @@ -99,14 +99,15 @@ TExpType CAltarArtifacts::calcExpAltarForHero() void CAltarArtifacts::makeDeal() { - std::vector positions; + std::vector positions; for(const auto art : arts->artifactsOnAltar) { positions.push_back(hero->getSlotByInstance(art)); } - std::sort(positions.begin(), positions.end(), std::greater<>()); + std::sort(positions.begin(), positions.end()); + std::reverse(positions.begin(), positions.end()); - LOCPLINT->cb->trade(market, EMarketMode::ARTIFACT_EXP, positions, {}, {}, hero); + LOCPLINT->cb->trade(market, EMarketMode::ARTIFACT_EXP, positions, std::vector(), std::vector(), hero); arts->artifactsOnAltar.clear(); for(auto item : items[0]) @@ -374,14 +375,14 @@ void CAltarCreatures::makeDeal() unitsSlider->scrollTo(0); expForHero->setText(std::to_string(0)); - std::vector ids; + std::vector ids; std::vector toSacrifice; for(int i = 0; i < unitsOnAltar.size(); i++) { if(unitsOnAltar[i]) { - ids.push_back(i); + ids.push_back(SlotID(i)); toSacrifice.push_back(unitsOnAltar[i]); } } diff --git a/client/windows/CHeroWindow.cpp b/client/windows/CHeroWindow.cpp index e4e93337d..3ff4fc950 100644 --- a/client/windows/CHeroWindow.cpp +++ b/client/windows/CHeroWindow.cpp @@ -306,7 +306,7 @@ void CHeroWindow::update(const CGHeroInstance * hero, bool redrawNeeded) formations->resetCallback(); //setting formations formations->setSelected(curHero->formation == EArmyFormation::TIGHT ? 1 : 0); - formations->addCallback([=](int value){ LOCPLINT->cb->setFormation(curHero, value);}); + formations->addCallback([=](int value){ LOCPLINT->cb->setFormation(curHero, static_cast(value));}); morale->set(curHero); luck->set(curHero); diff --git a/client/windows/CTradeWindow.cpp b/client/windows/CTradeWindow.cpp index 5cb261793..ccea4ad11 100644 --- a/client/windows/CTradeWindow.cpp +++ b/client/windows/CTradeWindow.cpp @@ -503,14 +503,27 @@ void CMarketplaceWindow::makeDeal() if(allowDeal) { - if(slider) + switch(mode) { - LOCPLINT->cb->trade(market, mode, leftIdToSend, hRight->id, slider->getValue() * r1, hero); + case EMarketMode::RESOURCE_RESOURCE: + LOCPLINT->cb->trade(market, mode, GameResID(leftIdToSend), GameResID(hRight->id), slider->getValue() * r1, hero); slider->scrollTo(0); - } - else - { - LOCPLINT->cb->trade(market, mode, leftIdToSend, hRight->id, r2, hero); + break; + case EMarketMode::CREATURE_RESOURCE: + LOCPLINT->cb->trade(market, mode, SlotID(leftIdToSend), GameResID(hRight->id), slider->getValue() * r1, hero); + slider->scrollTo(0); + break; + case EMarketMode::RESOURCE_PLAYER: + LOCPLINT->cb->trade(market, mode, GameResID(leftIdToSend), PlayerColor(hRight->id), slider->getValue() * r1, hero); + slider->scrollTo(0); + break; + + case EMarketMode::RESOURCE_ARTIFACT: + LOCPLINT->cb->trade(market, mode, GameResID(leftIdToSend), ArtifactID(hRight->id), r2, hero); + break; + case EMarketMode::ARTIFACT_RESOURCE: + LOCPLINT->cb->trade(market, mode, ArtifactInstanceID(leftIdToSend), GameResID(hRight->id), r2, hero); + break; } } diff --git a/client/windows/GUIClasses.cpp b/client/windows/GUIClasses.cpp index 0d0a1e710..9e5fa50d8 100644 --- a/client/windows/GUIClasses.cpp +++ b/client/windows/GUIClasses.cpp @@ -988,7 +988,7 @@ void CTransformerWindow::makeDeal() for(auto & elem : items) { if(!elem->left) - LOCPLINT->cb->trade(market, EMarketMode::CREATURE_UNDEAD, elem->id, 0, 0, hero); + LOCPLINT->cb->trade(market, EMarketMode::CREATURE_UNDEAD, SlotID(elem->id), {}, {}, hero); } } @@ -1163,13 +1163,13 @@ void CUniversityWindow::close() CStatusbarWindow::close(); } -void CUniversityWindow::makeDeal(int skill) +void CUniversityWindow::makeDeal(SecondarySkill skill) { - LOCPLINT->cb->trade(market, EMarketMode::RESOURCE_SKILL, 6, skill, 1, hero); + LOCPLINT->cb->trade(market, EMarketMode::RESOURCE_SKILL, GameResID(GameResID::GOLD), skill, 1, hero); } -CUnivConfirmWindow::CUnivConfirmWindow(CUniversityWindow * owner_, int SKILL, bool available) +CUnivConfirmWindow::CUnivConfirmWindow(CUniversityWindow * owner_, SecondarySkill SKILL, bool available) : CStatusbarWindow(PLAYER_COLORED, ImagePath::builtin("UNIVERS2.PCX")), owner(owner_) { @@ -1204,7 +1204,7 @@ CUnivConfirmWindow::CUnivConfirmWindow(CUniversityWindow * owner_, int SKILL, bo statusbar = CGStatusBar::create(std::make_shared(background->getSurface(), Rect(8, pos.h - 26, pos.w - 16, 19), 8, pos.h - 26)); } -void CUnivConfirmWindow::makeDeal(int skill) +void CUnivConfirmWindow::makeDeal(SecondarySkill skill) { owner->makeDeal(skill); close(); diff --git a/client/windows/GUIClasses.h b/client/windows/GUIClasses.h index 07b47b8eb..98413fa4a 100644 --- a/client/windows/GUIClasses.h +++ b/client/windows/GUIClasses.h @@ -403,7 +403,7 @@ class CUniversityWindow : public CStatusbarWindow public: CUniversityWindow(const CGHeroInstance * _hero, const IMarket * _market, const std::function & onWindowClosed); - void makeDeal(int skill); + void makeDeal(SecondarySkill skill); void close(); }; @@ -422,10 +422,10 @@ class CUnivConfirmWindow : public CStatusbarWindow std::shared_ptr costIcon; std::shared_ptr cost; - void makeDeal(int skill); + void makeDeal(SecondarySkill skill); public: - CUnivConfirmWindow(CUniversityWindow * PARENT, int SKILL, bool available); + CUnivConfirmWindow(CUniversityWindow * PARENT, SecondarySkill SKILL, bool available); }; /// Garrison window where you can take creatures out of the hero to place it on the garrison diff --git a/cmake_modules/VCMI_lib.cmake b/cmake_modules/VCMI_lib.cmake index 85515c7c1..be60f369b 100644 --- a/cmake_modules/VCMI_lib.cmake +++ b/cmake_modules/VCMI_lib.cmake @@ -484,12 +484,14 @@ macro(add_main_lib TARGET_NAME LIBRARY_TYPE) ${MAIN_LIB_DIR}/networkPacks/EOpenWindowMode.h ${MAIN_LIB_DIR}/networkPacks/NetPacksBase.h ${MAIN_LIB_DIR}/networkPacks/NetPackVisitor.h + ${MAIN_LIB_DIR}/networkPacks/ObjProperty.h ${MAIN_LIB_DIR}/networkPacks/PacksForClient.h ${MAIN_LIB_DIR}/networkPacks/PacksForClientBattle.h ${MAIN_LIB_DIR}/networkPacks/PacksForLobby.h ${MAIN_LIB_DIR}/networkPacks/PacksForServer.h ${MAIN_LIB_DIR}/networkPacks/SetStackEffect.h ${MAIN_LIB_DIR}/networkPacks/StackLocation.h + ${MAIN_LIB_DIR}/networkPacks/TradeItem.h ${MAIN_LIB_DIR}/pathfinder/INodeStorage.h ${MAIN_LIB_DIR}/pathfinder/CGPathNode.h diff --git a/lib/CCreatureSet.cpp b/lib/CCreatureSet.cpp index 1a75578cc..8d79606ba 100644 --- a/lib/CCreatureSet.cpp +++ b/lib/CCreatureSet.cpp @@ -415,12 +415,9 @@ int CCreatureSet::stacksCount() const return static_cast(stacks.size()); } -void CCreatureSet::setFormation(bool tight) +void CCreatureSet::setFormation(EArmyFormation mode) { - if (tight) - formation = EArmyFormation::TIGHT; - else - formation = EArmyFormation::LOOSE; + formation = mode; } void CCreatureSet::setStackCount(const SlotID & slot, TQuantity count) diff --git a/lib/CCreatureSet.h b/lib/CCreatureSet.h index 9b3cad26c..305149b5b 100644 --- a/lib/CCreatureSet.h +++ b/lib/CCreatureSet.h @@ -203,12 +203,6 @@ public: } }; -enum class EArmyFormation : uint8_t -{ - LOOSE, - TIGHT -}; - namespace NArmyFormation { static const std::vector names{ "wide", "tight" }; @@ -235,7 +229,7 @@ public: void addToSlot(const SlotID & slot, const CreatureID & cre, TQuantity count, bool allowMerging = true); //Adds stack to slot. Slot must be empty or with same type creature void addToSlot(const SlotID & slot, CStackInstance * stack, bool allowMerging = true); //Adds stack to slot. Slot must be empty or with same type creature void clearSlots() override; - void setFormation(bool tight); + void setFormation(EArmyFormation tight); CArmedInstance *castToArmyObj(); //basic operations diff --git a/lib/IGameCallback.h b/lib/IGameCallback.h index dd80b9dde..ef9e95221 100644 --- a/lib/IGameCallback.h +++ b/lib/IGameCallback.h @@ -13,6 +13,7 @@ #include "CGameInfoCallback.h" // for CGameInfoCallback #include "CRandomGenerator.h" +#include "networkPacks/ObjProperty.h" VCMI_LIB_NAMESPACE_BEGIN @@ -73,14 +74,15 @@ public: class DLL_LINKAGE IGameEventCallback { public: - virtual void setObjProperty(ObjectInstanceID objid, int prop, si64 val) = 0; + virtual void setObjPropertyValue(ObjectInstanceID objid, ObjProperty prop, int32_t value = 0) = 0; + virtual void setObjPropertyID(ObjectInstanceID objid, ObjProperty prop, ObjPropertyID identifier) = 0; virtual void showInfoDialog(InfoWindow * iw) = 0; virtual void showInfoDialog(const std::string & msg, PlayerColor player) = 0; virtual void changeSpells(const CGHeroInstance * hero, bool give, const std::set &spells)=0; virtual bool removeObject(const CGObjectInstance * obj, const PlayerColor & initiator) = 0; - virtual void createObject(const int3 & visitablePosition, const PlayerColor & initiator, Obj type, int32_t subtype = 0) = 0; + virtual void createObject(const int3 & visitablePosition, const PlayerColor & initiator, MapObjectID type, MapObjectSubID subtype) = 0; virtual void setOwner(const CGObjectInstance * objid, PlayerColor owner)=0; virtual void changePrimSkill(const CGHeroInstance * hero, PrimarySkill which, si64 val, bool abs=false)=0; virtual void changeSecSkill(const CGHeroInstance * hero, SecondarySkill which, int val, bool abs=false)=0; diff --git a/lib/constants/Enumerations.h b/lib/constants/Enumerations.h index e358ed202..67ddc1b4a 100644 --- a/lib/constants/Enumerations.h +++ b/lib/constants/Enumerations.h @@ -246,4 +246,10 @@ enum class ETileVisibility : int8_t // Fog of war change REVEALED }; +enum class EArmyFormation : int8_t +{ + LOOSE, + TIGHT +}; + VCMI_LIB_NAMESPACE_END diff --git a/lib/constants/VariantIdentifier.h b/lib/constants/VariantIdentifier.h index 8ea6a6096..90269a3bb 100644 --- a/lib/constants/VariantIdentifier.h +++ b/lib/constants/VariantIdentifier.h @@ -13,7 +13,7 @@ VCMI_LIB_NAMESPACE_BEGIN -/// This class represents field that may contain value of multiple different identifer types +/// This class represents field that may contain value of multiple different identifier types template class VariantIdentifier { diff --git a/lib/mapObjects/CBank.cpp b/lib/mapObjects/CBank.cpp index e62163e61..9f32ae1c2 100644 --- a/lib/mapObjects/CBank.cpp +++ b/lib/mapObjects/CBank.cpp @@ -94,12 +94,12 @@ void CBank::setConfig(const BankConfig & config) setCreature (SlotID(stacksCount()), stack.type->getId(), stack.count); } -void CBank::setPropertyDer (ui8 what, ui32 val) +void CBank::setPropertyDer (ObjProperty what, ObjPropertyID identifier) { switch (what) { case ObjProperty::BANK_DAYCOUNTER: //daycounter - daycounter+=val; + daycounter+= identifier.getNum(); break; case ObjProperty::BANK_RESET: // FIXME: Object reset must be done by separate netpack from server @@ -119,9 +119,9 @@ void CBank::newTurn(CRandomGenerator & rand) const if (resetDuration != 0) { if (daycounter >= resetDuration) - cb->setObjProperty (id, ObjProperty::BANK_RESET, 0); //daycounter 0 + cb->setObjPropertyValue(id, ObjProperty::BANK_RESET); //daycounter 0 else - cb->setObjProperty (id, ObjProperty::BANK_DAYCOUNTER, 1); //daycounter++ + cb->setObjPropertyValue(id, ObjProperty::BANK_DAYCOUNTER, 1); //daycounter++ } } } @@ -210,7 +210,7 @@ void CBank::doVisit(const CGHeroInstance * hero) const case Obj::CRYPT: { GiveBonus gbonus; - gbonus.id = hero->id.getNum(); + gbonus.id = hero->id; gbonus.bonus.duration = BonusDuration::ONE_BATTLE; gbonus.bonus.source = BonusSource::OBJECT_TYPE; gbonus.bonus.sid = BonusSourceID(ID); @@ -240,7 +240,7 @@ void CBank::doVisit(const CGHeroInstance * hero) const { GiveBonus gb; gb.bonus = Bonus(BonusDuration::ONE_BATTLE, BonusType::LUCK, BonusSource::OBJECT_INSTANCE, -2, BonusSourceID(id), VLC->generaltexth->arraytxt[70]); - gb.id = hero->id.getNum(); + gb.id = hero->id; cb->giveHeroBonus(&gb); textID = 107; iw.components.emplace_back(ComponentType::LUCK, -2); @@ -369,7 +369,7 @@ void CBank::doVisit(const CGHeroInstance * hero) const cb->showInfoDialog(&iw); cb->giveCreatures(this, hero, ourArmy, false); } - cb->setObjProperty(id, ObjProperty::BANK_CLEAR, 0); //bc = nullptr + cb->setObjPropertyValue(id, ObjProperty::BANK_CLEAR); //bc = nullptr } } diff --git a/lib/mapObjects/CBank.h b/lib/mapObjects/CBank.h index 8f7105689..99bb4fdd7 100644 --- a/lib/mapObjects/CBank.h +++ b/lib/mapObjects/CBank.h @@ -23,7 +23,7 @@ class DLL_LINKAGE CBank : public CArmedInstance ui32 resetDuration; bool coastVisitable; - void setPropertyDer(ui8 what, ui32 val) override; + void setPropertyDer(ObjProperty what, ObjPropertyID identifier) override; void doVisit(const CGHeroInstance * hero) const; public: diff --git a/lib/mapObjects/CGCreature.cpp b/lib/mapObjects/CGCreature.cpp index 48349beb5..f76915582 100644 --- a/lib/mapObjects/CGCreature.cpp +++ b/lib/mapObjects/CGCreature.cpp @@ -266,31 +266,28 @@ void CGCreature::newTurn(CRandomGenerator & rand) const if (stacks.begin()->second->count < VLC->settings()->getInteger(EGameSettings::CREATURES_WEEKLY_GROWTH_CAP) && cb->getDate(Date::DAY_OF_WEEK) == 1 && cb->getDate(Date::DAY) > 1) { ui32 power = static_cast(temppower * (100 + VLC->settings()->getInteger(EGameSettings::CREATURES_WEEKLY_GROWTH_PERCENT)) / 100); - cb->setObjProperty(id, ObjProperty::MONSTER_COUNT, std::min(power / 1000, VLC->settings()->getInteger(EGameSettings::CREATURES_WEEKLY_GROWTH_CAP))); //set new amount - cb->setObjProperty(id, ObjProperty::MONSTER_POWER, power); //increase temppower + cb->setObjPropertyValue(id, ObjProperty::MONSTER_COUNT, std::min(power / 1000, VLC->settings()->getInteger(EGameSettings::CREATURES_WEEKLY_GROWTH_CAP))); //set new amount + cb->setObjPropertyValue(id, ObjProperty::MONSTER_POWER, power); //increase temppower } } if (VLC->settings()->getBoolean(EGameSettings::MODULE_STACK_EXPERIENCE)) - cb->setObjProperty(id, ObjProperty::MONSTER_EXP, VLC->settings()->getInteger(EGameSettings::CREATURES_DAILY_STACK_EXPERIENCE)); //for testing purpose + cb->setObjPropertyValue(id, ObjProperty::MONSTER_EXP, VLC->settings()->getInteger(EGameSettings::CREATURES_DAILY_STACK_EXPERIENCE)); //for testing purpose } -void CGCreature::setPropertyDer(ui8 what, ui32 val) +void CGCreature::setPropertyDer(ObjProperty what, ObjPropertyID identifier) { switch (what) { case ObjProperty::MONSTER_COUNT: - stacks[SlotID(0)]->count = val; + stacks[SlotID(0)]->count = identifier.getNum(); break; case ObjProperty::MONSTER_POWER: - temppower = val; + temppower = identifier.getNum(); break; case ObjProperty::MONSTER_EXP: - giveStackExp(val); - break; - case ObjProperty::MONSTER_RESTORE_TYPE: - formation.basicType = val; + giveStackExp(identifier.getNum()); break; case ObjProperty::MONSTER_REFUSED_JOIN: - refusedJoining = val; + refusedJoining = identifier.getNum(); break; } } @@ -368,7 +365,7 @@ int CGCreature::takenAction(const CGHeroInstance *h, bool allowJoin) const void CGCreature::fleeDecision(const CGHeroInstance *h, ui32 pursue) const { if(refusedJoining) - cb->setObjProperty(id, ObjProperty::MONSTER_REFUSED_JOIN, false); + cb->setObjPropertyValue(id, ObjProperty::MONSTER_REFUSED_JOIN, false); if(pursue) { @@ -386,7 +383,7 @@ void CGCreature::joinDecision(const CGHeroInstance *h, int cost, ui32 accept) co { if(takenAction(h,false) == FLEE) { - cb->setObjProperty(id, ObjProperty::MONSTER_REFUSED_JOIN, true); + cb->setObjPropertyValue(id, ObjProperty::MONSTER_REFUSED_JOIN, true); flee(h); } else //they fight @@ -421,10 +418,6 @@ void CGCreature::joinDecision(const CGHeroInstance *h, int cost, ui32 accept) co void CGCreature::fight( const CGHeroInstance *h ) const { //split stacks - //TODO: multiple creature types in a stack? - int basicType = stacks.begin()->second->type->getId(); - cb->setObjProperty(id, ObjProperty::MONSTER_RESTORE_TYPE, basicType); //store info about creature stack - int stacksCount = getNumberOfStacks(h); //source: http://heroescommunity.com/viewthread.php3?TID=27539&PID=1266335#focus @@ -488,7 +481,7 @@ void CGCreature::battleFinished(const CGHeroInstance *hero, const BattleResult & { //merge stacks into one TSlots::const_iterator i; - CCreature * cre = VLC->creh->objects[formation.basicType]; + const CCreature * cre = getCreature().toCreature(); for(i = stacks.begin(); i != stacks.end(); i++) { if(cre->isMyUpgrade(i->second->type)) @@ -513,7 +506,7 @@ void CGCreature::battleFinished(const CGHeroInstance *hero, const BattleResult & cb->moveStack(StackLocation(this, i->first), StackLocation(this, slot), i->second->count); } - cb->setObjProperty(id, ObjProperty::MONSTER_POWER, stacks.begin()->second->count * 1000); //remember casualties + cb->setObjPropertyValue(id, ObjProperty::MONSTER_POWER, stacks.begin()->second->count * 1000); //remember casualties } } diff --git a/lib/mapObjects/CGCreature.h b/lib/mapObjects/CGCreature.h index f2101d3b0..4d33ecdf3 100644 --- a/lib/mapObjects/CGCreature.h +++ b/lib/mapObjects/CGCreature.h @@ -54,17 +54,6 @@ public: bool containsUpgradedStack() const; int getNumberOfStacks(const CGHeroInstance *hero) const; - struct DLL_LINKAGE formationInfo // info about merging stacks after battle back into one - { - si32 basicType; - ui8 upgrade; //random seed used to determine number of stacks and is there's upgraded stack - template void serialize(Handler &h, const int version) - { - h & basicType; - h & upgrade; - } - } formation; - template void serialize(Handler &h, const int version) { h & static_cast(*this); @@ -80,7 +69,7 @@ public: h & formation; } protected: - void setPropertyDer(ui8 what, ui32 val) override; + void setPropertyDer(ObjProperty what, ObjPropertyID identifier) override; void serializeJsonOptions(JsonSerializeFormat & handler) override; private: diff --git a/lib/mapObjects/CGDwelling.cpp b/lib/mapObjects/CGDwelling.cpp index 262aab99d..f405ed8d7 100644 --- a/lib/mapObjects/CGDwelling.cpp +++ b/lib/mapObjects/CGDwelling.cpp @@ -201,7 +201,7 @@ void CGDwelling::initObj(CRandomGenerator & rand) } } -void CGDwelling::setPropertyDer(ui8 what, ui32 val) +void CGDwelling::setPropertyDer(ObjProperty what, ObjPropertyID identifier) { switch (what) { @@ -214,14 +214,14 @@ void CGDwelling::setPropertyDer(ui8 what, ui32 val) std::vector >* dwellings = &cb->gameState()->players[tempOwner].dwellings; dwellings->erase (std::find(dwellings->begin(), dwellings->end(), this)); } - if (PlayerColor(val) != PlayerColor::NEUTRAL) //can new owner be neutral? - cb->gameState()->players[PlayerColor(val)].dwellings.emplace_back(this); + if (identifier.as().isValidPlayer()) + cb->gameState()->players[identifier.as()].dwellings.emplace_back(this); } break; case ObjProperty::AVAILABLE_CREATURE: creatures.resize(1); creatures[0].second.resize(1); - creatures[0].second[0] = CreatureID(val); + creatures[0].second[0] = identifier.as(); break; } } @@ -300,7 +300,7 @@ void CGDwelling::newTurn(CRandomGenerator & rand) const if(ID == Obj::REFUGEE_CAMP) //if it's a refugee camp, we need to pick an available creature { - cb->setObjProperty(id, ObjProperty::AVAILABLE_CREATURE, VLC->creh->pickRandomMonster(rand)); + cb->setObjPropertyID(id, ObjProperty::AVAILABLE_CREATURE, VLC->creh->pickRandomMonster(rand)); } bool change = false; diff --git a/lib/mapObjects/CGDwelling.h b/lib/mapObjects/CGDwelling.h index 7bed887db..09fc96ca4 100644 --- a/lib/mapObjects/CGDwelling.h +++ b/lib/mapObjects/CGDwelling.h @@ -52,7 +52,7 @@ private: void initObj(CRandomGenerator & rand) override; void onHeroVisit(const CGHeroInstance * h) const override; void newTurn(CRandomGenerator & rand) const override; - void setPropertyDer(ui8 what, ui32 val) override; + void setPropertyDer(ObjProperty what, ObjPropertyID identifier) override; void battleFinished(const CGHeroInstance *hero, const BattleResult &result) const override; void blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const override; std::vector getPopupComponents(PlayerColor player) const override; diff --git a/lib/mapObjects/CGHeroInstance.cpp b/lib/mapObjects/CGHeroInstance.cpp index 241493075..6fa16d8ce 100644 --- a/lib/mapObjects/CGHeroInstance.cpp +++ b/lib/mapObjects/CGHeroInstance.cpp @@ -348,7 +348,7 @@ void CGHeroInstance::initHero(CRandomGenerator & rand) if (gender == EHeroGender::DEFAULT) gender = type->gender; - setFormation(false); + setFormation(EArmyFormation::LOOSE); if (!stacksCount()) //standard army//initial army { initArmy(rand); @@ -501,7 +501,7 @@ void CGHeroInstance::onHeroVisit(const CGHeroInstance * h) const SetMovePoints smp; smp.hid = id; - cb->setManaPoints (id, manaLimit()); + cb->setManaPoints (id, manaLimit()); ObjectInstanceID boatId; const auto boatPos = visitablePos(); @@ -520,7 +520,7 @@ void CGHeroInstance::onHeroVisit(const CGHeroInstance * h) const smp.val = movementPointsLimit(true); } cb->giveHero(id, h->tempOwner, boatId); //recreates def and adds hero to player - cb->setObjProperty(id, ObjProperty::ID, Obj::HERO); //set ID to 34 AFTER hero gets correct flag color + cb->setObjPropertyID(id, ObjProperty::ID, Obj(Obj::HERO)); //set ID to 34 AFTER hero gets correct flag color cb->setMovePoints (&smp); h->showInfoDialog(102); @@ -620,10 +620,10 @@ void CGHeroInstance::updateSkillBonus(const SecondarySkill & which, int val) addNewBonus(std::make_shared(*b)); } -void CGHeroInstance::setPropertyDer( ui8 what, ui32 val ) +void CGHeroInstance::setPropertyDer(ObjProperty what, ObjPropertyID identifier) { if(what == ObjProperty::PRIMARY_STACK_COUNT) - setStackCount(SlotID(0), val); + setStackCount(SlotID(0), identifier.getNum()); } double CGHeroInstance::getFightingStrength() const diff --git a/lib/mapObjects/CGHeroInstance.h b/lib/mapObjects/CGHeroInstance.h index a07ccff9c..2ddc83e2c 100644 --- a/lib/mapObjects/CGHeroInstance.h +++ b/lib/mapObjects/CGHeroInstance.h @@ -307,7 +307,7 @@ public: bool isCoastVisitable() const override; BattleField getBattlefield() const override; protected: - void setPropertyDer(ui8 what, ui32 val) override;//synchr + void setPropertyDer(ObjProperty what, ObjPropertyID identifier) override;//synchr ///common part of hero instance and hero definition void serializeCommonOptions(JsonSerializeFormat & handler); diff --git a/lib/mapObjects/CGMarket.cpp b/lib/mapObjects/CGMarket.cpp index d6a1e433d..b429a84fe 100644 --- a/lib/mapObjects/CGMarket.cpp +++ b/lib/mapObjects/CGMarket.cpp @@ -91,7 +91,7 @@ void CGBlackMarket::newTurn(CRandomGenerator & rand) const return; SetAvailableArtifacts saa; - saa.id = id.getNum(); + saa.id = id; cb->pickAllowedArtsSet(saa.arts, rand); cb->sendAndApply(&saa); } diff --git a/lib/mapObjects/CGObjectInstance.cpp b/lib/mapObjects/CGObjectInstance.cpp index 74546c07c..3112c8e85 100644 --- a/lib/mapObjects/CGObjectInstance.cpp +++ b/lib/mapObjects/CGObjectInstance.cpp @@ -181,23 +181,20 @@ void CGObjectInstance::initObj(CRandomGenerator & rand) } } -void CGObjectInstance::setProperty( ui8 what, ui32 val ) +void CGObjectInstance::setProperty( ObjProperty what, ObjPropertyID identifier ) { - setPropertyDer(what, val); // call this before any actual changes (needed at least for dwellings) + setPropertyDer(what, identifier); // call this before any actual changes (needed at least for dwellings) switch(what) { case ObjProperty::OWNER: - tempOwner = PlayerColor(val); + tempOwner = identifier.as(); break; case ObjProperty::BLOCKVIS: - blockVisit = val; + blockVisit = identifier.getNum(); break; case ObjProperty::ID: - ID = Obj(val); - break; - case ObjProperty::SUBID: - subID = val; + ID = identifier.as(); break; } } @@ -207,7 +204,7 @@ TObjectTypeHandler CGObjectInstance::getObjectHandler() const return VLC->objtypeh->getHandlerFor(ID, subID); } -void CGObjectInstance::setPropertyDer( ui8 what, ui32 val ) +void CGObjectInstance::setPropertyDer( ObjProperty what, ObjPropertyID identifier ) {} int3 CGObjectInstance::getSightCenter() const @@ -229,7 +226,7 @@ void CGObjectInstance::giveDummyBonus(const ObjectInstanceID & heroID, BonusDura { GiveBonus gbonus; gbonus.bonus.type = BonusType::NONE; - gbonus.id = heroID.getNum(); + gbonus.id = heroID; gbonus.bonus.duration = duration; gbonus.bonus.source = BonusSource::OBJECT_TYPE; gbonus.bonus.sid = BonusSourceID(ID); diff --git a/lib/mapObjects/CGObjectInstance.h b/lib/mapObjects/CGObjectInstance.h index 01eeffd2d..71cbabd41 100644 --- a/lib/mapObjects/CGObjectInstance.h +++ b/lib/mapObjects/CGObjectInstance.h @@ -127,7 +127,7 @@ public: void pickRandomObject(CRandomGenerator & rand) override; void onHeroVisit(const CGHeroInstance * h) const override; /// method for synchronous update. Note: For new properties classes should override setPropertyDer instead - void setProperty(ui8 what, ui32 val) final; + void setProperty(ObjProperty what, ObjPropertyID identifier) final; virtual void afterAddToMap(CMap * map); virtual void afterRemoveFromMap(CMap * map); @@ -154,7 +154,7 @@ public: protected: /// virtual method that allows synchronously update object state on server and all clients - virtual void setPropertyDer(ui8 what, ui32 val); + virtual void setPropertyDer(ObjProperty what, ObjPropertyID identifier); /// Called mostly during map randomization to turn random object into a regular one (e.g. "Random Monster" into "Pikeman") void setType(MapObjectID ID, MapObjectSubID subID); diff --git a/lib/mapObjects/CGTownBuilding.cpp b/lib/mapObjects/CGTownBuilding.cpp index 1406786f9..f00aa72f2 100644 --- a/lib/mapObjects/CGTownBuilding.cpp +++ b/lib/mapObjects/CGTownBuilding.cpp @@ -120,12 +120,12 @@ COPWBonus::COPWBonus(const BuildingID & bid, BuildingSubID::EBuildingSubID subId indexOnTV = static_cast(town->bonusingBuildings.size()); } -void COPWBonus::setProperty(ui8 what, ui32 val) +void COPWBonus::setProperty(ObjProperty what, ObjPropertyID identifier) { switch (what) { case ObjProperty::VISITORS: - visitors.insert(val); + visitors.insert(identifier.as()); break; case ObjProperty::STRUCTURE_CLEAR_VISITORS: visitors.clear(); @@ -148,7 +148,7 @@ void COPWBonus::onHeroVisit (const CGHeroInstance * h) const { GiveBonus gb; gb.bonus = Bonus(BonusDuration::ONE_WEEK, BonusType::MOVEMENT, BonusSource::OBJECT_TYPE, 600, BonusSourceID(Obj(Obj::STABLES)), BonusCustomSubtype::heroMovementLand, VLC->generaltexth->arraytxt[100]); - gb.id = heroID.getNum(); + gb.id = heroID; cb->giveHeroBonus(&gb); SetMovePoints mp; @@ -187,10 +187,10 @@ CTownBonus::CTownBonus(const BuildingID & index, BuildingSubID::EBuildingSubID s indexOnTV = static_cast(town->bonusingBuildings.size()); } -void CTownBonus::setProperty (ui8 what, ui32 val) +void CTownBonus::setProperty(ObjProperty what, ObjPropertyID identifier) { if(what == ObjProperty::VISITORS) - visitors.insert(ObjectInstanceID(val)); + visitors.insert(identifier.as()); } void CTownBonus::onHeroVisit (const CGHeroInstance * h) const @@ -272,7 +272,7 @@ void CTownBonus::applyBonuses(CGHeroInstance * h, const BonusList & bonuses) con bonus->duration = BonusDuration::ONE_DAY; } gb.bonus = * bonus; - gb.id = h->id.getNum(); + gb.id = h->id; cb->giveHeroBonus(&gb); if(bonus->duration == BonusDuration::PERMANENT) @@ -318,21 +318,21 @@ void CTownRewardableBuilding::newTurn(CRandomGenerator & rand) const { if(configuration.resetParameters.rewards) { - cb->setObjProperty(town->id, ObjProperty::REWARD_RANDOMIZE, indexOnTV); + cb->setObjPropertyValue(town->id, ObjProperty::REWARD_RANDOMIZE, indexOnTV); } if(configuration.resetParameters.visitors) { - cb->setObjProperty(town->id, ObjProperty::STRUCTURE_CLEAR_VISITORS, indexOnTV); + cb->setObjPropertyValue(town->id, ObjProperty::STRUCTURE_CLEAR_VISITORS, indexOnTV); } } } -void CTownRewardableBuilding::setProperty(ui8 what, ui32 val) +void CTownRewardableBuilding::setProperty(ObjProperty what, ObjPropertyID identifier) { switch (what) { case ObjProperty::VISITORS: - visitors.insert(ObjectInstanceID(val)); + visitors.insert(identifier.as()); break; case ObjProperty::STRUCTURE_CLEAR_VISITORS: visitors.clear(); @@ -341,7 +341,7 @@ void CTownRewardableBuilding::setProperty(ui8 what, ui32 val) initObj(cb->gameState()->getRandomGenerator()); break; case ObjProperty::REWARD_SELECT: - selectedReward = val; + selectedReward = identifier.getNum(); break; } } diff --git a/lib/mapObjects/CGTownBuilding.h b/lib/mapObjects/CGTownBuilding.h index 77085f67f..47da63af5 100644 --- a/lib/mapObjects/CGTownBuilding.h +++ b/lib/mapObjects/CGTownBuilding.h @@ -69,8 +69,8 @@ protected: class DLL_LINKAGE COPWBonus : public CGTownBuilding {///used for OPW bonusing structures public: - std::set visitors; - void setProperty(ui8 what, ui32 val) override; + std::set visitors; + void setProperty(ObjProperty what, ObjPropertyID identifier) override; void onHeroVisit (const CGHeroInstance * h) const override; COPWBonus(const BuildingID & index, BuildingSubID::EBuildingSubID subId, CGTownInstance * TOWN); @@ -89,7 +89,7 @@ class DLL_LINKAGE CTownBonus : public CGTownBuilding ///feel free to merge inheritance tree public: std::set visitors; - void setProperty(ui8 what, ui32 val) override; + void setProperty(ObjProperty what, ObjPropertyID identifier) override; void onHeroVisit (const CGHeroInstance * h) const override; CTownBonus(const BuildingID & index, BuildingSubID::EBuildingSubID subId, CGTownInstance * TOWN); @@ -117,7 +117,7 @@ class DLL_LINKAGE CTownRewardableBuilding : public CGTownBuilding, public Reward void grantReward(ui32 rewardID, const CGHeroInstance * hero) const; public: - void setProperty(ui8 what, ui32 val) override; + void setProperty(ObjProperty what, ObjPropertyID identifier) override; void onHeroVisit(const CGHeroInstance * h) const override; void newTurn(CRandomGenerator & rand) const override; diff --git a/lib/mapObjects/CGTownInstance.cpp b/lib/mapObjects/CGTownInstance.cpp index 4916af24a..f2c331f50 100644 --- a/lib/mapObjects/CGTownInstance.cpp +++ b/lib/mapObjects/CGTownInstance.cpp @@ -53,28 +53,28 @@ int CGTownInstance::getSightRadius() const //returns sight distance return ret; } -void CGTownInstance::setPropertyDer(ui8 what, ui32 val) +void CGTownInstance::setPropertyDer(ObjProperty what, ObjPropertyID identifier) { ///this is freakin' overcomplicated solution switch (what) { case ObjProperty::STRUCTURE_ADD_VISITING_HERO: - bonusingBuildings[val]->setProperty(ObjProperty::VISITORS, visitingHero->id.getNum()); + bonusingBuildings[identifier.getNum()]->setProperty(ObjProperty::VISITORS, visitingHero->id); break; case ObjProperty::STRUCTURE_CLEAR_VISITORS: - bonusingBuildings[val]->setProperty(ObjProperty::STRUCTURE_CLEAR_VISITORS, 0); + bonusingBuildings[identifier.getNum()]->setProperty(ObjProperty::STRUCTURE_CLEAR_VISITORS, NumericID(0)); break; case ObjProperty::STRUCTURE_ADD_GARRISONED_HERO: //add garrisoned hero to visitors - bonusingBuildings[val]->setProperty(ObjProperty::VISITORS, garrisonHero->id.getNum()); + bonusingBuildings[identifier.getNum()]->setProperty(ObjProperty::VISITORS, garrisonHero->id); break; case ObjProperty::BONUS_VALUE_FIRST: - bonusValue.first = val; + bonusValue.first = identifier.getNum(); break; case ObjProperty::BONUS_VALUE_SECOND: - bonusValue.second = val; + bonusValue.second = identifier.getNum(); break; case ObjProperty::REWARD_RANDOMIZE: - bonusingBuildings[val]->setProperty(ObjProperty::REWARD_RANDOMIZE, 0); + bonusingBuildings[identifier.getNum()]->setProperty(ObjProperty::REWARD_RANDOMIZE, NumericID(0)); break; } } @@ -534,12 +534,12 @@ void CGTownInstance::newTurn(CRandomGenerator & rand) const resID = (resID==2)?1:resID; int resVal = rand.nextInt(1, 4);//with size 1..4 cb->giveResource(tempOwner, static_cast(resID), resVal); - cb->setObjProperty (id, ObjProperty::BONUS_VALUE_FIRST, resID); - cb->setObjProperty (id, ObjProperty::BONUS_VALUE_SECOND, resVal); + cb->setObjPropertyValue(id, ObjProperty::BONUS_VALUE_FIRST, resID); + cb->setObjPropertyValue(id, ObjProperty::BONUS_VALUE_SECOND, resVal); } for(const auto * manaVortex : getBonusingBuildings(BuildingSubID::MANA_VORTEX)) - cb->setObjProperty(id, ObjProperty::STRUCTURE_CLEAR_VISITORS, manaVortex->indexOnTV); //reset visitors for Mana Vortex + cb->setObjPropertyValue(id, ObjProperty::STRUCTURE_CLEAR_VISITORS, manaVortex->indexOnTV); //reset visitors for Mana Vortex //get Mana Vortex or Stables bonuses //same code is in the CGameHandler::buildStructure method @@ -1072,9 +1072,9 @@ CBuilding::TRequired CGTownInstance::genBuildingRequirements(const BuildingID & void CGTownInstance::addHeroToStructureVisitors(const CGHeroInstance *h, si64 structureInstanceID ) const { if(visitingHero == h) - cb->setObjProperty(id, ObjProperty::STRUCTURE_ADD_VISITING_HERO, structureInstanceID); //add to visitors + cb->setObjPropertyValue(id, ObjProperty::STRUCTURE_ADD_VISITING_HERO, structureInstanceID); //add to visitors else if(garrisonHero == h) - cb->setObjProperty(id, ObjProperty::STRUCTURE_ADD_GARRISONED_HERO, structureInstanceID); //then it must be garrisoned hero + cb->setObjPropertyValue(id, ObjProperty::STRUCTURE_ADD_GARRISONED_HERO, structureInstanceID); //then it must be garrisoned hero else { //should never ever happen diff --git a/lib/mapObjects/CGTownInstance.h b/lib/mapObjects/CGTownInstance.h index 4a5e00511..37b6f7dfc 100644 --- a/lib/mapObjects/CGTownInstance.h +++ b/lib/mapObjects/CGTownInstance.h @@ -211,7 +211,7 @@ public: return defendingHero && garrisonHero && defendingHero != garrisonHero; } protected: - void setPropertyDer(ui8 what, ui32 val) override; + void setPropertyDer(ObjProperty what, ObjPropertyID identifier) override; void serializeJsonOptions(JsonSerializeFormat & handler) override; void blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const override; diff --git a/lib/mapObjects/CQuest.cpp b/lib/mapObjects/CQuest.cpp index 5868869ca..957c81757 100644 --- a/lib/mapObjects/CQuest.cpp +++ b/lib/mapObjects/CQuest.cpp @@ -544,18 +544,18 @@ std::vector CGSeerHut::getPopupComponents(const CGHeroInstance * hero return result; } -void CGSeerHut::setPropertyDer(ui8 what, ui32 val) +void CGSeerHut::setPropertyDer(ObjProperty what, ObjPropertyID identifier) { switch(what) { - case CGSeerHut::SEERHUT_VISITED: + case ObjProperty::SEERHUT_VISITED: { - quest->activeForPlayers.emplace(val); + quest->activeForPlayers.emplace(identifier.as()); break; } - case CGSeerHut::SEERHUT_COMPLETE: + case ObjProperty::SEERHUT_COMPLETE: { - quest->isCompleted = val; + quest->isCompleted = identifier.getNum(); quest->activeForPlayers.clear(); break; } @@ -567,7 +567,7 @@ void CGSeerHut::newTurn(CRandomGenerator & rand) const CRewardableObject::newTurn(rand); if(quest->lastDay >= 0 && quest->lastDay <= cb->getDate() - 1) //time is up { - cb->setObjProperty (id, CGSeerHut::SEERHUT_COMPLETE, true); + cb->setObjPropertyValue(id, ObjProperty::SEERHUT_COMPLETE, true); } } @@ -582,7 +582,7 @@ void CGSeerHut::onHeroVisit(const CGHeroInstance * h) const if(firstVisit) { - cb->setObjProperty(id, CGSeerHut::SEERHUT_VISITED, h->getOwner()); + cb->setObjPropertyID(id, ObjProperty::SEERHUT_VISITED, h->getOwner()); AddQuest aq; aq.quest = QuestInfo (quest, this, visitablePos()); @@ -665,7 +665,7 @@ void CGSeerHut::blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) if(answer) { quest->completeQuest(cb, hero); - cb->setObjProperty(id, CGSeerHut::SEERHUT_COMPLETE, !quest->repeatedQuest); //mission complete + cb->setObjPropertyValue(id, ObjProperty::SEERHUT_COMPLETE, !quest->repeatedQuest); //mission complete } } @@ -764,7 +764,7 @@ void CGQuestGuard::onHeroVisit(const CGHeroInstance * h) const if(!quest->isCompleted) CGSeerHut::onHeroVisit(h); else - cb->setObjProperty(id, CGSeerHut::SEERHUT_COMPLETE, false); + cb->setObjPropertyValue(id, ObjProperty::SEERHUT_COMPLETE, false); } bool CGQuestGuard::passableFor(PlayerColor color) const @@ -783,15 +783,14 @@ void CGKeys::reset() playerKeyMap.clear(); } -void CGKeys::setPropertyDer (ui8 what, ui32 val) //101-108 - enable key for player 1-8 +void CGKeys::setPropertyDer (ObjProperty what, ObjPropertyID identifier) { - if (what >= 101 && what <= (100 + PlayerColor::PLAYER_LIMIT_I)) + if (what == ObjProperty::KEYMASTER_VISITED) { - PlayerColor player(what-101); - playerKeyMap[player].insert(static_cast(val)); + playerKeyMap[identifier.as()].insert(subID); } else - logGlobal->error("Unexpected properties requested to set: what=%d, val=%d", static_cast(what), val); + logGlobal->error("Unexpected properties requested to set: what=%d, val=%d", static_cast(what), identifier.getNum()); } bool CGKeys::wasMyColorVisited(const PlayerColor & player) const @@ -819,7 +818,7 @@ void CGKeymasterTent::onHeroVisit( const CGHeroInstance * h ) const int txt_id; if (!wasMyColorVisited (h->getOwner()) ) { - cb->setObjProperty(id, h->tempOwner.getNum()+101, subID); + cb->setObjPropertyID(id, ObjProperty::KEYMASTER_VISITED, h->tempOwner); txt_id=19; } else diff --git a/lib/mapObjects/CQuest.h b/lib/mapObjects/CQuest.h index 6f9dbd017..3dba2903d 100644 --- a/lib/mapObjects/CQuest.h +++ b/lib/mapObjects/CQuest.h @@ -144,10 +144,7 @@ public: h & seerName; } protected: - static constexpr int SEERHUT_VISITED = 10; - static constexpr int SEERHUT_COMPLETE = 11; - - void setPropertyDer(ui8 what, ui32 val) override; + void setPropertyDer(ObjProperty what, ObjPropertyID identifier) override; void serializeJsonOptions(JsonSerializeFormat & handler) override; }; @@ -186,7 +183,7 @@ public: h & static_cast(*this); } protected: - void setPropertyDer(ui8 what, ui32 val) override; + void setPropertyDer(ObjProperty what, ObjPropertyID identifier) override; }; class DLL_LINKAGE CGKeymasterTent : public CGKeys diff --git a/lib/mapObjects/CRewardableObject.cpp b/lib/mapObjects/CRewardableObject.cpp index 1d441b9f3..eaf9b797a 100644 --- a/lib/mapObjects/CRewardableObject.cpp +++ b/lib/mapObjects/CRewardableObject.cpp @@ -169,7 +169,7 @@ void CRewardableObject::blockingDialogAnswered(const CGHeroInstance *hero, ui32 void CRewardableObject::markAsVisited(const CGHeroInstance * hero) const { - cb->setObjProperty(id, ObjProperty::REWARD_CLEARED, true); + cb->setObjPropertyValue(id, ObjProperty::REWARD_CLEARED, true); ChangeObjectVisitors cov(ChangeObjectVisitors::VISITOR_ADD, id, hero->id); cb->sendAndApply(&cov); @@ -177,7 +177,7 @@ void CRewardableObject::markAsVisited(const CGHeroInstance * hero) const void CRewardableObject::grantReward(ui32 rewardID, const CGHeroInstance * hero) const { - cb->setObjProperty(id, ObjProperty::REWARD_SELECT, rewardID); + cb->setObjPropertyValue(id, ObjProperty::REWARD_SELECT, rewardID); grantRewardBeforeLevelup(cb, configuration.info.at(rewardID), hero); // hero is not blocked by levelup dialog - grant remainer immediately @@ -338,7 +338,7 @@ std::vector CRewardableObject::getPopupComponents(const CGHeroInstanc return getPopupComponentsImpl(hero->getOwner(), hero); } -void CRewardableObject::setPropertyDer(ui8 what, ui32 val) +void CRewardableObject::setPropertyDer(ObjProperty what, ObjPropertyID identifier) { switch (what) { @@ -346,10 +346,10 @@ void CRewardableObject::setPropertyDer(ui8 what, ui32 val) initObj(cb->gameState()->getRandomGenerator()); break; case ObjProperty::REWARD_SELECT: - selectedReward = val; + selectedReward = identifier.getNum(); break; case ObjProperty::REWARD_CLEARED: - onceVisitableObjectCleared = val; + onceVisitableObjectCleared = identifier.getNum(); break; } } @@ -360,11 +360,11 @@ void CRewardableObject::newTurn(CRandomGenerator & rand) const { if (configuration.resetParameters.rewards) { - cb->setObjProperty(id, ObjProperty::REWARD_RANDOMIZE, 0); + cb->setObjPropertyValue(id, ObjProperty::REWARD_RANDOMIZE, 0); } if (configuration.resetParameters.visitors) { - cb->setObjProperty(id, ObjProperty::REWARD_CLEARED, false); + cb->setObjPropertyValue(id, ObjProperty::REWARD_CLEARED, false); ChangeObjectVisitors cov(ChangeObjectVisitors::VISITOR_CLEAR, id); cb->sendAndApply(&cov); } diff --git a/lib/mapObjects/CRewardableObject.h b/lib/mapObjects/CRewardableObject.h index 3d9484dca..fa31f963d 100644 --- a/lib/mapObjects/CRewardableObject.h +++ b/lib/mapObjects/CRewardableObject.h @@ -65,7 +65,7 @@ public: void initObj(CRandomGenerator & rand) override; - void setPropertyDer(ui8 what, ui32 val) override; + void setPropertyDer(ObjProperty what, ObjPropertyID identifier) override; CRewardableObject(); diff --git a/lib/mapObjects/IObjectInterface.cpp b/lib/mapObjects/IObjectInterface.cpp index b0e0b11cd..caaa497b8 100644 --- a/lib/mapObjects/IObjectInterface.cpp +++ b/lib/mapObjects/IObjectInterface.cpp @@ -49,7 +49,7 @@ void IObjectInterface::initObj(CRandomGenerator & rand) void IObjectInterface::pickRandomObject(CRandomGenerator & rand) {} -void IObjectInterface::setProperty( ui8 what, ui32 val ) +void IObjectInterface::setProperty(ObjProperty what, ObjPropertyID identifier) {} bool IObjectInterface::wasVisited (PlayerColor player) const diff --git a/lib/mapObjects/IObjectInterface.h b/lib/mapObjects/IObjectInterface.h index 8dab1a59d..7cf9c8525 100644 --- a/lib/mapObjects/IObjectInterface.h +++ b/lib/mapObjects/IObjectInterface.h @@ -10,6 +10,7 @@ #pragma once #include "../networkPacks/EInfoWindowMode.h" +#include "../networkPacks/ObjProperty.h" #include "../constants/EntityIdentifiers.h" VCMI_LIB_NAMESPACE_BEGIN @@ -46,7 +47,7 @@ public: virtual void newTurn(CRandomGenerator & rand) const; virtual void initObj(CRandomGenerator & rand); //synchr virtual void pickRandomObject(CRandomGenerator & rand); - virtual void setProperty(ui8 what, ui32 val);//synchr + virtual void setProperty(ObjProperty what, ObjPropertyID identifier);//synchr //Called when queries created DURING HERO VISIT are resolved //First parameter is always hero that visited object and triggered the query diff --git a/lib/mapObjects/MiscObjects.cpp b/lib/mapObjects/MiscObjects.cpp index ae7daee89..c82484c54 100644 --- a/lib/mapObjects/MiscObjects.cpp +++ b/lib/mapObjects/MiscObjects.cpp @@ -44,10 +44,10 @@ static std::string visitedTxt(const bool visited) return VLC->generaltexth->allTexts[id]; } -void CTeamVisited::setPropertyDer(ui8 what, ui32 val) +void CTeamVisited::setPropertyDer(ObjProperty what, ObjPropertyID identifier) { - if(what == CTeamVisited::OBJPROP_VISITED) - players.insert(PlayerColor(val)); + if(what == ObjProperty::VISITED) + players.insert(identifier.as()); } bool CTeamVisited::wasVisited(PlayerColor player) const @@ -1195,13 +1195,13 @@ void CGObelisk::onHeroVisit( const CGHeroInstance * h ) const cb->sendAndApply(&iw); // increment general visited obelisks counter - cb->setObjProperty(id, CGObelisk::OBJPROP_INC, team.getNum()); + cb->setObjPropertyID(id, ObjProperty::OBELISK_VISITED, team); cb->showObjectWindow(this, EOpenWindowMode::PUZZLE_MAP, h, false); // mark that particular obelisk as visited for all players in the team for(const auto & color : ts->players) { - cb->setObjProperty(id, CGObelisk::OBJPROP_VISITED, color.getNum()); + cb->setObjPropertyID(id, ObjProperty::VISITED, color); } } else @@ -1228,14 +1228,14 @@ std::string CGObelisk::getHoverText(PlayerColor player) const return getObjectName() + " " + visitedTxt(wasVisited(player)); } -void CGObelisk::setPropertyDer( ui8 what, ui32 val ) +void CGObelisk::setPropertyDer(ObjProperty what, ObjPropertyID identifier) { switch(what) { - case CGObelisk::OBJPROP_INC: + case ObjProperty::OBELISK_VISITED: { - auto progress = ++visited[TeamID(val)]; - logGlobal->debug("Player %d: obelisk progress %d / %d", val, static_cast(progress) , static_cast(obeliskCount)); + auto progress = ++visited[identifier.as()]; + logGlobal->debug("Player %d: obelisk progress %d / %d", identifier.getNum(), static_cast(progress) , static_cast(obeliskCount)); if(progress > obeliskCount) { @@ -1246,7 +1246,7 @@ void CGObelisk::setPropertyDer( ui8 what, ui32 val ) break; } default: - CTeamVisited::setPropertyDer(what, val); + CTeamVisited::setPropertyDer(what, identifier); break; } } @@ -1263,7 +1263,7 @@ void CGLighthouse::onHeroVisit( const CGHeroInstance * h ) const if(oldOwner.isValidPlayer()) //remove bonus from old owner { RemoveBonus rb(GiveBonus::ETarget::PLAYER); - rb.whoID = oldOwner.getNum(); + rb.whoID = oldOwner; rb.source = BonusSource::OBJECT_INSTANCE; rb.id = BonusSourceID(id); cb->sendAndApply(&rb); @@ -1285,7 +1285,7 @@ void CGLighthouse::giveBonusTo(const PlayerColor & player, bool onInit) const GiveBonus gb(GiveBonus::ETarget::PLAYER); gb.bonus.type = BonusType::MOVEMENT; gb.bonus.val = 500; - gb.id = player.getNum(); + gb.id = player; gb.bonus.duration = BonusDuration::PERMANENT; gb.bonus.source = BonusSource::OBJECT_INSTANCE; gb.bonus.sid = BonusSourceID(id); diff --git a/lib/mapObjects/MiscObjects.h b/lib/mapObjects/MiscObjects.h index 6851888fa..de8ae3862 100644 --- a/lib/mapObjects/MiscObjects.h +++ b/lib/mapObjects/MiscObjects.h @@ -29,15 +29,13 @@ public: bool wasVisited (const CGHeroInstance * h) const override; bool wasVisited(PlayerColor player) const override; bool wasVisited(const TeamID & team) const; - void setPropertyDer(ui8 what, ui32 val) override; + void setPropertyDer(ObjProperty what, ObjPropertyID identifier) override; template void serialize(Handler &h, const int version) { h & static_cast(*this); h & players; } - - static constexpr int OBJPROP_VISITED = 10; }; class DLL_LINKAGE CGSignBottle : public CGObjectInstance //signs and ocean bottles @@ -361,7 +359,6 @@ class DLL_LINKAGE CGDenOfthieves : public CGObjectInstance class DLL_LINKAGE CGObelisk : public CTeamVisited { public: - static constexpr int OBJPROP_INC = 20; static ui8 obeliskCount; //how many obelisks are on map static std::map visited; //map: team_id => how many obelisks has been visited @@ -375,7 +372,7 @@ public: h & static_cast(*this); } protected: - void setPropertyDer(ui8 what, ui32 val) override; + void setPropertyDer(ObjProperty what, ObjPropertyID identifier) override; }; class DLL_LINKAGE CGLighthouse : public CGObjectInstance diff --git a/lib/networkPacks/NetPacksLib.cpp b/lib/networkPacks/NetPacksLib.cpp index c7041fd2e..41890cf47 100644 --- a/lib/networkPacks/NetPacksLib.cpp +++ b/lib/networkPacks/NetPacksLib.cpp @@ -971,18 +971,15 @@ void GiveBonus::applyGs(CGameState *gs) CBonusSystemNode *cbsn = nullptr; switch(who) { - case ETarget::HERO: - cbsn = gs->getHero(ObjectInstanceID(id)); + case ETarget::OBJECT: + cbsn = dynamic_cast(gs->getObjInstance(id.as())); break; case ETarget::PLAYER: - cbsn = gs->getPlayerState(PlayerColor(id)); - break; - case ETarget::TOWN: - cbsn = gs->getTown(ObjectInstanceID(id)); + cbsn = gs->getPlayerState(id.as()); break; case ETarget::BATTLE: assert(Bonus::OneBattle(&bonus)); - cbsn = dynamic_cast(gs->getBattle(BattleID(id))); + cbsn = dynamic_cast(gs->getBattle(id.as())); break; } @@ -1114,11 +1111,20 @@ void PlayerReinitInterface::applyGs(CGameState *gs) void RemoveBonus::applyGs(CGameState *gs) { - CBonusSystemNode * node = nullptr; - if (who == GiveBonus::ETarget::HERO) - node = gs->getHero(ObjectInstanceID(whoID)); - else - node = gs->getPlayerState(PlayerColor(whoID)); + CBonusSystemNode *node = nullptr; + switch(who) + { + case GiveBonus::ETarget::OBJECT: + node = dynamic_cast(gs->getObjInstance(whoID.as())); + break; + case GiveBonus::ETarget::PLAYER: + node = gs->getPlayerState(whoID.as()); + break; + case GiveBonus::ETarget::BATTLE: + assert(Bonus::OneBattle(&bonus)); + node = dynamic_cast(gs->getBattle(whoID.as())); + break; + } BonusList &bonuses = node->getExportedBonusList(); @@ -1483,7 +1489,7 @@ void NewObject::applyGs(CGameState *gs) const TerrainTile & t = gs->map->getTile(targetPos); terrainType = t.terType->getId(); - auto handler = VLC->objtypeh->getHandlerFor(ID, subID); + auto handler = VLC->objtypeh->getHandlerFor(ID, subID.getNum()); CGObjectInstance * o = handler->create(); handler->configureObject(o, gs->getRandomGenerator()); @@ -1499,13 +1505,13 @@ void NewObject::applyGs(CGameState *gs) cre->character = 2; cre->gainedArtifact = ArtifactID::NONE; cre->identifier = -1; - cre->addToSlot(SlotID(0), new CStackInstance(CreatureID(subID), -1)); //add placeholder stack + cre->addToSlot(SlotID(0), new CStackInstance(subID.as(), -1)); //add placeholder stack } assert(!handler->getTemplates(terrainType).empty()); if (handler->getTemplates().empty()) { - logGlobal->error("Attempt to create object (%d %d) with no templates!", ID, subID); + logGlobal->error("Attempt to create object (%d %d) with no templates!", ID, subID.getNum()); return; } @@ -2049,9 +2055,9 @@ void SetObjectProperty::applyGs(CGameState * gs) const if(state->towns.empty()) state->daysWithoutCastle = 0; } - if(PlayerColor(val).isValidPlayer()) + if(identifier.as().isValidPlayer()) { - PlayerState * p = gs->getPlayerState(PlayerColor(val)); + PlayerState * p = gs->getPlayerState(identifier.as()); p->towns.emplace_back(t); //reset counter before NewTurn to avoid no town message if game loaded at turn when one already captured @@ -2062,12 +2068,12 @@ void SetObjectProperty::applyGs(CGameState * gs) const CBonusSystemNode & nodeToMove = cai->whatShouldBeAttached(); nodeToMove.detachFrom(cai->whereShouldBeAttached(gs)); - obj->setProperty(what,val); + obj->setProperty(what, identifier); nodeToMove.attachTo(cai->whereShouldBeAttached(gs)); } else //not an armed instance { - obj->setProperty(what,val); + obj->setProperty(what, identifier); } } diff --git a/lib/networkPacks/ObjProperty.h b/lib/networkPacks/ObjProperty.h new file mode 100644 index 000000000..b375ef476 --- /dev/null +++ b/lib/networkPacks/ObjProperty.h @@ -0,0 +1,69 @@ +/* + * ObjProperty.h, 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 + * + */ +#pragma once + +#include "../constants/VariantIdentifier.h" +#include "../constants/EntityIdentifiers.h" + +enum class ObjProperty : int8_t +{ + INVALID, + OWNER, + BLOCKVIS, + PRIMARY_STACK_COUNT, + VISITORS, + VISITED, + ID, + AVAILABLE_CREATURE, + MONSTER_COUNT, + MONSTER_POWER, + MONSTER_EXP, + MONSTER_RESTORE_TYPE, + MONSTER_REFUSED_JOIN, + + //town-specific + STRUCTURE_ADD_VISITING_HERO, + STRUCTURE_CLEAR_VISITORS, + STRUCTURE_ADD_GARRISONED_HERO, //changing buildings state + BONUS_VALUE_FIRST, + BONUS_VALUE_SECOND, //used in Rampart for special building that generates resources (storing resource type and quantity) + + SEERHUT_VISITED, + SEERHUT_COMPLETE, + KEYMASTER_VISITED, + OBELISK_VISITED, + + //creature-bank specific + BANK_DAYCOUNTER, + BANK_RESET, + BANK_CLEAR, + + //object with reward + REWARD_RANDOMIZE, + REWARD_SELECT, + REWARD_CLEARED +}; + +class NumericID : public Identifier +{ +public: + using Identifier::Identifier; + + static si32 decode(const std::string & identifier) + { + return std::stoi(identifier); + } + static std::string encode(const si32 index) + { + return std::to_string(index); + } +}; + +using ObjPropertyID = VariantIdentifier; diff --git a/lib/networkPacks/PacksForClient.h b/lib/networkPacks/PacksForClient.h index f768c297d..7066f3315 100644 --- a/lib/networkPacks/PacksForClient.h +++ b/lib/networkPacks/PacksForClient.h @@ -15,6 +15,7 @@ #include "EOpenWindowMode.h" #include "EntityChanges.h" #include "NetPacksBase.h" +#include "ObjProperty.h" #include "../CCreatureSet.h" #include "../MetaString.h" @@ -366,17 +367,17 @@ struct DLL_LINKAGE SetAvailableHero : public CPackForClient struct DLL_LINKAGE GiveBonus : public CPackForClient { - enum class ETarget : ui8 { HERO, PLAYER, TOWN, BATTLE }; + enum class ETarget : int8_t { OBJECT, PLAYER, BATTLE }; - explicit GiveBonus(ETarget Who = ETarget::HERO) + explicit GiveBonus(ETarget Who = ETarget::OBJECT) :who(Who) { } void applyGs(CGameState * gs); - ETarget who = ETarget::HERO; //who receives bonus - si32 id = 0; //hero. town or player id - whoever receives it + ETarget who = ETarget::OBJECT; + VariantIdentifier id; Bonus bonus; MetaString bdescr; @@ -388,7 +389,7 @@ struct DLL_LINKAGE GiveBonus : public CPackForClient h & id; h & bdescr; h & who; - assert(id != -1); + assert(id.getNum() != -1); } }; @@ -461,7 +462,7 @@ struct DLL_LINKAGE PlayerReinitInterface : public CPackForClient struct DLL_LINKAGE RemoveBonus : public CPackForClient { - explicit RemoveBonus(GiveBonus::ETarget Who = GiveBonus::ETarget::HERO) + explicit RemoveBonus(GiveBonus::ETarget Who = GiveBonus::ETarget::OBJECT) :who(Who) { } @@ -469,7 +470,7 @@ struct DLL_LINKAGE RemoveBonus : public CPackForClient void applyGs(CGameState * gs); GiveBonus::ETarget who; //who receives bonus - ui32 whoID = 0; //hero, town or player id - whoever loses bonus + VariantIdentifier whoID; //vars to identify bonus: its source BonusSource source; @@ -574,7 +575,7 @@ struct DLL_LINKAGE UpdateCastleEvents : public CPackForClient struct DLL_LINKAGE ChangeFormation : public CPackForClient { ObjectInstanceID hid; - ui8 formation = 0; + EArmyFormation formation{}; void applyGs(CGameState * gs) const; void visitTyped(ICPackVisitor & visitor) override; @@ -781,9 +782,9 @@ struct DLL_LINKAGE NewObject : public CPackForClient void applyGs(CGameState * gs); /// Object ID to create - Obj ID; + MapObjectID ID; /// Object secondary ID to create - ui32 subID = 0; + VariantIdentifier subID; /// Position of visitable tile of created object int3 targetPos; /// Which player initiated creation of this object @@ -806,7 +807,8 @@ struct DLL_LINKAGE SetAvailableArtifacts : public CPackForClient { void applyGs(CGameState * gs) const; - si32 id = 0; //two variants: id < 0: set artifact pool for Artifact Merchants in towns; id >= 0: set pool for adv. map Black Market (id is the id of Black Market instance then) + //two variants: id < 0: set artifact pool for Artifact Merchants in towns; id >= 0: set pool for adv. map Black Market (id is the id of Black Market instance then) + ObjectInstanceID id; std::vector arts; void visitTyped(ICPackVisitor & visitor) override; @@ -1207,38 +1209,16 @@ struct DLL_LINKAGE InfoWindow : public CPackForClient //103 - displays simple i InfoWindow() = default; }; -namespace ObjProperty -{ - enum - { - OWNER = 1, BLOCKVIS = 2, PRIMARY_STACK_COUNT = 3, VISITORS = 4, VISITED = 5, ID = 6, AVAILABLE_CREATURE = 7, SUBID = 8, - MONSTER_COUNT = 10, MONSTER_POWER = 11, MONSTER_EXP = 12, MONSTER_RESTORE_TYPE = 13, MONSTER_REFUSED_JOIN, - - //town-specific - STRUCTURE_ADD_VISITING_HERO, STRUCTURE_CLEAR_VISITORS, STRUCTURE_ADD_GARRISONED_HERO, //changing buildings state - BONUS_VALUE_FIRST, BONUS_VALUE_SECOND, //used in Rampart for special building that generates resources (storing resource type and quantity) - - //creature-bank specific - BANK_DAYCOUNTER, BANK_RESET, BANK_CLEAR, - - //object with reward - REWARD_RANDOMIZE, REWARD_SELECT, REWARD_CLEARED - }; -} - struct DLL_LINKAGE SetObjectProperty : public CPackForClient { void applyGs(CGameState * gs) const; ObjectInstanceID id; - ui8 what = 0; // see ObjProperty enum - ui32 val = 0; + ObjProperty what{}; + + ObjPropertyID identifier; + int32_t value = 0; + SetObjectProperty() = default; - SetObjectProperty(const ObjectInstanceID & ID, ui8 What, ui32 Val) - : id(ID) - , what(What) - , val(Val) - { - } void visitTyped(ICPackVisitor & visitor) override; @@ -1246,7 +1226,8 @@ struct DLL_LINKAGE SetObjectProperty : public CPackForClient { h & id; h & what; - h & val; + h & identifier; + h & value; } }; diff --git a/lib/networkPacks/PacksForServer.h b/lib/networkPacks/PacksForServer.h index 9911d1ba8..de1d7d613 100644 --- a/lib/networkPacks/PacksForServer.h +++ b/lib/networkPacks/PacksForServer.h @@ -11,6 +11,7 @@ #include "ArtifactLocation.h" #include "NetPacksBase.h" +#include "TradeItem.h" #include "../int3.h" #include "../battle/BattleAction.h" @@ -472,7 +473,8 @@ struct DLL_LINKAGE TradeOnMarketplace : public CPackForServer ObjectInstanceID heroId; EMarketMode mode = EMarketMode::RESOURCE_RESOURCE; - std::vector r1, r2; //mode 0: r1 - sold resource, r2 - bought res (exception: when sacrificing art r1 is art id [todo: make r2 preferred slot?] + std::vector r1; + std::vector r2; //mode 0: r1 - sold resource, r2 - bought res (exception: when sacrificing art r1 is art id [todo: make r2 preferred slot?] std::vector val; //units of sold resource void visitTyped(ICPackVisitor & visitor) override; @@ -493,13 +495,13 @@ struct DLL_LINKAGE SetFormation : public CPackForServer { SetFormation() = default; ; - SetFormation(const ObjectInstanceID & HID, ui8 Formation) + SetFormation(const ObjectInstanceID & HID, EArmyFormation Formation) : hid(HID) , formation(Formation) { } ObjectInstanceID hid; - ui8 formation = 0; + EArmyFormation formation{}; void visitTyped(ICPackVisitor & visitor) override; diff --git a/lib/networkPacks/TradeItem.h b/lib/networkPacks/TradeItem.h new file mode 100644 index 000000000..43846d1d1 --- /dev/null +++ b/lib/networkPacks/TradeItem.h @@ -0,0 +1,20 @@ +/* + * TradeItem.h, 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 + * + */ +#pragma once + +#include "../constants/VariantIdentifier.h" +#include "../constants/EntityIdentifiers.h" + +VCMI_LIB_NAMESPACE_BEGIN + +using TradeItemSell = VariantIdentifier; +using TradeItemBuy = VariantIdentifier; + +VCMI_LIB_NAMESPACE_END diff --git a/lib/rewardable/Interface.cpp b/lib/rewardable/Interface.cpp index b1f41e8ce..b7cc60c25 100644 --- a/lib/rewardable/Interface.cpp +++ b/lib/rewardable/Interface.cpp @@ -150,9 +150,9 @@ void Rewardable::Interface::grantRewardAfterLevelup(IGameCallback * cb, const Re for(const Bonus & bonus : info.reward.bonuses) { GiveBonus gb; - gb.who = GiveBonus::ETarget::HERO; + gb.who = GiveBonus::ETarget::OBJECT; gb.bonus = bonus; - gb.id = hero->id.getNum(); + gb.id = hero->id; cb->giveHeroBonus(&gb); } diff --git a/lib/spells/AdventureSpellMechanics.cpp b/lib/spells/AdventureSpellMechanics.cpp index 2f8b056b3..b6b440d02 100644 --- a/lib/spells/AdventureSpellMechanics.cpp +++ b/lib/spells/AdventureSpellMechanics.cpp @@ -83,7 +83,7 @@ ESpellCastResult AdventureSpellMechanics::applyAdventureEffects(SpellCastEnviron for(const Bonus & b : bonuses) { GiveBonus gb; - gb.id = parameters.caster->getCasterUnitId(); + gb.id = ObjectInstanceID(parameters.caster->getCasterUnitId()); gb.bonus = b; env->apply(&gb); } @@ -323,7 +323,7 @@ ESpellCastResult DimensionDoorMechanics::applyAdventureEffects(SpellCastEnvironm } GiveBonus gb; - gb.id = parameters.caster->getCasterUnitId(); + gb.id = ObjectInstanceID(parameters.caster->getCasterUnitId()); gb.bonus = Bonus(BonusDuration::ONE_DAY, BonusType::NONE, BonusSource::SPELL_EFFECT, 0, BonusSourceID(owner->id)); env->apply(&gb); diff --git a/lib/spells/effects/Moat.cpp b/lib/spells/effects/Moat.cpp index 8546f779b..359f2460b 100644 --- a/lib/spells/effects/Moat.cpp +++ b/lib/spells/effects/Moat.cpp @@ -117,7 +117,7 @@ void Moat::apply(ServerCallback * server, const Mechanics * m, const EffectTarge for(auto & b : converted) { GiveBonus gb(GiveBonus::ETarget::BATTLE); - gb.id = m->battle()->getBattle()->getBattleID().getNum(); + gb.id = m->battle()->getBattle()->getBattleID(); gb.bonus = b; server->apply(&gb); } diff --git a/mapeditor/inspector/armywidget.cpp b/mapeditor/inspector/armywidget.cpp index 65740a54a..fcba00cf0 100644 --- a/mapeditor/inspector/armywidget.cpp +++ b/mapeditor/inspector/armywidget.cpp @@ -101,7 +101,7 @@ bool ArmyWidget::commitChanges() } } - army.setFormation(ui->formationTight->isChecked()); + army.setFormation(ui->formationTight->isChecked() ? EArmyFormation::TIGHT : EArmyFormation::LOOSE ); return isArmed; } diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index 0f2d4ca3c..32463f6c3 100644 --- a/server/CGameHandler.cpp +++ b/server/CGameHandler.cpp @@ -886,7 +886,7 @@ void CGameHandler::onNewTurn() if (newMonth) { SetAvailableArtifacts saa; - saa.id = -1; + saa.id = ObjectInstanceID::NONE; pickAllowedArtsSet(saa.arts, getRandomGenerator()); sendAndApply(&saa); } @@ -1328,8 +1328,8 @@ bool CGameHandler::teleportHero(ObjectInstanceID hid, ObjectInstanceID dstid, ui void CGameHandler::setOwner(const CGObjectInstance * obj, const PlayerColor owner) { PlayerColor oldOwner = getOwner(obj->id); - SetObjectProperty sop(obj->id, ObjProperty::OWNER, owner.getNum()); - sendAndApply(&sop); + + setObjPropertyID(obj->id, ObjProperty::OWNER, owner); std::set playerColors = {owner, oldOwner}; checkVictoryLossConditions(playerColors); @@ -2973,12 +2973,12 @@ bool CGameHandler::buyArtifact(const IMarket *m, const CGHeroInstance *h, GameRe SetAvailableArtifacts saa; if(dynamic_cast(m)) { - saa.id = -1; + saa.id = ObjectInstanceID::NONE; saa.arts = CGTownInstance::merchantArtifacts; } else if(const CGBlackMarket *bm = dynamic_cast(m)) //black market { - saa.id = bm->id.getNum(); + saa.id = bm->id; saa.arts = bm->artifacts; } else @@ -3044,23 +3044,23 @@ bool CGameHandler::buySecSkill(const IMarket *m, const CGHeroInstance *h, Second return true; } -bool CGameHandler::tradeResources(const IMarket *market, ui32 val, PlayerColor player, ui32 id1, ui32 id2) +bool CGameHandler::tradeResources(const IMarket *market, ui32 amountToSell, PlayerColor player, GameResID toSell, GameResID toBuy) { - TResourceCap r1 = getPlayerState(player)->resources[id1]; + TResourceCap haveToSell = getPlayerState(player)->resources[toSell]; - vstd::amin(val, r1); //can't trade more resources than have + vstd::amin(amountToSell, haveToSell); //can't trade more resources than have int b1, b2; //base quantities for trade - market->getOffer(id1, id2, b1, b2, EMarketMode::RESOURCE_RESOURCE); - int units = val / b1; //how many base quantities we trade + market->getOffer(toSell, toBuy, b1, b2, EMarketMode::RESOURCE_RESOURCE); + int amountToBoy = amountToSell / b1; //how many base quantities we trade - if (val%b1) //all offered units of resource should be used, if not -> somewhere in calculations must be an error + if (amountToSell % b1 != 0) //all offered units of resource should be used, if not -> somewhere in calculations must be an error { COMPLAIN_RET("Invalid deal, not all offered units of resource were used."); } - giveResource(player, GameResID(id1), - b1 * units); - giveResource(player, GameResID(id2), b2 * units); + giveResource(player, toSell, -b1 * amountToBoy); + giveResource(player, toBuy, b2 * amountToBoy); return true; } @@ -3144,7 +3144,7 @@ bool CGameHandler::sendResources(ui32 val, PlayerColor player, GameResID r1, Pla return true; } -bool CGameHandler::setFormation(ObjectInstanceID hid, ui8 formation) +bool CGameHandler::setFormation(ObjectInstanceID hid, EArmyFormation formation) { const CGHeroInstance *h = getHero(hid); if (!h) @@ -4047,8 +4047,8 @@ void CGameHandler::spawnWanderingMonsters(CreatureID creatureID) createObject(*tile, PlayerColor::NEUTRAL, Obj::MONSTER, creatureID); auto monsterId = getTopObj(*tile)->id; - setObjProperty(monsterId, ObjProperty::MONSTER_COUNT, count); - setObjProperty(monsterId, ObjProperty::MONSTER_POWER, (si64)1000*count); + setObjPropertyValue(monsterId, ObjProperty::MONSTER_COUNT, count); + setObjPropertyValue(monsterId, ObjProperty::MONSTER_POWER, (si64)1000*count); } tiles.erase(tile); //not use it again } @@ -4170,12 +4170,21 @@ bool CGameHandler::isVisitCoveredByAnotherQuery(const CGObjectInstance *obj, con return true; } -void CGameHandler::setObjProperty(ObjectInstanceID objid, int prop, si64 val) +void CGameHandler::setObjPropertyValue(ObjectInstanceID objid, ObjProperty prop, int32_t value) { SetObjectProperty sob; sob.id = objid; sob.what = prop; - sob.val = static_cast(val); + sob.identifier = NumericID(value); + sendAndApply(&sob); +} + +void CGameHandler::setObjPropertyID(ObjectInstanceID objid, ObjProperty prop, ObjPropertyID identifier) +{ + SetObjectProperty sob; + sob.id = objid; + sob.what = prop; + sob.identifier = identifier; sendAndApply(&sob); } @@ -4209,7 +4218,7 @@ scripting::Pool * CGameHandler::getGlobalContextPool() const //} #endif -void CGameHandler::createObject(const int3 & visitablePosition, const PlayerColor & initiator, Obj type, int32_t subtype) +void CGameHandler::createObject(const int3 & visitablePosition, const PlayerColor & initiator, MapObjectID type, MapObjectSubID subtype) { NewObject no; no.ID = type; diff --git a/server/CGameHandler.h b/server/CGameHandler.h index a71d6a1dd..e100bfcbd 100644 --- a/server/CGameHandler.h +++ b/server/CGameHandler.h @@ -101,7 +101,7 @@ public: //do sth void changeSpells(const CGHeroInstance * hero, bool give, const std::set &spells) override; bool removeObject(const CGObjectInstance * obj, const PlayerColor & initiator) override; - void createObject(const int3 & visitablePosition, const PlayerColor & initiator, Obj type, int32_t subtype ) override; + void createObject(const int3 & visitablePosition, const PlayerColor & initiator, MapObjectID type, MapObjectSubID subtype) override; void setOwner(const CGObjectInstance * obj, PlayerColor owner) override; void changePrimSkill(const CGHeroInstance * hero, PrimarySkill which, si64 val, bool abs=false) override; void changeSecSkill(const CGHeroInstance * hero, SecondarySkill which, int val, bool abs=false) override; @@ -156,7 +156,8 @@ public: /// Returns hero that is currently visiting this object, or nullptr if no visit is active const CGHeroInstance * getVisitingHero(const CGObjectInstance *obj); bool isVisitCoveredByAnotherQuery(const CGObjectInstance *obj, const CGHeroInstance *hero) override; - void setObjProperty(ObjectInstanceID objid, int prop, si64 val) override; + void setObjPropertyValue(ObjectInstanceID objid, ObjProperty prop, int32_t value) override; + void setObjPropertyID(ObjectInstanceID objid, ObjProperty prop, ObjPropertyID identifier) override; void showInfoDialog(InfoWindow * iw) override; void showInfoDialog(const std::string & msg, PlayerColor player) override; @@ -182,8 +183,8 @@ public: bool queryReply( QueryID qid, std::optional reply, PlayerColor player ); bool buildBoat( ObjectInstanceID objid, PlayerColor player ); - bool setFormation( ObjectInstanceID hid, ui8 formation ); - bool tradeResources(const IMarket *market, ui32 val, PlayerColor player, ui32 id1, ui32 id2); + bool setFormation( ObjectInstanceID hid, EArmyFormation formation ); + bool tradeResources(const IMarket *market, ui32 amountToSell, PlayerColor player, GameResID toSell, GameResID toBuy); bool sacrificeCreatures(const IMarket * market, const CGHeroInstance * hero, const std::vector & slot, const std::vector & count); bool sendResources(ui32 val, PlayerColor player, GameResID r1, PlayerColor r2); bool sellCreatures(ui32 count, const IMarket *market, const CGHeroInstance * hero, SlotID slot, GameResID resourceID); diff --git a/server/NetPacksServer.cpp b/server/NetPacksServer.cpp index c5e03acf5..a3d77db31 100644 --- a/server/NetPacksServer.cpp +++ b/server/NetPacksServer.cpp @@ -221,42 +221,49 @@ void ApplyGhNetPackVisitor::visitTradeOnMarketplace(TradeOnMarketplace & pack) { case EMarketMode::RESOURCE_RESOURCE: for(int i = 0; i < pack.r1.size(); ++i) - result &= gh.tradeResources(market, pack.val[i], pack.player, pack.r1[i], pack.r2[i]); + result &= gh.tradeResources(market, pack.val[i], pack.player, pack.r1[i].as(), pack.r2[i].as()); break; case EMarketMode::RESOURCE_PLAYER: for(int i = 0; i < pack.r1.size(); ++i) - result &= gh.sendResources(pack.val[i], pack.player, GameResID(pack.r1[i]), PlayerColor(pack.r2[i])); + result &= gh.sendResources(pack.val[i], pack.player, pack.r1[i].as(), pack.r2[i].as()); break; case EMarketMode::CREATURE_RESOURCE: for(int i = 0; i < pack.r1.size(); ++i) - result &= gh.sellCreatures(pack.val[i], market, hero, SlotID(pack.r1[i]), GameResID(pack.r2[i])); + result &= gh.sellCreatures(pack.val[i], market, hero, pack.r1[i].as(), pack.r2[i].as()); break; case EMarketMode::RESOURCE_ARTIFACT: for(int i = 0; i < pack.r1.size(); ++i) - result &= gh.buyArtifact(market, hero, GameResID(pack.r1[i]), ArtifactID(pack.r2[i])); + result &= gh.buyArtifact(market, hero, pack.r1[i].as(), pack.r2[i].as()); break; case EMarketMode::ARTIFACT_RESOURCE: for(int i = 0; i < pack.r1.size(); ++i) - result &= gh.sellArtifact(market, hero, ArtifactInstanceID(pack.r1[i]), GameResID(pack.r2[i])); + result &= gh.sellArtifact(market, hero, pack.r1[i].as(), pack.r2[i].as()); break; case EMarketMode::CREATURE_UNDEAD: for(int i = 0; i < pack.r1.size(); ++i) - result &= gh.transformInUndead(market, hero, SlotID(pack.r1[i])); + result &= gh.transformInUndead(market, hero, pack.r1[i].as()); break; case EMarketMode::RESOURCE_SKILL: for(int i = 0; i < pack.r2.size(); ++i) - result &= gh.buySecSkill(market, hero, SecondarySkill(pack.r2[i])); + result &= gh.buySecSkill(market, hero, pack.r2[i].as()); break; case EMarketMode::CREATURE_EXP: { - std::vector slotIDs(pack.r1.begin(), pack.r1.end()); + std::vector slotIDs; std::vector count(pack.val.begin(), pack.val.end()); + + for(auto const & slot : pack.r1) + slotIDs.push_back(slot.as()); + result = gh.sacrificeCreatures(market, hero, slotIDs, count); return; } case EMarketMode::ARTIFACT_EXP: { - std::vector positions(pack.r1.begin(), pack.r1.end()); + std::vector positions; + for(auto const & slot : pack.r1) + positions.push_back(slot.as()); + result = gh.sacrificeArtifact(market, hero, positions); return; } diff --git a/server/battles/BattleProcessor.cpp b/server/battles/BattleProcessor.cpp index e32811505..00a238dd1 100644 --- a/server/battles/BattleProcessor.cpp +++ b/server/battles/BattleProcessor.cpp @@ -122,8 +122,8 @@ void BattleProcessor::startBattlePrimary(const CArmedInstance *army1, const CArm { for(auto bonus : attackerInfo->battleBonuses) { - GiveBonus giveBonus(GiveBonus::ETarget::HERO); - giveBonus.id = hero1->id.getNum(); + GiveBonus giveBonus(GiveBonus::ETarget::OBJECT); + giveBonus.id = hero1->id; giveBonus.bonus = bonus; gameHandler->sendAndApply(&giveBonus); } diff --git a/server/processors/PlayerMessageProcessor.cpp b/server/processors/PlayerMessageProcessor.cpp index c2d319380..030169019 100644 --- a/server/processors/PlayerMessageProcessor.cpp +++ b/server/processors/PlayerMessageProcessor.cpp @@ -139,8 +139,8 @@ void PlayerMessageProcessor::cheatGiveSpells(PlayerColor player, const CGHeroIns gameHandler->giveHeroNewArtifact(hero, VLC->arth->objects[ArtifactID::SPELLBOOK], ArtifactPosition::SPELLBOOK); ///Give all spells with bonus (to allow banned spells) - GiveBonus giveBonus(GiveBonus::ETarget::HERO); - giveBonus.id = hero->id.getNum(); + GiveBonus giveBonus(GiveBonus::ETarget::OBJECT); + giveBonus.id = hero->id; giveBonus.bonus = Bonus(BonusDuration::PERMANENT, BonusType::SPELLS_OF_LEVEL, BonusSource::OTHER, 0, BonusSourceID()); //start with level 0 to skip abilities for (int level = 1; level <= GameConstants::SPELL_LEVELS; level++) @@ -300,11 +300,11 @@ void PlayerMessageProcessor::cheatMovement(PlayerColor player, const CGHeroInsta gameHandler->sendAndApply(&smp); - GiveBonus gb(GiveBonus::ETarget::HERO); + GiveBonus gb(GiveBonus::ETarget::OBJECT); gb.bonus.type = BonusType::FREE_SHIP_BOARDING; gb.bonus.duration = BonusDuration::ONE_DAY; gb.bonus.source = BonusSource::OTHER; - gb.id = hero->id.getNum(); + gb.id = hero->id; gameHandler->giveHeroBonus(&gb); }