diff --git a/AI/Nullkiller/AIUtility.cpp b/AI/Nullkiller/AIUtility.cpp index 6b2c389d4..bf6b1536e 100644 --- a/AI/Nullkiller/AIUtility.cpp +++ b/AI/Nullkiller/AIUtility.cpp @@ -15,6 +15,7 @@ #include "../../lib/UnlockGuard.h" #include "../../lib/CConfigHandler.h" #include "../../lib/entities/artifact/CArtifact.h" +#include "../../lib/entities/ResourceTypeHandler.h" #include "../../lib/mapObjects/MapObjects.h" #include "../../lib/mapObjects/CQuest.h" #include "../../lib/mapping/TerrainTile.h" @@ -470,7 +471,7 @@ int32_t getArtifactBonusScoreImpl(const std::shared_ptr & bonus) case BonusType::UNDEAD_RAISE_PERCENTAGE: return bonus->val * 400; case BonusType::GENERATE_RESOURCE: - return bonus->val * LIBRARY->objh->resVals.at(bonus->subtype.as().getNum()) * 10; + return bonus->val * bonus->subtype.as().toResource()->getPrice() * 10; case BonusType::SPELL_DURATION: return bonus->val * 200; case BonusType::MAGIC_RESISTANCE: diff --git a/AI/Nullkiller/Engine/PriorityEvaluator.cpp b/AI/Nullkiller/Engine/PriorityEvaluator.cpp index 2e36755eb..4335570bf 100644 --- a/AI/Nullkiller/Engine/PriorityEvaluator.cpp +++ b/AI/Nullkiller/Engine/PriorityEvaluator.cpp @@ -12,6 +12,7 @@ #include "Nullkiller.h" #include "../../../lib/entities/artifact/CArtifact.h" +#include "../../../lib/entities/ResourceTypeHandler.h" #include "../../../lib/mapObjectConstructors/AObjectTypeHandler.h" #include "../../../lib/mapObjectConstructors/CObjectClassesHandler.h" #include "../../../lib/mapObjects/CGResource.h" @@ -22,6 +23,7 @@ #include "../../../lib/StartInfo.h" #include "../../../lib/GameSettings.h" #include "../../../lib/filesystem/Filesystem.h" +#include "../../../lib/entities/ResourceTypeHandler.h" #include "../Goals/ExecuteHeroChain.h" #include "../Goals/BuildThis.h" #include "../Goals/StayAtTown.h" @@ -136,7 +138,7 @@ int32_t getResourcesGoldReward(const TResources & res) { int32_t result = 0; - for(auto r : GameResID::ALL_RESOURCES()) + for(auto r : LIBRARY->resourceTypeHandler->getAllObjects()) { if(res[r] > 0) result += r == EGameResID::GOLD ? res[r] : res[r] * 100; @@ -1589,7 +1591,7 @@ float PriorityEvaluator::evaluate(Goals::TSubgoal task, int priorityTier) needed.positive(); int turnsTo = needed.maxPurchasableCount(income); bool haveEverythingButGold = true; - for (int i = 0; i < GameConstants::RESOURCE_QUANTITY; i++) + for (auto & i : LIBRARY->resourceTypeHandler->getAllObjects()) { if (i != GameResID::GOLD && resourcesAvailable[i] < evaluationContext.buildingCost[i]) haveEverythingButGold = false; diff --git a/AI/Nullkiller/Goals/AbstractGoal.cpp b/AI/Nullkiller/Goals/AbstractGoal.cpp index 9adee7f96..6f92d1ec8 100644 --- a/AI/Nullkiller/Goals/AbstractGoal.cpp +++ b/AI/Nullkiller/Goals/AbstractGoal.cpp @@ -12,6 +12,7 @@ #include "../AIGateway.h" #include "../../../lib/constants/StringConstants.h" #include "../../../lib/entities/artifact/CArtifact.h" +#include "../../../lib/entities/ResourceTypeHandler.h" namespace NKAI { @@ -43,13 +44,13 @@ std::string AbstractGoal::toString() const switch(goalType) { case COLLECT_RES: - desc = "COLLECT RESOURCE " + GameConstants::RESOURCE_NAMES[resID] + " (" + std::to_string(value) + ")"; + desc = "COLLECT RESOURCE " + GameResID(resID).toResource()->getJsonKey() + " (" + std::to_string(value) + ")"; break; case TRADE: { auto obj = cb->getObjInstance(ObjectInstanceID(objid)); if (obj) - desc = (boost::format("TRADE %d of %s at %s") % value % GameConstants::RESOURCE_NAMES[resID] % obj->getObjectName()).str(); + desc = (boost::format("TRADE %d of %s at %s") % value % GameResID(resID).toResource()->getJsonKey() % obj->getObjectName()).str(); } break; case GATHER_TROOPS: diff --git a/AI/VCAI/Goals/AbstractGoal.cpp b/AI/VCAI/Goals/AbstractGoal.cpp index 527cbcc41..8e9811a62 100644 --- a/AI/VCAI/Goals/AbstractGoal.cpp +++ b/AI/VCAI/Goals/AbstractGoal.cpp @@ -16,6 +16,7 @@ #include "../BuildingManager.h" #include "../../../lib/constants/StringConstants.h" #include "../../../lib/entities/artifact/CArtifact.h" +#include "../../../lib/entities/ResourceTypeHandler.h" using namespace Goals; @@ -56,13 +57,13 @@ std::string AbstractGoal::name() const //TODO: virtualize case BUILD_STRUCTURE: return "BUILD STRUCTURE"; case COLLECT_RES: - desc = "COLLECT RESOURCE " + GameConstants::RESOURCE_NAMES[resID] + " (" + std::to_string(value) + ")"; + desc = "COLLECT RESOURCE " + GameResID(resID).toResource()->getJsonKey() + " (" + std::to_string(value) + ")"; break; case TRADE: { auto obj = cb->getObjInstance(ObjectInstanceID(objid)); if (obj) - desc = (boost::format("TRADE %d of %s at %s") % value % GameConstants::RESOURCE_NAMES[resID] % obj->getObjectName()).str(); + desc = (boost::format("TRADE %d of %s at %s") % value % GameResID(resID).toResource()->getJsonKey() % obj->getObjectName()).str(); } break; case GATHER_TROOPS: diff --git a/AI/VCAI/Goals/CollectRes.cpp b/AI/VCAI/Goals/CollectRes.cpp index 1bdfa5f64..f69032ef7 100644 --- a/AI/VCAI/Goals/CollectRes.cpp +++ b/AI/VCAI/Goals/CollectRes.cpp @@ -18,6 +18,7 @@ #include "../../../lib/mapObjects/CGMarket.h" #include "../../../lib/mapObjects/CGResource.h" #include "../../../lib/constants/StringConstants.h" +#include "../../../lib/entities/ResourceTypeHandler.h" using namespace Goals; @@ -171,7 +172,7 @@ TSubgoal CollectRes::whatToDoToTrade() const IMarket * m = markets.back(); //attempt trade at back (best prices) int howManyCanWeBuy = 0; - for (GameResID i = EGameResID::WOOD; i <= EGameResID::GOLD; ++i) + for (auto & i : LIBRARY->resourceTypeHandler->getAllObjects()) { if (i.getNum() == resID) continue; diff --git a/client/adventureMap/AdventureMapWidget.cpp b/client/adventureMap/AdventureMapWidget.cpp index 24fecc0a0..43cb8dea4 100644 --- a/client/adventureMap/AdventureMapWidget.cpp +++ b/client/adventureMap/AdventureMapWidget.cpp @@ -31,10 +31,12 @@ #include "../CPlayerInterface.h" #include "../PlayerLocalState.h" +#include "../../lib/GameLibrary.h" #include "../../lib/callback/CCallback.h" #include "../../lib/constants/StringConstants.h" #include "../../lib/mapping/CMapHeader.h" #include "../../lib/filesystem/ResourcePath.h" +#include "../../lib/entities/ResourceTypeHandler.h" AdventureMapWidget::AdventureMapWidget( std::shared_ptr shortcuts ) : shortcuts(shortcuts) @@ -294,14 +296,14 @@ std::shared_ptr AdventureMapWidget::buildResourceDateBar(const JsonN auto result = std::make_shared(image, area.topLeft()); - for(auto i = 0; i < GameConstants::RESOURCE_QUANTITY; i++) + for (auto & i : LIBRARY->resourceTypeHandler->getAllObjects()) { - const auto & node = input[GameConstants::RESOURCE_NAMES[i]]; + const auto & node = input[i.toResource()->getJsonKey()]; if(node.isNull()) continue; - result->setResourcePosition(GameResID(i), Point(node["x"].Integer(), node["y"].Integer())); + result->setResourcePosition(i, Point(node["x"].Integer(), node["y"].Integer())); } result->setDatePosition(Point(input["date"]["x"].Integer(), input["date"]["y"].Integer())); diff --git a/client/adventureMap/CResDataBar.cpp b/client/adventureMap/CResDataBar.cpp index ab540b935..adbc1fb9d 100644 --- a/client/adventureMap/CResDataBar.cpp +++ b/client/adventureMap/CResDataBar.cpp @@ -18,15 +18,21 @@ #include "../GameInstance.h" #include "../gui/TextAlignment.h" #include "../widgets/Images.h" +#include "../widgets/CComponent.h" +#include "../windows/InfoWindows.h" #include "../../lib/CConfigHandler.h" #include "../../lib/callback/CCallback.h" #include "../../lib/texts/CGeneralTextHandler.h" #include "../../lib/ResourceSet.h" #include "../../lib/GameLibrary.h" +#include "../../lib/entities/ResourceTypeHandler.h" +#include "../../lib/networkPacks/Component.h" CResDataBar::CResDataBar(const ImagePath & imageName, const Point & position) { + addUsedEvents(SHOW_POPUP); + pos.x += position.x; pos.y += position.y; @@ -89,3 +95,12 @@ void CResDataBar::setPlayerColor(PlayerColor player) { background->setPlayerColor(player); } + +void CResDataBar::showPopupWindow(const Point & cursorPosition) +{ + std::vector> comp; + for (auto & i : LIBRARY->resourceTypeHandler->getAllObjects()) + comp.push_back(std::make_shared(ComponentType::RESOURCE, i, GAME->interface()->cb->getResourceAmount(i))); + + CRClickPopup::createAndPush(LIBRARY->generaltexth->translate("core.genrltxt.270"), comp); +} diff --git a/client/adventureMap/CResDataBar.h b/client/adventureMap/CResDataBar.h index 3363802c4..ec578756a 100644 --- a/client/adventureMap/CResDataBar.h +++ b/client/adventureMap/CResDataBar.h @@ -35,6 +35,7 @@ public: void setResourcePosition(const GameResID & resource, const Point & position); void setPlayerColor(PlayerColor player); + void showPopupWindow(const Point & cursorPosition) override; void showAll(Canvas & to) override; }; diff --git a/client/lobby/OptionsTab.cpp b/client/lobby/OptionsTab.cpp index 0c3c1134f..ed4756d9d 100644 --- a/client/lobby/OptionsTab.cpp +++ b/client/lobby/OptionsTab.cpp @@ -41,6 +41,7 @@ #include "../../lib/entities/faction/CTownHandler.h" #include "../../lib/entities/hero/CHeroHandler.h" #include "../../lib/entities/hero/CHeroClass.h" +#include "../../lib/entities/ResourceTypeHandler.h" #include "../../lib/filesystem/Filesystem.h" #include "../../lib/networkPacks/PacksForLobby.h" #include "../../lib/texts/CGeneralTextHandler.h" @@ -161,8 +162,6 @@ size_t OptionsTab::CPlayerSettingsHelper::getImageIndex(bool big) return GEM; case EGameResID::GOLD: return GOLD; - case EGameResID::MITHRIL: - return MITHRIL; } } } @@ -1057,7 +1056,7 @@ OptionsTab::PlayerOptionsEntry::PlayerOptionsEntry(const PlayerSettings & S, con { auto str = MetaString::createFromTextID("vcmi.lobby.handicap"); str.appendRawString(":\n"); - for(auto & res : EGameResID::ALL_RESOURCES()) + for(auto & res : LIBRARY->resourceTypeHandler->getAllObjects()) if(s->handicap.startBonus[res] != 0) { str.appendRawString("\n"); diff --git a/client/mainmenu/CStatisticScreen.cpp b/client/mainmenu/CStatisticScreen.cpp index b54f3323a..2596de69d 100644 --- a/client/mainmenu/CStatisticScreen.cpp +++ b/client/mainmenu/CStatisticScreen.cpp @@ -28,6 +28,7 @@ #include "../windows/InfoWindows.h" #include "../widgets/Slider.h" +#include "../../lib/entities/ResourceTypeHandler.h" #include "../../lib/gameState/GameStatistics.h" #include "../../lib/gameState/CGameState.h" #include "../../lib/texts/CGeneralTextHandler.h" @@ -76,10 +77,10 @@ void CStatisticScreen::onSelectButton() else { auto content = static_cast(selectedIndex); - auto possibleRes = std::vector{EGameResID::GOLD, EGameResID::WOOD, EGameResID::MERCURY, EGameResID::ORE, EGameResID::SULFUR, EGameResID::CRYSTAL, EGameResID::GEMS}; + auto possibleRes = LIBRARY->resourceTypeHandler->getAllObjects(); std::vector resourceText; for(const auto & res : possibleRes) - resourceText.emplace_back(LIBRARY->generaltexth->translate(TextIdentifier("core.restypes", res.getNum()).get())); + resourceText.emplace_back(res.toResource()->getNameTranslated()); ENGINE->windows().createAndPushWindow(resourceText, [this, content, possibleRes](int index) { @@ -169,7 +170,7 @@ std::shared_ptr CStatisticScreen::getContent(Content c, EGameResID r case CHART_RESOURCES: plotData = extractData(statistic, [res](const StatisticDataSetEntry & val) -> float { return val.resources[res]; }); - return std::make_shared(contentArea.resize(-5), LIBRARY->generaltexth->translate(std::get<0>(contentInfo[c])) + " - " + LIBRARY->generaltexth->translate(TextIdentifier("core.restypes", res.getNum()).get()), plotData, icons, 0); + return std::make_shared(contentArea.resize(-5), LIBRARY->generaltexth->translate(std::get<0>(contentInfo[c])) + " - " + res.toResource()->getNameTranslated(), plotData, icons, 0); case CHART_INCOME: plotData = extractData(statistic, [](const StatisticDataSetEntry & val) -> float { return val.income; }); @@ -193,7 +194,7 @@ std::shared_ptr CStatisticScreen::getContent(Content c, EGameResID r case CHART_NUMBER_OF_MINES: plotData = extractData(statistic, [res](StatisticDataSetEntry val) -> float { return val.numMines[res]; }); - return std::make_shared(contentArea.resize(-5), LIBRARY->generaltexth->translate(std::get<0>(contentInfo[c])) + " - " + LIBRARY->generaltexth->translate(TextIdentifier("core.restypes", res.getNum()).get()), plotData, icons, 0); + return std::make_shared(contentArea.resize(-5), LIBRARY->generaltexth->translate(std::get<0>(contentInfo[c])) + " - " + res.toResource()->getNameTranslated(), plotData, icons, 0); case CHART_ARMY_STRENGTH: plotData = extractData(statistic, [](const StatisticDataSetEntry & val) -> float { return val.armyStrength; }); @@ -205,11 +206,11 @@ std::shared_ptr CStatisticScreen::getContent(Content c, EGameResID r case CHART_RESOURCES_SPENT_ARMY: plotData = extractData(statistic, [res](const StatisticDataSetEntry & val) -> float { return val.spentResourcesForArmy[res]; }); - return std::make_shared(contentArea.resize(-5), LIBRARY->generaltexth->translate(std::get<0>(contentInfo[c])) + " - " + LIBRARY->generaltexth->translate(TextIdentifier("core.restypes", res.getNum()).get()), plotData, icons, 0); + return std::make_shared(contentArea.resize(-5), LIBRARY->generaltexth->translate(std::get<0>(contentInfo[c])) + " - " + res.toResource()->getNameTranslated(), plotData, icons, 0); case CHART_RESOURCES_SPENT_BUILDINGS: plotData = extractData(statistic, [res](const StatisticDataSetEntry & val) -> float { return val.spentResourcesForBuildings[res]; }); - return std::make_shared(contentArea.resize(-5), LIBRARY->generaltexth->translate(std::get<0>(contentInfo[c])) + " - " + LIBRARY->generaltexth->translate(TextIdentifier("core.restypes", res.getNum()).get()), plotData, icons, 0); + return std::make_shared(contentArea.resize(-5), LIBRARY->generaltexth->translate(std::get<0>(contentInfo[c])) + " - " + res.toResource()->getNameTranslated(), plotData, icons, 0); case CHART_MAP_EXPLORED: plotData = extractData(statistic, [](const StatisticDataSetEntry & val) -> float { return val.mapExploredRatio; }); @@ -330,43 +331,43 @@ OverviewPanel::OverviewPanel(Rect position, std::string title, const StatisticDa } }, { - LIBRARY->generaltexth->translate("vcmi.statisticWindow.param.tradeVolume") + " - " + LIBRARY->generaltexth->translate(TextIdentifier("core.restypes", EGameResID::GOLD).get()), [this](PlayerColor color){ + LIBRARY->generaltexth->translate("vcmi.statisticWindow.param.tradeVolume") + " - " + GameResID(EGameResID::GOLD).toResource()->getNameTranslated(), [this](PlayerColor color){ auto val = playerDataFilter(color).back(); return std::to_string(val.tradeVolume[EGameResID::GOLD]); } }, { - LIBRARY->generaltexth->translate("vcmi.statisticWindow.param.tradeVolume") + " - " + LIBRARY->generaltexth->translate(TextIdentifier("core.restypes", EGameResID::WOOD).get()), [this](PlayerColor color){ + LIBRARY->generaltexth->translate("vcmi.statisticWindow.param.tradeVolume") + " - " + GameResID(EGameResID::WOOD).toResource()->getNameTranslated(), [this](PlayerColor color){ auto val = playerDataFilter(color).back(); return std::to_string(val.tradeVolume[EGameResID::WOOD]); } }, { - LIBRARY->generaltexth->translate("vcmi.statisticWindow.param.tradeVolume") + " - " + LIBRARY->generaltexth->translate(TextIdentifier("core.restypes", EGameResID::MERCURY).get()), [this](PlayerColor color){ + LIBRARY->generaltexth->translate("vcmi.statisticWindow.param.tradeVolume") + " - " + GameResID(EGameResID::MERCURY).toResource()->getNameTranslated(), [this](PlayerColor color){ auto val = playerDataFilter(color).back(); return std::to_string(val.tradeVolume[EGameResID::MERCURY]); } }, { - LIBRARY->generaltexth->translate("vcmi.statisticWindow.param.tradeVolume") + " - " + LIBRARY->generaltexth->translate(TextIdentifier("core.restypes", EGameResID::ORE).get()), [this](PlayerColor color){ + LIBRARY->generaltexth->translate("vcmi.statisticWindow.param.tradeVolume") + " - " + GameResID(EGameResID::ORE).toResource()->getNameTranslated(), [this](PlayerColor color){ auto val = playerDataFilter(color).back(); return std::to_string(val.tradeVolume[EGameResID::ORE]); } }, { - LIBRARY->generaltexth->translate("vcmi.statisticWindow.param.tradeVolume") + " - " + LIBRARY->generaltexth->translate(TextIdentifier("core.restypes", EGameResID::SULFUR).get()), [this](PlayerColor color){ + LIBRARY->generaltexth->translate("vcmi.statisticWindow.param.tradeVolume") + " - " + GameResID(EGameResID::SULFUR).toResource()->getNameTranslated(), [this](PlayerColor color){ auto val = playerDataFilter(color).back(); return std::to_string(val.tradeVolume[EGameResID::SULFUR]); } }, { - LIBRARY->generaltexth->translate("vcmi.statisticWindow.param.tradeVolume") + " - " + LIBRARY->generaltexth->translate(TextIdentifier("core.restypes", EGameResID::CRYSTAL).get()), [this](PlayerColor color){ + LIBRARY->generaltexth->translate("vcmi.statisticWindow.param.tradeVolume") + " - " + GameResID(EGameResID::CRYSTAL).toResource()->getNameTranslated(), [this](PlayerColor color){ auto val = playerDataFilter(color).back(); return std::to_string(val.tradeVolume[EGameResID::CRYSTAL]); } }, { - LIBRARY->generaltexth->translate("vcmi.statisticWindow.param.tradeVolume") + " - " + LIBRARY->generaltexth->translate(TextIdentifier("core.restypes", EGameResID::GEMS).get()), [this](PlayerColor color){ + LIBRARY->generaltexth->translate("vcmi.statisticWindow.param.tradeVolume") + " - " + GameResID(EGameResID::GEMS).toResource()->getNameTranslated(), [this](PlayerColor color){ auto val = playerDataFilter(color).back(); return std::to_string(val.tradeVolume[EGameResID::GEMS]); } diff --git a/client/mapView/MapViewCache.cpp b/client/mapView/MapViewCache.cpp index fc7aed2dc..e8bf91ebb 100644 --- a/client/mapView/MapViewCache.cpp +++ b/client/mapView/MapViewCache.cpp @@ -25,7 +25,6 @@ #include "../GameEngine.h" #include "../widgets/TextControls.h" -#include "../../lib/mapObjects/CObjectHandler.h" #include "../../lib/int3.h" MapViewCache::~MapViewCache() = default; diff --git a/client/renderSDL/RenderHandler.cpp b/client/renderSDL/RenderHandler.cpp index 582fcccc7..346ee8dce 100644 --- a/client/renderSDL/RenderHandler.cpp +++ b/client/renderSDL/RenderHandler.cpp @@ -43,6 +43,7 @@ #include #include #include +#include RenderHandler::RenderHandler() :assetGenerator(std::make_unique()) @@ -494,6 +495,7 @@ void RenderHandler::onLibraryLoadingFinished(const Services * services) addImageListEntries(services->factions()); addImageListEntries(services->spells()); addImageListEntries(services->skills()); + addImageListEntries(services->resources()); if (settings["mods"]["validation"].String() == "full") { diff --git a/client/widgets/MiscWidgets.cpp b/client/widgets/MiscWidgets.cpp index c851fde55..14cd41969 100644 --- a/client/widgets/MiscWidgets.cpp +++ b/client/widgets/MiscWidgets.cpp @@ -227,7 +227,7 @@ void CMinorResDataBar::showAll(Canvas & to) { CIntObject::showAll(to); - for (GameResID i=EGameResID::WOOD; i<=EGameResID::GOLD; ++i) + for (GameResID i=EGameResID::WOOD; i<=EGameResID::GOLD; ++i) //todo: configurable resource support { std::string text = std::to_string(GAME->interface()->cb->getResourceAmount(i)); diff --git a/client/widgets/markets/TradePanels.cpp b/client/widgets/markets/TradePanels.cpp index c8dfc71b5..bb6a35212 100644 --- a/client/widgets/markets/TradePanels.cpp +++ b/client/widgets/markets/TradePanels.cpp @@ -23,6 +23,7 @@ #include "../../../lib/entities/artifact/CArtHandler.h" #include "../../../lib/texts/CGeneralTextHandler.h" #include "../../../lib/mapObjects/CGHeroInstance.h" +#include "../../../lib/entities/ResourceTypeHandler.h" CTradeableItem::CTradeableItem(const Rect & area, EType Type, int32_t ID, int32_t serial) : SelectableSlot(area, Point(1, 1)) @@ -175,7 +176,7 @@ void CTradeableItem::hover(bool on) ENGINE->statusbar()->write(LIBRARY->artifacts()->getByIndex(id)->getNameTranslated()); break; case EType::RESOURCE: - ENGINE->statusbar()->write(LIBRARY->generaltexth->restypes[id]); + ENGINE->statusbar()->write(GameResID(id).toResource()->getNameTranslated()); break; case EType::PLAYER: ENGINE->statusbar()->write(LIBRARY->generaltexth->capColors[id]); diff --git a/client/windows/CCastleInterface.cpp b/client/windows/CCastleInterface.cpp index ae8589133..10038bf1d 100644 --- a/client/windows/CCastleInterface.cpp +++ b/client/windows/CCastleInterface.cpp @@ -58,6 +58,7 @@ #include "../../lib/campaign/CampaignState.h" #include "../../lib/entities/artifact/CArtifact.h" #include "../../lib/entities/building/CBuilding.h" +#include "../../lib/entities/ResourceTypeHandler.h" #include "../../lib/mapObjects/CGHeroInstance.h" #include "../../lib/mapObjects/CGTownInstance.h" #include "../../lib/mapObjects/TownBuildingInstance.h" @@ -292,7 +293,7 @@ CDwellingInfoBox::CDwellingInfoBox(int centerX, int centerY, const CGTownInstanc available = std::make_shared(80,190, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE, LIBRARY->generaltexth->allTexts[217] + text); costPerTroop = std::make_shared(80, 227, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE, LIBRARY->generaltexth->allTexts[346]); - for(int i = 0; iresourceTypeHandler->getAllObjects()) { auto res = static_cast(i); if(creature->getRecruitCost(res)) @@ -1126,7 +1127,7 @@ void CCastleBuildings::enterFountain(const BuildingID & building, BuildingSubID: else //Mystic Pond produced something; { descr += "\n\n" + hasProduced; - boost::algorithm::replace_first(descr,"%s",LIBRARY->generaltexth->restypes[town->bonusValue.first]); + boost::algorithm::replace_first(descr,"%s",GameResID(town->bonusValue.first).toResource()->getNameTranslated()); boost::algorithm::replace_first(descr,"%d",std::to_string(town->bonusValue.second)); } } @@ -1795,7 +1796,7 @@ CBuildWindow::CBuildWindow(const CGTownInstance *Town, const CBuilding * Buildin //Create components for all required resources std::vector> components; - for(GameResID i : GameResID::ALL_RESOURCES()) + for(GameResID i : LIBRARY->resourceTypeHandler->getAllObjects()) { if(building->resources[i]) { @@ -2211,7 +2212,8 @@ void CMageGuildScreen::Scroll::clickPressed(const Point & cursorPosition) return; } - auto costBase = TResources(GAME->interface()->cb->getSettings().getValue(EGameSettings::TOWNS_SPELL_RESEARCH_COST).Vector()[level]); + ResourceSet costBase; + costBase.resolveFromJson(GAME->interface()->cb->getSettings().getValue(EGameSettings::TOWNS_SPELL_RESEARCH_COST).Vector()[level]); auto costExponent = GAME->interface()->cb->getSettings().getValue(EGameSettings::TOWNS_SPELL_RESEARCH_COST_EXPONENT_PER_RESEARCH).Vector()[level].Float(); auto cost = costBase * std::pow(town->spellResearchAcceptedCounter + 1, costExponent); diff --git a/client/windows/GUIClasses.cpp b/client/windows/GUIClasses.cpp index 26eca17e3..060a08f84 100644 --- a/client/windows/GUIClasses.cpp +++ b/client/windows/GUIClasses.cpp @@ -46,6 +46,7 @@ #include "../lib/entities/building/CBuilding.h" #include "../lib/entities/faction/CTownHandler.h" #include "../lib/entities/hero/CHeroHandler.h" +#include "../lib/entities/ResourceTypeHandler.h" #include "../lib/mapObjectConstructors/CObjectClassesHandler.h" #include "../lib/mapObjectConstructors/CommonConstructors.h" #include "../lib/mapObjects/CGHeroInstance.h" @@ -830,7 +831,7 @@ CShipyardWindow::CShipyardWindow(const TResources & cost, int state, BoatId boat build = std::make_shared(Point(42, 312), AnimationPath::builtin("IBUY30"), CButton::tooltip(LIBRARY->generaltexth->allTexts[598]), std::bind(&CShipyardWindow::close, this), EShortcut::GLOBAL_ACCEPT); build->addCallback(onBuy); - for(GameResID i = EGameResID::WOOD; i <= EGameResID::GOLD; ++i) + for(auto & i : LIBRARY->resourceTypeHandler->getAllObjects()) { if(cost[i] > GAME->interface()->cb->getResourceAmount(i)) { @@ -1215,7 +1216,6 @@ void CHillFortWindow::updateGarrisons() for(int i=0; i +{ + virtual int getPrice() const = 0; +}; + + +VCMI_LIB_NAMESPACE_END diff --git a/lib/mapObjects/CObjectHandler.h b/include/vcmi/ResourceTypeService.h similarity index 54% rename from lib/mapObjects/CObjectHandler.h rename to include/vcmi/ResourceTypeService.h index 7413918b2..4788bc243 100644 --- a/lib/mapObjects/CObjectHandler.h +++ b/include/vcmi/ResourceTypeService.h @@ -1,5 +1,5 @@ /* - * CObjectHandler.h, part of VCMI engine + * ResourceTypeService.h, part of VCMI engine * * Authors: listed in file AUTHORS in main folder * @@ -7,21 +7,19 @@ * Full text of license available in license.txt file, in main folder * */ + #pragma once -#include "../GameConstants.h" +#include "EntityService.h" VCMI_LIB_NAMESPACE_BEGIN -class CGObjectInstance; -class int3; +class GameResID; +class ResourceType; -class DLL_LINKAGE CObjectHandler +class DLL_LINKAGE ResourceTypeService : public EntityServiceT { public: - std::vector resVals; //default values of resources in gold - - CObjectHandler(); }; VCMI_LIB_NAMESPACE_END diff --git a/include/vcmi/Services.h b/include/vcmi/Services.h index 9ca566e48..45ce55f9a 100644 --- a/include/vcmi/Services.h +++ b/include/vcmi/Services.h @@ -19,6 +19,7 @@ class CreatureService; class FactionService; class HeroClassService; class HeroTypeService; +class ResourceTypeService; class SkillService; class JsonNode; class BattleFieldService; @@ -52,6 +53,7 @@ public: virtual const FactionService * factions() const = 0; virtual const HeroClassService * heroClasses() const = 0; virtual const HeroTypeService * heroTypes() const = 0; + virtual const ResourceTypeService * resources() const = 0; #if SCRIPTING_ENABLED virtual const scripting::Service * scripts() const = 0; #endif diff --git a/launcher/modManager/modstateitemmodel_moc.cpp b/launcher/modManager/modstateitemmodel_moc.cpp index 2ce68d341..4ae93f6ec 100644 --- a/launcher/modManager/modstateitemmodel_moc.cpp +++ b/launcher/modManager/modstateitemmodel_moc.cpp @@ -54,6 +54,7 @@ QString ModStateItemModel::modTypeName(QString modTypeID) const QT_TR_NOOP("Campaigns"), QT_TR_NOOP("Artifacts"), QT_TR_NOOP("AI"), + QT_TR_NOOP("Resources"), }; if (modTypes.contains(modTypeID)) diff --git a/lib/CCreatureHandler.cpp b/lib/CCreatureHandler.cpp index 6a9d5c58a..e31d22a4f 100644 --- a/lib/CCreatureHandler.cpp +++ b/lib/CCreatureHandler.cpp @@ -568,7 +568,7 @@ std::vector CCreatureHandler::loadLegacyData() data["name"]["plural"].String() = parser.readString(); - for(int v=0; v<7; ++v) + for(int v=0; v CCreatureHandler::loadFromJson(const std::string & sc JsonDeserializer handler(nullptr, node); cre->serializeJson(handler); - cre->cost = ResourceSet(node["cost"]); + cre->cost.resolveFromJson(node["cost"]); LIBRARY->generaltexth->registerString(scope, cre->getNameSingularTextID(), node["name"]["singular"]); LIBRARY->generaltexth->registerString(scope, cre->getNamePluralTextID(), node["name"]["plural"]); diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 0f797dd2b..074421588 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -111,6 +111,7 @@ set(lib_MAIN_SRCS entities/hero/CHeroClass.cpp entities/hero/CHeroClassHandler.cpp entities/hero/CHeroHandler.cpp + entities/ResourceTypeHandler.cpp events/ApplyDamage.cpp events/GameResumed.cpp @@ -152,7 +153,6 @@ set(lib_MAIN_SRCS mapObjects/CGResource.cpp mapObjects/TownBuildingInstance.cpp mapObjects/CGTownInstance.cpp - mapObjects/CObjectHandler.cpp mapObjects/CQuest.cpp mapObjects/CRewardableObject.cpp mapObjects/FlaggableMapObject.cpp @@ -428,6 +428,8 @@ set(lib_MAIN_HEADERS ../include/vcmi/HeroClassService.h ../include/vcmi/HeroType.h ../include/vcmi/HeroTypeService.h + ../include/vcmi/ResourceType.h + ../include/vcmi/ResourceTypeService.h ../include/vcmi/Metatype.h ../include/vcmi/Player.h ../include/vcmi/ServerCallback.h @@ -534,6 +536,7 @@ set(lib_MAIN_HEADERS entities/hero/CHeroClassHandler.h entities/hero/CHeroHandler.h entities/hero/EHeroGender.h + entities/ResourceTypeHandler.h events/ApplyDamage.h events/GameResumed.h @@ -581,7 +584,6 @@ set(lib_MAIN_HEADERS mapObjects/TownBuildingInstance.h mapObjects/CGResource.h mapObjects/CGTownInstance.h - mapObjects/CObjectHandler.h mapObjects/CQuest.h mapObjects/CRewardableObject.h mapObjects/FlaggableMapObject.h diff --git a/lib/CPlayerState.cpp b/lib/CPlayerState.cpp index 7a92d325d..4a5d833fc 100644 --- a/lib/CPlayerState.cpp +++ b/lib/CPlayerState.cpp @@ -98,7 +98,7 @@ const IBonusBearer * PlayerState::getBonusBearer() const int PlayerState::getResourceAmount(int type) const { - return vstd::atOrDefault(resources, static_cast(type), 0); + return resources[type]; } template diff --git a/lib/GameLibrary.cpp b/lib/GameLibrary.cpp index c7dc5ea8f..029acb560 100644 --- a/lib/GameLibrary.cpp +++ b/lib/GameLibrary.cpp @@ -25,6 +25,7 @@ #include "entities/faction/CTownHandler.h" #include "entities/hero/CHeroClassHandler.h" #include "entities/hero/CHeroHandler.h" +#include "entities/ResourceTypeHandler.h" #include "texts/CGeneralTextHandler.h" #include "campaign/CampaignRegionsHandler.h" #include "mapping/MapFormatSettings.h" @@ -36,7 +37,6 @@ #include "filesystem/Filesystem.h" #include "rmg/CRmgTemplateStorage.h" #include "mapObjectConstructors/CObjectClassesHandler.h" -#include "mapObjects/CObjectHandler.h" #include "mapObjects/ObstacleSetHandler.h" #include "mapping/CMapEditManager.h" #include "ScriptHandler.h" @@ -75,6 +75,11 @@ const HeroTypeService * GameLibrary::heroTypes() const return heroh.get(); } +const ResourceTypeService * GameLibrary::resources() const +{ + return resourceTypeHandler.get(); +} + #if SCRIPTING_ENABLED const scripting::Service * GameLibrary::scripts() const { @@ -171,6 +176,7 @@ void GameLibrary::initializeLibrary() createHandler(generaltexth); createHandler(bth); + createHandler(resourceTypeHandler); createHandler(roadTypeHandler); createHandler(riverTypeHandler); createHandler(terrainTypeHandler); @@ -180,7 +186,6 @@ void GameLibrary::initializeLibrary() createHandler(creh); createHandler(townh); createHandler(biomeHandler); - createHandler(objh); createHandler(objtypeh); createHandler(spellSchoolHandler); createHandler(spellh); diff --git a/lib/GameLibrary.h b/lib/GameLibrary.h index 7e7fee1ba..2218a0817 100644 --- a/lib/GameLibrary.h +++ b/lib/GameLibrary.h @@ -20,7 +20,6 @@ class CHeroClassHandler; class CCreatureHandler; class CSpellHandler; class CSkillHandler; -class CObjectHandler; class CObjectClassesHandler; class ObstacleSetHandler; class CTownHandler; @@ -31,6 +30,7 @@ class BattleFieldHandler; class IBonusTypeHandler; class CBonusTypeHandler; class TerrainTypeHandler; +class ResourceTypeHandler; class RoadTypeHandler; class RiverTypeHandler; class ObstacleHandler; @@ -60,6 +60,7 @@ public: const FactionService * factions() const override; const HeroClassService * heroClasses() const override; const HeroTypeService * heroTypes() const override; + const ResourceTypeService * resources() const override; #if SCRIPTING_ENABLED const scripting::Service * scripts() const override; #endif @@ -83,13 +84,12 @@ public: std::unique_ptr spellh; std::unique_ptr spellSchoolHandler; std::unique_ptr skillh; - // TODO: Remove ObjectHandler altogether? - std::unique_ptr objh; std::unique_ptr objtypeh; std::unique_ptr townh; std::unique_ptr generaltexth; std::unique_ptr modh; std::unique_ptr terrainTypeHandler; + std::unique_ptr resourceTypeHandler; std::unique_ptr roadTypeHandler; std::unique_ptr riverTypeHandler; std::unique_ptr identifiersHandler; diff --git a/lib/ResourceSet.cpp b/lib/ResourceSet.cpp index 5b5168cff..e60f3faef 100644 --- a/lib/ResourceSet.cpp +++ b/lib/ResourceSet.cpp @@ -13,17 +13,34 @@ #include "ResourceSet.h" #include "constants/StringConstants.h" #include "serializer/JsonSerializeFormat.h" -#include "mapObjects/CObjectHandler.h" +#include "entities/ResourceTypeHandler.h" #include "GameLibrary.h" VCMI_LIB_NAMESPACE_BEGIN -ResourceSet::ResourceSet() = default; - -ResourceSet::ResourceSet(const JsonNode & node) +ResourceSet::ResourceSet() { - for(auto i = 0; i < GameConstants::RESOURCE_QUANTITY; i++) - container[i] = static_cast(node[GameConstants::RESOURCE_NAMES[i]].Float()); + resizeContainer(); +}; + +ResourceSet::ResourceSet(const ResourceSet& rhs) + : container(rhs.container) // vector copy constructor +{ + resizeContainer(); +} + +void ResourceSet::resizeContainer() +{ + container.resize(std::max(static_cast(LIBRARY->resourceTypeHandler->getAllObjects().size()), GameConstants::RESOURCE_QUANTITY)); +} + +void ResourceSet::resolveFromJson(const JsonNode & node) +{ + for(auto & n : node.Struct()) + LIBRARY->identifiers()->requestIdentifier(n.second.getModScope(), "resource", n.first, [n, this](int32_t identifier) + { + (*this)[identifier] = static_cast(n.second.Float()); + }); } void ResourceSet::serializeJson(JsonSerializeFormat & handler, const std::string & fieldName) @@ -32,9 +49,8 @@ void ResourceSet::serializeJson(JsonSerializeFormat & handler, const std::string return; auto s = handler.enterStruct(fieldName); - //TODO: add proper support for mithril to map format - for(int idx = 0; idx < GameConstants::RESOURCE_QUANTITY - 1; idx ++) - handler.serializeInt(GameConstants::RESOURCE_NAMES[idx], this->operator[](idx), 0); + for(auto & idx : LIBRARY->resourceTypeHandler->getAllObjects()) + handler.serializeInt(idx.toResource()->getJsonKey(), this->operator[](idx), 0); } bool ResourceSet::nonZero() const @@ -76,8 +92,7 @@ void ResourceSet::applyHandicap(int percentage) static bool canAfford(const ResourceSet &res, const ResourceSet &price) { - assert(res.size() == price.size() && price.size() == GameConstants::RESOURCE_QUANTITY); - for(int i = 0; i < GameConstants::RESOURCE_QUANTITY; i++) + for(auto & i : LIBRARY->resourceTypeHandler->getAllObjects()) if(price[i] > res[i]) return false; @@ -97,8 +112,8 @@ bool ResourceSet::canAfford(const ResourceSet &price) const TResourceCap ResourceSet::marketValue() const { TResourceCap total = 0; - for(int i = 0; i < GameConstants::RESOURCE_QUANTITY; i++) - total += static_cast(LIBRARY->objh->resVals[i]) * static_cast(operator[](i)); + for(auto & i : LIBRARY->resourceTypeHandler->getAllObjects()) + total += static_cast(i.toResource()->getPrice()) * static_cast(operator[](i)); return total; } @@ -117,7 +132,7 @@ std::string ResourceSet::toString() const bool ResourceSet::nziterator::valid() const { - return cur.resType < GameResID::COUNT && cur.resVal; + return static_cast(cur.resType) < LIBRARY->resourceTypeHandler->getAllObjects().size() && cur.resVal; } ResourceSet::nziterator ResourceSet::nziterator::operator++() @@ -148,9 +163,9 @@ void ResourceSet::nziterator::advance() do { ++cur.resType; - } while(cur.resType < GameResID::COUNT && !(cur.resVal=rs[cur.resType])); + } while(static_cast(cur.resType) < LIBRARY->resourceTypeHandler->getAllObjects().size() && !(cur.resVal=rs[cur.resType])); - if(cur.resType >= GameResID::COUNT) + if(static_cast(cur.resType) >= LIBRARY->resourceTypeHandler->getAllObjects().size()) cur.resVal = -1; } diff --git a/lib/ResourceSet.h b/lib/ResourceSet.h index 9c33db5fc..a77beb7f8 100644 --- a/lib/ResourceSet.h +++ b/lib/ResourceSet.h @@ -26,16 +26,19 @@ class ResourceSet; class ResourceSet { private: - std::array container = {}; + std::vector container = {}; + DLL_LINKAGE void resizeContainer(); public: - // read resources set from json. Format example: { "gold": 500, "wood":5 } - DLL_LINKAGE ResourceSet(const JsonNode & node); DLL_LINKAGE ResourceSet(); + DLL_LINKAGE ResourceSet(const ResourceSet& rhs); + + DLL_LINKAGE void resolveFromJson(const JsonNode & node); #define scalarOperator(OPSIGN) \ ResourceSet& operator OPSIGN ## =(const TResource &rhs) \ { \ + resizeContainer(); \ for(auto i = 0; i < container.size(); i++) \ container.at(i) OPSIGN ## = rhs; \ \ @@ -45,6 +48,7 @@ public: #define vectorOperator(OPSIGN) \ ResourceSet& operator OPSIGN ## =(const ResourceSet &rhs) \ { \ + resizeContainer(); \ for(auto i = 0; i < container.size(); i++) \ container.at(i) OPSIGN ## = rhs[i]; \ \ @@ -84,21 +88,31 @@ public: // Array-like interface TResource & operator[](GameResID index) { + resizeContainer(); return operator[](index.getNum()); } const TResource & operator[](GameResID index) const { + if (index.getNum() >= container.size()) { + static const TResource defaultValue{}; + return defaultValue; + } return operator[](index.getNum()); } TResource & operator[](size_t index) { + resizeContainer(); return container.at(index); } const TResource & operator[](size_t index) const { + if (index >= container.size()) { + static const TResource defaultValue{}; + return defaultValue; + } return container.at(index); } @@ -176,6 +190,15 @@ public: return *this; } + ResourceSet& operator=(const ResourceSet& rhs) + { + if (this != &rhs) + { + container = rhs.container; + } + return *this; + } + ResourceSet operator-() const { ResourceSet ret; diff --git a/lib/constants/EntityIdentifiers.cpp b/lib/constants/EntityIdentifiers.cpp index 17421a685..35158f6e5 100644 --- a/lib/constants/EntityIdentifiers.cpp +++ b/lib/constants/EntityIdentifiers.cpp @@ -21,6 +21,8 @@ #include #include #include +#include +#include #include #include @@ -37,6 +39,7 @@ #include "entities/faction/CFaction.h" #include "entities/hero/CHero.h" #include "entities/hero/CHeroClass.h" +#include "entities/ResourceTypeHandler.h" #include "mapObjectConstructors/AObjectTypeHandler.h" #include "constants/StringConstants.h" #include "texts/CGeneralTextHandler.h" @@ -398,6 +401,16 @@ const HeroType * HeroTypeID::toEntity(const Services * services) const return services->heroTypes()->getByIndex(num); } +const Resource * GameResID::toResource() const +{ + return dynamic_cast(toEntity(LIBRARY)); +} + +const ResourceType * GameResID::toEntity(const Services * services) const +{ + return services->resources()->getByIndex(num); +} + si32 SpellID::decode(const std::string & identifier) { if (identifier == "preset") @@ -628,7 +641,7 @@ si32 GameResID::decode(const std::string & identifier) std::string GameResID::encode(const si32 index) { - return GameConstants::RESOURCE_NAMES[index]; + return GameResID(index).toResource()->getJsonKey(); } si32 BuildingTypeUniqueID::decode(const std::string & identifier) @@ -676,21 +689,6 @@ const std::array & PrimarySkill::ALL_SKILLS() return allSkills; } -const std::array & GameResID::ALL_RESOURCES() -{ - static const std::array allResources = { - GameResID(WOOD), - GameResID(MERCURY), - GameResID(ORE), - GameResID(SULFUR), - GameResID(CRYSTAL), - GameResID(GEMS), - GameResID(GOLD) - }; - - return allResources; -} - std::string SecondarySkill::entityType() { return "secondarySkill"; diff --git a/lib/constants/EntityIdentifiers.h b/lib/constants/EntityIdentifiers.h index 2294055da..fc70d9cb8 100644 --- a/lib/constants/EntityIdentifiers.h +++ b/lib/constants/EntityIdentifiers.h @@ -25,6 +25,9 @@ class CHero; class CHeroClass; class HeroClass; class HeroTypeService; +class Resource; +class ResourceType; +class ResourceTypeService; class CFaction; class Faction; class Skill; @@ -1061,7 +1064,6 @@ public: CRYSTAL, GEMS, GOLD, - MITHRIL, COUNT, WOOD_AND_ORE = -4, // special case for town bonus resource @@ -1080,7 +1082,8 @@ public: static std::string encode(const si32 index); static std::string entityType(); - static const std::array & ALL_RESOURCES(); + const Resource * toResource() const; + const ResourceType * toEntity(const Services * services) const; }; class DLL_LINKAGE BuildingTypeUniqueID : public Identifier diff --git a/lib/constants/NumericConstants.h b/lib/constants/NumericConstants.h index 09c408a6d..a7fef4c0f 100644 --- a/lib/constants/NumericConstants.h +++ b/lib/constants/NumericConstants.h @@ -37,7 +37,7 @@ namespace GameConstants constexpr int SKILL_QUANTITY=28; constexpr int PRIMARY_SKILLS=4; - constexpr int RESOURCE_QUANTITY=8; + constexpr int RESOURCE_QUANTITY=7; constexpr int HEROES_PER_TYPE=8; //amount of heroes of each type // amounts of OH3 objects. Can be changed by mods, should be used only during H3 loading phase diff --git a/lib/constants/StringConstants.h b/lib/constants/StringConstants.h index e78323871..97016e852 100644 --- a/lib/constants/StringConstants.h +++ b/lib/constants/StringConstants.h @@ -19,7 +19,7 @@ VCMI_LIB_NAMESPACE_BEGIN namespace GameConstants { const std::string RESOURCE_NAMES [RESOURCE_QUANTITY] = { - "wood", "mercury", "ore", "sulfur", "crystal", "gems", "gold", "mithril" + "wood", "mercury", "ore", "sulfur", "crystal", "gems", "gold" }; const std::string PLAYER_COLOR_NAMES [PlayerColor::PLAYER_LIMIT_I] = { diff --git a/lib/entities/ResourceTypeHandler.cpp b/lib/entities/ResourceTypeHandler.cpp new file mode 100644 index 000000000..ffea20fee --- /dev/null +++ b/lib/entities/ResourceTypeHandler.cpp @@ -0,0 +1,83 @@ +/* + * ResourceTypeHandler.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 "ResourceTypeHandler.h" + +#include "../GameLibrary.h" +#include "../json/JsonNode.h" +#include "../texts/CGeneralTextHandler.h" +#include "../texts/TextIdentifier.h" + +VCMI_LIB_NAMESPACE_BEGIN + +std::string Resource::getNameTextID() const +{ + if(id.getNum() < GameConstants::RESOURCE_QUANTITY) // OH3 resources + return TextIdentifier("core.restypes", id).get(); + return TextIdentifier( "resources", modScope, identifier, "name" ).get(); +} + +std::string Resource::getNameTranslated() const +{ + return LIBRARY->generaltexth->translate(getNameTextID()); +} + +void Resource::registerIcons(const IconRegistar & cb) const +{ + cb(getIconIndex(), 0, "SMALRES", iconSmall); + cb(getIconIndex(), 0, "RESOURCE", iconMedium); + cb(getIconIndex(), 0, "RESOUR82", iconLarge); +} + +std::vector ResourceTypeHandler::loadLegacyData() +{ + objects.resize(GameConstants::RESOURCE_QUANTITY); + + return std::vector(GameConstants::RESOURCE_QUANTITY, JsonNode(JsonMap())); +} + +std::shared_ptr ResourceTypeHandler::loadFromJson(const std::string & scope, const JsonNode & json, const std::string & identifier, size_t index) +{ + auto ret = std::make_shared(); + + ret->id = GameResID(index); + ret->modScope = scope; + ret->identifier = identifier; + + ret->price = json["price"].Integer(); + ret->iconSmall = json["images"]["small"].String(); + ret->iconMedium = json["images"]["medium"].String(); + ret->iconLarge = json["images"]["large"].String(); + + if(ret->id.getNum() >= GameConstants::RESOURCE_QUANTITY) // not OH3 resources + LIBRARY->generaltexth->registerString(scope, ret->getNameTextID(), json["name"]); + + return ret; +} + +const std::vector & ResourceTypeHandler::getTypeNames() const +{ + static const std::vector types = { "resource" }; + return types; +} + +std::vector ResourceTypeHandler::getAllObjects() const +{ + std::vector result; + + for (const auto & resource : objects) + if(resource) + result.push_back(resource->getId()); + + return result; +} + +VCMI_LIB_NAMESPACE_END diff --git a/lib/entities/ResourceTypeHandler.h b/lib/entities/ResourceTypeHandler.h new file mode 100644 index 000000000..66d7f2701 --- /dev/null +++ b/lib/entities/ResourceTypeHandler.h @@ -0,0 +1,66 @@ +/* + * ResourceTypeHandler.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 +#include +#include +#include +#include "../constants/EntityIdentifiers.h" +#include "../IHandlerBase.h" +#include "../filesystem/ResourcePath.h" + +VCMI_LIB_NAMESPACE_BEGIN + +class ResourceTypeHandler; + +class DLL_LINKAGE Resource : public ResourceType +{ + friend class ResourceTypeHandler; + + GameResID id; //backlink + + int price; + std::string iconSmall; + std::string iconMedium; + std::string iconLarge; + + std::string identifier; + std::string modScope; + +public: + int getPrice() const override { return price; } + + std::string getJsonKey() const override { return identifier; } + int32_t getIndex() const override { return id.getNum(); } + GameResID getId() const override { return id;} + int32_t getIconIndex() const override { return id.getNum(); } + std::string getModScope() const override { return modScope; }; + void registerIcons(const IconRegistar & cb) const override; + std::string getNameTextID() const override; + std::string getNameTranslated() const override; +}; + +class DLL_LINKAGE ResourceTypeHandler : public CHandlerBase +{ +public: + std::shared_ptr loadFromJson(const std::string & scope, + const JsonNode & json, + const std::string & identifier, + size_t index) override; + + const std::vector & getTypeNames() const override; + std::vector loadLegacyData() override; + + std::vector getAllObjects() const; +}; + +VCMI_LIB_NAMESPACE_END diff --git a/lib/entities/faction/CTownHandler.cpp b/lib/entities/faction/CTownHandler.cpp index 2a969e69c..b43721386 100644 --- a/lib/entities/faction/CTownHandler.cpp +++ b/lib/entities/faction/CTownHandler.cpp @@ -53,12 +53,9 @@ JsonNode readBuilding(CLegacyConfigParser & parser) JsonNode ret; JsonNode & cost = ret["cost"]; - //note: this code will try to parse mithril as well but wil always return 0 for it for(const std::string & resID : GameConstants::RESOURCE_NAMES) cost[resID].Float() = parser.readNumber(); - - cost.Struct().erase("mithril"); // erase mithril to avoid confusing validator - + parser.endLine(); return ret; @@ -284,8 +281,8 @@ void CTownHandler::loadBuilding(CTown * town, const std::string & stringID, cons LIBRARY->generaltexth->registerString(source.getModScope(), ret->getDescriptionTextID(), source["description"]); ret->subId = vstd::find_or(MappedKeys::SPECIAL_BUILDINGS, source["type"].String(), BuildingSubID::NONE); - ret->resources = TResources(source["cost"]); - ret->produce = TResources(source["produce"]); + ret->resources.resolveFromJson(source["cost"]); + ret->produce.resolveFromJson(source["produce"]); ret->manualHeroVisit = source["manualHeroVisit"].Bool(); ret->upgradeReplacesBonuses = source["upgradeReplacesBonuses"].Bool(); diff --git a/lib/gameState/CGameState.cpp b/lib/gameState/CGameState.cpp index b264dc90a..57b198686 100644 --- a/lib/gameState/CGameState.cpp +++ b/lib/gameState/CGameState.cpp @@ -397,7 +397,7 @@ void CGameState::initDifficulty() auto setDifficulty = [this](PlayerState & state, const JsonNode & json) { //set starting resources - state.resources = TResources(json["resources"]); + state.resources.resolveFromJson(json["resources"]); //handicap const PlayerSettings &ps = scenarioOps->getIthPlayersSettings(state.color); diff --git a/lib/gameState/GameStatistics.cpp b/lib/gameState/GameStatistics.cpp index 3bc6c4cf3..ffeea49fe 100644 --- a/lib/gameState/GameStatistics.cpp +++ b/lib/gameState/GameStatistics.cpp @@ -24,6 +24,7 @@ #include "../entities/building/CBuilding.h" #include "../serializer/JsonDeserializer.h" #include "../serializer/JsonUpdater.h" +#include "../entities/ResourceTypeHandler.h" VCMI_LIB_NAMESPACE_BEGIN @@ -105,8 +106,8 @@ void StatisticDataSetEntry::serializeJson(JsonSerializeFormat & handler) handler.serializeBool("hasGrail", hasGrail); { auto zonesData = handler.enterStruct("numMines"); - for(TResource idx = 0; idx < (GameConstants::RESOURCE_QUANTITY - 1); idx++) - handler.serializeInt(GameConstants::RESOURCE_NAMES[idx], numMines[idx], 0); + for(auto & idx : LIBRARY->resourceTypeHandler->getAllObjects()) + handler.serializeInt(idx.toResource()->getJsonKey(), numMines[idx], 0); } handler.serializeInt("score", score); handler.serializeInt("maxHeroLevel", maxHeroLevel); @@ -158,7 +159,7 @@ std::string StatisticDataSet::toCsv(std::string sep) const { std::stringstream ss; - auto resources = std::vector{EGameResID::GOLD, EGameResID::WOOD, EGameResID::MERCURY, EGameResID::ORE, EGameResID::SULFUR, EGameResID::CRYSTAL, EGameResID::GEMS}; + auto resources = std::vector{EGameResID::GOLD, EGameResID::WOOD, EGameResID::MERCURY, EGameResID::ORE, EGameResID::SULFUR, EGameResID::CRYSTAL, EGameResID::GEMS}; //todo: configurable resource support ss << "Map" << sep; ss << "Timestamp" << sep; @@ -191,15 +192,15 @@ std::string StatisticDataSet::toCsv(std::string sep) const ss << "EventDefeatedStrongestHero" << sep; ss << "MovementPointsUsed"; for(auto & resource : resources) - ss << sep << GameConstants::RESOURCE_NAMES[resource]; + ss << sep << resource.toResource()->getJsonKey(); for(auto & resource : resources) - ss << sep << GameConstants::RESOURCE_NAMES[resource] + "Mines"; + ss << sep << resource.toResource()->getJsonKey() + "Mines"; for(auto & resource : resources) - ss << sep << GameConstants::RESOURCE_NAMES[resource] + "SpentResourcesForArmy"; + ss << sep << resource.toResource()->getJsonKey() + "SpentResourcesForArmy"; for(auto & resource : resources) - ss << sep << GameConstants::RESOURCE_NAMES[resource] + "SpentResourcesForBuildings"; + ss << sep << resource.toResource()->getJsonKey() + "SpentResourcesForBuildings"; for(auto & resource : resources) - ss << sep << GameConstants::RESOURCE_NAMES[resource] + "TradeVolume"; + ss << sep << resource.toResource()->getJsonKey() + "TradeVolume"; ss << "\r\n"; for(auto & entry : data) @@ -403,7 +404,7 @@ std::map Statistic::getNumMines(const CGameState * gs, const Pl { std::map tmp; - for(auto & res : EGameResID::ALL_RESOURCES()) + for(auto & res : LIBRARY->resourceTypeHandler->getAllObjects()) tmp[res] = 0; for(const auto * object : ps->getOwnedObjects()) diff --git a/lib/json/JsonRandom.cpp b/lib/json/JsonRandom.cpp index 8f1e2878f..1dc269721 100644 --- a/lib/json/JsonRandom.cpp +++ b/lib/json/JsonRandom.cpp @@ -28,6 +28,7 @@ #include "../entities/artifact/CArtHandler.h" #include "../entities/hero/CHero.h" #include "../entities/hero/CHeroClass.h" +#include "../entities/ResourceTypeHandler.h" #include "../gameState/CGameState.h" #include "../mapObjects/army/CStackBasicDescriptor.h" #include "../mapObjects/IObjectInterface.h" @@ -298,9 +299,9 @@ JsonRandom::JsonRandom(IGameInfoCallback * cb, IGameRandomizer & gameRandomizer) return ret; } - for (size_t i=0; iresourceTypeHandler->getAllObjects()) { - ret[i] = loadValue(value[GameConstants::RESOURCE_NAMES[i]], variables); + ret[i] = loadValue(value[i.toResource()->getJsonKey()], variables); } return ret; } @@ -315,7 +316,7 @@ JsonRandom::JsonRandom(IGameInfoCallback * cb, IGameRandomizer & gameRandomizer) GameResID::CRYSTAL, GameResID::GEMS, GameResID::GOLD - }; + }; //todo: configurable resource support std::set potentialPicks = filterKeys(value, defaultResources, variables); GameResID resourceID = *RandomGeneratorUtil::nextItem(potentialPicks, rng); diff --git a/lib/mapObjectConstructors/CommonConstructors.cpp b/lib/mapObjectConstructors/CommonConstructors.cpp index 3019e0e28..241d715b9 100644 --- a/lib/mapObjectConstructors/CommonConstructors.cpp +++ b/lib/mapObjectConstructors/CommonConstructors.cpp @@ -17,6 +17,7 @@ #include "../callback/IGameInfoCallback.h" #include "../entities/faction/CTownHandler.h" #include "../entities/hero/CHeroClass.h" +#include "../entities/ResourceTypeHandler.h" #include "../mapObjects/CGHeroInstance.h" #include "../mapObjects/CGTownInstance.h" #include "../mapObjects/MiscObjects.h" @@ -60,7 +61,7 @@ bool ResourceInstanceConstructor::hasNameTextID() const std::string ResourceInstanceConstructor::getNameTextID() const { - return TextIdentifier("core", "restypes", resourceType.getNum()).get(); + return resourceType.toResource()->getNameTextID(); } GameResID ResourceInstanceConstructor::getResourceType() const diff --git a/lib/mapObjectConstructors/FlaggableInstanceConstructor.cpp b/lib/mapObjectConstructors/FlaggableInstanceConstructor.cpp index 56dd9656e..ad629ce7e 100644 --- a/lib/mapObjectConstructors/FlaggableInstanceConstructor.cpp +++ b/lib/mapObjectConstructors/FlaggableInstanceConstructor.cpp @@ -40,7 +40,7 @@ void FlaggableInstanceConstructor::initTypeData(const JsonNode & config) } } - dailyIncome = ResourceSet(config["dailyIncome"]); + dailyIncome.resolveFromJson(config["dailyIncome"]); } void FlaggableInstanceConstructor::initializeObject(FlaggableMapObject * flaggable) const diff --git a/lib/mapObjects/CGCreature.cpp b/lib/mapObjects/CGCreature.cpp index 62cf11f5f..1e9e227b3 100644 --- a/lib/mapObjects/CGCreature.cpp +++ b/lib/mapObjects/CGCreature.cpp @@ -25,6 +25,7 @@ #include "../networkPacks/StackLocation.h" #include "../serializer/JsonSerializeFormat.h" #include "../entities/faction/CTownHandler.h" +#include "../entities/ResourceTypeHandler.h" #include @@ -630,7 +631,7 @@ void CGCreature::giveReward(IGameEventCallback & gameEvents, const CGHeroInstanc if(!resources.empty()) { gameEvents.giveResources(h->tempOwner, resources); - for(const auto & res : GameResID::ALL_RESOURCES()) + for(const auto & res : LIBRARY->resourceTypeHandler->getAllObjects()) { if(resources[res] > 0) iw.components.emplace_back(ComponentType::RESOURCE, res, resources[res]); diff --git a/lib/mapObjects/CGHeroInstance.cpp b/lib/mapObjects/CGHeroInstance.cpp index 02a58af77..cfb0ec938 100644 --- a/lib/mapObjects/CGHeroInstance.cpp +++ b/lib/mapObjects/CGHeroInstance.cpp @@ -38,6 +38,7 @@ #include "../entities/faction/CTownHandler.h" #include "../entities/hero/CHeroHandler.h" #include "../entities/hero/CHeroClass.h" +#include "../entities/ResourceTypeHandler.h" #include "../battle/CBattleInfoEssentials.h" #include "../campaign/CampaignState.h" #include "../json/JsonBonus.h" @@ -1816,7 +1817,7 @@ ResourceSet CGHeroInstance::dailyIncome() const { ResourceSet income; - for (GameResID k : GameResID::ALL_RESOURCES()) + for (GameResID k : LIBRARY->resourceTypeHandler->getAllObjects()) income[k] += valOfBonuses(BonusType::GENERATE_RESOURCE, BonusSubtypeID(k)); const auto & playerSettings = cb->getPlayerSettings(getOwner()); diff --git a/lib/mapObjects/CGObjectInstance.cpp b/lib/mapObjects/CGObjectInstance.cpp index af03d50f9..4370918f7 100644 --- a/lib/mapObjects/CGObjectInstance.cpp +++ b/lib/mapObjects/CGObjectInstance.cpp @@ -1,5 +1,5 @@ /* - * CObjectHandler.cpp, part of VCMI engine + * CGObjectInstance.cpp, part of VCMI engine * * Authors: listed in file AUTHORS in main folder * diff --git a/lib/mapObjects/CGResource.cpp b/lib/mapObjects/CGResource.cpp index e95d25069..3bcb8773e 100644 --- a/lib/mapObjects/CGResource.cpp +++ b/lib/mapObjects/CGResource.cpp @@ -21,6 +21,7 @@ #include "../gameState/CGameState.h" #include "../serializer/JsonSerializeFormat.h" #include "../CSoundBase.h" +#include "../entities/ResourceTypeHandler.h" #include @@ -50,7 +51,7 @@ GameResID CGResource::resourceID() const std::string CGResource::getHoverText(PlayerColor player) const { - return LIBRARY->generaltexth->restypes[resourceID().getNum()]; + return resourceID().toResource()->getNameTranslated(); } void CGResource::pickRandomObject(IGameRandomizer & gameRandomizer) @@ -60,7 +61,7 @@ void CGResource::pickRandomObject(IGameRandomizer & gameRandomizer) if (ID == Obj::RANDOM_RESOURCE) { ID = Obj::RESOURCE; - subID = gameRandomizer.getDefault().nextInt(EGameResID::WOOD, EGameResID::GOLD); + subID = gameRandomizer.getDefault().nextInt(EGameResID::WOOD, EGameResID::GOLD); //todo: configurable resource support setType(ID, subID); amount *= getAmountMultiplier(); diff --git a/lib/mapObjects/CGTownInstance.cpp b/lib/mapObjects/CGTownInstance.cpp index 8407872d6..9f99f74b3 100644 --- a/lib/mapObjects/CGTownInstance.cpp +++ b/lib/mapObjects/CGTownInstance.cpp @@ -32,6 +32,7 @@ #include "../callback/IGameRandomizer.h" #include "../entities/building/CBuilding.h" #include "../entities/faction/CTownHandler.h" +#include "../entities/ResourceTypeHandler.h" #include "../mapObjectConstructors/AObjectTypeHandler.h" #include "../mapObjectConstructors/CObjectClassesHandler.h" #include "../mapObjects/CGHeroInstance.h" @@ -209,7 +210,7 @@ TResources CGTownInstance::dailyIncome() const { ResourceSet ret; - for (GameResID k : GameResID::ALL_RESOURCES()) + for (GameResID k : LIBRARY->resourceTypeHandler->getAllObjects()) ret[k] += valOfBonuses(BonusType::GENERATE_RESOURCE, BonusSubtypeID(k)); for(const auto & p : getTown()->buildings) diff --git a/lib/mapObjects/CObjectHandler.cpp b/lib/mapObjects/CObjectHandler.cpp deleted file mode 100644 index 8226d01ef..000000000 --- a/lib/mapObjects/CObjectHandler.cpp +++ /dev/null @@ -1,31 +0,0 @@ -/* - * CObjectHandler.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 "CObjectHandler.h" - -#include "CGObjectInstance.h" -#include "../filesystem/ResourcePath.h" -#include "../json/JsonNode.h" - -VCMI_LIB_NAMESPACE_BEGIN - -CObjectHandler::CObjectHandler() -{ - logGlobal->trace("\t\tReading resources prices "); - const JsonNode config2(JsonPath::builtin("config/resources.json")); - for(const JsonNode &price : config2["resources_prices"].Vector()) - { - resVals.push_back(static_cast(price.Float())); - } - logGlobal->trace("\t\tDone loading resource prices!"); -} - -VCMI_LIB_NAMESPACE_END diff --git a/lib/mapObjects/CQuest.cpp b/lib/mapObjects/CQuest.cpp index b2e99e7a3..738988b92 100644 --- a/lib/mapObjects/CQuest.cpp +++ b/lib/mapObjects/CQuest.cpp @@ -22,6 +22,7 @@ #include "../callback/IGameRandomizer.h" #include "../entities/artifact/CArtifact.h" #include "../entities/hero/CHeroHandler.h" +#include "../entities/ResourceTypeHandler.h" #include "../mapObjectConstructors/CObjectClassesHandler.h" #include "../serializer/JsonSerializeFormat.h" #include "../GameConstants.h" @@ -233,7 +234,7 @@ void CQuest::addTextReplacements(const IGameInfoCallback * cb, MetaString & text if(mission.resources.nonZero()) { MetaString loot; - for(auto i : GameResID::ALL_RESOURCES()) + for(auto i : LIBRARY->resourceTypeHandler->getAllObjects()) { if(mission.resources[i]) { @@ -372,11 +373,9 @@ void CQuest::serializeJson(JsonSerializeFormat & handler, const std::string & fi if(missionType == "Resources") { auto r = handler.enterStruct("resources"); - - for(size_t idx = 0; idx < (GameConstants::RESOURCE_QUANTITY - 1); idx++) - { - handler.serializeInt(GameConstants::RESOURCE_NAMES[idx], mission.resources[idx], 0); - } + + for(auto & idx : LIBRARY->resourceTypeHandler->getAllObjects()) + handler.serializeInt(idx.toResource()->getJsonKey(), mission.resources[idx], 0); } if(missionType == "Hero") diff --git a/lib/mapObjects/IMarket.cpp b/lib/mapObjects/IMarket.cpp index 43e687d9e..414d57de5 100644 --- a/lib/mapObjects/IMarket.cpp +++ b/lib/mapObjects/IMarket.cpp @@ -13,10 +13,10 @@ #include "CCreatureHandler.h" #include "CGObjectInstance.h" -#include "CObjectHandler.h" #include "../GameLibrary.h" #include "../entities/artifact/CArtHandler.h" +#include "../entities/ResourceTypeHandler.h" VCMI_LIB_NAMESPACE_BEGIN @@ -33,8 +33,8 @@ bool IMarket::getOffer(int id1, int id2, int &val1, int &val2, EMarketMode mode) { double effectiveness = std::min((getMarketEfficiency() + 1.0) / 20.0, 0.5); - double r = LIBRARY->objh->resVals[id1]; //value of given resource - double g = LIBRARY->objh->resVals[id2] / effectiveness; //value of wanted resource + double r = GameResID(id1).toResource()->getPrice(); //value of given resource + double g = GameResID(id2).toResource()->getPrice() / effectiveness; //value of wanted resource if(r>g) //if given resource is more expensive than wanted { @@ -54,7 +54,7 @@ bool IMarket::getOffer(int id1, int id2, int &val1, int &val2, EMarketMode mode) double effectiveness = effectivenessArray[std::min(getMarketEfficiency(), 8)]; double r = LIBRARY->creatures()->getByIndex(id1)->getRecruitCost(EGameResID::GOLD); //value of given creature in gold - double g = LIBRARY->objh->resVals[id2] / effectiveness; //value of wanted resource + double g = GameResID(id2).toResource()->getPrice() / effectiveness; //value of wanted resource if(r>g) //if given resource is more expensive than wanted { @@ -75,7 +75,7 @@ bool IMarket::getOffer(int id1, int id2, int &val1, int &val2, EMarketMode mode) case EMarketMode::RESOURCE_ARTIFACT: { double effectiveness = std::min((getMarketEfficiency() + 3.0) / 20.0, 0.6); - double r = LIBRARY->objh->resVals[id1]; //value of offered resource + double r = GameResID(id1).toResource()->getPrice(); //value of offered resource double g = LIBRARY->artifacts()->getByIndex(id2)->getPrice() / effectiveness; //value of bought artifact in gold if(id1 != 6) //non-gold prices are doubled @@ -89,7 +89,7 @@ bool IMarket::getOffer(int id1, int id2, int &val1, int &val2, EMarketMode mode) { double effectiveness = std::min((getMarketEfficiency() + 3.0) / 20.0, 0.6); double r = LIBRARY->artifacts()->getByIndex(id1)->getPrice() * effectiveness; - double g = LIBRARY->objh->resVals[id2]; + double g = GameResID(id2).toResource()->getPrice(); // if(id2 != 6) //non-gold prices are doubled // r /= 2; @@ -163,7 +163,7 @@ std::vector IMarket::availableItemsIds(const EMarketMode mode) con case EMarketMode::RESOURCE_RESOURCE: case EMarketMode::ARTIFACT_RESOURCE: case EMarketMode::CREATURE_RESOURCE: - for(const auto & res : GameResID::ALL_RESOURCES()) + for(const auto & res : LIBRARY->resourceTypeHandler->getAllObjects()) ret.push_back(res); } return ret; diff --git a/lib/mapObjects/MapObjects.h b/lib/mapObjects/MapObjects.h index 918a05e14..3493f45f2 100644 --- a/lib/mapObjects/MapObjects.h +++ b/lib/mapObjects/MapObjects.h @@ -10,8 +10,6 @@ #pragma once // Helper header that includes all map objects, similar to old CObjectHandler.h -// Possible TODO - remove this header after CObjectHandler.cpp will be fully split into smaller files -#include "CObjectHandler.h" #include "CGDwelling.h" #include "CGHeroInstance.h" diff --git a/lib/mapObjects/MiscObjects.cpp b/lib/mapObjects/MiscObjects.cpp index f5fda550b..c9cc8bfe1 100644 --- a/lib/mapObjects/MiscObjects.cpp +++ b/lib/mapObjects/MiscObjects.cpp @@ -18,6 +18,7 @@ #include "../constants/StringConstants.h" #include "../entities/artifact/ArtifactUtils.h" #include "../entities/artifact/CArtifact.h" +#include "../entities/ResourceTypeHandler.h" #include "../CConfigHandler.h" #include "../texts/CGeneralTextHandler.h" #include "../CSkillHandler.h" @@ -143,7 +144,7 @@ ResourceSet CGMine::dailyIncome() const { ResourceSet result; - for (GameResID k : GameResID::ALL_RESOURCES()) + for (GameResID k : LIBRARY->resourceTypeHandler->getAllObjects()) result[k] += valOfBonuses(BonusType::GENERATE_RESOURCE, BonusSubtypeID(k)); result[producedResource] += defaultResProduction(); @@ -164,7 +165,7 @@ std::string CGMine::getHoverText(PlayerColor player) const std::string hoverName = CArmedInstance::getHoverText(player); if (tempOwner != PlayerColor::NEUTRAL) - hoverName += "\n(" + LIBRARY->generaltexth->restypes[producedResource.getNum()] + ")"; + hoverName += "\n(" + producedResource.toResource()->getNameTranslated() + ")"; if(stacksCount()) { @@ -238,7 +239,7 @@ void CGMine::serializeJsonOptions(JsonSerializeFormat & handler) { JsonNode node; for(const auto & resID : abandonedMineResources) - node.Vector().emplace_back(GameConstants::RESOURCE_NAMES[resID.getNum()]); + node.Vector().emplace_back(resID.toResource()->getJsonKey()); handler.serializeRaw("possibleResources", node, std::nullopt); } @@ -251,7 +252,10 @@ void CGMine::serializeJsonOptions(JsonSerializeFormat & handler) for(const std::string & s : names) { - int raw_res = vstd::find_pos(GameConstants::RESOURCE_NAMES, s); + std::vector resNames; + for(auto & res : LIBRARY->resourceTypeHandler->getAllObjects()) + resNames.push_back(res.toResource()->getJsonKey()); + int raw_res = vstd::find_pos(resNames, s); if(raw_res < 0) logGlobal->error("Invalid resource name: %s", s); else @@ -872,7 +876,7 @@ const IOwnableObject * CGGarrison::asOwnable() const ResourceSet CGGarrison::dailyIncome() const { ResourceSet result; - for (GameResID k : GameResID::ALL_RESOURCES()) + for (GameResID k : LIBRARY->resourceTypeHandler->getAllObjects()) result[k] += valOfBonuses(BonusType::GENERATE_RESOURCE, BonusSubtypeID(k)); return result; diff --git a/lib/modding/ContentTypeHandler.cpp b/lib/modding/ContentTypeHandler.cpp index 4e1abf178..6d7e1c220 100644 --- a/lib/modding/ContentTypeHandler.cpp +++ b/lib/modding/ContentTypeHandler.cpp @@ -23,6 +23,7 @@ #include "../entities/faction/CTownHandler.h" #include "../entities/hero/CHeroClassHandler.h" #include "../entities/hero/CHeroHandler.h" +#include "../entities/ResourceTypeHandler.h" #include "../texts/CGeneralTextHandler.h" #include "../CBonusTypeHandler.h" #include "../CSkillHandler.h" @@ -263,6 +264,7 @@ void CContentHandler::init() handlers.insert(std::make_pair("roads", ContentTypeHandler(LIBRARY->roadTypeHandler.get(), "road"))); handlers.insert(std::make_pair("obstacles", ContentTypeHandler(LIBRARY->obstacleHandler.get(), "obstacle"))); handlers.insert(std::make_pair("biomes", ContentTypeHandler(LIBRARY->biomeHandler.get(), "biome"))); + handlers.insert(std::make_pair("resources", ContentTypeHandler(LIBRARY->resourceTypeHandler.get(), "resources"))); } bool CContentHandler::preloadData(const ModDescription & mod, bool validate) diff --git a/lib/rewardable/Info.cpp b/lib/rewardable/Info.cpp index 7f60b5041..b2711ba44 100644 --- a/lib/rewardable/Info.cpp +++ b/lib/rewardable/Info.cpp @@ -22,6 +22,7 @@ #include "../mapObjects/IObjectInterface.h" #include "../modding/IdentifierStorage.h" #include "../texts/CGeneralTextHandler.h" +#include "../entities/ResourceTypeHandler.h" #include @@ -296,7 +297,7 @@ void Rewardable::Info::replaceTextPlaceholders(MetaString & target, const Variab MetaString loot; - for (GameResID it : GameResID::ALL_RESOURCES()) + for (GameResID it : LIBRARY->resourceTypeHandler->getAllObjects()) { if (info.reward.resources[it] != 0) { diff --git a/lib/rmg/CRmgTemplate.cpp b/lib/rmg/CRmgTemplate.cpp index a794da171..693e8ef6d 100644 --- a/lib/rmg/CRmgTemplate.cpp +++ b/lib/rmg/CRmgTemplate.cpp @@ -18,6 +18,7 @@ #include "../GameLibrary.h" #include "../constants/StringConstants.h" #include "../entities/faction/CTownHandler.h" +#include "../entities/ResourceTypeHandler.h" #include "../modding/ModScope.h" #include "../serializer/JsonSerializeFormat.h" @@ -258,12 +259,12 @@ std::set ZoneOptions::getMonsterTypes() const return vstd::difference(monsterTypes, bannedMonsters); } -void ZoneOptions::setMinesInfo(const std::map & value) +void ZoneOptions::setMinesInfo(const std::map & value) { mines = value; } -std::map ZoneOptions::getMinesInfo() const +std::map ZoneOptions::getMinesInfo() const { return mines; } @@ -532,12 +533,7 @@ void ZoneOptions::serializeJson(JsonSerializeFormat & handler) if((minesLikeZone == NO_ZONE) && (!handler.saving || !mines.empty())) { - auto minesData = handler.enterStruct("mines"); - - for(TResource idx = 0; idx < (GameConstants::RESOURCE_QUANTITY - 1); idx++) - { - handler.serializeInt(GameConstants::RESOURCE_NAMES[idx], mines[idx], 0); - } + handler.serializeIdMap("mines", mines); } handler.serializeStruct("customObjects", objectConfig); diff --git a/lib/rmg/CRmgTemplate.h b/lib/rmg/CRmgTemplate.h index b1680deef..4c639a38c 100644 --- a/lib/rmg/CRmgTemplate.h +++ b/lib/rmg/CRmgTemplate.h @@ -209,8 +209,8 @@ public: void setMonsterTypes(const std::set & value); - void setMinesInfo(const std::map & value); - std::map getMinesInfo() const; + void setMinesInfo(const std::map & value); + std::map getMinesInfo() const; void setTreasureInfo(const std::vector & value); void addTreasureInfo(const CTreasureInfo & value); @@ -277,7 +277,7 @@ protected: std::set monsterTypes; std::set bannedMonsters; - std::map mines; //obligatory mines to spawn in this zone + std::map mines; //obligatory mines to spawn in this zone std::vector treasureInfo; @@ -373,7 +373,7 @@ private: std::set bannedHeroes; std::set inheritTerrainType(std::shared_ptr zone, uint32_t iteration = 0); - std::map inheritMineTypes(std::shared_ptr zone, uint32_t iteration = 0); + std::map inheritMineTypes(std::shared_ptr zone, uint32_t iteration = 0); std::vector inheritTreasureInfo(std::shared_ptr zone, uint32_t iteration = 0); void inheritTownProperties(std::shared_ptr zone, uint32_t iteration = 0); diff --git a/lib/serializer/JsonDeserializer.cpp b/lib/serializer/JsonDeserializer.cpp index 87cda93d6..06735316d 100644 --- a/lib/serializer/JsonDeserializer.cpp +++ b/lib/serializer/JsonDeserializer.cpp @@ -119,6 +119,16 @@ void JsonDeserializer::serializeInternal(const std::string & fieldName, std::vec } } +void JsonDeserializer::serializeInternal(const std::string & fieldName, std::map & value) +{ + const JsonMap & data = currentObject->operator[](fieldName).Struct(); + + value.clear(); + + for(const auto & [id, elem] : data) + value[id] = elem.Integer(); +} + void JsonDeserializer::serializeInternal(std::string & value) { value = currentObject->String(); diff --git a/lib/serializer/JsonDeserializer.h b/lib/serializer/JsonDeserializer.h index 9a3aab5ee..98dd058c2 100644 --- a/lib/serializer/JsonDeserializer.h +++ b/lib/serializer/JsonDeserializer.h @@ -32,6 +32,7 @@ protected: void serializeInternal(const std::string & fieldName, si64 & value, const std::optional & defaultValue) override; void serializeInternal(const std::string & fieldName, si32 & value, const std::optional & defaultValue, const std::vector & enumMap) override; void serializeInternal(const std::string & fieldName, std::vector & value) override; + void serializeInternal(const std::string & fieldName, std::map & value) override; void serializeInternal(std::string & value) override; void serializeInternal(int64_t & value) override; diff --git a/lib/serializer/JsonSerializeFormat.h b/lib/serializer/JsonSerializeFormat.h index 3ec30f37c..53b2aa69d 100644 --- a/lib/serializer/JsonSerializeFormat.h +++ b/lib/serializer/JsonSerializeFormat.h @@ -331,6 +331,33 @@ public: } } + /// si32-convertible identifier map <-> Json object of {key: string} + template + void serializeIdMap(const std::string & fieldName, std::map & value) + { + if (saving) + { + std::map fieldValue; + + for (const auto & [key, val] : value) + fieldValue[Key::encode(key.getNum())] = val; + + serializeInternal(fieldName, fieldValue); + } + else + { + const JsonNode & node = getCurrent()[fieldName]; + for (const auto & [keyStr, jsonVal] : node.Struct()) + { + Key key = Key::decode(keyStr); + + LIBRARY->identifiers()->requestIdentifier(node.getModScope(), Key::entityType(), keyStr, [&value, key](int32_t index) { + value[key] = T(index); + }); + } + } + } + ///si32-convertible identifier vector <-> Json array of string template void serializeIdArray(const std::string & fieldName, std::vector & value) @@ -443,6 +470,9 @@ protected: ///String vector <-> Json string vector virtual void serializeInternal(const std::string & fieldName, std::vector & value) = 0; + ///String map <-> Json map of int + virtual void serializeInternal(const std::string & fieldName, std::map & value) = 0; + virtual void pop() = 0; virtual void pushStruct(const std::string & fieldName) = 0; virtual void pushArray(const std::string & fieldName) = 0; diff --git a/lib/serializer/JsonSerializer.cpp b/lib/serializer/JsonSerializer.cpp index adcb3ffd3..2fba350a9 100644 --- a/lib/serializer/JsonSerializer.cpp +++ b/lib/serializer/JsonSerializer.cpp @@ -75,6 +75,17 @@ void JsonSerializer::serializeInternal(const std::string & fieldName, std::vecto data.emplace_back(rawId); } +void JsonSerializer::serializeInternal(const std::string & fieldName, std::map & value) +{ + if(value.empty()) + return; + + JsonMap & data = currentObject->operator[](fieldName).Struct(); + + for(const auto & [rawId, val] : value) + data[rawId].Integer() = val; +} + void JsonSerializer::serializeInternal(std::string & value) { currentObject->String() = value; diff --git a/lib/serializer/JsonSerializer.h b/lib/serializer/JsonSerializer.h index 89bbbf26d..8a29074a6 100644 --- a/lib/serializer/JsonSerializer.h +++ b/lib/serializer/JsonSerializer.h @@ -32,6 +32,7 @@ protected: void serializeInternal(const std::string & fieldName, si64 & value, const std::optional & defaultValue) override; void serializeInternal(const std::string & fieldName, si32 & value, const std::optional & defaultValue, const std::vector & enumMap) override; void serializeInternal(const std::string & fieldName, std::vector & value) override; + void serializeInternal(const std::string & fieldName, std::map & value) override; void serializeInternal(std::string & value) override; void serializeInternal(int64_t & value) override; diff --git a/lib/serializer/JsonUpdater.cpp b/lib/serializer/JsonUpdater.cpp index 0d31638c7..d427cb612 100644 --- a/lib/serializer/JsonUpdater.cpp +++ b/lib/serializer/JsonUpdater.cpp @@ -65,6 +65,11 @@ void JsonUpdater::serializeInternal(const std::string & fieldName, std::vector & value) +{ + // TODO +} + void JsonUpdater::serializeInternal(const std::string & fieldName, double & value, const std::optional & defaultValue) { const JsonNode & data = currentObject->operator[](fieldName); diff --git a/lib/serializer/JsonUpdater.h b/lib/serializer/JsonUpdater.h index e0cd5f508..d517a8e0d 100644 --- a/lib/serializer/JsonUpdater.h +++ b/lib/serializer/JsonUpdater.h @@ -36,6 +36,7 @@ protected: void serializeInternal(const std::string & fieldName, si64 & value, const std::optional & defaultValue) override; void serializeInternal(const std::string & fieldName, si32 & value, const std::optional & defaultValue, const std::vector & enumMap) override; void serializeInternal(const std::string & fieldName, std::vector & value) override; + void serializeInternal(const std::string & fieldName, std::map & value) override; void serializeInternal(std::string & value) override; void serializeInternal(int64_t & value) override; diff --git a/lib/texts/MetaString.cpp b/lib/texts/MetaString.cpp index 60a3375b4..60e037a61 100644 --- a/lib/texts/MetaString.cpp +++ b/lib/texts/MetaString.cpp @@ -14,6 +14,7 @@ #include "entities/artifact/CArtifact.h" #include "entities/faction/CFaction.h" #include "entities/hero/CHero.h" +#include "entities/ResourceTypeHandler.h" #include "texts/CGeneralTextHandler.h" #include "CSkillHandler.h" #include "GameConstants.h" @@ -378,7 +379,7 @@ void MetaString::appendName(const CreatureID & id, TQuantity count) void MetaString::appendName(const GameResID& id) { - appendTextID(TextIdentifier("core.restypes", id.getNum()).get()); + appendTextID(id.toResource()->getNameTextID()); } void MetaString::appendNameSingular(const CreatureID & id) @@ -423,7 +424,7 @@ void MetaString::replaceName(const SpellID & id) void MetaString::replaceName(const GameResID& id) { - replaceTextID(TextIdentifier("core.restypes", id.getNum()).get()); + replaceTextID(id.toResource()->getNameTextID()); } void MetaString::replaceNameSingular(const CreatureID & id) diff --git a/mapeditor/graphics.cpp b/mapeditor/graphics.cpp index 00eb6f558..7dd03e122 100644 --- a/mapeditor/graphics.cpp +++ b/mapeditor/graphics.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include "../lib/filesystem/Filesystem.h" #include "../lib/filesystem/CBinaryReader.h" @@ -342,4 +343,5 @@ void Graphics::initializeImageLists() addImageListEntries(LIBRARY->factions()); addImageListEntries(LIBRARY->spells()); addImageListEntries(LIBRARY->skills()); + addImageListEntries(LIBRARY->resources()); } diff --git a/mapeditor/inspector/questwidget.cpp b/mapeditor/inspector/questwidget.cpp index 697306f2f..5d2d73d5c 100644 --- a/mapeditor/inspector/questwidget.cpp +++ b/mapeditor/inspector/questwidget.cpp @@ -17,6 +17,7 @@ #include "../lib/CCreatureHandler.h" #include "../lib/constants/StringConstants.h" #include "../lib/entities/artifact/CArtHandler.h" +#include "../lib/entities/ResourceTypeHandler.h" #include "../lib/mapping/CMap.h" #include "../lib/mapObjects/CGHeroInstance.h" #include "../lib/mapObjects/CGCreature.h" @@ -40,13 +41,13 @@ QuestWidget::QuestWidget(MapController & _controller, CQuest & _sh, QWidget *par ui->lDayOfWeek->addItem(tr("Day %1").arg(i)); //fill resources - ui->lResources->setRowCount(GameConstants::RESOURCE_QUANTITY - 1); - for(int i = 0; i < GameConstants::RESOURCE_QUANTITY - 1; ++i) + ui->lResources->setRowCount(LIBRARY->resourceTypeHandler->getAllObjects().size() - 1); + for(auto & i : LIBRARY->resourceTypeHandler->getAllObjects()) { MetaString str; str.appendName(GameResID(i)); auto * item = new QTableWidgetItem(QString::fromStdString(str.toString())); - item->setData(Qt::UserRole, QVariant::fromValue(i)); + item->setData(Qt::UserRole, QVariant::fromValue(i.getNum())); ui->lResources->setItem(i, 0, item); auto * spinBox = new QSpinBox; spinBox->setMaximum(i == GameResID::GOLD ? 999999 : 999); @@ -455,8 +456,6 @@ void QuestDelegate::updateModelData(QAbstractItemModel * model, const QModelInde QStringList resourcesList; for(GameResID resource = GameResID::WOOD; resource < GameResID::COUNT ; resource++) { - if(resource == GameResID::MITHRIL) - continue; if(quest.mission.resources[resource] == 0) continue; MetaString str; diff --git a/mapeditor/inspector/rewardswidget.cpp b/mapeditor/inspector/rewardswidget.cpp index 103aa32da..0669e4fb2 100644 --- a/mapeditor/inspector/rewardswidget.cpp +++ b/mapeditor/inspector/rewardswidget.cpp @@ -17,6 +17,7 @@ #include "../lib/CCreatureHandler.h" #include "../lib/constants/StringConstants.h" #include "../lib/entities/artifact/CArtifact.h" +#include "../lib/entities/ResourceTypeHandler.h" #include "../lib/mapping/CMap.h" #include "../lib/modding/IdentifierStorage.h" #include "../lib/modding/ModScope.h" @@ -55,16 +56,16 @@ RewardsWidget::RewardsWidget(CMap & m, CRewardableObject & p, QWidget *parent) : ui->lDayOfWeek->addItem(tr("Day %1").arg(i)); //fill resources - ui->rResources->setRowCount(GameConstants::RESOURCE_QUANTITY - 1); - ui->lResources->setRowCount(GameConstants::RESOURCE_QUANTITY - 1); - for(int i = 0; i < GameConstants::RESOURCE_QUANTITY - 1; ++i) + ui->rResources->setRowCount(LIBRARY->resourceTypeHandler->getAllObjects().size() - 1); + ui->lResources->setRowCount(LIBRARY->resourceTypeHandler->getAllObjects().size() - 1); + for(auto & i : LIBRARY->resourceTypeHandler->getAllObjects()) { MetaString str; str.appendName(GameResID(i)); for(auto * w : {ui->rResources, ui->lResources}) { auto * item = new QTableWidgetItem(QString::fromStdString(str.toString())); - item->setData(Qt::UserRole, QVariant::fromValue(i)); + item->setData(Qt::UserRole, QVariant::fromValue(i.getNum())); w->setItem(i, 0, item); auto * spinBox = new QSpinBox; spinBox->setMaximum(i == GameResID::GOLD ? 999999 : 999); @@ -779,8 +780,6 @@ void RewardsDelegate::updateModelData(QAbstractItemModel * model, const QModelIn QStringList resourcesList; for(GameResID resource = GameResID::WOOD; resource < GameResID::COUNT ; resource++) { - if(resource == GameResID::MITHRIL) - continue; // translated as "Abandoned"? if(vinfo.reward.resources[resource] == 0) continue; MetaString str; diff --git a/mapeditor/inspector/towneventdialog.cpp b/mapeditor/inspector/towneventdialog.cpp index 14724212f..2ed52009c 100644 --- a/mapeditor/inspector/towneventdialog.cpp +++ b/mapeditor/inspector/towneventdialog.cpp @@ -18,6 +18,8 @@ #include "../../lib/entities/faction/CTownHandler.h" #include "../../lib/constants/NumericConstants.h" #include "../../lib/constants/StringConstants.h" +#include "../../lib/GameLibrary.h" +#include "../../lib/entities/ResourceTypeHandler.h" static const int FIRST_DAY_FOR_EVENT = 1; static const int LAST_DAY_FOR_EVENT = 999; @@ -79,9 +81,9 @@ void TownEventDialog::initPlayers() void TownEventDialog::initResources() { - ui->resourcesTable->setRowCount(GameConstants::RESOURCE_QUANTITY); + ui->resourcesTable->setRowCount(LIBRARY->resourceTypeHandler->getAllObjects().size()); auto resourcesMap = params.value("resources").toMap(); - for (int i = 0; i < GameConstants::RESOURCE_QUANTITY; ++i) + for(auto & i : LIBRARY->resourceTypeHandler->getAllObjects()) { MetaString str; str.appendName(GameResID(i)); @@ -91,7 +93,7 @@ void TownEventDialog::initResources() item->setText(name); ui->resourcesTable->setItem(i, 0, item); - int val = resourcesMap.value(QString::fromStdString(GameConstants::RESOURCE_NAMES[i])).toInt(); + int val = resourcesMap.value(QString::fromStdString(i.toResource()->getJsonKey())).toInt(); auto * edit = new QSpinBox(ui->resourcesTable); edit->setMaximum(i == GameResID::GOLD ? MAXIMUM_GOLD_CHANGE : MAXIMUM_RESOURCE_CHANGE); edit->setMinimum(i == GameResID::GOLD ? -MAXIMUM_GOLD_CHANGE : -MAXIMUM_RESOURCE_CHANGE); @@ -228,9 +230,9 @@ QVariant TownEventDialog::playersToVariant() QVariantMap TownEventDialog::resourcesToVariant() { auto res = params.value("resources").toMap(); - for (int i = 0; i < GameConstants::RESOURCE_QUANTITY; ++i) + for(auto & i : LIBRARY->resourceTypeHandler->getAllObjects()) { - auto itemType = QString::fromStdString(GameConstants::RESOURCE_NAMES[i]); + auto itemType = QString::fromStdString(i.toResource()->getJsonKey()); auto * itemQty = static_cast (ui->resourcesTable->cellWidget(i, 1)); res[itemType] = QVariant::fromValue(itemQty->value()); diff --git a/mapeditor/mapsettings/eventsettings.cpp b/mapeditor/mapsettings/eventsettings.cpp index 7eae1b493..63a287863 100644 --- a/mapeditor/mapsettings/eventsettings.cpp +++ b/mapeditor/mapsettings/eventsettings.cpp @@ -14,6 +14,8 @@ #include "../mapcontroller.h" #include "../../lib/constants/NumericConstants.h" #include "../../lib/constants/StringConstants.h" +#include "../../lib/GameLibrary.h" +#include "../../lib/entities/ResourceTypeHandler.h" QString toQString(const PlayerColor & player) { @@ -41,8 +43,8 @@ std::set playersFromVariant(const QVariant & v) QVariant toVariant(const TResources & resources) { QVariantMap result; - for(int i = 0; i < GameConstants::RESOURCE_QUANTITY; ++i) - result[QString::fromStdString(GameConstants::RESOURCE_NAMES[i])] = QVariant::fromValue(resources[i]); + for(auto & i : LIBRARY->resourceTypeHandler->getAllObjects()) + result[QString::fromStdString(i.toResource()->getJsonKey())] = QVariant::fromValue(resources[i]); return result; } @@ -51,7 +53,9 @@ TResources resourcesFromVariant(const QVariant & v) JsonNode vJson; for(auto r : v.toMap().keys()) vJson[r.toStdString()].Integer() = v.toMap().value(r).toInt(); - return TResources(vJson); + ResourceSet res; + res.resolveFromJson(vJson); + return res; } QVariant toVariant(std::vector objects) diff --git a/mapeditor/mapsettings/timedevent.cpp b/mapeditor/mapsettings/timedevent.cpp index 5cbb25ca8..879af496e 100644 --- a/mapeditor/mapsettings/timedevent.cpp +++ b/mapeditor/mapsettings/timedevent.cpp @@ -14,6 +14,8 @@ #include "../mapeditorroles.h" #include "../../lib/constants/EntityIdentifiers.h" #include "../../lib/constants/StringConstants.h" +#include "../../lib/GameLibrary.h" +#include "../../lib/entities/ResourceTypeHandler.h" TimedEvent::TimedEvent(MapController & c, QListWidgetItem * t, QWidget *parent) : controller(c), @@ -45,13 +47,13 @@ TimedEvent::TimedEvent(MapController & c, QListWidgetItem * t, QWidget *parent) ui->playersAffected->addItem(item); } - ui->resources->setRowCount(GameConstants::RESOURCE_QUANTITY); - for(int i = 0; i < GameConstants::RESOURCE_QUANTITY; ++i) + ui->resources->setRowCount(LIBRARY->resourceTypeHandler->getAllObjects().size()); + for(auto & i : LIBRARY->resourceTypeHandler->getAllObjects()) { MetaString str; str.appendName(GameResID(i)); auto name = QString::fromStdString(str.toString()); - int val = params.value("resources").toMap().value(QString::fromStdString(GameConstants::RESOURCE_NAMES[i])).toInt(); + int val = params.value("resources").toMap().value(QString::fromStdString(i.toResource()->getJsonKey())).toInt(); ui->resources->setItem(i, 0, new QTableWidgetItem(name)); auto nval = new QTableWidgetItem(QString::number(val)); nval->setFlags(nval->flags() | Qt::ItemIsEditable); @@ -94,9 +96,9 @@ void TimedEvent::on_TimedEvent_finished(int result) descriptor["players"] = QVariant::fromValue(players); auto res = target->data(Qt::UserRole).toMap().value("resources").toMap(); - for(int i = 0; i < GameConstants::RESOURCE_QUANTITY; ++i) + for(auto & i : LIBRARY->resourceTypeHandler->getAllObjects()) { - auto itemType = QString::fromStdString(GameConstants::RESOURCE_NAMES[i]); + auto itemType = QString::fromStdString(i.toResource()->getJsonKey()); auto * itemQty = ui->resources->item(i, 1); res[itemType] = QVariant::fromValue(itemQty->text().toInt()); } diff --git a/mapeditor/mapsettings/victoryconditions.cpp b/mapeditor/mapsettings/victoryconditions.cpp index ea337b73b..1034dec1b 100644 --- a/mapeditor/mapsettings/victoryconditions.cpp +++ b/mapeditor/mapsettings/victoryconditions.cpp @@ -12,9 +12,11 @@ #include "ui_victoryconditions.h" #include "../mapcontroller.h" +#include "../../lib/GameLibrary.h" #include "../../lib/constants/StringConstants.h" #include "../../lib/entities/artifact/CArtHandler.h" #include "../../lib/entities/faction/CTownHandler.h" +#include "../../lib/entities/ResourceTypeHandler.h" #include "../../lib/mapObjects/CGCreature.h" #include "../../lib/texts/CGeneralTextHandler.h" @@ -406,12 +408,12 @@ void VictoryConditions::on_victoryComboBox_currentIndexChanged(int index) victoryTypeWidget = new QComboBox; ui->victoryParamsLayout->addWidget(victoryTypeWidget); { - for(int resType = 0; resType < GameConstants::RESOURCE_QUANTITY; ++resType) + for(auto & resType : LIBRARY->resourceTypeHandler->getAllObjects()) { MetaString str; str.appendName(GameResID(resType)); auto resName = QString::fromStdString(str.toString()); - victoryTypeWidget->addItem(resName, QVariant::fromValue(resType)); + victoryTypeWidget->addItem(resName, QVariant::fromValue(resType.getNum())); } } diff --git a/mapeditor/templateeditor/graphicelements/CardItem.cpp b/mapeditor/templateeditor/graphicelements/CardItem.cpp index e3770b115..2e5059d05 100644 --- a/mapeditor/templateeditor/graphicelements/CardItem.cpp +++ b/mapeditor/templateeditor/graphicelements/CardItem.cpp @@ -16,6 +16,8 @@ #include "../../../lib/constants/EntityIdentifiers.h" #include "../../../lib/constants/StringConstants.h" #include "../../../lib/rmg/CRmgTemplate.h" +#include "../../../lib/GameLibrary.h" +#include "../../../lib/entities/ResourceTypeHandler.h" QDomElement CardItem::getElementById(const QDomDocument& doc, const QString& id) { @@ -149,11 +151,11 @@ int CardItem::getId() void CardItem::setResAmount(GameResID res, int val) { - auto textElem = getElementById(doc, "text" + QString::fromStdString(GameConstants::RESOURCE_NAMES[res])); + auto textElem = getElementById(doc, "text" + QString::fromStdString(res.toResource()->getJsonKey())); textElem.setAttribute("style", textElem.attribute("style").replace(QRegularExpression("fill:.*?;"), "fill:" + QColor(useBlackText ? Qt::black : Qt::white).name() + ";")); textElem.firstChild().setNodeValue(val ? QString::number(val) : ""); - auto iconElem = getElementById(doc, "icon" + QString::fromStdString(GameConstants::RESOURCE_NAMES[res])); + auto iconElem = getElementById(doc, "icon" + QString::fromStdString(res.toResource()->getJsonKey())); iconElem.setAttribute("opacity", val ? "1.0" : "0.1"); } diff --git a/mapeditor/templateeditor/mineselector.cpp b/mapeditor/templateeditor/mineselector.cpp index fcb2b8176..201e42d3b 100644 --- a/mapeditor/templateeditor/mineselector.cpp +++ b/mapeditor/templateeditor/mineselector.cpp @@ -15,10 +15,12 @@ #include "../../lib/GameLibrary.h" #include "../../lib/texts/CGeneralTextHandler.h" +#include "../../lib/texts/MetaString.h" +#include "../../lib/entities/ResourceTypeHandler.h" -auto resources = std::vector{EGameResID::GOLD, EGameResID::WOOD, EGameResID::MERCURY, EGameResID::ORE, EGameResID::SULFUR, EGameResID::CRYSTAL, EGameResID::GEMS}; +auto resourcesToShow = std::vector{EGameResID::GOLD, EGameResID::WOOD, EGameResID::MERCURY, EGameResID::ORE, EGameResID::SULFUR, EGameResID::CRYSTAL, EGameResID::GEMS}; //todo: configurable resource support -MineSelector::MineSelector(std::map & mines) : +MineSelector::MineSelector(std::map & mines) : ui(new Ui::MineSelector), minesSelected(mines) { @@ -29,18 +31,18 @@ MineSelector::MineSelector(std::map & mines) : setWindowModality(Qt::ApplicationModal); ui->tableWidgetMines->setColumnCount(2); - ui->tableWidgetMines->setRowCount(resources.size()); + ui->tableWidgetMines->setRowCount(resourcesToShow.size()); ui->tableWidgetMines->setHorizontalHeaderLabels({tr("Resource"), tr("Mines")}); - for (int row = 0; row < resources.size(); ++row) + for (int row = 0; row < resourcesToShow.size(); ++row) { - auto name = LIBRARY->generaltexth->translate(TextIdentifier("core.restypes", resources[row].getNum()).get()); + auto name = resourcesToShow[row].toResource()->getNameTranslated(); auto label = new QLabel(QString::fromStdString(name)); label->setAlignment(Qt::AlignCenter); ui->tableWidgetMines->setCellWidget(row, 0, label); auto spinBox = new QSpinBox(); spinBox->setRange(0, 100); - spinBox->setValue(mines[resources[row]]); + spinBox->setValue(mines[resourcesToShow[row]]); ui->tableWidgetMines->setCellWidget(row, 1, spinBox); } ui->tableWidgetMines->resizeColumnsToContents(); @@ -48,7 +50,7 @@ MineSelector::MineSelector(std::map & mines) : show(); } -void MineSelector::showMineSelector(std::map & mines) +void MineSelector::showMineSelector(std::map & mines) { auto * dialog = new MineSelector(mines); dialog->setAttribute(Qt::WA_DeleteOnClose); @@ -57,8 +59,8 @@ void MineSelector::showMineSelector(std::map & mines) void MineSelector::on_buttonBoxResult_accepted() { - for (int row = 0; row < resources.size(); ++row) - minesSelected[resources[row]] = static_cast(ui->tableWidgetMines->cellWidget(row, 1))->value(); + for (int row = 0; row < resourcesToShow.size(); ++row) + minesSelected[resourcesToShow[row]] = static_cast(ui->tableWidgetMines->cellWidget(row, 1))->value(); close(); } diff --git a/mapeditor/templateeditor/mineselector.h b/mapeditor/templateeditor/mineselector.h index 29eac0809..a9a05d5ab 100644 --- a/mapeditor/templateeditor/mineselector.h +++ b/mapeditor/templateeditor/mineselector.h @@ -22,9 +22,9 @@ class MineSelector : public QDialog Q_OBJECT public: - explicit MineSelector(std::map & mines); + explicit MineSelector(std::map & mines); - static void showMineSelector(std::map & mines); + static void showMineSelector(std::map & mines); private slots: void on_buttonBoxResult_accepted(); @@ -33,5 +33,5 @@ private slots: private: Ui::MineSelector *ui; - std::map & minesSelected; + std::map & minesSelected; }; diff --git a/scripting/lua/api/ObjectInstance.h b/scripting/lua/api/ObjectInstance.h index a5542a650..e80073d00 100644 --- a/scripting/lua/api/ObjectInstance.h +++ b/scripting/lua/api/ObjectInstance.h @@ -14,8 +14,6 @@ #include "../LuaWrapper.h" -#include "../../../lib/mapObjects/CObjectHandler.h" - namespace scripting { namespace api diff --git a/scripting/lua/api/netpacks/SetResources.cpp b/scripting/lua/api/netpacks/SetResources.cpp index 9cd8a88cd..5b103669b 100644 --- a/scripting/lua/api/netpacks/SetResources.cpp +++ b/scripting/lua/api/netpacks/SetResources.cpp @@ -82,7 +82,7 @@ int SetResourcesProxy::getAmount(lua_State * L) S.clear(); - const TQuantity amount = vstd::atOrDefault(object->res, static_cast(type), 0); + const TQuantity amount = object->res[type]; S.push(amount); return 1; } diff --git a/scripts/lib/erm/MA.lua b/scripts/lib/erm/MA.lua index 9047d4678..ab0d9e971 100644 --- a/scripts/lib/erm/MA.lua +++ b/scripts/lib/erm/MA.lua @@ -8,7 +8,7 @@ local Bonus = require("Bonus") local BonusBearer = require("BonusBearer") local BonusList = require("BonusList") -local RES = {[0] = "wood", [1] = "mercury", [2] = "ore", [3] = "sulfur", [4] = "crystal", [5] = "gems", [6] = "gold", [7] = "mithril"} +local RES = {[0] = "wood", [1] = "mercury", [2] = "ore", [3] = "sulfur", [4] = "crystal", [5] = "gems", [6] = "gold"} local SERVICES = SERVICES local creatures = SERVICES:creatures() diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index 5694725c8..722c601d6 100644 --- a/server/CGameHandler.cpp +++ b/server/CGameHandler.cpp @@ -2293,7 +2293,8 @@ bool CGameHandler::spellResearch(ObjectInstanceID tid, SpellID spellAtSlot, bool return true; } - auto costBase = TResources(gameInfo().getSettings().getValue(EGameSettings::TOWNS_SPELL_RESEARCH_COST).Vector()[level]); + ResourceSet costBase; + costBase.resolveFromJson(gameInfo().getSettings().getValue(EGameSettings::TOWNS_SPELL_RESEARCH_COST).Vector()[level]); auto costExponent = gameInfo().getSettings().getValue(EGameSettings::TOWNS_SPELL_RESEARCH_COST_EXPONENT_PER_RESEARCH).Vector()[level].Float(); auto cost = costBase * std::pow(t->spellResearchAcceptedCounter + 1, costExponent); diff --git a/server/CVCMIServer.cpp b/server/CVCMIServer.cpp index d25b2be64..4dc44cb64 100644 --- a/server/CVCMIServer.cpp +++ b/server/CVCMIServer.cpp @@ -20,6 +20,7 @@ #include "../lib/campaign/CampaignState.h" #include "../lib/entities/hero/CHeroHandler.h" #include "../lib/entities/hero/CHeroClass.h" +#include "../lib/entities/ResourceTypeHandler.h" #include "../lib/gameState/CGameState.h" #include "../lib/mapping/CMapInfo.h" #include "../lib/mapping/CMapHeader.h" @@ -709,7 +710,7 @@ void CVCMIServer::setPlayerHandicap(PlayerColor color, Handicap handicap) return; } - for(auto & res : EGameResID::ALL_RESOURCES()) + for(auto & res : LIBRARY->resourceTypeHandler->getAllObjects()) if(handicap.startBonus[res] != 0) { str.appendRawString(" "); @@ -1008,7 +1009,7 @@ void CVCMIServer::multiplayerWelcomeMessage() str.appendRawString(" "); str.appendName(pi.first); str.appendRawString(":"); - for(auto & res : EGameResID::ALL_RESOURCES()) + for(auto & res : LIBRARY->resourceTypeHandler->getAllObjects()) if(pi.second.handicap.startBonus[res] != 0) { str.appendRawString(" "); diff --git a/server/processors/NewTurnProcessor.cpp b/server/processors/NewTurnProcessor.cpp index 846884fe0..8f1634620 100644 --- a/server/processors/NewTurnProcessor.cpp +++ b/server/processors/NewTurnProcessor.cpp @@ -21,6 +21,7 @@ #include "../../lib/constants/StringConstants.h" #include "../../lib/entities/building/CBuilding.h" #include "../../lib/entities/faction/CTownHandler.h" +#include "../../lib/entities/ResourceTypeHandler.h" #include "../../lib/gameState/CGameState.h" #include "../../lib/gameState/SThievesGuildInfo.h" #include "../../lib/mapObjects/CGHeroInstance.h" @@ -58,7 +59,7 @@ void NewTurnProcessor::handleTimeEvents(PlayerColor color) if (!event.resources.empty()) { gameHandler->giveResources(color, event.resources); - for (GameResID i : GameResID::ALL_RESOURCES()) + for (GameResID i : LIBRARY->resourceTypeHandler->getAllObjects()) if (event.resources[i]) iw.components.emplace_back(ComponentType::RESOURCE, i, event.resources[i]); } @@ -94,7 +95,7 @@ void NewTurnProcessor::handleTownEvents(const CGTownInstance * town) { gameHandler->giveResources(player, event.resources); - for (GameResID i : GameResID::ALL_RESOURCES()) + for (GameResID i : LIBRARY->resourceTypeHandler->getAllObjects()) if (event.resources[i]) iw.components.emplace_back(ComponentType::RESOURCE, i, event.resources[i]); } @@ -256,9 +257,9 @@ ResourceSet NewTurnProcessor::generatePlayerIncome(PlayerColor playerID, bool ne const JsonNode & difficultyConfig = weeklyBonusesConfig[difficultyName]; // Distribute weekly bonuses over 7 days, depending on the current day of the week - for (GameResID i : GameResID::ALL_RESOURCES()) + for (GameResID i : LIBRARY->resourceTypeHandler->getAllObjects()) { - const std::string & name = GameConstants::RESOURCE_NAMES[i.getNum()]; + const std::string & name = i.toResource()->getJsonKey(); int64_t weeklyBonus = difficultyConfig[name].Integer(); int64_t dayOfWeek = gameHandler->gameState().getDate(Date::DAY_OF_WEEK); int64_t dailyIncome = incomeHandicapped[i]; diff --git a/server/processors/PlayerMessageProcessor.cpp b/server/processors/PlayerMessageProcessor.cpp index ae3b567cd..87985100a 100644 --- a/server/processors/PlayerMessageProcessor.cpp +++ b/server/processors/PlayerMessageProcessor.cpp @@ -23,6 +23,7 @@ #include "../../lib/entities/artifact/CArtHandler.h" #include "../../lib/entities/building/CBuilding.h" #include "../../lib/entities/hero/CHeroHandler.h" +#include "../../lib/entities/ResourceTypeHandler.h" #include "../../lib/gameState/CGameState.h" #include "../../lib/mapObjects/CGTownInstance.h" #include "../../lib/mapObjects/CGHeroInstance.h" @@ -593,7 +594,7 @@ void PlayerMessageProcessor::cheatResources(PlayerColor player, std::vectorresourceTypeHandler->getAllObjects()) resources[i] = baseResourceAmount; gameHandler->giveResources(player, resources); diff --git a/test/erm/ERM_OB_T.cpp b/test/erm/ERM_OB_T.cpp index f8767f667..fa221d264 100644 --- a/test/erm/ERM_OB_T.cpp +++ b/test/erm/ERM_OB_T.cpp @@ -13,8 +13,6 @@ #include "../scripting/ScriptFixture.h" -#include "../../lib/mapObjects/CObjectHandler.h" - namespace test { namespace scripting diff --git a/test/mock/mock_Services.h b/test/mock/mock_Services.h index cd6159141..0a7e5b201 100644 --- a/test/mock/mock_Services.h +++ b/test/mock/mock_Services.h @@ -21,6 +21,7 @@ public: MOCK_CONST_METHOD0(factions, const FactionService *()); MOCK_CONST_METHOD0(heroClasses, const HeroClassService *()); MOCK_CONST_METHOD0(heroTypes, const HeroTypeService *()); + MOCK_CONST_METHOD0(resources, const ResourceTypeService *()); #if SCRIPTING_ENABLED MOCK_CONST_METHOD0(scripts, const scripting::Service *()); #endif diff --git a/test/vcai/ResourceManagerTest.cpp b/test/vcai/ResourceManagerTest.cpp index abeba4748..26636fe67 100644 --- a/test/vcai/ResourceManagerTest.cpp +++ b/test/vcai/ResourceManagerTest.cpp @@ -214,7 +214,6 @@ TEST_F(ResourceManagerTest, freeResources) ASSERT_GE(res[EGameResID::CRYSTAL], 0); ASSERT_GE(res[EGameResID::GEMS], 0); ASSERT_GE(res[EGameResID::GOLD], 0); - ASSERT_GE(res[EGameResID::MITHRIL], 0); } TEST_F(ResourceManagerTest, freeResourcesWithManyGoals)