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

Win/loss conditions now use VariantIdentifier. Removed non-implemented
options

Ivan Savenko пре 1 година
родитељ
комит
96c81be68e

+ 0 - 5
AI/VCAI/Goals/Win.cpp

@@ -173,11 +173,6 @@ TSubgoal Win::whatToDoToAchieve()
 		case EventCondition::CONST_VALUE:
 			break;
 
-		case EventCondition::HAVE_0:
-		case EventCondition::HAVE_BUILDING_0:
-		case EventCondition::DESTROY_0:
-			//TODO: support new condition format
-			return sptr(Conquer());
 		default:
 			assert(0);
 		}

+ 15 - 0
lib/constants/EntityIdentifiers.h

@@ -417,6 +417,21 @@ class BuildingID : public IdentifierWithEnum<BuildingID, BuildingIDBase>
 {
 public:
 	using IdentifierWithEnum<BuildingID, BuildingIDBase>::IdentifierWithEnum;
+
+	static BuildingID TOWN_HALL_LEVEL(uint level)
+	{
+		assert(level < 4);
+		return BuildingID(Type::TOWN_HALL + level);
+	}
+	static BuildingID FORT_LEVEL(uint level)
+	{
+		assert(level < 3);
+		return BuildingID(Type::TOWN_HALL + level);
+	}
+
+	static std::string encode(int32_t index);
+	static si32 decode(const std::string & identifier);
+
 };
 
 class MapObjectBaseID : public IdentifierBase

+ 3 - 2
lib/constants/VariantIdentifier.h

