mirror of
https://github.com/vcmi/vcmi.git
synced 2025-05-31 22:59:54 +02:00
Support for parsing HotA 1.7.2 h3m's and h3c's
This commit is contained in:
parent
a12ea45276
commit
091029e0bb
@ -35,6 +35,7 @@ enum class EQuestMission {
|
||||
KEYMASTER = 11,
|
||||
HOTA_HERO_CLASS = 12,
|
||||
HOTA_REACH_DATE = 13,
|
||||
HOTA_GAME_DIFFICULTY = 13,
|
||||
};
|
||||
|
||||
class DLL_LINKAGE CQuest final : public Serializeable
|
||||
|
@ -131,15 +131,17 @@ MapFormatFeaturesH3M MapFormatFeaturesH3M::getFeaturesHOTA(uint32_t hotaVersion)
|
||||
{
|
||||
// even if changes are minimal, we might not be able to parse map header in map selection screen
|
||||
// throw exception - to be caught by map selection screen & excluded as invalid
|
||||
if(hotaVersion > 6)
|
||||
if(hotaVersion > 7)
|
||||
throw std::runtime_error("Invalid map format!");
|
||||
|
||||
MapFormatFeaturesH3M result = getFeaturesSOD();
|
||||
result.levelHOTA0 = true;
|
||||
result.levelHOTA1 = hotaVersion > 0;
|
||||
result.levelHOTA2 = hotaVersion > 1;
|
||||
result.levelHOTA3 = hotaVersion > 2;
|
||||
result.levelHOTA5 = hotaVersion > 4;
|
||||
result.levelHOTA6 = hotaVersion > 5;
|
||||
result.levelHOTA7 = hotaVersion > 6;
|
||||
|
||||
result.artifactsBytes = 21;
|
||||
result.heroesBytes = 23;
|
||||
|
@ -69,9 +69,12 @@ public:
|
||||
bool levelWOG = false;
|
||||
bool levelHOTA0 = false;
|
||||
bool levelHOTA1 = false;
|
||||
bool levelHOTA2 = false;
|
||||
bool levelHOTA3 = false; // 1.6.0
|
||||
// level 4 - not released publicly?
|
||||
bool levelHOTA5 = false; // 1.7.0
|
||||
bool levelHOTA6 = false; // 1.7.1
|
||||
bool levelHOTA7 = false; // 1.7.2
|
||||
};
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@ -168,7 +168,7 @@ void CMapLoaderH3M::readHeader()
|
||||
features = MapFormatFeaturesH3M::find(mapHeader->version, hotaVersion);
|
||||
reader->setFormatLevel(features);
|
||||
|
||||
if(hotaVersion > 0)
|
||||
if(features.levelHOTA1)
|
||||
{
|
||||
bool isMirrorMap = reader->readBool();
|
||||
bool isArenaMap = reader->readBool();
|
||||
@ -181,7 +181,7 @@ void CMapLoaderH3M::readHeader()
|
||||
logGlobal->warn("Map '%s': Arena maps are not supported!", mapName);
|
||||
}
|
||||
|
||||
if(hotaVersion > 1)
|
||||
if(features.levelHOTA2)
|
||||
{
|
||||
int32_t terrainTypesCount = reader->readUInt32();
|
||||
assert(features.terrainsCount == terrainTypesCount);
|
||||
@ -190,7 +190,7 @@ void CMapLoaderH3M::readHeader()
|
||||
logGlobal->warn("Map '%s': Expected %d terrains, but %d found!", mapName, features.terrainsCount, terrainTypesCount);
|
||||
}
|
||||
|
||||
if(hotaVersion > 4)
|
||||
if(features.levelHOTA5)
|
||||
{
|
||||
int32_t townTypesCount = reader->readUInt32();
|
||||
int8_t allowedDifficultiesMask = reader->readInt8Checked(0, 31);
|
||||
@ -203,6 +203,14 @@ void CMapLoaderH3M::readHeader()
|
||||
if (allowedDifficultiesMask != 0)
|
||||
logGlobal->warn("Map '%s': List of allowed difficulties (%d) is not implemented!", mapName, allowedDifficultiesMask);
|
||||
}
|
||||
|
||||
if(features.levelHOTA7)
|
||||
{
|
||||
bool canHireDefeatedHeroes = reader->readBool();
|
||||
|
||||
if (!canHireDefeatedHeroes)
|
||||
logGlobal->warn("Map '%s': Option to block hiring of defeated heroes is not implemented!", mapName);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -745,13 +753,15 @@ void CMapLoaderH3M::readMapOptions()
|
||||
|
||||
if(features.levelHOTA1)
|
||||
{
|
||||
// Unknown, may be another "sized bitmap", e.g
|
||||
// 4 bytes - size of bitmap (16)
|
||||
// 2 bytes - bitmap data (16 bits / 2 bytes)
|
||||
// potentially - combo_artifact_count / combo_artifacts
|
||||
[[maybe_unused]] uint8_t unknownConstant = reader->readUInt8();
|
||||
assert(unknownConstant == 16);
|
||||
reader->skipZero(5);
|
||||
int32_t combinedArtifactsCount = reader->readInt32();
|
||||
int32_t combinedArtifactsBytes = (combinedArtifactsCount + 7) / 8;
|
||||
|
||||
for (int i = 0; i < combinedArtifactsBytes; ++i)
|
||||
{
|
||||
uint8_t mask = reader->readUInt8();
|
||||
if (mask != 0)
|
||||
logGlobal->warn("Map '%s': Option to ban specific combined artifacts is not implemented!", mapName);
|
||||
}
|
||||
}
|
||||
|
||||
if(features.levelHOTA3)
|
||||
@ -1235,10 +1245,11 @@ CGObjectInstance * CMapLoaderH3M::readMonster(const int3 & mapPosition, const Ob
|
||||
|
||||
if (features.levelHOTA5)
|
||||
{
|
||||
[[maybe_unused]] int8_t unknownA = reader->readInt8();
|
||||
[[maybe_unused]] int32_t unknownB = reader->readInt32();
|
||||
assert(unknownA == 0);
|
||||
assert(unknownB == 0);
|
||||
int8_t unknownA = reader->readInt8();
|
||||
int32_t unknownB = reader->readInt32();
|
||||
|
||||
if (unknownA != 0 || unknownB != 0)
|
||||
logGlobal->warn( "Map '%s': Wandering monsters %s unknown settings %d %d is not implemented!", mapName, mapPosition.toString(), unknownA, unknownB);
|
||||
}
|
||||
|
||||
return object;
|
||||
@ -2466,6 +2477,7 @@ EQuestMission CMapLoaderH3M::readQuest(IQuestObject * guard, const int3 & positi
|
||||
case EQuestMission::HOTA_MULTI:
|
||||
{
|
||||
uint32_t missionSubID = reader->readUInt32();
|
||||
assert(missionSubID < 3);
|
||||
|
||||
if(missionSubID == 0)
|
||||
{
|
||||
@ -2482,6 +2494,14 @@ EQuestMission CMapLoaderH3M::readQuest(IQuestObject * guard, const int3 & positi
|
||||
guard->quest->mission.daysPassed = reader->readUInt32() + 1;
|
||||
break;
|
||||
}
|
||||
if(missionSubID == 2)
|
||||
{
|
||||
missionId = EQuestMission::HOTA_GAME_DIFFICULTY;
|
||||
int32_t difficultyMask = reader->readUInt32();
|
||||
assert(difficultyMask > 0 && difficultyMask < 32);
|
||||
logGlobal->warn("Map '%s': Seer Hut at %s: Difficulty-specific quest (%d) is not implemented!", mapName, position.toString(), difficultyMask);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@ -2588,16 +2608,22 @@ CGObjectInstance * CMapLoaderH3M::readTown(const int3 & position, std::shared_pt
|
||||
|
||||
event.computerAffected = reader->readBool();
|
||||
event.firstOccurrence = reader->readUInt16();
|
||||
event.nextOccurrence = reader->readUInt8();
|
||||
event.nextOccurrence = reader->readUInt16();
|
||||
|
||||
reader->skipZero(17);
|
||||
reader->skipZero(16);
|
||||
|
||||
if(features.levelHOTA5)
|
||||
{
|
||||
[[maybe_unused]] int32_t allowedDifficulties = reader->readInt32();
|
||||
[[maybe_unused]] int32_t hota_level_7b = reader->readInt32();
|
||||
[[maybe_unused]] int32_t hota_amount = reader->readInt32();
|
||||
[[maybe_unused]] int16_t apply_neutral_towns = reader->readInt16();
|
||||
[[maybe_unused]] int16_t hota_special = reader->readInt16();
|
||||
}
|
||||
|
||||
if(features.levelHOTA7)
|
||||
{
|
||||
[[maybe_unused]] int32_t hota_amount = reader->readInt32();
|
||||
[[maybe_unused]] bool apply_neutral_towns = reader->readBool();
|
||||
}
|
||||
|
||||
// New buildings
|
||||
@ -2669,17 +2695,20 @@ void CMapLoaderH3M::readEvents()
|
||||
}
|
||||
event.computerAffected = reader->readBool();
|
||||
event.firstOccurrence = reader->readUInt16();
|
||||
event.nextOccurrence = reader->readUInt8();
|
||||
event.nextOccurrence = reader->readUInt16();
|
||||
|
||||
reader->skipZero(17);
|
||||
reader->skipZero(16);
|
||||
|
||||
if (features.levelHOTA5)
|
||||
if (features.levelHOTA7)
|
||||
{
|
||||
[[maybe_unused]] int32_t difficulties = reader->readInt32();
|
||||
}
|
||||
else if (features.levelHOTA5)
|
||||
{
|
||||
[[maybe_unused]] int32_t difficulties = reader->readInt32();
|
||||
[[maybe_unused]] int32_t unknownA= reader->readInt32();
|
||||
[[maybe_unused]] int32_t unknownB= reader->readInt32();
|
||||
[[maybe_unused]] int16_t unknownC= reader->readInt16();
|
||||
|
||||
}
|
||||
|
||||
map->events.push_back(event);
|
||||
|
Loading…
x
Reference in New Issue
Block a user