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:
parent
13763cad8e
commit
96c81be68e
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
{}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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)
|
||||
{}
|
||||
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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))
|
||||
{
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user