@@ -17,9 +17,10 @@ VCMI_LIB_NAMESPACE_BEGIN
 template<typename... Types>
 class VariantIdentifier
 {
-	std::variant<Types...> value;
-public:
+	using Type = std::variant<Types...>;
+	Type value;
 
+public:
 	VariantIdentifier()
 	{}
 

+ 12 - 30
lib/gameState/CGameState.cpp

@@ -1380,7 +1380,7 @@ bool CGameState::checkForVictory(const PlayerColor & player, const EventConditio
 		case EventCondition::HAVE_ARTIFACT: //check if any hero has winning artifact
 		{
 			for(const auto & elem : p->heroes)
-				if(elem->hasArt(ArtifactID(condition.objectType)))
+				if(elem->hasArt(condition.objectType.as<ArtifactID>()))
 					return true;
 			return false;
 		}
@@ -1396,7 +1396,7 @@ bool CGameState::checkForVictory(const PlayerColor & player, const EventConditio
 					&& (ai = dynamic_cast<const CArmedInstance *>(object.get()))) //contains army
 				{
 					for(const auto & elem : ai->Slots()) //iterate through army
-						if(elem.second->type->getIndex() == condition.objectType) //it's searched creature
+						if(elem.second->getId() == condition.objectType.as<CreatureID>()) //it's searched creature
 							total += elem.second->count;
 				}
 			}
@@ -1404,20 +1404,20 @@ bool CGameState::checkForVictory(const PlayerColor & player, const EventConditio
 		}
 		case EventCondition::HAVE_RESOURCES:
 		{
-			return p->resources[condition.objectType] >= condition.value;
+			return p->resources[condition.objectType.as<GameResID>()] >= condition.value;
 		}
 		case EventCondition::HAVE_BUILDING:
 		{
 			if (condition.object) // specific town
 			{
 				const auto * t = dynamic_cast<const CGTownInstance *>(condition.object);
-				return (t->tempOwner == player && t->hasBuilt(BuildingID(condition.objectType)));
+				return (t->tempOwner == player && t->hasBuilt(condition.objectType.as<BuildingID>()));
 			}
 			else // any town
 			{
 				for (const CGTownInstance * t : p->towns)
 				{
-					if (t->hasBuilt(BuildingID(condition.objectType)))
+					if (t->hasBuilt(condition.objectType.as<BuildingID>()))
 						return true;
 				}
 				return false;
@@ -1436,7 +1436,7 @@ bool CGameState::checkForVictory(const PlayerColor & player, const EventConditio
 			{
 				for(const auto & elem : map->objects) // mode B - destroy all objects of this type
 				{
-					if(elem && elem->ID.getNum() == condition.objectType)
+					if(elem && elem->ID == condition.objectType.as<MapObjectID>())
 						return false;
 				}
 				return true;
@@ -1457,7 +1457,7 @@ bool CGameState::checkForVictory(const PlayerColor & player, const EventConditio
 				for(const auto & elem : map->objects) // mode B - flag all objects of this type
 				{
 					 //check not flagged objs
-					if ( elem && elem->ID.getNum() == condition.objectType && team.count(elem->tempOwner) == 0 )
+					if ( elem && elem->ID == condition.objectType.as<MapObjectID>() && team.count(elem->tempOwner) == 0 )
 						return false;
 				}
 				return true;
@@ -1466,8 +1466,8 @@ bool CGameState::checkForVictory(const PlayerColor & player, const EventConditio
 		case EventCondition::TRANSPORT:
 		{
 			const auto * t = dynamic_cast<const CGTownInstance *>(condition.object);
-			return (t->visitingHero && t->visitingHero->hasArt(ArtifactID(condition.objectType))) ||
-				   (t->garrisonHero && t->garrisonHero->hasArt(ArtifactID(condition.objectType)));
+			return (t->visitingHero && t->visitingHero->hasArt(condition.objectType.as<ArtifactID>())) ||
+				   (t->garrisonHero && t->garrisonHero->hasArt(condition.objectType.as<ArtifactID>()));
 		}
 		case EventCondition::DAYS_PASSED:
 		{
@@ -1488,24 +1488,6 @@ bool CGameState::checkForVictory(const PlayerColor & player, const EventConditio
 		{
 			return condition.value; // just convert to bool
 		}
-		case EventCondition::HAVE_0:
-		{
-			logGlobal->debug("Not implemented event condition type: %d", (int)condition.condition);
-			//TODO: support new condition format
-			return false;
-		}
-		case EventCondition::HAVE_BUILDING_0:
-		{
-			logGlobal->debug("Not implemented event condition type: %d", (int)condition.condition);
-			//TODO: support new condition format
-			return false;
-		}
-		case EventCondition::DESTROY_0:
-		{
-			logGlobal->debug("Not implemented event condition type: %d", (int)condition.condition);
-			//TODO: support new condition format
-			return false;
-		}
 		default:
 			logGlobal->error("Invalid event condition type: %d", (int)condition.condition);
 			return false;
@@ -1789,13 +1771,13 @@ void CGameState::obtainPlayersStats(SThievesGuildInfo & tgi, int level)
 		{
 			if(playerInactive(player.second.color)) //do nothing for neutral player
 				continue;
-			int bestCre = -1; //best creature's ID
+			CreatureID bestCre; //best creature's ID
 			for(const auto & elem : player.second.heroes)
 			{
 				for(const auto & it : elem->Slots())
 				{
-					int toCmp = it.second->type->getId(); //ID of creature we should compare with the best one
-					if(bestCre == -1 || VLC->creh->objects[bestCre]->getAIValue() < VLC->creh->objects[toCmp]->getAIValue())
+					CreatureID toCmp = it.second->type->getId(); //ID of creature we should compare with the best one
+					if(bestCre == -1 || bestCre.toEntity(VLC)->getAIValue() < toCmp.toEntity(VLC)->getAIValue())
 					{
 						bestCre = toCmp;
 					}

+ 1 - 1
lib/mapObjects/CGHeroInstance.cpp

@@ -1778,7 +1778,7 @@ bool CGHeroInstance::isMissionCritical() const
 
 		auto const & testFunctor = [&](const EventCondition & condition)
 		{
-			if ((condition.condition == EventCondition::CONTROL || condition.condition == EventCondition::HAVE_0) && condition.object)
+			if ((condition.condition == EventCondition::CONTROL) && condition.object)
 			{
 				const auto * hero = dynamic_cast<const CGHeroInstance *>(condition.object);
 				return (hero != this);

+ 2 - 2
lib/mapObjects/CGTownInstance.cpp

@@ -1149,7 +1149,7 @@ void CGTownInstance::serializeJsonOptions(JsonSerializeFormat & handler)
 
 			for(const BuildingID & id : forbiddenBuildings)
 			{
-				buildingsLIC.none.insert(id);
+				buildingsLIC.none.insert(id.getNum());
 				customBuildings = true;
 			}
 
@@ -1166,7 +1166,7 @@ void CGTownInstance::serializeJsonOptions(JsonSerializeFormat & handler)
 				if(id == BuildingID::FORT)
 					hasFort = true;
 
-				buildingsLIC.all.insert(id);
+				buildingsLIC.all.insert(id.getNum());
 				customBuildings = true;
 			}
 

+ 6 - 14
lib/mapping/CMap.cpp

@@ -79,7 +79,7 @@ void CCastleEvent::serializeJson(JsonSerializeFormat & handler)
 		a.syncSize(temp);
 		for(int i = 0; i < temp.size(); ++i)
 		{
-			a.serializeInt(i, temp[i]);
+			a.serializeInt(i, temp[i].getNum());
 			buildings.insert(temp[i]);
 		}
 	}
@@ -429,16 +429,16 @@ void CMap::checkForObjectives()
 			switch (cond.condition)
 			{
 				case EventCondition::HAVE_ARTIFACT:
-					event.onFulfill.replaceTextID(VLC->artifacts()->getByIndex(cond.objectType)->getNameTextID());
+					event.onFulfill.replaceTextID(cond.objectType.as<ArtifactID>().toEntity(VLC)->getNameTextID());
 					break;
 
 				case EventCondition::HAVE_CREATURES:
-					event.onFulfill.replaceTextID(VLC->creatures()->getByIndex(cond.objectType)->getNameSingularTextID());
+					event.onFulfill.replaceTextID(cond.objectType.as<CreatureID>().toEntity(VLC)->getNameSingularTextID());
 					event.onFulfill.replaceNumber(cond.value);
 					break;
 
 				case EventCondition::HAVE_RESOURCES:
-					event.onFulfill.replaceLocalString(EMetaText::RES_NAMES, cond.objectType);
+					event.onFulfill.replaceName(cond.objectType.as<GameResID>());
 					event.onFulfill.replaceNumber(cond.value);
 					break;
 
@@ -449,7 +449,7 @@ void CMap::checkForObjectives()
 
 				case EventCondition::CONTROL:
 					if (isInTheMap(cond.position))
-						cond.object = getObjectiveObjectFrom(cond.position, static_cast<Obj>(cond.objectType));
+						cond.object = getObjectiveObjectFrom(cond.position, cond.objectType.as<MapObjectID>());
 
 					if (cond.object)
 					{
@@ -464,7 +464,7 @@ void CMap::checkForObjectives()
 
 				case EventCondition::DESTROY:
 					if (isInTheMap(cond.position))
-						cond.object = getObjectiveObjectFrom(cond.position, static_cast<Obj>(cond.objectType));
+						cond.object = getObjectiveObjectFrom(cond.position, cond.objectType.as<MapObjectID>());
 
 					if (cond.object)
 					{
@@ -480,14 +480,6 @@ void CMap::checkForObjectives()
 				//break; case EventCondition::IS_HUMAN:
 				//break; case EventCondition::DAYS_WITHOUT_TOWN:
 				//break; case EventCondition::STANDARD_WIN:
-
-				//TODO: support new condition format
-				case EventCondition::HAVE_0:
-					break;
-				case EventCondition::DESTROY_0:
-					break;
-				case EventCondition::HAVE_BUILDING_0:
-					break;
 			}
 			return cond;
 		};

+ 1 - 6
lib/mapping/CMapHeader.cpp

@@ -69,21 +69,16 @@ bool PlayerInfo::hasCustomMainHero() const
 
 EventCondition::EventCondition(EWinLoseType condition):
 	object(nullptr),
-	metaType(EMetaclass::INVALID),
 	value(-1),
-	objectType(-1),
-	objectSubtype(-1),
 	position(-1, -1, -1),
 	condition(condition)
 {
 }
 
-EventCondition::EventCondition(EWinLoseType condition, si32 value, si32 objectType, const int3 & position):
+EventCondition::EventCondition(EWinLoseType condition, si32 value, TargetTypeID objectType, const int3 & position):
 	object(nullptr),
-	metaType(EMetaclass::INVALID),
 	value(value),
 	objectType(objectType),
-	objectSubtype(-1),
 	position(position),
 	condition(condition)
 {}

+ 5 - 13
lib/mapping/CMapHeader.h

@@ -10,6 +10,7 @@
 
 #pragma once
 
+#include "../constants/VariantIdentifier.h"
 #include "../modding/CModInfo.h"
 #include "../LogicalExpression.h"
 #include "../int3.h"
@@ -99,7 +100,6 @@ struct DLL_LINKAGE PlayerInfo
 struct DLL_LINKAGE EventCondition
 {
 	enum EWinLoseType {
-		//internal use, deprecated
 		HAVE_ARTIFACT,     // type - required artifact
 		HAVE_CREATURES,    // type - creatures to collect, value - amount to collect
 		HAVE_RESOURCES,    // type - resource ID, value - amount to collect
@@ -108,27 +108,21 @@ struct DLL_LINKAGE EventCondition
 		DESTROY,           // position - position of object, optional, type - type of object
 		TRANSPORT,         // position - where artifact should be transported, type - type of artifact
 
-		//map format version pre 1.0
 		DAYS_PASSED,       // value - number of days from start of the game
 		IS_HUMAN,          // value - 0 = player is AI, 1 = player is human
 		DAYS_WITHOUT_TOWN, // value - how long player can live without town, 0=instakill
 		STANDARD_WIN,      // normal defeat all enemies condition
 		CONST_VALUE,        // condition that always evaluates to "value" (0 = false, 1 = true)
-
-		//map format version 1.0+
-		HAVE_0,
-		HAVE_BUILDING_0,
-		DESTROY_0
 	};
 
+	using TargetTypeID = VariantIdentifier<ArtifactID, CreatureID, GameResID, BuildingID, MapObjectID>;
+
 	EventCondition(EWinLoseType condition = STANDARD_WIN);
-	EventCondition(EWinLoseType condition, si32 value, si32 objectType, const int3 & position = int3(-1, -1, -1));
+	EventCondition(EWinLoseType condition, si32 value, TargetTypeID objectType, const int3 & position = int3(-1, -1, -1));
 
 	const CGObjectInstance * object; // object that was at specified position or with instance name on start
-	EMetaclass metaType;
 	si32 value;
-	si32 objectType;
-	si32 objectSubtype;
+	TargetTypeID objectType;
 	std::string objectInstanceName;
 	int3 position;
 	EWinLoseType condition;
@@ -141,9 +135,7 @@ struct DLL_LINKAGE EventCondition
 		h & objectType;
 		h & position;
 		h & condition;
-		h & objectSubtype;
 		h & objectInstanceName;
-		h & metaType;
 	}
 };
 

+ 17 - 17
lib/mapping/MapFormatH3M.cpp

@@ -268,7 +268,7 @@ void CMapLoaderH3M::readPlayerInfo()
 			{
 				SHeroName vv;
 				vv.heroId = reader->readHero();
-				vv.heroName = readLocalizedString(TextIdentifier("header", "heroNames", vv.heroId));
+				vv.heroName = readLocalizedString(TextIdentifier("header", "heroNames", vv.heroId.getNum()));
 
 				playerInfo.heroesNames.push_back(vv);
 			}
@@ -381,7 +381,7 @@ void CMapLoaderH3M::readVictoryLossConditions()
 			case EVictoryConditionType::GATHERRESOURCE:
 			{
 				EventCondition cond(EventCondition::HAVE_RESOURCES);
-				cond.objectType = reader->readUInt8();
+				cond.objectType = reader->readGameResID();
 				cond.value = reader->readInt32();
 
 				specialVictory.effect.toOtherMessage.appendTextID("core.genrltxt.279");
@@ -397,9 +397,9 @@ void CMapLoaderH3M::readVictoryLossConditions()
 				EventExpression::OperatorAll oper;
 				EventCondition cond(EventCondition::HAVE_BUILDING);
 				cond.position = reader->readInt3();
-				cond.objectType = BuildingID::TOWN_HALL + reader->readUInt8();
+				cond.objectType = BuildingID::TOWN_HALL_LEVEL(reader->readUInt8());
 				oper.expressions.emplace_back(cond);
-				cond.objectType = BuildingID::FORT + reader->readUInt8();
+				cond.objectType = BuildingID::FORT_LEVEL(reader->readUInt8());
 				oper.expressions.emplace_back(cond);
 
 				specialVictory.effect.toOtherMessage.appendTextID("core.genrltxt.283");
@@ -414,7 +414,7 @@ void CMapLoaderH3M::readVictoryLossConditions()
 				assert(allowNormalVictory == true); // not selectable in editor
 				assert(appliesToAI == true); // not selectable in editor
 				EventCondition cond(EventCondition::HAVE_BUILDING);
-				cond.objectType = BuildingID::GRAIL;
+				cond.objectType = BuildingID(BuildingID::GRAIL);
 				cond.position = reader->readInt3();
 				if(cond.position.z > 2)
 					cond.position = int3(-1, -1, -1);
@@ -433,7 +433,7 @@ void CMapLoaderH3M::readVictoryLossConditions()
 				allowNormalVictory = true; // H3 behavior
 				assert(appliesToAI == false); // not selectable in editor
 				EventCondition cond(EventCondition::DESTROY);
-				cond.objectType = Obj::HERO;
+				cond.objectType = MapObjectID(MapObjectID::HERO);
 				cond.position = reader->readInt3();
 
 				specialVictory.effect.toOtherMessage.appendTextID("core.genrltxt.253");
@@ -446,7 +446,7 @@ void CMapLoaderH3M::readVictoryLossConditions()
 			case EVictoryConditionType::CAPTURECITY:
 			{
 				EventCondition cond(EventCondition::CONTROL);
-				cond.objectType = Obj::TOWN;
+				cond.objectType = MapObjectID(MapObjectID::TOWN);
 				cond.position = reader->readInt3();
 
 				specialVictory.effect.toOtherMessage.appendTextID("core.genrltxt.250");
@@ -460,7 +460,7 @@ void CMapLoaderH3M::readVictoryLossConditions()
 			{
 				assert(appliesToAI == true); // not selectable in editor
 				EventCondition cond(EventCondition::DESTROY);
-				cond.objectType = Obj::MONSTER;
+				cond.objectType = MapObjectID(MapObjectID::MONSTER);
 				cond.position = reader->readInt3();
 
 				specialVictory.effect.toOtherMessage.appendTextID("core.genrltxt.287");
@@ -473,8 +473,8 @@ void CMapLoaderH3M::readVictoryLossConditions()
 			case EVictoryConditionType::TAKEDWELLINGS:
 			{
 				EventExpression::OperatorAll oper;
-				oper.expressions.emplace_back(EventCondition(EventCondition::CONTROL, 0, Obj::CREATURE_GENERATOR1));
-				oper.expressions.emplace_back(EventCondition(EventCondition::CONTROL, 0, Obj::CREATURE_GENERATOR4));
+				oper.expressions.emplace_back(EventCondition(EventCondition::CONTROL, 0, Obj(Obj::CREATURE_GENERATOR1)));
+				oper.expressions.emplace_back(EventCondition(EventCondition::CONTROL, 0, Obj(Obj::CREATURE_GENERATOR4)));
 
 				specialVictory.effect.toOtherMessage.appendTextID("core.genrltxt.289");
 				specialVictory.onFulfill.appendTextID("core.genrltxt.288");
@@ -486,7 +486,7 @@ void CMapLoaderH3M::readVictoryLossConditions()
 			case EVictoryConditionType::TAKEMINES:
 			{
 				EventCondition cond(EventCondition::CONTROL);
-				cond.objectType = Obj::MINE;
+				cond.objectType = MapObjectID(MapObjectID::MINE);
 
 				specialVictory.effect.toOtherMessage.appendTextID("core.genrltxt.291");
 				specialVictory.onFulfill.appendTextID("core.genrltxt.290");
@@ -499,7 +499,7 @@ void CMapLoaderH3M::readVictoryLossConditions()
 			{
 				assert(allowNormalVictory == true); // not selectable in editor
 				EventCondition cond(EventCondition::TRANSPORT);
-				cond.objectType = reader->readUInt8();
+				cond.objectType = reader->readArtifact8();
 				cond.position = reader->readInt3();
 
 				specialVictory.effect.toOtherMessage.appendTextID("core.genrltxt.293");
@@ -513,7 +513,7 @@ void CMapLoaderH3M::readVictoryLossConditions()
 			{
 				assert(appliesToAI == false); // not selectable in editor
 				EventCondition cond(EventCondition::DESTROY);
-				cond.objectType = Obj::MONSTER;
+				cond.objectType = MapObjectID(MapObjectID::MONSTER);
 
 				specialVictory.effect.toOtherMessage.appendTextID("vcmi.map.victoryCondition.eliminateMonsters.toOthers");
 				specialVictory.onFulfill.appendTextID("vcmi.map.victoryCondition.eliminateMonsters.toSelf");
@@ -602,7 +602,7 @@ void CMapLoaderH3M::readVictoryLossConditions()
 			{
 				EventExpression::OperatorNone noneOf;
 				EventCondition cond(EventCondition::CONTROL);
-				cond.objectType = Obj::TOWN;
+				cond.objectType = Obj(Obj::TOWN);
 				cond.position = reader->readInt3();
 
 				noneOf.expressions.emplace_back(cond);
@@ -616,7 +616,7 @@ void CMapLoaderH3M::readVictoryLossConditions()
 			{
 				EventExpression::OperatorNone noneOf;
 				EventCondition cond(EventCondition::CONTROL);
-				cond.objectType = Obj::HERO;
+				cond.objectType = Obj(Obj::HERO);
 				cond.position = reader->readInt3();
 
 				noneOf.expressions.emplace_back(cond);
@@ -708,7 +708,7 @@ void CMapLoaderH3M::readDisposedHeroes()
 		{
 			map->disposedHeroes[g].heroId = reader->readHero();
 			map->disposedHeroes[g].portrait = reader->readHeroPortrait();
-			map->disposedHeroes[g].name = readLocalizedString(TextIdentifier("header", "heroes", map->disposedHeroes[g].heroId));
+			map->disposedHeroes[g].name = readLocalizedString(TextIdentifier("header", "heroes", map->disposedHeroes[g].heroId.getNum()));
 			reader->readBitmaskPlayers(map->disposedHeroes[g].players, false);
 		}
 	}
@@ -780,7 +780,7 @@ void CMapLoaderH3M::readAllowedArtifacts()
 		{
 			if(cond.condition == EventCondition::HAVE_ARTIFACT || cond.condition == EventCondition::TRANSPORT)
 			{
-				map->allowedArtifact.erase(cond.objectType);
+				map->allowedArtifact.erase(cond.objectType.as<ArtifactID>());
 			}
 			return cond;
 		};

+ 24 - 135
lib/mapping/MapFormatJson.cpp

@@ -139,63 +139,6 @@ namespace TriggeredEventsDetail
 
 	static const std::array<std::string, 2> typeNames = { "victory", "defeat" };
 
-	static EMetaclass decodeMetaclass(const std::string & source)
-	{
-		if(source.empty())
-			return EMetaclass::INVALID;
-		auto rawId = vstd::find_pos(NMetaclass::names, source);
-
-		if(rawId >= 0)
-			return static_cast<EMetaclass>(rawId);
-		else
-			return EMetaclass::INVALID;
-	}
-
-	static std::string encodeIdentifier(EMetaclass metaType, si32 type)
-	{
-		std::string metaclassName = NMetaclass::names[static_cast<int>(metaType)];
-		std::string identifier;
-
-		switch(metaType)
-		{
-		case EMetaclass::ARTIFACT:
-			{
-				identifier = ArtifactID::encode(type);
-			}
-			break;
-		case EMetaclass::CREATURE:
-			{
-				identifier = CreatureID::encode(type);
-			}
-			break;
-		case EMetaclass::OBJECT:
-			{
-				//TODO
-				auto subtypes = VLC->objtypeh->knownSubObjects(type);
-				if(!subtypes.empty())
-				{
-					auto subtype = *subtypes.begin();
-					auto handler = VLC->objtypeh->getHandlerFor(type, subtype);
-					identifier = handler->getTypeName();
-				}
-			}
-			break;
-		case EMetaclass::RESOURCE:
-			{
-				identifier = GameConstants::RESOURCE_NAMES[type];
-			}
-			break;
-		default:
-			{
-				logGlobal->error("Unsupported metaclass %s for event condition", metaclassName);
-				return "";
-			}
-			break;
-		}
-
-		return ModUtility::makeFullIdentifier("", metaclassName, identifier);
-	}
-
 	static EventCondition JsonToCondition(const JsonNode & node)
 	{
 		EventCondition event;
@@ -210,54 +153,28 @@ namespace TriggeredEventsDetail
 		{
 			const JsonNode & data = node.Vector()[1];
 
+			event.objectInstanceName = data["object"].String();
+			event.value = data["value"].Integer();
+
 			switch (event.condition)
 			{
-			case EventCondition::HAVE_0:
-			case EventCondition::DESTROY_0:
-				{
-					//todo: support subtypes
-
-					std::string fullIdentifier = data["type"].String();
-					std::string metaTypeName;
-					std::string scope;
-					std::string identifier;
-					ModUtility::parseIdentifier(fullIdentifier, scope, metaTypeName, identifier);
-
-					event.metaType = decodeMetaclass(metaTypeName);
-
-					auto type = VLC->identifiers()->getIdentifier(ModScope::scopeBuiltin(), fullIdentifier, false);
-
-					if(type)
-						event.objectType = type.value();
-					event.objectInstanceName = data["object"].String();
-					if(data["value"].isNumber())
-						event.value = static_cast<si32>(data["value"].Integer());
-				}
-				break;
-			case EventCondition::HAVE_BUILDING_0:
-				{
-					//todo: support of new condition format HAVE_BUILDING_0
-				}
-				break;
-			default:
-				{
-					//old format
-					if (data["type"].getType() == JsonNode::JsonType::DATA_STRING)
-					{
-						auto identifier = VLC->identifiers()->getIdentifier(data["type"]);
-						if(identifier)
-							event.objectType = identifier.value();
-						else
-							throw std::runtime_error("Identifier resolution failed in event condition");
-					}
-
-					if (data["type"].isNumber())
-						event.objectType = static_cast<si32>(data["type"].Float());
-
-					if (!data["value"].isNull())
-						event.value = static_cast<si32>(data["value"].Float());
-				}
-				break;
+				case EventCondition::HAVE_ARTIFACT:
+				case EventCondition::TRANSPORT:
+					event.objectType = ArtifactID(ArtifactID::decode(data["type"].String()));
+					break;
+				case EventCondition::HAVE_CREATURES:
+					event.objectType = CreatureID(CreatureID::decode(data["type"].String()));
+					break;
+				case EventCondition::HAVE_RESOURCES:
+					event.objectType = GameResID(GameResID::decode(data["type"].String()));
+					break;
+				case EventCondition::HAVE_BUILDING:
+					event.objectType = BuildingID(BuildingID::decode(data["type"].String()));
+					break;
+				case EventCondition::CONTROL:
+				case EventCondition::DESTROY:
+					event.objectType = MapObjectID(MapObjectID::decode(data["type"].String()));
+					break;
 			}
 
 			if (!data["position"].isNull())
@@ -283,39 +200,11 @@ namespace TriggeredEventsDetail
 
 		JsonNode data;
 
-		switch (event.condition)
-		{
-		case EventCondition::HAVE_0:
-		case EventCondition::DESTROY_0:
-			{
-				//todo: support subtypes
+		if(!event.objectInstanceName.empty())
+			data["object"].String() = event.objectInstanceName;
 
-				if(event.metaType != EMetaclass::INVALID)
-					data["type"].String() = encodeIdentifier(event.metaType, event.objectType);
-
-				if(event.value > 0)
-					data["value"].Integer() = event.value;
-
-				if(!event.objectInstanceName.empty())
-					data["object"].String() = event.objectInstanceName;
-			}
-			break;
-		case EventCondition::HAVE_BUILDING_0:
-			{
-			//todo: support of new condition format HAVE_BUILDING_0
-			}
-			break;
-		default:
-			{
-				//old format
-				if(event.objectType != -1)
-					data["type"].Integer() = event.objectType;
-
-				if(event.value != -1)
-					data["value"].Integer() = event.value;
-			}
-			break;
-		}
+		data["type"].String() = event.objectType.toString();
+		data["value"].Integer() = event.value;
 
 		if(event.position != int3(-1, -1, -1))
 		{

+ 18 - 0
lib/mapping/MapReaderH3M.cpp

@@ -81,6 +81,17 @@ ArtifactID MapReaderH3M::readArtifact()
 	return ArtifactID::NONE;
 }
 
+ArtifactID MapReaderH3M::readArtifact8()
+{
+	ArtifactID result(reader->readInt8());
+
+	if (result.getNum() < features.artifactsCount)
+		return remapIdentifier(result);
+
+	logGlobal->warn("Map contains invalid artifact %d. Will be removed!", result.getNum());
+	return ArtifactID::NONE;
+}
+
 ArtifactID MapReaderH3M::readArtifact32()
 {
 	ArtifactID result(reader->readInt32());
@@ -197,6 +208,13 @@ SpellID MapReaderH3M::readSpell32()
 	return result;
 }
 
+GameResID MapReaderH3M::readGameResID()
+{
+	GameResID result(readInt8());
+	assert(result.getNum() < features.resourcesCount);
+	return result;
+}
+
 PlayerColor MapReaderH3M::readPlayer()
 {
 	uint8_t value = readUInt8();

+ 2 - 0
lib/mapping/MapReaderH3M.h

@@ -32,6 +32,7 @@ public:
 	void setIdentifierRemapper(const MapIdentifiersH3M & remapper);
 
 	ArtifactID readArtifact();
+	ArtifactID readArtifact8();
 	ArtifactID readArtifact32();
 	CreatureID readCreature();
 	HeroTypeID readHero();
@@ -42,6 +43,7 @@ public:
 	SecondarySkill readSkill();
 	SpellID readSpell();
 	SpellID readSpell32();
+	GameResID readGameResID();
 	PlayerColor readPlayer();
 	PlayerColor readPlayer32();
 

+ 2 - 2
lib/networkPacks/NetPacksLib.cpp

@@ -1218,12 +1218,12 @@ void RemoveObject::applyGs(CGameState *gs)
 		{
 			if (cond.object == obj)
 			{
-				if (cond.condition == EventCondition::DESTROY || cond.condition == EventCondition::DESTROY_0)
+				if (cond.condition == EventCondition::DESTROY)
 				{
 					cond.condition = EventCondition::CONST_VALUE;
 					cond.value = 1; // destroyed object, from now on always fulfilled
 				}
-				else if (cond.condition == EventCondition::CONTROL || cond.condition == EventCondition::HAVE_0)
+				else if (cond.condition == EventCondition::CONTROL)
 				{
 					cond.condition = EventCondition::CONST_VALUE;
 					cond.value = 0; // destroyed object, from now on can not be fulfilled

+ 0 - 2
mapeditor/mapsettings/abstractsettings.cpp

@@ -129,9 +129,7 @@ JsonNode AbstractSettings::conditionToJson(const EventCondition & event)
 	result["condition"].Integer() = event.condition;
 	result["value"].Integer() = event.value;
 	result["objectType"].Integer() = event.objectType;
-	result["objectSubytype"].Integer() = event.objectSubtype;
 	result["objectInstanceName"].String() = event.objectInstanceName;
-	result["metaType"].Integer() = (ui8)event.metaType;
 	{
 		auto & position = result["position"].Vector();
 		position.resize(3);