1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-01-12 02:28:11 +02:00

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

options
This commit is contained in:
Ivan Savenko 2023-11-08 17:35:17 +02:00
parent 13763cad8e
commit 96c81be68e
15 changed files with 108 additions and 229 deletions

View File

@ -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);
}

View File

@ -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

View File

@ -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()
{}

View File

@ -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;
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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;
};

View File

@ -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)
{}

View File

@ -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;
}
};

View File

@ -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;
};

View File

@ -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))
{

View File

@ -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();

View File

@ -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();

View File

@ -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

View File

@ -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);