瀏覽代碼

ResourceTrader improvements and testing WIP

Mircea TheHonestCTO 2 月之前
父節點
當前提交
1b5cacfc13

+ 26 - 4
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)

+ 1 - 0
AI/Nullkiller2/Analyzers/BuildAnalyzer.h

@@ -104,6 +104,7 @@ public:
 		std::shared_ptr<CCallback> & 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);
 };

+ 1 - 1
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})

+ 5 - 7
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))
 			{

+ 21 - 20
AI/Nullkiller2/Engine/ResourceTrader.cpp

@@ -11,17 +11,14 @@
 
 namespace NK2AI
 {
-bool ResourceTrader::trade(const std::unique_ptr<BuildAnalyzer> & buildAnalyzer, std::shared_ptr<CCallback> 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> & 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> & 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> & 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> & buildAnalyzer,
-	std::shared_ptr<CCallback> 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<int>(mostExpendableAmountPos * EXPENDABLE_BULK_RATIO / givenPerUnit),
+		static_cast<int>(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

+ 9 - 5
AI/Nullkiller2/Engine/ResourceTrader.h

@@ -16,15 +16,19 @@ namespace NK2AI
 class ResourceTrader
 {
 public:
-	static bool trade(const std::unique_ptr<BuildAnalyzer> & buildAnalyzer, std::shared_ptr<CCallback> 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> & buildAnalyzer,
-		std::shared_ptr<CCallback> cc
+		const BuildAnalyzer & buildAnalyzer,
+		CCallback & cc
 	);
 };
 

+ 2 - 2
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<TradeItemBuy> availableItemsIds(const EMarketMode mode) const;
 	virtual std::set<EMarketMode> 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<CArtifactSetAltar> altarArtifactsStorage;

+ 3 - 2
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()
 

+ 209 - 42
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, 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<TradeItemBuy>, availableItemsIds, (const EMarketMode mode), (const, override));
+	MOCK_METHOD(std::set<EMarketMode>, availableModes, (), (const, override));
+	MOCK_METHOD(int, getMarketEfficiency, (), (const, override));
+	ObjectInstanceID getObjInstanceID() const override
 	{
+		return ObjectInstanceID();
 	}
-	~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<EMarketMode> availableModes() const override;
 };
 
-TEST(Nullkiller2_Engine_ResourceTrader, tradeHelper)
+class MockBuildAnalyzer final : public NK2AI::BuildAnalyzer
 {
-	// 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;
-}
+public:
+	explicit MockBuildAnalyzer() : BuildAnalyzer(nullptr) {}
+	MOCK_METHOD(bool, getGoldPressure, (), (const));
+};
 
-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)
+class MockCCallback final : public CCallback
 {
-	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;
+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)
+{
+	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);
 }
 
-// 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

+ 29 - 0
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;
+	}
+};