Преглед изворни кода

Merge pull request #5301 from IvanSavenko/map_loading_fix

Map loading fixes
Ivan Savenko пре 9 месеци
родитељ
комит
df99645eca

+ 1 - 1
AI/Nullkiller/Behaviors/StartupBehavior.cpp

@@ -15,7 +15,7 @@
 #include "../Goals/RecruitHero.h"
 #include "../Goals/ExecuteHeroChain.h"
 #include "../Goals/ExchangeSwapTownHeroes.h"
-#include "lib/mapObjects/MapObjects.h" //for victory conditions
+#include "../../../lib/mapObjects/CGResource.h"
 #include "../Engine/Nullkiller.h"
 
 namespace NKAI

+ 2 - 2
AI/Nullkiller/Engine/PriorityEvaluator.cpp

@@ -14,7 +14,7 @@
 #include "../../../lib/mapObjectConstructors/AObjectTypeHandler.h"
 #include "../../../lib/mapObjectConstructors/CObjectClassesHandler.h"
 #include "../../../lib/mapObjectConstructors/CBankInstanceConstructor.h"
-#include "../../../lib/mapObjects/MapObjects.h"
+#include "../../../lib/mapObjects/CGResource.h"
 #include "../../../lib/mapping/CMapDefines.h"
 #include "../../../lib/RoadHandler.h"
 #include "../../../lib/CCreatureHandler.h"
@@ -508,7 +508,7 @@ float RewardEvaluator::getStrategicalValue(const CGObjectInstance * target, cons
 	{
 		auto resource = dynamic_cast<const CGResource *>(target);
 		TResources res;
-		res[resource->resourceID()] = resource->amount;
+		res[resource->resourceID()] = resource->getAmount();
 		
 		return getResourceRequirementStrength(res);
 	}

+ 1 - 0
AI/VCAI/Goals/CollectRes.cpp

@@ -16,6 +16,7 @@
 #include "../ResourceManager.h"
 #include "../BuildingManager.h"
 #include "../../../lib/mapObjects/CGMarket.h"
+#include "../../../lib/mapObjects/CGResource.h"
 #include "../../../lib/constants/StringConstants.h"
 
 using namespace Goals;

+ 9 - 7
config/objects/moddables.json

@@ -96,13 +96,15 @@
 			}
 		},
 		"types" : {
-			"wood" :    { "index" : 0, "aiValue" : 1400, "rmg" : { "value" : 1400, "rarity" : 300 }, "templates" : { "res" : { "animation" : "AVTwood0.def" } } },
-			"mercury" : { "index" : 1, "aiValue" : 2000, "rmg" : { "value" : 2000, "rarity" : 300 }, "templates" : { "res" : { "animation" : "AVTmerc0.def" } } },
-			"ore" :     { "index" : 2, "aiValue" : 1400, "rmg" : { "value" : 1400, "rarity" : 300 }, "templates" : { "res" : { "animation" : "AVTore0.def"  } } },
-			"sulfur" :  { "index" : 3, "aiValue" : 2000, "rmg" : { "value" : 2000, "rarity" : 300 }, "templates" : { "res" : { "animation" : "AVTsulf0.def" } } },
-			"crystal" : { "index" : 4, "aiValue" : 2000, "rmg" : { "value" : 2000, "rarity" : 300 }, "templates" : { "res" : { "animation" : "AVTcrys0.def" } } },
-			"gems" :    { "index" : 5, "aiValue" : 2000, "rmg" : { "value" : 2000, "rarity" : 300 }, "templates" : { "res" : { "animation" : "AVTgems0.def" } } },
-			"gold" :    { "index" : 6, "aiValue" : 750, "rmg" : { "value" : 750,  "rarity" : 300 }, "templates" : { "res" : { "animation" : "AVTgold0.def" } } }
+			"wood" :    { "index" : 0, "aiValue" : 1400, "resource" : "wood", "amounts" : [ 6,7,8,9,10], "rmg" : { "value" : 1400, "rarity" : 300 }, "templates" : { "res" : { "animation" : "AVTwood0.def" } } },
+			"ore" :     { "index" : 2, "aiValue" : 1400, "resource" : "ore",  "amounts" : [ 6,7,8,9,10], "rmg" : { "value" : 1400, "rarity" : 300 }, "templates" : { "res" : { "animation" : "AVTore0.def"  } } },
+
+			"mercury" : { "index" : 1, "aiValue" : 2000, "resource" : "mercury", "amounts" : [ 3,4,5], "rmg" : { "value" : 2000, "rarity" : 300 }, "templates" : { "res" : { "animation" : "AVTmerc0.def" } } },
+			"sulfur" :  { "index" : 3, "aiValue" : 2000, "resource" : "sulfur",  "amounts" : [ 3,4,5], "rmg" : { "value" : 2000, "rarity" : 300 }, "templates" : { "res" : { "animation" : "AVTsulf0.def" } } },
+			"crystal" : { "index" : 4, "aiValue" : 2000, "resource" : "crystal", "amounts" : [ 3,4,5], "rmg" : { "value" : 2000, "rarity" : 300 }, "templates" : { "res" : { "animation" : "AVTcrys0.def" } } },
+			"gems" :    { "index" : 5, "aiValue" : 2000, "resource" : "gems",    "amounts" : [ 3,4,5], "rmg" : { "value" : 2000, "rarity" : 300 }, "templates" : { "res" : { "animation" : "AVTgems0.def" } } },
+
+			"gold" :    { "index" : 6, "aiValue" : 750,  "resource" : "gold", "amounts" : [ 5,6,7,8,9,10], "amountMultiplier" : 100, "rmg" : { "value" : 750,  "rarity" : 300 }, "templates" : { "res" : { "animation" : "AVTgold0.def" } } }
 		}
 	},
 	

