1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-05-31 22:59:54 +02:00

Implemented parsing of HotA h3m header

This commit is contained in:
Ivan Savenko 2023-04-03 18:56:49 +03:00
parent f93335d678
commit 838d45b32c
4 changed files with 76 additions and 33 deletions

View File

@ -253,13 +253,15 @@ struct DLL_LINKAGE DisposedHero
enum class EMapFormat: uint8_t
{
INVALID = 0,
// HEX DEC
ROE = 0x0e, // 14
AB = 0x15, // 21
SOD = 0x1c, // 28
HOTA = 0x1e, // 30
WOG = 0x33, // 51
VCMI = 0xF0
// HEX DEC
ROE = 0x0e, // 14
AB = 0x15, // 21
SOD = 0x1c, // 28
HOTA1 = 0x1e, // 30
HOTA2 = 0x1f, // 31
HOTA3 = 0x20, // 32
WOG = 0x33, // 51
VCMI = 0xF0
};
/// The map header holds information about loss/victory condition,map format, version, players, height, width,...

View File

@ -124,6 +124,9 @@ std::unique_ptr<IMapLoader> CMapService::getMapLoader(std::unique_ptr<CInputStre
case static_cast<int>(EMapFormat::AB) :
case static_cast<int>(EMapFormat::ROE) :
case static_cast<int>(EMapFormat::SOD) :
case static_cast<int>(EMapFormat::HOTA1) :
case static_cast<int>(EMapFormat::HOTA2) :
case static_cast<int>(EMapFormat::HOTA3) :
return std::unique_ptr<IMapLoader>(new CMapLoaderH3M(mapName, modName, encoding, stream.get()));
default :
throw std::runtime_error("Unknown map format");

View File

@ -27,7 +27,9 @@ MapFormatFeaturesH3M MapFormatFeaturesH3M::find(EMapFormat format)
return getFeaturesSOD();
case EMapFormat::WOG:
return getFeaturesWOG();
case EMapFormat::HOTA:
//case EMapFormat::HOTA1: //TODO: find such maps? Not present in current HotA release (1.6)
//case EMapFormat::HOTA2:
case EMapFormat::HOTA3:
return getFeaturesHOTA();
default:
throw std::runtime_error("Invalid map format!");
@ -116,6 +118,14 @@ MapFormatFeaturesH3M MapFormatFeaturesH3M::getFeaturesHOTA()
MapFormatFeaturesH3M result = getFeaturesSOD();
result.levelHOTA = true;
result.factionsCount = 10; // + Cove
result.creaturesCount = 162; // + Cove + neutrals
result.artifactsCount = 161; // + HotA artifacts
result.heroesBytes = 24;
result.heroesCount = 179; // + Cove
result.heroesPortraitsCount = 186; // + Cove
return result;
}

View File

@ -154,22 +154,17 @@ void CMapLoaderH3M::readHeader()
features = MapFormatFeaturesH3M::find(mapHeader->version);
reader->setFormatLevel(mapHeader->version);
if (mapHeader->version == EMapFormat::HOTA)
if(mapHeader->version == EMapFormat::HOTA1 || mapHeader->version == EMapFormat::HOTA2 || mapHeader->version == EMapFormat::HOTA3)
{
//unknown values
std::vector<uint8_t> bytes;
for(int i = 0; i < 10; ++i)
bytes.push_back(reader->readInt8());
assert(bytes[0] == 3);
assert(bytes[1] == 0);
assert(bytes[2] == 0);
assert(bytes[3] == 0);
assert(bytes[4] == 0);
assert(bytes[5] == 0);
assert(bytes[6] == 12);
assert(bytes[7] == 0);
assert(bytes[8] == 0);
assert(bytes[9] == 0);
uint8_t hotaVersion = reader->readUInt8();
reader->skipZero(5);
if (hotaVersion == 3)
{
uint8_t unknown = reader->readUInt8();
logGlobal->error("%s -> header unknown: %d", mapName, int(unknown));
reader->skipZero(3);
}
}
// Read map name, description, dimensions,...
@ -268,22 +263,37 @@ void CMapLoaderH3M::readPlayerInfo()
}
}
namespace EVictoryConditionType
enum class EVictoryConditionType : uint8_t
{
enum EVictoryConditionType { ARTIFACT, GATHERTROOP, GATHERRESOURCE, BUILDCITY, BUILDGRAIL, BEATHERO,
CAPTURECITY, BEATMONSTER, TAKEDWELLINGS, TAKEMINES, TRANSPORTITEM, WINSTANDARD = 255 };
}
ARTIFACT = 0,
GATHERTROOP = 1,
GATHERRESOURCE = 2,
BUILDCITY = 3,
BUILDGRAIL = 4,
BEATHERO = 5,
CAPTURECITY = 6,
BEATMONSTER = 7,
TAKEDWELLINGS = 8,
TAKEMINES = 9,
TRANSPORTITEM = 10,
HOTA_ELIMINATE_ALL_MONSTERS = 11,
HOTA_SURVIVE_FOR_DAYS = 12,
WINSTANDARD = 255
};
namespace ELossConditionType
enum class ELossConditionType : uint8_t
{
enum ELossConditionType { LOSSCASTLE, LOSSHERO, TIMEEXPIRES, LOSSSTANDARD = 255 };
}
LOSSCASTLE,
LOSSHERO,
TIMEEXPIRES,
LOSSSTANDARD = 255
};
void CMapLoaderH3M::readVictoryLossConditions()
{
mapHeader->triggeredEvents.clear();
auto vicCondition = static_cast<EVictoryConditionType::EVictoryConditionType>(reader->readUInt8());
auto vicCondition = static_cast<EVictoryConditionType>(reader->readUInt8());
EventCondition victoryCondition(EventCondition::STANDARD_WIN);
EventCondition defeatCondition(EventCondition::DAYS_WITHOUT_TOWN);
@ -464,6 +474,15 @@ void CMapLoaderH3M::readVictoryLossConditions()
specialVictory.trigger = EventExpression(cond);
break;
}
case EVictoryConditionType::HOTA_ELIMINATE_ALL_MONSTERS:
logGlobal->error("Map %s - victory condition 'Eliminate all monsters' is not supported!", mapName);
//TODO: HOTA
break;
case EVictoryConditionType::HOTA_SURVIVE_FOR_DAYS:
logGlobal->error("Map %s - victory condition 'Survive for certain time' is not supported!", mapName);
//TODO: HOTA
reader->readUInt32(); // Number of days
break;
default:
assert(0);
}
@ -490,7 +509,7 @@ void CMapLoaderH3M::readVictoryLossConditions()
}
// Read loss conditions
auto lossCond = static_cast<ELossConditionType::ELossConditionType>(reader->readUInt8());
auto lossCond = static_cast<ELossConditionType>(reader->readUInt8());
if (lossCond == ELossConditionType::LOSSSTANDARD)
{
mapHeader->defeatIconIndex = 3;
@ -591,7 +610,16 @@ void CMapLoaderH3M::readAllowedHeroes()
{
mapHeader->allowedHeroes = VLC->heroh->getDefaultAllowed();
reader->readBitmask(mapHeader->allowedHeroes, features.heroesBytes, features.heroesCount, false);
uint32_t heroesCount = features.heroesCount;
if (features.levelHOTA)
{
heroesCount = reader->readUInt32();
}
assert(heroesCount <= features.heroesCount);
reader->readBitmask(mapHeader->allowedHeroes, features.heroesBytes, heroesCount, false);
//TODO: unknown value. Check meaning? Only present in campaign maps.
if(features.levelAB)