From 96c81be68ea106c88185b0d1a4f3fc19fea41343 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Wed, 8 Nov 2023 17:35:17 +0200 Subject: [PATCH] Win/loss conditions now use VariantIdentifier. Removed non-implemented options --- AI/VCAI/Goals/Win.cpp | 5 - lib/constants/EntityIdentifiers.h | 15 ++ lib/constants/VariantIdentifier.h | 5 +- lib/gameState/CGameState.cpp | 42 ++---- lib/mapObjects/CGHeroInstance.cpp | 2 +- lib/mapObjects/CGTownInstance.cpp | 4 +- lib/mapping/CMap.cpp | 20 +-- lib/mapping/CMapHeader.cpp | 7 +- lib/mapping/CMapHeader.h | 18 +-- lib/mapping/MapFormatH3M.cpp | 34 ++--- lib/mapping/MapFormatJson.cpp | 159 ++++----------------- lib/mapping/MapReaderH3M.cpp | 18 +++ lib/mapping/MapReaderH3M.h | 2 + lib/networkPacks/NetPacksLib.cpp | 4 +- mapeditor/mapsettings/abstractsettings.cpp | 2 - 15 files changed, 108 insertions(+), 229 deletions(-) diff --git a/AI/VCAI/Goals/Win.cpp b/AI/VCAI/Goals/Win.cpp index 2ad9abdf8..86e6ddc8d 100644 --- a/AI/VCAI/Goals/Win.cpp +++ b/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); } diff --git a/lib/constants/EntityIdentifiers.h b/lib/constants/EntityIdentifiers.h index bbba7b9b6..637eb9e98 100644 --- a/lib/constants/EntityIdentifiers.h +++ b/lib/constants/EntityIdentifiers.h @@ -417,6 +417,21 @@ class BuildingID : public IdentifierWithEnum { public: using IdentifierWithEnum::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 diff --git a/lib/constants/VariantIdentifier.h b/lib/constants/VariantIdentifier.h index 90269a3bb..175411f67 100644 --- a/lib/constants/VariantIdentifier.h +++ b/lib/constants/VariantIdentifier.h @@ -17,9 +17,10 @@ VCMI_LIB_NAMESPACE_BEGIN template class VariantIdentifier { - std::variant value; -public: + using Type = std::variant; + Type value; +public: VariantIdentifier() {} diff --git a/lib/gameState/CGameState.cpp b/lib/gameState/CGameState.cpp index 3a1e040f1..82c79c06e 100644 --- a/lib/gameState/CGameState.cpp +++ b/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())) return true; return false; } @@ -1396,7 +1396,7 @@ bool CGameState::checkForVictory(const PlayerColor & player, const EventConditio && (ai = dynamic_cast(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()) //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()] >= condition.value; } case EventCondition::HAVE_BUILDING: { if (condition.object) // specific town { const auto * t = dynamic_cast(condition.object); - return (t->tempOwner == player && t->hasBuilt(BuildingID(condition.objectType))); + return (t->tempOwner == player && t->hasBuilt(condition.objectType.as())); } else // any town { for (const CGTownInstance * t : p->towns) { - if (t->hasBuilt(BuildingID(condition.objectType))) + if (t->hasBuilt(condition.objectType.as())) 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()) 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() && 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(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())) || + (t->garrisonHero && t->garrisonHero->hasArt(condition.objectType.as())); } 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; } diff --git a/lib/mapObjects/CGHeroInstance.cpp b/lib/mapObjects/CGHeroInstance.cpp index 80ae5b9f5..febfd8231 100644 --- a/lib/mapObjects/CGHeroInstance.cpp +++ b/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(condition.object); return (hero != this); diff --git a/lib/mapObjects/CGTownInstance.cpp b/lib/mapObjects/CGTownInstance.cpp index 84bda3112..891ad3d74 100644 --- a/lib/mapObjects/CGTownInstance.cpp +++ b/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; } diff --git a/lib/mapping/CMap.cpp b/lib/mapping/CMap.cpp index 98d629adb..3f0e285d0 100644 --- a/lib/mapping/CMap.cpp +++ b/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().toEntity(VLC)->getNameTextID()); break; case EventCondition::HAVE_CREATURES: - event.onFulfill.replaceTextID(VLC->creatures()->getByIndex(cond.objectType)->getNameSingularTextID()); + event.onFulfill.replaceTextID(cond.objectType.as().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()); 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(cond.objectType)); + cond.object = getObjectiveObjectFrom(cond.position, cond.objectType.as()); if (cond.object) { @@ -464,7 +464,7 @@ void CMap::checkForObjectives() case EventCondition::DESTROY: if (isInTheMap(cond.position)) - cond.object = getObjectiveObjectFrom(cond.position, static_cast(cond.objectType)); + cond.object = getObjectiveObjectFrom(cond.position, cond.objectType.as()); 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; }; diff --git a/lib/mapping/CMapHeader.cpp b/lib/mapping/CMapHeader.cpp index 2ca1ee8e0..bdc3a808e 100644 --- a/lib/mapping/CMapHeader.cpp +++ b/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) {} diff --git a/lib/mapping/CMapHeader.h b/lib/mapping/CMapHeader.h index 2a83e7d0e..e5b34892c 100644 --- a/lib/mapping/CMapHeader.h +++ b/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; + 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; } }; diff --git a/lib/mapping/MapFormatH3M.cpp b/lib/mapping/MapFormatH3M.cpp index 204d9c925..7d7c5676a 100644 --- a/lib/mapping/MapFormatH3M.cpp +++ b/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()); } return cond; }; diff --git a/lib/mapping/MapFormatJson.cpp b/lib/mapping/MapFormatJson.cpp index 90b747419..ba30eeb21 100644 --- a/lib/mapping/MapFormatJson.cpp +++ b/lib/mapping/MapFormatJson.cpp @@ -139,63 +139,6 @@ namespace TriggeredEventsDetail static const std::array 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(rawId); - else - return EMetaclass::INVALID; - } - - static std::string encodeIdentifier(EMetaclass metaType, si32 type) - { - std::string metaclassName = NMetaclass::names[static_cast(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(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(data["type"].Float()); - - if (!data["value"].isNull()) - event.value = static_cast(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)) { diff --git a/lib/mapping/MapReaderH3M.cpp b/lib/mapping/MapReaderH3M.cpp index 00334d443..e0ee0a83c 100644 --- a/lib/mapping/MapReaderH3M.cpp +++ b/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(); diff --git a/lib/mapping/MapReaderH3M.h b/lib/mapping/MapReaderH3M.h index 92da10ab0..e2b5e01b8 100644 --- a/lib/mapping/MapReaderH3M.h +++ b/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(); diff --git a/lib/networkPacks/NetPacksLib.cpp b/lib/networkPacks/NetPacksLib.cpp index 2fd3b9cbb..90ae0064d 100644 --- a/lib/networkPacks/NetPacksLib.cpp +++ b/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 diff --git a/mapeditor/mapsettings/abstractsettings.cpp b/mapeditor/mapsettings/abstractsettings.cpp index c15c52cd9..6b4d251a1 100644 --- a/mapeditor/mapsettings/abstractsettings.cpp +++ b/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);