+ 2 - 0
lib/CMakeLists.txt

@@ -130,6 +130,7 @@ set(lib_MAIN_SRCS
 	mapObjects/CGMarket.cpp
 	mapObjects/CGObjectInstance.cpp
 	mapObjects/CGPandoraBox.cpp
+	mapObjects/CGResource.cpp
 	mapObjects/TownBuildingInstance.cpp
 	mapObjects/CGTownInstance.cpp
 	mapObjects/CObjectHandler.cpp
@@ -519,6 +520,7 @@ set(lib_MAIN_HEADERS
 	mapObjects/CGObjectInstance.h
 	mapObjects/CGPandoraBox.h
 	mapObjects/TownBuildingInstance.h
+	mapObjects/CGResource.h
 	mapObjects/CGTownInstance.h
 	mapObjects/CObjectHandler.h
 	mapObjects/CQuest.h

+ 2 - 0
lib/constants/EntityIdentifiers.h

@@ -405,6 +405,8 @@ public:
 	enum Type
 	{
 		NO_OBJ = -1,
+
+		NOTHING = 0,
 		ALTAR_OF_SACRIFICE [[deprecated]] = 2,
 		ANCHOR_POINT = 3,
 		ARENA = 4,

+ 38 - 1
lib/mapObjectConstructors/CommonConstructors.cpp

@@ -48,6 +48,17 @@ std::string CreatureInstanceConstructor::getNameTextID() const
 	return VLC->creatures()->getByIndex(getSubIndex())->getNamePluralTextID();
 }
 
+void ResourceInstanceConstructor::initTypeData(const JsonNode & input)
+{
+	config = input;
+
+	resourceType = GameResID::GOLD; //set up fallback
+	VLC->identifiers()->requestIdentifierOptional("resource", input["resource"], [&](si32 index)
+	{
+		resourceType = GameResID(index);
+	});
+}
+
 bool ResourceInstanceConstructor::hasNameTextID() const
 {
 	return true;
@@ -55,7 +66,33 @@ bool ResourceInstanceConstructor::hasNameTextID() const
 
 std::string ResourceInstanceConstructor::getNameTextID() const
 {
-	return TextIdentifier("core", "restypes", getSubIndex()).get();
+	return TextIdentifier("core", "restypes", resourceType.getNum()).get();
+}
+
+GameResID ResourceInstanceConstructor::getResourceType() const
+{
+	return resourceType;
+}
+
+int ResourceInstanceConstructor::getAmountMultiplier() const
+{
+	if (config["amountMultiplier"].isNull())
+		return 1;
+	return config["amountMultiplier"].Integer();
+}
+
+void ResourceInstanceConstructor::randomizeObject(CGResource * object, vstd::RNG & rng) const
+{
+	if (object->amount != CGResource::RANDOM_AMOUNT)
+		return;
+
+	JsonRandom randomizer(object->cb);
+	JsonRandom::Variables dummy;
+
+	if (!config["amounts"].isNull())
+		object->amount = randomizer.loadValue(config["amounts"], rng, dummy, 0) * getAmountMultiplier();
+	else
+		object->amount = 5 * getAmountMultiplier();
 }
 
 void CTownInstanceConstructor::initTypeData(const JsonNode & input)

+ 13 - 0
lib/mapObjectConstructors/CommonConstructors.h

@@ -15,6 +15,9 @@
 #include "../mapObjects/MiscObjects.h"
 #include "../mapObjects/CGCreature.h"
 #include "../mapObjects/CGHeroInstance.h"
+#include "../mapObjects/CGMarket.h"
+#include "../mapObjects/CGResource.h"
+#include "../mapObjects/CGTownInstance.h"
 #include "../mapObjects/ObstacleSetHandler.h"
 
 VCMI_LIB_NAMESPACE_BEGIN
@@ -46,9 +49,19 @@ public:
 
 class ResourceInstanceConstructor : public CDefaultObjectTypeHandler<CGResource>
 {
+	JsonNode config;
+	GameResID resourceType;
 public:
+	void initTypeData(const JsonNode & input) override;
+
 	bool hasNameTextID() const override;
 	std::string getNameTextID() const override;
+
+	GameResID getResourceType() const;
+	int getAmountMultiplier() const;
+	int getBaseAmount(vstd::RNG & rng) const;
+
+	void randomizeObject(CGResource * object, vstd::RNG & rng) const override;
 };
 
 class CTownInstanceConstructor : public CDefaultObjectTypeHandler<CGTownInstance>

+ 138 - 0
lib/mapObjects/CGResource.cpp

@@ -0,0 +1,138 @@
+/*
+ * MiscObjects.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 "CGResource.h"
+
+#include "../mapObjectConstructors/CommonConstructors.h"
+#include "../texts/CGeneralTextHandler.h"
+#include "../networkPacks/PacksForClient.h"
+#include "../networkPacks/PacksForClientBattle.h"
+#include "../IGameCallback.h"
+#include "../gameState/CGameState.h"
+#include "../serializer/JsonSerializeFormat.h"
+#include "../CSoundBase.h"
+
+#include <vstd/RNG.h>
+
+VCMI_LIB_NAMESPACE_BEGIN
+
+std::shared_ptr<ResourceInstanceConstructor> CGResource::getResourceHandler() const
+{
+	const auto & baseHandler = getObjectHandler();
+	const auto & ourHandler = std::dynamic_pointer_cast<ResourceInstanceConstructor>(baseHandler);
+	return ourHandler;
+}
+
+int CGResource::getAmountMultiplier() const
+{
+	return getResourceHandler()->getAmountMultiplier();
+}
+
+uint32_t CGResource::getAmount() const
+{
+	return amount;
+}
+
+GameResID CGResource::resourceID() const
+{
+	return getResourceHandler()->getResourceType();
+}
+
+std::string CGResource::getHoverText(PlayerColor player) const
+{
+	return VLC->generaltexth->restypes[resourceID().getNum()];
+}
+
+void CGResource::pickRandomObject(vstd::RNG & rand)
+{
+	assert(ID == Obj::RESOURCE || ID == Obj::RANDOM_RESOURCE);
+
+	if (ID == Obj::RANDOM_RESOURCE)
+	{
+		ID = Obj::RESOURCE;
+		subID = rand.nextInt(EGameResID::WOOD, EGameResID::GOLD);
+		setType(ID, subID);
+
+		amount *= getAmountMultiplier();
+	}
+}
+
+void CGResource::initObj(vstd::RNG & rand)
+{
+	blockVisit = true;
+	getResourceHandler()->randomizeObject(this, rand);
+}
+
+void CGResource::onHeroVisit( const CGHeroInstance * h ) const
+{
+	if(stacksCount())
+	{
+		if(!message.empty())
+		{
+			BlockingDialog ynd(true,false);
+			ynd.player = h->getOwner();
+			ynd.text = message;
+			cb->showBlockingDialog(this, &ynd);
+		}
+		else
+		{
+			blockingDialogAnswered(h, true); //behave as if player accepted battle
+		}
+	}
+	else
+		collectRes(h->getOwner());
+}
+
+void CGResource::collectRes(const PlayerColor & player) const
+{
+	cb->giveResource(player, resourceID(), amount);
+	InfoWindow sii;
+	sii.player = player;
+	if(!message.empty())
+	{
+		sii.type = EInfoWindowMode::AUTO;
+		sii.text = message;
+	}
+	else
+	{
+		sii.type = EInfoWindowMode::INFO;
+		sii.text.appendLocalString(EMetaText::ADVOB_TXT,113);
+		sii.text.replaceName(resourceID());
+	}
+	sii.components.emplace_back(ComponentType::RESOURCE, resourceID(), amount);
+	sii.soundID = soundBase::pickup01 + cb->gameState()->getRandomGenerator().nextInt(6);
+	cb->showInfoDialog(&sii);
+	cb->removeObject(this, player);
+}
+
+void CGResource::battleFinished(const CGHeroInstance *hero, const BattleResult &result) const
+{
+	if(result.winner == BattleSide::ATTACKER) //attacker won
+		collectRes(hero->getOwner());
+}
+
+void CGResource::blockingDialogAnswered(const CGHeroInstance *hero, int32_t answer) const
+{
+	if(answer)
+		cb->startBattle(hero, this);
+}
+
+void CGResource::serializeJsonOptions(JsonSerializeFormat & handler)
+{
+	CArmedInstance::serializeJsonOptions(handler);
+	if(!handler.saving && !handler.getCurrent()["guards"].Vector().empty())
+		CCreatureSet::serializeJson(handler, "guards", 7);
+	handler.serializeInt("amount", amount, 0);
+	handler.serializeStruct("guardMessage", message);
+}
+
+
+VCMI_LIB_NAMESPACE_END

+ 55 - 0
lib/mapObjects/CGResource.h

@@ -0,0 +1,55 @@
+/*
+ * CGResource.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 "CArmedInstance.h"
+
+VCMI_LIB_NAMESPACE_BEGIN
+
+class ResourceInstanceConstructor;
+
+class DLL_LINKAGE CGResource : public CArmedInstance
+{
+	friend class Inspector;
+	friend class CMapLoaderH3M;
+	friend class ResourceInstanceConstructor;
+
+	MetaString message;
+
+	static constexpr uint32_t RANDOM_AMOUNT = 0;
+	uint32_t amount = RANDOM_AMOUNT; //0 if random
+
+	std::shared_ptr<ResourceInstanceConstructor> getResourceHandler() const;
+	int getAmountMultiplier() const;
+	void collectRes(const PlayerColor & player) const;
+	void serializeJsonOptions(JsonSerializeFormat & handler) override;
+
+public:
+	using CArmedInstance::CArmedInstance;
+
+	void onHeroVisit(const CGHeroInstance * h) const override;
+	void initObj(vstd::RNG & rand) override;
+	void pickRandomObject(vstd::RNG & rand) override;
+	void battleFinished(const CGHeroInstance *hero, const BattleResult &result) const override;
+	void blockingDialogAnswered(const CGHeroInstance *hero, int32_t answer) const override;
+	std::string getHoverText(PlayerColor player) const override;
+
+	GameResID resourceID() const;
+	uint32_t getAmount() const;
+
+	template <typename Handler> void serialize(Handler &h)
+	{
+		h & static_cast<CArmedInstance&>(*this);
+		h & amount;
+		h & message;
+	}
+};
+
+VCMI_LIB_NAMESPACE_END

+ 0 - 109
lib/mapObjects/MiscObjects.cpp

@@ -256,115 +256,6 @@ void CGMine::serializeJsonOptions(JsonSerializeFormat & handler)
 	}
 }
 
-GameResID CGResource::resourceID() const
-{
-	return getObjTypeIndex().getNum();
-}
-
-std::string CGResource::getHoverText(PlayerColor player) const
-{
-	return VLC->generaltexth->restypes[resourceID().getNum()];
-}
-
-void CGResource::pickRandomObject(vstd::RNG & rand)
-{
-	assert(ID == Obj::RESOURCE || ID == Obj::RANDOM_RESOURCE);
-
-	if (ID == Obj::RANDOM_RESOURCE)
-	{
-		ID = Obj::RESOURCE;
-		subID = rand.nextInt(EGameResID::WOOD, EGameResID::GOLD);
-		setType(ID, subID);
-
-		if (subID == EGameResID::GOLD && amount != CGResource::RANDOM_AMOUNT)
-			amount *= CGResource::GOLD_AMOUNT_MULTIPLIER;
-	}
-}
-
-void CGResource::initObj(vstd::RNG & rand)
-{
-	blockVisit = true;
-
-	if(amount == CGResource::RANDOM_AMOUNT)
-	{
-		switch(resourceID().toEnum())
-		{
-		case EGameResID::GOLD:
-			amount = rand.nextInt(5, 10) * CGResource::GOLD_AMOUNT_MULTIPLIER;
-			break;
-		case EGameResID::WOOD: case EGameResID::ORE:
-			amount = rand.nextInt(6, 10);
-			break;
-		default:
-			amount = rand.nextInt(3, 5);
-			break;
-		}
-	}
-}
-
-void CGResource::onHeroVisit( const CGHeroInstance * h ) const
-{
-	if(stacksCount())
-	{
-		if(!message.empty())
-		{
-			BlockingDialog ynd(true,false);
-			ynd.player = h->getOwner();
-			ynd.text = message;
-			cb->showBlockingDialog(this, &ynd);
-		}
-		else
-		{
-			blockingDialogAnswered(h, true); //behave as if player accepted battle
-		}
-	}
-	else
-		collectRes(h->getOwner());
-}
-
-void CGResource::collectRes(const PlayerColor & player) const
-{
-	cb->giveResource(player, resourceID(), amount);
-	InfoWindow sii;
-	sii.player = player;
-	if(!message.empty())
-	{
-		sii.type = EInfoWindowMode::AUTO;
-		sii.text = message;
-	}
-	else
-	{
-		sii.type = EInfoWindowMode::INFO;
-		sii.text.appendLocalString(EMetaText::ADVOB_TXT,113);
-		sii.text.replaceName(resourceID());
-	}
-	sii.components.emplace_back(ComponentType::RESOURCE, resourceID(), amount);
-	sii.soundID = soundBase::pickup01 + cb->gameState()->getRandomGenerator().nextInt(6);
-	cb->showInfoDialog(&sii);
-	cb->removeObject(this, player);
-}
-
-void CGResource::battleFinished(const CGHeroInstance *hero, const BattleResult &result) const
-{
-	if(result.winner == BattleSide::ATTACKER) //attacker won
-		collectRes(hero->getOwner());
-}
-
-void CGResource::blockingDialogAnswered(const CGHeroInstance *hero, int32_t answer) const
-{
-	if(answer)
-		cb->startBattle(hero, this);
-}
-
-void CGResource::serializeJsonOptions(JsonSerializeFormat & handler)
-{
-	CArmedInstance::serializeJsonOptions(handler);
-	if(!handler.saving && !handler.getCurrent()["guards"].Vector().empty())
-		CCreatureSet::serializeJson(handler, "guards", 7);
-	handler.serializeInt("amount", amount, 0);
-	handler.serializeStruct("guardMessage", message);
-}
-
 bool CGTeleport::isEntrance() const
 {
 	return type == BOTH || type == ENTRANCE;

+ 0 - 31
lib/mapObjects/MiscObjects.h

@@ -124,37 +124,6 @@ protected:
 	void serializeJsonOptions(JsonSerializeFormat & handler) override;
 };
 
-class DLL_LINKAGE CGResource : public CArmedInstance
-{
-public:
-	using CArmedInstance::CArmedInstance;
-
-	static constexpr uint32_t RANDOM_AMOUNT = 0;
-	static constexpr uint32_t GOLD_AMOUNT_MULTIPLIER = 100;
-	uint32_t amount = RANDOM_AMOUNT; //0 if random
-	
-	MetaString message;
-
-	void onHeroVisit(const CGHeroInstance * h) const override;
-	void initObj(vstd::RNG & rand) override;
-	void pickRandomObject(vstd::RNG & rand) override;
-	void battleFinished(const CGHeroInstance *hero, const BattleResult &result) const override;
-	void blockingDialogAnswered(const CGHeroInstance *hero, int32_t answer) const override;
-	std::string getHoverText(PlayerColor player) const override;
-
-	void collectRes(const PlayerColor & player) const;
-	GameResID resourceID() const;
-
-	template <typename Handler> void serialize(Handler &h)
-	{
-		h & static_cast<CArmedInstance&>(*this);
-		h & amount;
-		h & message;
-	}
-protected:
-	void serializeJsonOptions(JsonSerializeFormat & handler) override;
-};
-
 class DLL_LINKAGE CGMine : public CArmedInstance, public IOwnableObject
 {
 public:

+ 0 - 1
lib/mapping/CMap.cpp

@@ -178,7 +178,6 @@ EDiggingStatus TerrainTile::getDiggingStatus(const bool excludeTop) const
 
 CMap::CMap(IGameCallback * cb)
 	: GameCallbackHolder(cb)
-	, checksum(0)
 	, grailPos(-1, -1, -1)
 	, grailRadius(0)
 	, waterMap(false)

+ 0 - 1
lib/mapping/CMap.h

@@ -137,7 +137,6 @@ public:
 
 	void reindexObjects();
 
-	ui32 checksum;
 	std::vector<Rumor> rumors;
 	std::vector<DisposedHero> disposedHeroes;
 	std::vector<ConstTransitivePtr<CGHeroInstance> > predefinedHeroes;

+ 9 - 18
lib/mapping/MapFormatH3M.cpp

@@ -31,7 +31,9 @@
 #include "../filesystem/Filesystem.h"
 #include "../mapObjectConstructors/AObjectTypeHandler.h"
 #include "../mapObjectConstructors/CObjectClassesHandler.h"
+#include "../mapObjectConstructors/CommonConstructors.h"
 #include "../mapObjects/CGCreature.h"
+#include "../mapObjects/CGResource.h"
 #include "../mapObjects/MapObjects.h"
 #include "../mapObjects/ObjectTemplate.h"
 #include "../modding/ModScope.h"
@@ -40,8 +42,6 @@
 #include "../spells/CSpellHandler.h"
 #include "../texts/TextOperations.h"
 
-#include <boost/crc.hpp>
-
 VCMI_LIB_NAMESPACE_BEGIN
 
 static std::string convertMapName(std::string input)
@@ -92,19 +92,6 @@ std::unique_ptr<CMapHeader> CMapLoaderH3M::loadMapHeader()
 
 void CMapLoaderH3M::init()
 {
-	//TODO: get rid of double input process
-	si64 temp_size = inputStream->getSize();
-	inputStream->seek(0);
-
-	auto * temp_buffer = new ui8[temp_size];
-	inputStream->read(temp_buffer, temp_size);
-
-	// Compute checksum
-	boost::crc_32_type result;
-	result.process_bytes(temp_buffer, temp_size);
-	map->checksum = result.checksum();
-
-	delete[] temp_buffer;
 	inputStream->seek(0);
 
 	readHeader();
@@ -1315,11 +1302,15 @@ CGObjectInstance * CMapLoaderH3M::readResource(const int3 & mapPosition, std::sh
 	readMessageAndGuards(object->message, object, mapPosition);
 
 	object->amount = reader->readUInt32();
-	if(GameResID(objectTemplate->subid) == GameResID(EGameResID::GOLD))
+
+	if (objectTemplate->id != Obj::RANDOM_RESOURCE)
 	{
-		// Gold is multiplied by 100.
-		object->amount *= CGResource::GOLD_AMOUNT_MULTIPLIER;
+		const auto & baseHandler = VLC->objtypeh->getHandlerFor(objectTemplate->id, objectTemplate->subid);
+		const auto & ourHandler = std::dynamic_pointer_cast<ResourceInstanceConstructor>(baseHandler);
+
+		object->amount *= ourHandler->getAmountMultiplier();
 	}
+
 	reader->skipZero(4);
 	return object;
 }

+ 16 - 0
lib/mapping/MapIdentifiersH3M.cpp

@@ -116,6 +116,22 @@ void MapIdentifiersH3M::remapTemplate(ObjectTemplate & objectTemplate)
 		objectTemplate.subid = mappedType.subID;
 	}
 
+	if (VLC->objtypeh->knownObjects().count(objectTemplate.id) == 0)
+	{
+		logGlobal->warn("Unknown object found: %d | %d", objectTemplate.id, objectTemplate.subid);
+
+		objectTemplate.id = Obj::NOTHING;
+		objectTemplate.subid = {};
+	}
+	else
+	{
+		if (VLC->objtypeh->knownSubObjects(objectTemplate.id).count(objectTemplate.subid) == 0)
+		{
+			logGlobal->warn("Unknown subobject found: %d | %d", objectTemplate.id, objectTemplate.subid);
+			objectTemplate.subid = {};
+		}
+	}
+
 	if (objectTemplate.id == Obj::TOWN || objectTemplate.id == Obj::RANDOM_DWELLING_FACTION)
 		objectTemplate.subid = remap(FactionID(objectTemplate.subid));
 

+ 1 - 1
lib/rmg/modificators/MinePlacer.cpp

@@ -12,6 +12,7 @@
 #include "../RmgMap.h"
 #include "../../mapObjectConstructors/AObjectTypeHandler.h"
 #include "../../mapObjectConstructors/CObjectClassesHandler.h"
+#include "../../mapObjects/CGResource.h"
 #include "../../mapObjects/MiscObjects.h"
 #include "../../mapping/CMapEditManager.h"
 #include "../RmgPath.h"
@@ -91,7 +92,6 @@ bool MinePlacer::placeMines(ObjectManager & manager)
 			for(int rc = zone.getRand().nextInt(1, extraRes); rc > 0; --rc)
 			{
 				auto * resource = dynamic_cast<CGResource *>(VLC->objtypeh->getHandlerFor(Obj::RESOURCE, mine->producedResource)->create(map.mapInstance->cb, nullptr));
-				resource->amount = CGResource::RANDOM_AMOUNT;
 
 				RequiredObjectInfo roi;
 				roi.obj = resource;

+ 1 - 0
lib/serializer/RegisterTypes.h

@@ -23,6 +23,7 @@
 
 #include "../mapObjects/CGCreature.h"
 #include "../mapObjects/CGDwelling.h"
+#include "../mapObjects/CGResource.h"
 #include "../mapObjects/CGMarket.h"
 #include "../mapObjects/CGPandoraBox.h"
 #include "../mapObjects/CGTownInstance.h"

+ 0 - 7
mapeditor/inspector/inspector.cpp

@@ -225,13 +225,6 @@ void Initializer::initialize(CGMine * o)
 	}
 }
 
-void Initializer::initialize(CGResource * o)
-{
-	if(!o) return;
-	
-	o->amount = CGResource::RANDOM_AMOUNT;
-}
-
 //===============IMPLEMENT PROPERTIES SETUP===============================
 void Inspector::updateProperties(CArmedInstance * o)
 {

+ 1 - 1
mapeditor/inspector/inspector.h

@@ -17,6 +17,7 @@
 #include "../lib/int3.h"
 #include "../lib/GameConstants.h"
 #include "../lib/mapObjects/CGCreature.h"
+#include "../lib/mapObjects/CGResource.h"
 #include "../lib/mapObjects/MapObjects.h"
 #include "../lib/mapObjects/FlaggableMapObject.h"
 #include "../lib/mapObjects/CRewardableObject.h"
@@ -43,7 +44,6 @@ public:
 	DECLARE_OBJ_TYPE(CGTownInstance);
 	DECLARE_OBJ_TYPE(CGArtifact);
 	DECLARE_OBJ_TYPE(CGMine);
-	DECLARE_OBJ_TYPE(CGResource);
 	DECLARE_OBJ_TYPE(CGDwelling);
 	DECLARE_OBJ_TYPE(CGGarrison);
 	DECLARE_OBJ_TYPE(CGHeroPlaceholder);