diff --git a/AI/Nullkiller2/Analyzers/BuildAnalyzer.cpp b/AI/Nullkiller2/Analyzers/BuildAnalyzer.cpp index afa8fda49..aba2e835a 100644 --- a/AI/Nullkiller2/Analyzers/BuildAnalyzer.cpp +++ b/AI/Nullkiller2/Analyzers/BuildAnalyzer.cpp @@ -449,10 +449,32 @@ BuildingInfo BuildAnalyzer::getBuildingOrPrerequisite( TResource BuildAnalyzer::goldApproximate(const TResources & res) { - // TODO: Would it make sense to use the marketplace rate of the player? See Nullkiller::handleTrading() - return res[EGameResID::GOLD] - + 75 * (res[EGameResID::WOOD] + res[EGameResID::ORE]) - + 125 * (res[EGameResID::GEMS] + res[EGameResID::CRYSTAL] + res[EGameResID::MERCURY] + res[EGameResID::SULFUR]); + // TODO: Mircea: Would it make sense to use the marketplace rate of the player? See ResourceTrader::trade() + return goldApproximate(res[EGameResID::WOOD], EGameResID::WOOD) + goldApproximate(res[EGameResID::MERCURY], EGameResID::MERCURY) + + goldApproximate(res[EGameResID::ORE], EGameResID::ORE) + goldApproximate(res[EGameResID::SULFUR], EGameResID::SULFUR) + + goldApproximate(res[EGameResID::CRYSTAL], EGameResID::CRYSTAL) + goldApproximate(res[EGameResID::GEMS], EGameResID::GEMS) + + goldApproximate(res[EGameResID::GOLD], EGameResID::GOLD) + goldApproximate(res[EGameResID::MITHRIL], EGameResID::MITHRIL); +} + +TResource BuildAnalyzer::goldApproximate(const TResource & res, EGameResID resId) +{ + switch(resId) + { + case EGameResID::WOOD: + case EGameResID::ORE: + return res * 75; + case EGameResID::MERCURY: + case EGameResID::SULFUR: + case EGameResID::CRYSTAL: + case EGameResID::GEMS: + return res * 125; + case EGameResID::GOLD: + return res; + case EGameResID::MITHRIL: + return res; // TODO: Mircea: What multiplier to give for mithril? + default: + throw std::runtime_error("Unsupported resource ID" + std::to_string(resId)); + } } TResources BuildAnalyzer::goldRemove(TResources other) diff --git a/AI/Nullkiller2/Analyzers/BuildAnalyzer.h b/AI/Nullkiller2/Analyzers/BuildAnalyzer.h index 3e5351775..ac7f88e06 100644 --- a/AI/Nullkiller2/Analyzers/BuildAnalyzer.h +++ b/AI/Nullkiller2/Analyzers/BuildAnalyzer.h @@ -104,6 +104,7 @@ public: std::shared_ptr & cc, bool excludeDwellingDependencies = true); static TResource goldApproximate(const TResources & res); + static TResource goldApproximate(const TResource & res, EGameResID resId); static TResources goldRemove(TResources other); static TResources goldOnly(TResources other); }; diff --git a/AI/Nullkiller2/CMakeLists.txt b/AI/Nullkiller2/CMakeLists.txt index 1fd9b8bf3..235ca6ef4 100644 --- a/AI/Nullkiller2/CMakeLists.txt +++ b/AI/Nullkiller2/CMakeLists.txt @@ -151,7 +151,7 @@ if(NOT ENABLE_STATIC_LIBS) endif() assign_source_group(${Nullkiller2_SRCS} ${Nullkiller2_HEADERS}) -if(ENABLE_STATIC_LIBS OR ENABLE_TEST) +if(ENABLE_STATIC_LIBS) add_library(Nullkiller2 STATIC ${Nullkiller2_SRCS} ${Nullkiller2_HEADERS}) else() add_library(Nullkiller2 SHARED ${Nullkiller2_SRCS} ${Nullkiller2_HEADERS}) diff --git a/AI/Nullkiller2/Engine/Nullkiller.cpp b/AI/Nullkiller2/Engine/Nullkiller.cpp index 59c3d4674..f96a92b7b 100644 --- a/AI/Nullkiller2/Engine/Nullkiller.cpp +++ b/AI/Nullkiller2/Engine/Nullkiller.cpp @@ -466,7 +466,7 @@ void Nullkiller::makeTurn() if(HeroPtr heroPtr(selectedTask->getHero(), cc); selectedTask->getHero() && !heroPtr.isVerified(false)) { - logAi->warn("Nullkiller::makeTurn Skipping pass due to unverified hero: %s", heroPtr.nameOrDefault()); + logAi->error("Nullkiller::makeTurn Skipping pass due to unverified hero: %s", heroPtr.nameOrDefault()); } else { @@ -480,21 +480,19 @@ void Nullkiller::makeTurn() } } - hasAnySuccess |= ResourceTrader::trade(buildAnalyzer, cc, getFreeResources()); + hasAnySuccess |= ResourceTrader::trade(*buildAnalyzer, *cc, getFreeResources()); if(!hasAnySuccess) { - logAi->trace("Nothing was done this turn. Ending turn."); + logAi->trace("Nothing was done this turn pass. Ending turn."); tracePlayerStatus(false); return; } - for (const auto *heroInfo : cc->getHeroesInfo()) + for(const auto * heroInfo : cc->getHeroesInfo()) AIGateway::pickBestArtifacts(cc, heroInfo); if(i == settings->getMaxPass()) - { logAi->warn("MaxPass reached. Terminating AI turn."); - } } } @@ -521,7 +519,7 @@ bool Nullkiller::updateStateAndExecutePriorityPass(Goals::TGoalVec & tempResults HeroPtr heroPtr(bestPrioPassTask->getHero(), cc); if(!isRecruitHeroGoal && bestPrioPassTask->getHero() && !heroPtr.isVerified(false)) { - logAi->warn("Nullkiller::updateStateAndExecutePriorityPass Skipping priorityPass due to unverified hero: %s", heroPtr.nameOrDefault()); + logAi->error("Nullkiller::updateStateAndExecutePriorityPass Skipping priorityPass due to unverified hero: %s", heroPtr.nameOrDefault()); } else if(!executeTask(bestPrioPassTask)) { diff --git a/AI/Nullkiller2/Engine/ResourceTrader.cpp b/AI/Nullkiller2/Engine/ResourceTrader.cpp index 0c5952bcc..57b89f7a0 100644 --- a/AI/Nullkiller2/Engine/ResourceTrader.cpp +++ b/AI/Nullkiller2/Engine/ResourceTrader.cpp @@ -11,17 +11,14 @@ namespace NK2AI { -bool ResourceTrader::trade(const std::unique_ptr & buildAnalyzer, std::shared_ptr cc, TResources freeResources) +bool ResourceTrader::trade(BuildAnalyzer & buildAnalyzer, CCallback & cc, const TResources & freeResources) { - // TODO: Mircea: Maybe include based on how close danger is: X as default + proportion of close danger or something around that - constexpr float ARMY_GOLD_RATIO_PER_MAKE_TURN_PASS = 0.1f; - constexpr float EXPENDABLE_BULK_RATIO = 0.3f; bool haveTraded = false; ObjectInstanceID marketId; // TODO: Mircea: What about outside town markets that have better rates than a single town for example? // Are those used anywhere? To inspect. - for (const auto * const town : cc->getTownsInfo()) + for (const auto * const town : cc.getTownsInfo()) { if (town->hasBuiltSomeTradeBuilding()) { @@ -33,7 +30,7 @@ bool ResourceTrader::trade(const std::unique_ptr & buildAnalyzer, if (!marketId.hasValue()) return false; - const CGObjectInstance * obj = cc->getObj(marketId, false); + const CGObjectInstance * obj = cc.getObj(marketId, false); assert(obj); // if (!obj) // return false; @@ -47,22 +44,22 @@ bool ResourceTrader::trade(const std::unique_ptr & buildAnalyzer, while(shouldTryToTrade) { shouldTryToTrade = false; - buildAnalyzer->update(); + buildAnalyzer.update(); // if we favor getResourcesRequiredNow is better on short term, if we favor getTotalResourcesRequired is better on long term - TResources missingNow = buildAnalyzer->getMissingResourcesNow(ARMY_GOLD_RATIO_PER_MAKE_TURN_PASS); + TResources missingNow = buildAnalyzer.getMissingResourcesNow(ARMY_GOLD_RATIO_PER_MAKE_TURN_PASS); if(missingNow.empty()) break; - TResources income = buildAnalyzer->getDailyIncome(); + TResources income = buildAnalyzer.getDailyIncome(); // We don't want to sell something that's necessary later on, though that could make short term a bit harder sometimes - TResources freeAfterMissingTotal = buildAnalyzer->getFreeResourcesAfterMissingTotal(ARMY_GOLD_RATIO_PER_MAKE_TURN_PASS); + TResources freeAfterMissingTotal = buildAnalyzer.getFreeResourcesAfterMissingTotal(ARMY_GOLD_RATIO_PER_MAKE_TURN_PASS); #if NK2AI_TRACE_LEVEL >= 2 logAi->info("ResourceTrader: Free %s. FreeAfterMissingTotal %s. MissingNow %s", freeResources.toString(), freeAfterMissingTotal.toString(), missingNow.toString()); #endif - if(ResourceTrader::tradeHelper(EXPENDABLE_BULK_RATIO, market, missingNow, income, freeAfterMissingTotal, buildAnalyzer, cc)) + if(ResourceTrader::tradeHelper(EXPENDABLE_BULK_RATIO, *market, missingNow, income, freeAfterMissingTotal, buildAnalyzer, cc)) { haveTraded = true; shouldTryToTrade = true; @@ -72,13 +69,13 @@ bool ResourceTrader::trade(const std::unique_ptr & buildAnalyzer, } bool ResourceTrader::tradeHelper( - float EXPENDABLE_BULK_RATIO, - const IMarket * market, + const float expendableBulkRatio, + const IMarket & market, TResources missingNow, TResources income, TResources freeAfterMissingTotal, - const std::unique_ptr & buildAnalyzer, - std::shared_ptr cc + const BuildAnalyzer & buildAnalyzer, + CCallback & cc ) { constexpr int EMPTY = -1; @@ -93,7 +90,7 @@ bool ResourceTrader::tradeHelper( if(missingNow[i] == 0) continue; - const TResource score = income[i] - missingNow[i]; + const TResource score = BuildAnalyzer::goldApproximate(income[i] - missingNow[i], GameResID(i)); if(score < mostWantedScoreNeg) { mostWanted = i; @@ -112,7 +109,7 @@ bool ResourceTrader::tradeHelper( if(i == GameResID::GOLD) { // TODO: Mircea: Check if we should negate isGoldPressureOverMax() instead - if(income[GameResID::GOLD] > 0 && !buildAnalyzer->isGoldPressureOverMax()) + if(income[GameResID::GOLD] > 0 && !buildAnalyzer.isGoldPressureOverMax()) okToSell = true; } else @@ -142,7 +139,11 @@ bool ResourceTrader::tradeHelper( int givenPerUnit; int receivedPerUnit; - market->getOffer(mostExpendable, mostWanted, givenPerUnit, receivedPerUnit, EMarketMode::RESOURCE_RESOURCE); + market.getOffer(mostExpendable, mostWanted, givenPerUnit, receivedPerUnit, EMarketMode::RESOURCE_RESOURCE); +#if NK2AI_TRACE_LEVEL >= 2 + logAi->info("ResourceTrader: Offer: %d of %d for %d of %d", givenPerUnit, mostExpendable, receivedPerUnit, mostWanted); +#endif + if(!givenPerUnit || !receivedPerUnit) { logGlobal->error( @@ -160,7 +161,7 @@ bool ResourceTrader::tradeHelper( return false; TResource multiplier = std::min( - static_cast(mostExpendableAmountPos * EXPENDABLE_BULK_RATIO / givenPerUnit), + static_cast(mostExpendableAmountPos * expendableBulkRatio / givenPerUnit), missingNow[mostWanted] / receivedPerUnit ); // for gold we have to / receivedUnits, because 1 ore gives many gold units if(multiplier == 0) // could happen for very small values due to EXPENDABLE_BULK_RATIO @@ -173,7 +174,7 @@ bool ResourceTrader::tradeHelper( return false; } - cc->trade(market->getObjInstanceID(), EMarketMode::RESOURCE_RESOURCE, GameResID(mostExpendable), GameResID(mostWanted), givenMultiplied); + cc.trade(market.getObjInstanceID(), EMarketMode::RESOURCE_RESOURCE, GameResID(mostExpendable), GameResID(mostWanted), givenMultiplied); #if NK2AI_TRACE_LEVEL >= 2 logAi->info("ResourceTrader: Traded %d of %s for %d receivedPerUnit of %s", givenMultiplied, mostExpendable, receivedPerUnit, mostWanted); #endif diff --git a/AI/Nullkiller2/Engine/ResourceTrader.h b/AI/Nullkiller2/Engine/ResourceTrader.h index 8a46eb020..f099ef2fb 100644 --- a/AI/Nullkiller2/Engine/ResourceTrader.h +++ b/AI/Nullkiller2/Engine/ResourceTrader.h @@ -16,15 +16,19 @@ namespace NK2AI class ResourceTrader { public: - static bool trade(const std::unique_ptr & buildAnalyzer, std::shared_ptr cc, TResources freeResources); + // TODO: Mircea: Maybe include based on how close danger is: X as default + proportion of close danger or something around that + static constexpr float ARMY_GOLD_RATIO_PER_MAKE_TURN_PASS = 0.1f; + static constexpr float EXPENDABLE_BULK_RATIO = 0.3f; + + static bool trade(BuildAnalyzer & buildAnalyzer, CCallback & cc, const TResources & freeResources); static bool tradeHelper( - float EXPENDABLE_BULK_RATIO, - const IMarket * market, + float expendableBulkRatio, + const IMarket & market, TResources missingNow, TResources income, TResources freeAfterMissingTotal, - const std::unique_ptr & buildAnalyzer, - std::shared_ptr cc + const BuildAnalyzer & buildAnalyzer, + CCallback & cc ); }; diff --git a/lib/mapObjects/IMarket.h b/lib/mapObjects/IMarket.h index 2db7e5f17..055e77aef 100644 --- a/lib/mapObjects/IMarket.h +++ b/lib/mapObjects/IMarket.h @@ -35,13 +35,13 @@ public: }; virtual ObjectInstanceID getObjInstanceID() const = 0; // The market is always an object on the map - virtual int getMarketEfficiency() const = 0; + virtual int getMarketEfficiency() const = 0; // marketCount in CGTownInstance::getMarketEfficiency() virtual bool allowsTrade(const EMarketMode mode) const; virtual int availableUnits(const EMarketMode mode, const int marketItemSerial) const; //-1 if unlimited virtual std::vector availableItemsIds(const EMarketMode mode) const; virtual std::set availableModes() const = 0; CArtifactSet * getArtifactsStorage() const; - bool getOffer(int id1, int id2, int &val1, int &val2, EMarketMode mode) const; //val1 - how many units of id1 player has to give to receive val2 units + virtual bool getOffer(int id1, int id2, int &val1, int &val2, EMarketMode mode) const; //val1 - how many units of id1 player has to give to receive val2 units private: std::unique_ptr altarArtifactsStorage; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 6befd4c46..e38fdced0 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -141,17 +141,18 @@ if(ENABLE_ERM) endif() if(ENABLE_NULLKILLER_AI) - # Just linking the library below is not enough, we need the .cpp files as well + # When not static, linking the library below is not enough, we need the .cpp files as well file(GLOB_RECURSE NULLKILLER2_TEST_SRCS "../AI/Nullkiller2/*.cpp") list(FILTER NULLKILLER2_TEST_SRCS EXCLUDE REGEX ".*main\\.cpp$") list(APPEND test_SRCS -# ${NULLKILLER2_TEST_SRCS} + ${NULLKILLER2_TEST_SRCS} nullkiller2/Behaviors/RecruitHeroBehaviorTest.cpp nullkiller2/Engine/ResourceTraderTest.cpp ) list(APPEND test_HEADERS + nullkiller2/Nulkiller2TestUtils.h ) endif() diff --git a/test/nullkiller2/Engine/ResourceTraderTest.cpp b/test/nullkiller2/Engine/ResourceTraderTest.cpp index 85938ed29..e61744e05 100644 --- a/test/nullkiller2/Engine/ResourceTraderTest.cpp +++ b/test/nullkiller2/Engine/ResourceTraderTest.cpp @@ -10,57 +10,224 @@ #include "gmock/gmock.h" #include "gtest/gtest.h" -#include "AI/Nullkiller2/Behaviors/RecruitHeroBehavior.h" +#include "AI/Nullkiller2/Engine/ResourceTrader.h" +#include "test/nullkiller2/Nulkiller2TestUtils.h" -class MockMarket : public IMarket +class MockMarket final : public IMarket { public: - explicit MockMarket(IGameInfoCallback * cb) - : IMarket(cb) - { - } + explicit MockMarket(IGameInfoCallback * cb) : IMarket(cb) {} ~MockMarket() override = default; - MOCK_METHOD(bool, getOffer, (int id1, int id2, int & val1, int & val2, EMarketMode mode), ()); - ObjectInstanceID getObjInstanceID() const override; - int getMarketEfficiency() const override; - std::set availableModes() const override; + + MOCK_METHOD(bool, allowsTrade, (const EMarketMode mode), (const, override)); + MOCK_METHOD(bool, getOffer, (int id1, int id2, int & val1, int & val2, EMarketMode mode), (const, override)); + MOCK_METHOD(int, availableUnits, (const EMarketMode mode, const int marketItemSerial), (const, override)); + MOCK_METHOD(std::vector, availableItemsIds, (const EMarketMode mode), (const, override)); + MOCK_METHOD(std::set, availableModes, (), (const, override)); + MOCK_METHOD(int, getMarketEfficiency, (), (const, override)); + ObjectInstanceID getObjInstanceID() const override + { + return ObjectInstanceID(); + } +}; + +class MockBuildAnalyzer final : public NK2AI::BuildAnalyzer +{ +public: + explicit MockBuildAnalyzer() : BuildAnalyzer(nullptr) {} + MOCK_METHOD(bool, getGoldPressure, (), (const)); +}; + +class MockCCallback final : public CCallback +{ +public: + MockCCallback() : CCallback(nullptr, std::nullopt, nullptr) {} + MOCK_METHOD( + void, + trade, + (const ObjectInstanceID marketId, EMarketMode mode, TradeItemSell id1, TradeItemBuy id2, ui32 val1, const CGHeroInstance * hero), + (override) + ); }; TEST(Nullkiller2_Engine_ResourceTrader, tradeHelper) { - // auto * const market = new MockMarket(nullptr); - // EXPECT_CALL(*market, getOffer(testing::internal::Any, testing::internal::Any, testing::internal::Any, testing::internal::Any, EMarketMode::RESOURCE_RESOURCE)).Times(1); - // market->getOffer(0, 0, 0, 0, EMarketMode::RESOURCE_RESOURCE); - // delete market; + const TResources missingNow = Nulkiller2TestUtils::res(0, 0, 0, 0, 0, 0, 193445, 0); + const TResources income = Nulkiller2TestUtils::res(2, 2, 2, 2, 2, 2, 1000, 0); + const TResources freeAfterMissingTotal = Nulkiller2TestUtils::res(1000, 1000, 1000, 1001, 1002, 1000, 0, 0); + + MockMarket market(nullptr); + EXPECT_CALL(market, getOffer(4, 6, testing::_, testing::_, EMarketMode::RESOURCE_RESOURCE)).Times(1); + MockBuildAnalyzer buildAnalyzer; + MockCCallback callback; + NK2AI::ResourceTrader::tradeHelper(NK2AI::ResourceTrader::EXPENDABLE_BULK_RATIO, market, missingNow, income, freeAfterMissingTotal, buildAnalyzer, callback); } -TResources res(const int wood, const int mercury, const int ore, const int sulfur, const int crystals, const int gems, const int gold, const int mithril) -{ - TResources resources; - resources[0] = wood; - resources[1] = mercury; - resources[2] = ore; - resources[3] = sulfur; - resources[4] = crystals; - resources[5] = gems; - resources[6] = gold; - resources[7] = mithril; - return resources; -} - -// Nullkiller::handleTrading Free [13919, 13883, 13921, 13857, 13792, 13883, 14, 0]. FreeAfterMissingTotal [13859, 13819, 13891, 13833, 13718, 13763, 0, 0]. MissingNow [0, 0, 0, 0, 0, 0, 193445, 0] -// Nullkiller::handleTrading Traded 1547 of 2 for 125 of 6 -// Nullkiller::handleTrading Free [13919, 13883, 13921, 13857, 13792, 13883, 14, 0]. FreeAfterMissingTotal [13859, 13819, 12344, 13833, 13718, 13763, 0, 0]. MissingNow [0, 0, 0, 0, 0, 0, 70, 0] -// Nullkiller::handleTrading Traded 1 of 0 for 125 of 6 -// Nullkiller::handleTrading Free [13908, 13883, 12374, 13857, 13722, 13883, 414, 0]. FreeAfterMissingTotal [13848, 13819, 12344, 13833, 13648, 13763, 0, 0]. MissingNow [0, 0, 0, 0, 0, 0, 193075, 0] -// Nullkiller::handleTrading Traded 1544 of 0 for 125 of 6 -// Nullkiller::handleTrading Free [13908, 13883, 12374, 13857, 13722, 13883, 414, 0]. FreeAfterMissingTotal [12304, 13819, 12344, 13833, 13648, 13763, 0, 0]. MissingNow [0, 0, 0, 0, 0, 0, 75, 0] -// Nullkiller::handleTrading Traded 1 of 3 for 250 of 6 -// Nullkiller::handleTrading Free [12364, 13883, 12374, 13841, 13722, 13883, 24, 0]. FreeAfterMissingTotal [12304, 13819, 12344, 13817, 13648, 13763, 0, 0]. MissingNow [0, 0, 0, 0, 0, 0, 193465, 0] -// Nullkiller::handleTrading Traded 773 of 1 for 250 of 6 -// Nullkiller::handleTrading Free [12364, 13883, 12374, 13841, 13722, 13883, 24, 0]. FreeAfterMissingTotal [12304, 13046, 12344, 13817, 13648, 13763, 0, 0]. MissingNow [0, 0, 0, 0, 0, 0, 215, 0] -// Nullkiller::handleTrading Traded 1 of 3 for 250 of 6 -// Nullkiller::handleTrading Free [12364, 13110, 12374, 13837, 13722, 13883, 52524, 0]. FreeAfterMissingTotal [12304, 13046, 12344, 13813, 13648, 13763, 0, 0]. MissingNow [0, 0, 0, 0, 0, 0, 140965, 0] -// Nullkiller::handleTrading Traded 563 of 3 for 250 of 6 -// Nullkiller::handleTrading Free [12364, 13110, 12374, 13837, 13722, 13883, 52524, 0]. FreeAfterMissingTotal [12304, 13046, 12344, 13250, 13648, 13763, 0, 0]. MissingNow [0, 0, 0, 0, 0, 0, 215, 0] -// Nullkiller::handleTrading Traded 1 of 5 for 250 of 6 +// ResourceTrader: Free [13919, 13883, 13921, 13857, 13792, 13883, 14, 0]. FreeAfterMissingTotal [13859, 13819, 13891, 13833, 13718, 13763, 0, 0]. MissingNow [0, 0, 0, 0, 0, 0, 193445, 0] +// ResourceTrader: got offer: 1 of mostExpendable 2 for 125 of mostWanted: 6 +// ResourceTrader: Traded 1547 of 2 for 125 receivedPerUnit of 6 +// ResourceTrader: Free [13919, 13883, 13921, 13857, 13792, 13883, 14, 0]. FreeAfterMissingTotal [13859, 13819, 12344, 13833, 13718, 13763, 0, 0]. MissingNow [0, 0, 0, 0, 0, 0, 70, 0] +// ResourceTrader: got offer: 1 of mostExpendable 0 for 125 of mostWanted: 6 +// ResourceTrader: Traded 1 of 0 for 125 receivedPerUnit of 6 +// ResourceTrader: Free [13908, 13883, 12374, 13857, 13722, 13883, 414, 0]. FreeAfterMissingTotal [13848, 13819, 12344, 13833, 13648, 13763, 0, 0]. MissingNow [0, 0, 0, 0, 0, 0, 193075, 0] +// ResourceTrader: got offer: 1 of mostExpendable 0 for 125 of mostWanted: 6 +// ResourceTrader: Traded 1544 of 0 for 125 receivedPerUnit of 6 +// ResourceTrader: Free [13908, 13883, 12374, 13857, 13722, 13883, 414, 0]. FreeAfterMissingTotal [12304, 13819, 12344, 13833, 13648, 13763, 0, 0]. MissingNow [0, 0, 0, 0, 0, 0, 75, 0] +// ResourceTrader: got offer: 1 of mostExpendable 3 for 250 of mostWanted: 6 +// ResourceTrader: Traded 1 of 3 for 250 receivedPerUnit of 6 +// ResourceTrader: Free [12364, 13883, 12374, 13841, 13722, 13883, 24, 0]. FreeAfterMissingTotal [12304, 13819, 12344, 13817, 13648, 13763, 0, 0]. MissingNow [0, 0, 0, 0, 0, 0, 193465, 0] +// ResourceTrader: got offer: 1 of mostExpendable 1 for 250 of mostWanted: 6 +// ResourceTrader: Traded 773 of 1 for 250 receivedPerUnit of 6 +// ResourceTrader: Free [12364, 13883, 12374, 13841, 13722, 13883, 24, 0]. FreeAfterMissingTotal [12304, 13046, 12344, 13817, 13648, 13763, 0, 0]. MissingNow [0, 0, 0, 0, 0, 0, 215, 0] +// ResourceTrader: got offer: 1 of mostExpendable 3 for 250 of mostWanted: 6 +// ResourceTrader: Traded 1 of 3 for 250 receivedPerUnit of 6 +// ResourceTrader: Free [12364, 13110, 12374, 13837, 13722, 13883, 52524, 0]. FreeAfterMissingTotal [12304, 13046, 12344, 13813, 13648, 13763, 0, 0]. MissingNow [0, 0, 0, 0, 0, 0, 140965, 0] +// ResourceTrader: got offer: 1 of mostExpendable 3 for 250 of mostWanted: 6 +// ResourceTrader: Traded 563 of 3 for 250 receivedPerUnit of 6 +// ResourceTrader: Free [12364, 13110, 12374, 13837, 13722, 13883, 52524, 0]. FreeAfterMissingTotal [12304, 13046, 12344, 13250, 13648, 13763, 0, 0]. MissingNow [0, 0, 0, 0, 0, 0, 215, 0] +// ResourceTrader: got offer: 1 of mostExpendable 5 for 250 of mostWanted: 6 +// ResourceTrader: Traded 1 of 5 for 250 receivedPerUnit of 6 +// ResourceTrader: Free [2097, 268, 1168, 10930, 10925, 3, 7, 0]. FreeAfterMissingTotal [2097, 268, 1168, 10900, 10925, 3, 0, 0]. MissingNow [0, 0, 0, 0, 0, 0, 17493, 0] +// ResourceTrader: got offer: 1 of mostExpendable 4 for 150 of mostWanted: 6 +// ResourceTrader: Traded 116 of 4 for 150 receivedPerUnit of 6 +// ResourceTrader: Free [2097, 268, 1168, 10930, 10925, 3, 7, 0]. FreeAfterMissingTotal [2097, 268, 1168, 10900, 10809, 3, 0, 0]. MissingNow [0, 0, 0, 0, 0, 0, 93, 0] +// ResourceTrader: got offer: 1 of mostExpendable 3 for 150 of mostWanted: 6 +// ResourceTrader: Traded 1 of 3 for 150 receivedPerUnit of 6 +// ResourceTrader: Free [2097, 268, 1168, 10929, 10809, 3, 47, 0]. FreeAfterMissingTotal [2097, 268, 1168, 10899, 10809, 3, 0, 0]. MissingNow [0, 0, 0, 0, 0, 0, 17453, 0] +// ResourceTrader: got offer: 1 of mostExpendable 3 for 150 of mostWanted: 6 +// ResourceTrader: Traded 116 of 3 for 150 receivedPerUnit of 6 +// ResourceTrader: Free [2097, 268, 1168, 10929, 10809, 3, 47, 0]. FreeAfterMissingTotal [2097, 268, 1168, 10783, 10809, 3, 0, 0]. MissingNow [0, 0, 0, 0, 0, 0, 53, 0] +// ResourceTrader: got offer: 1 of mostExpendable 4 for 150 of mostWanted: 6 +// ResourceTrader: Traded 1 of 4 for 150 receivedPerUnit of 6 +// ResourceTrader: Free [2097, 268, 1168, 10813, 10808, 3, 22, 0]. FreeAfterMissingTotal [2097, 268, 1168, 10783, 10808, 3, 0, 0]. MissingNow [0, 0, 0, 0, 0, 0, 17478, 0] +// ResourceTrader: got offer: 1 of mostExpendable 4 for 150 of mostWanted: 6 +// ResourceTrader: Traded 116 of 4 for 150 receivedPerUnit of 6 +// ResourceTrader: Free [2097, 268, 1168, 10813, 10808, 3, 22, 0]. FreeAfterMissingTotal [2097, 268, 1168, 10783, 10692, 3, 0, 0]. MissingNow [0, 0, 0, 0, 0, 0, 78, 0] +// ResourceTrader: got offer: 1 of mostExpendable 3 for 150 of mostWanted: 6 +// ResourceTrader: Traded 1 of 3 for 150 receivedPerUnit of 6 +// ResourceTrader: Free [2097, 268, 1168, 10812, 10692, 3, 27, 0]. FreeAfterMissingTotal [2097, 268, 1168, 10782, 10692, 3, 0, 0]. MissingNow [0, 0, 0, 0, 0, 0, 17473, 0] +// ResourceTrader: got offer: 1 of mostExpendable 3 for 150 of mostWanted: 6 +// ResourceTrader: Traded 116 of 3 for 150 receivedPerUnit of 6 +// ResourceTrader: Free [2097, 268, 1168, 10812, 10692, 3, 27, 0]. FreeAfterMissingTotal [2097, 268, 1168, 10666, 10692, 3, 0, 0]. MissingNow [0, 0, 0, 0, 0, 0, 73, 0] +// ResourceTrader: got offer: 1 of mostExpendable 4 for 150 of mostWanted: 6 +// ResourceTrader: Traded 1 of 4 for 150 receivedPerUnit of 6 +// ResourceTrader: Free [2097, 268, 1168, 10696, 10691, 3, 2, 0]. FreeAfterMissingTotal [2097, 268, 1168, 10666, 10691, 3, 0, 0]. MissingNow [0, 0, 0, 0, 0, 0, 17498, 0] +// ResourceTrader: got offer: 1 of mostExpendable 4 for 150 of mostWanted: 6 +// ResourceTrader: Traded 116 of 4 for 150 receivedPerUnit of 6 +// ResourceTrader: Free [2097, 268, 1168, 10696, 10691, 3, 2, 0]. FreeAfterMissingTotal [2097, 268, 1168, 10666, 10575, 3, 0, 0]. MissingNow [0, 0, 0, 0, 0, 0, 98, 0] +// ResourceTrader: got offer: 1 of mostExpendable 3 for 150 of mostWanted: 6 +// ResourceTrader: Traded 1 of 3 for 150 receivedPerUnit of 6 +// ResourceTrader: Free [2097, 268, 1168, 10695, 10575, 3, 22, 0]. FreeAfterMissingTotal [2097, 268, 1168, 10665, 10575, 3, 0, 0]. MissingNow [0, 0, 0, 0, 0, 0, 17478, 0] +// ResourceTrader: got offer: 1 of mostExpendable 3 for 150 of mostWanted: 6 +// ResourceTrader: Traded 116 of 3 for 150 receivedPerUnit of 6 +// ResourceTrader: Free [2097, 268, 1168, 10695, 10575, 3, 22, 0]. FreeAfterMissingTotal [2097, 268, 1168, 10549, 10575, 3, 0, 0]. MissingNow [0, 0, 0, 0, 0, 0, 78, 0] +// ResourceTrader: got offer: 1 of mostExpendable 4 for 150 of mostWanted: 6 +// ResourceTrader: Traded 1 of 4 for 150 receivedPerUnit of 6 +// ResourceTrader: Free [2097, 268, 1168, 10579, 10574, 3, 42, 0]. FreeAfterMissingTotal [2097, 268, 1168, 10549, 10574, 3, 0, 0]. MissingNow [0, 0, 0, 0, 0, 0, 17458, 0] +// ResourceTrader: got offer: 1 of mostExpendable 4 for 150 of mostWanted: 6 +// ResourceTrader: Traded 116 of 4 for 150 receivedPerUnit of 6 +// ResourceTrader: Free [2097, 268, 1168, 10579, 10574, 3, 42, 0]. FreeAfterMissingTotal [2097, 268, 1168, 10549, 10458, 3, 0, 0]. MissingNow [0, 0, 0, 0, 0, 0, 58, 0] +// ResourceTrader: got offer: 1 of mostExpendable 3 for 150 of mostWanted: 6 +// ResourceTrader: Traded 1 of 3 for 150 receivedPerUnit of 6 +// ResourceTrader: Free [2097, 268, 1168, 10578, 10458, 3, 62, 0]. FreeAfterMissingTotal [2097, 268, 1168, 10548, 10458, 3, 0, 0]. MissingNow [0, 0, 0, 0, 0, 0, 17438, 0] +// ResourceTrader: got offer: 1 of mostExpendable 3 for 150 of mostWanted: 6 +// ResourceTrader: Traded 116 of 3 for 150 receivedPerUnit of 6 +// ResourceTrader: Free [2097, 268, 1168, 10578, 10458, 3, 62, 0]. FreeAfterMissingTotal [2097, 268, 1168, 10432, 10458, 3, 0, 0]. MissingNow [0, 0, 0, 0, 0, 0, 38, 0] +// ResourceTrader: got offer: 1 of mostExpendable 4 for 150 of mostWanted: 6 +// ResourceTrader: Traded 1 of 4 for 150 receivedPerUnit of 6 +// ResourceTrader: Free [2097, 268, 1168, 10462, 10457, 3, 17, 0]. FreeAfterMissingTotal [2097, 268, 1168, 10432, 10457, 3, 0, 0]. MissingNow [0, 0, 0, 0, 0, 0, 17483, 0] +// ResourceTrader: got offer: 1 of mostExpendable 4 for 150 of mostWanted: 6 +// ResourceTrader: Traded 116 of 4 for 150 receivedPerUnit of 6 +// ResourceTrader: Free [2097, 268, 1168, 10462, 10457, 3, 17, 0]. FreeAfterMissingTotal [2097, 268, 1168, 10432, 10341, 3, 0, 0]. MissingNow [0, 0, 0, 0, 0, 0, 83, 0] +// ResourceTrader: got offer: 1 of mostExpendable 3 for 150 of mostWanted: 6 +// ResourceTrader: Traded 1 of 3 for 150 receivedPerUnit of 6 +// ResourceTrader: Free [2097, 268, 1168, 10461, 10341, 3, 27, 0]. FreeAfterMissingTotal [2097, 268, 1168, 10431, 10341, 3, 0, 0]. MissingNow [0, 0, 0, 0, 0, 0, 17473, 0] +// ResourceTrader: got offer: 1 of mostExpendable 3 for 150 of mostWanted: 6 +// ResourceTrader: Traded 116 of 3 for 150 receivedPerUnit of 6 +// ResourceTrader: Free [2097, 268, 1168, 10461, 10341, 3, 27, 0]. FreeAfterMissingTotal [2097, 268, 1168, 10315, 10341, 3, 0, 0]. MissingNow [0, 0, 0, 0, 0, 0, 73, 0] +// ResourceTrader: got offer: 1 of mostExpendable 4 for 150 of mostWanted: 6 +// ResourceTrader: Traded 1 of 4 for 150 receivedPerUnit of 6 +// ResourceTrader: Free [2097, 268, 1168, 10345, 10340, 3, 2, 0]. FreeAfterMissingTotal [2097, 268, 1168, 10315, 10340, 3, 0, 0]. MissingNow [0, 0, 0, 0, 0, 0, 17498, 0] +// ResourceTrader: got offer: 1 of mostExpendable 4 for 150 of mostWanted: 6 +// ResourceTrader: Traded 116 of 4 for 150 receivedPerUnit of 6 +// ResourceTrader: Free [2097, 268, 1168, 10345, 10340, 3, 2, 0]. FreeAfterMissingTotal [2097, 268, 1168, 10315, 10224, 3, 0, 0]. MissingNow [0, 0, 0, 0, 0, 0, 98, 0] +// ResourceTrader: got offer: 1 of mostExpendable 3 for 150 of mostWanted: 6 +// ResourceTrader: Traded 1 of 3 for 150 receivedPerUnit of 6 +// ResourceTrader: Free [2097, 268, 1168, 10344, 10224, 3, 42, 0]. FreeAfterMissingTotal [2097, 268, 1168, 10314, 10224, 3, 0, 0]. MissingNow [0, 0, 0, 0, 0, 0, 17458, 0] +// ResourceTrader: got offer: 1 of mostExpendable 3 for 150 of mostWanted: 6 +// ResourceTrader: Traded 116 of 3 for 150 receivedPerUnit of 6 +// ResourceTrader: Free [2097, 268, 1168, 10344, 10224, 3, 42, 0]. FreeAfterMissingTotal [2097, 268, 1168, 10198, 10224, 3, 0, 0]. MissingNow [0, 0, 0, 0, 0, 0, 58, 0] +// ResourceTrader: got offer: 1 of mostExpendable 4 for 150 of mostWanted: 6 +// ResourceTrader: Traded 1 of 4 for 150 receivedPerUnit of 6 +// ResourceTrader: Free [2097, 268, 1168, 10228, 10223, 3, 17, 0]. FreeAfterMissingTotal [2097, 268, 1168, 10198, 10223, 3, 0, 0]. MissingNow [0, 0, 0, 0, 0, 0, 17483, 0] +// ResourceTrader: got offer: 1 of mostExpendable 4 for 150 of mostWanted: 6 +// ResourceTrader: Traded 116 of 4 for 150 receivedPerUnit of 6 +// ResourceTrader: Free [2097, 268, 1168, 10228, 10223, 3, 17, 0]. FreeAfterMissingTotal [2097, 268, 1168, 10198, 10107, 3, 0, 0]. MissingNow [0, 0, 0, 0, 0, 0, 83, 0] +// ResourceTrader: got offer: 1 of mostExpendable 3 for 150 of mostWanted: 6 +// ResourceTrader: Traded 1 of 3 for 150 receivedPerUnit of 6 +// ResourceTrader: Free [2097, 268, 1168, 10227, 10107, 3, 57, 0]. FreeAfterMissingTotal [2097, 268, 1168, 10197, 10107, 3, 0, 0]. MissingNow [0, 0, 0, 0, 0, 0, 17443, 0] +// ResourceTrader: got offer: 1 of mostExpendable 3 for 150 of mostWanted: 6 +// ResourceTrader: Traded 116 of 3 for 150 receivedPerUnit of 6 +// ResourceTrader: Free [2097, 268, 1168, 10227, 10107, 3, 57, 0]. FreeAfterMissingTotal [2097, 268, 1168, 10081, 10107, 3, 0, 0]. MissingNow [0, 0, 0, 0, 0, 0, 43, 0] +// ResourceTrader: got offer: 1 of mostExpendable 4 for 150 of mostWanted: 6 +// ResourceTrader: Traded 1 of 4 for 150 receivedPerUnit of 6 +// ResourceTrader: Free [2097, 268, 1168, 10111, 10106, 3, 7, 0]. FreeAfterMissingTotal [2097, 268, 1168, 10081, 10106, 3, 0, 0]. MissingNow [0, 0, 0, 0, 0, 0, 17493, 0] +// ResourceTrader: got offer: 1 of mostExpendable 4 for 150 of mostWanted: 6 +// ResourceTrader: Traded 116 of 4 for 150 receivedPerUnit of 6 +// ResourceTrader: Free [2097, 268, 1168, 10111, 10106, 3, 7, 0]. FreeAfterMissingTotal [2097, 268, 1168, 10081, 9990, 3, 0, 0]. MissingNow [0, 0, 0, 0, 0, 0, 93, 0] +// ResourceTrader: got offer: 1 of mostExpendable 3 for 150 of mostWanted: 6 +// ResourceTrader: Traded 1 of 3 for 150 receivedPerUnit of 6 +// ResourceTrader: Free [2097, 268, 1168, 10110, 9990, 3, 7, 0]. FreeAfterMissingTotal [2097, 268, 1168, 10080, 9990, 3, 0, 0]. MissingNow [0, 0, 0, 0, 0, 0, 17493, 0] +// ResourceTrader: got offer: 1 of mostExpendable 3 for 150 of mostWanted: 6 +// ResourceTrader: Traded 116 of 3 for 150 receivedPerUnit of 6 +// ResourceTrader: Free [2097, 268, 1168, 10110, 9990, 3, 7, 0]. FreeAfterMissingTotal [2097, 268, 1168, 9964, 9990, 3, 0, 0]. MissingNow [0, 0, 0, 0, 0, 0, 93, 0] +// ResourceTrader: got offer: 1 of mostExpendable 4 for 150 of mostWanted: 6 +// ResourceTrader: Traded 1 of 4 for 150 receivedPerUnit of 6 +// ResourceTrader: Free [2097, 268, 1168, 9994, 9989, 3, 7, 0]. FreeAfterMissingTotal [2097, 268, 1168, 9964, 9989, 3, 0, 0]. MissingNow [0, 0, 0, 0, 0, 0, 17493, 0] +// ResourceTrader: got offer: 1 of mostExpendable 4 for 150 of mostWanted: 6 +// ResourceTrader: Traded 116 of 4 for 150 receivedPerUnit of 6 +// ResourceTrader: Free [2097, 268, 1168, 9994, 9989, 3, 7, 0]. FreeAfterMissingTotal [2097, 268, 1168, 9964, 9873, 3, 0, 0]. MissingNow [0, 0, 0, 0, 0, 0, 93, 0] +// ResourceTrader: got offer: 1 of mostExpendable 3 for 150 of mostWanted: 6 +// ResourceTrader: Traded 1 of 3 for 150 receivedPerUnit of 6 +// ResourceTrader: Free [2097, 268, 1168, 9993, 9873, 3, 7, 0]. FreeAfterMissingTotal [2097, 268, 1168, 9963, 9873, 3, 0, 0]. MissingNow [0, 0, 0, 0, 0, 0, 17493, 0] +// ResourceTrader: got offer: 1 of mostExpendable 3 for 150 of mostWanted: 6 +// ResourceTrader: Traded 116 of 3 for 150 receivedPerUnit of 6 +// ResourceTrader: Free [2097, 268, 1168, 9993, 9873, 3, 7, 0]. FreeAfterMissingTotal [2097, 268, 1168, 9847, 9873, 3, 0, 0]. MissingNow [0, 0, 0, 0, 0, 0, 93, 0] +// ResourceTrader: got offer: 1 of mostExpendable 4 for 150 of mostWanted: 6 +// ResourceTrader: Traded 1 of 4 for 150 receivedPerUnit of 6 +// ResourceTrader: Free [2097, 268, 1168, 9877, 9872, 3, 7, 0]. FreeAfterMissingTotal [2097, 268, 1168, 9847, 9872, 3, 0, 0]. MissingNow [0, 0, 0, 0, 0, 0, 17493, 0] +// ResourceTrader: got offer: 1 of mostExpendable 4 for 150 of mostWanted: 6 +// ResourceTrader: Traded 116 of 4 for 150 receivedPerUnit of 6 +// ResourceTrader: Free [2097, 268, 1168, 9877, 9872, 3, 7, 0]. FreeAfterMissingTotal [2097, 268, 1168, 9847, 9756, 3, 0, 0]. MissingNow [0, 0, 0, 0, 0, 0, 93, 0] +// ResourceTrader: got offer: 1 of mostExpendable 3 for 150 of mostWanted: 6 +// ResourceTrader: Traded 1 of 3 for 150 receivedPerUnit of 6 +// ResourceTrader: Free [2097, 268, 1168, 9876, 9756, 3, 7, 0]. FreeAfterMissingTotal [2097, 268, 1168, 9846, 9756, 3, 0, 0]. MissingNow [0, 0, 0, 0, 0, 0, 17493, 0] +// ResourceTrader: got offer: 1 of mostExpendable 3 for 150 of mostWanted: 6 +// ResourceTrader: Traded 116 of 3 for 150 receivedPerUnit of 6 +// ResourceTrader: Free [2097, 268, 1168, 9876, 9756, 3, 7, 0]. FreeAfterMissingTotal [2097, 268, 1168, 9730, 9756, 3, 0, 0]. MissingNow [0, 0, 0, 0, 0, 0, 93, 0] +// ResourceTrader: got offer: 1 of mostExpendable 4 for 150 of mostWanted: 6 +// ResourceTrader: Traded 1 of 4 for 150 receivedPerUnit of 6 +// ResourceTrader: Free [2097, 268, 1168, 9760, 9755, 3, 7, 0]. FreeAfterMissingTotal [2097, 268, 1168, 9730, 9755, 3, 0, 0]. MissingNow [0, 0, 0, 0, 0, 0, 17493, 0] +// ResourceTrader: got offer: 1 of mostExpendable 4 for 150 of mostWanted: 6 +// ResourceTrader: Traded 116 of 4 for 150 receivedPerUnit of 6 +// ResourceTrader: Free [2097, 268, 1168, 9760, 9755, 3, 7, 0]. FreeAfterMissingTotal [2097, 268, 1168, 9730, 9639, 3, 0, 0]. MissingNow [0, 0, 0, 0, 0, 0, 93, 0] +// ResourceTrader: got offer: 1 of mostExpendable 3 for 150 of mostWanted: 6 +// ResourceTrader: Traded 1 of 3 for 150 receivedPerUnit of 6 +// ResourceTrader: Free [2097, 268, 1168, 9759, 9639, 3, 57, 0]. FreeAfterMissingTotal [2097, 268, 1168, 9729, 9639, 3, 0, 0]. MissingNow [0, 0, 0, 0, 0, 0, 17443, 0] +// ResourceTrader: got offer: 1 of mostExpendable 3 for 150 of mostWanted: 6 +// ResourceTrader: Traded 116 of 3 for 150 receivedPerUnit of 6 +// ResourceTrader: Free [2097, 268, 1168, 9759, 9639, 3, 57, 0]. FreeAfterMissingTotal [2097, 268, 1168, 9613, 9639, 3, 0, 0]. MissingNow [0, 0, 0, 0, 0, 0, 43, 0] +// ResourceTrader: got offer: 1 of mostExpendable 4 for 150 of mostWanted: 6 +// ResourceTrader: Traded 1 of 4 for 150 receivedPerUnit of 6 +// ResourceTrader: Free [2097, 268, 1168, 9643, 9638, 3, 47, 0]. FreeAfterMissingTotal [2097, 268, 1168, 9613, 9638, 3, 0, 0]. MissingNow [0, 0, 0, 0, 0, 0, 17453, 0] +// ResourceTrader: got offer: 1 of mostExpendable 4 for 150 of mostWanted: 6 +// ResourceTrader: Traded 116 of 4 for 150 receivedPerUnit of 6 +// ResourceTrader: Free [2097, 268, 1168, 9643, 9638, 3, 47, 0]. FreeAfterMissingTotal [2097, 268, 1168, 9613, 9522, 3, 0, 0]. MissingNow [0, 0, 0, 0, 0, 0, 53, 0] +// ResourceTrader: got offer: 1 of mostExpendable 3 for 150 of mostWanted: 6 +// ResourceTrader: Traded 1 of 3 for 150 receivedPerUnit of 6 +// ResourceTrader: Free [2097, 268, 1168, 9642, 9522, 3, 5232, 0]. FreeAfterMissingTotal [2097, 268, 1168, 9612, 9522, 3, 0, 0]. MissingNow [0, 0, 0, 0, 0, 0, 12268, 0] +// ResourceTrader: got offer: 1 of mostExpendable 3 for 150 of mostWanted: 6 +// ResourceTrader: Traded 81 of 3 for 150 receivedPerUnit of 6 +// ResourceTrader: Free [2097, 268, 1168, 9642, 9522, 3, 5232, 0]. FreeAfterMissingTotal [2097, 268, 1168, 9531, 9522, 3, 0, 0]. MissingNow [0, 0, 0, 0, 0, 0, 118, 0] +// ResourceTrader: got offer: 1 of mostExpendable 3 for 150 of mostWanted: 6 +// ResourceTrader: Traded 1 of 3 for 150 receivedPerUnit of 6 diff --git a/test/nullkiller2/Nulkiller2TestUtils.h b/test/nullkiller2/Nulkiller2TestUtils.h new file mode 100644 index 000000000..93d4e3fef --- /dev/null +++ b/test/nullkiller2/Nulkiller2TestUtils.h @@ -0,0 +1,29 @@ +/* +* Nulkiller2TestUtils.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 "ResourceSet.h" + +class Nulkiller2TestUtils +{ +public: + static TResources + res(const int wood, const int mercury, const int ore, const int sulfur, const int crystals, const int gems, const int gold, const int mithril) + { + TResources resources; + resources[0] = wood; + resources[1] = mercury; + resources[2] = ore; + resources[3] = sulfur; + resources[4] = crystals; + resources[5] = gems; + resources[6] = gold; + resources[7] = mithril; + return resources; + } +}; \ No newline at end of file