mirror of
https://github.com/vcmi/vcmi.git
synced 2025-06-02 23:07:36 +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,
|
KEYMASTER = 11,
|
||||||
HOTA_HERO_CLASS = 12,
|
HOTA_HERO_CLASS = 12,
|
||||||
HOTA_REACH_DATE = 13,
|
HOTA_REACH_DATE = 13,
|
||||||
|
HOTA_GAME_DIFFICULTY = 13,
|
||||||
};
|
};
|
||||||
|
|
||||||
class DLL_LINKAGE CQuest final : public Serializeable
|
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
|
// 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
|
// 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!");
|
throw std::runtime_error("Invalid map format!");
|
||||||
|
|
||||||
MapFormatFeaturesH3M result = getFeaturesSOD();
|
MapFormatFeaturesH3M result = getFeaturesSOD();
|
||||||
result.levelHOTA0 = true;
|
result.levelHOTA0 = true;
|
||||||
result.levelHOTA1 = hotaVersion > 0;
|
result.levelHOTA1 = hotaVersion > 0;
|
||||||
|
result.levelHOTA2 = hotaVersion > 1;
|
||||||
result.levelHOTA3 = hotaVersion > 2;
|
result.levelHOTA3 = hotaVersion > 2;
|
||||||
result.levelHOTA5 = hotaVersion > 4;
|
result.levelHOTA5 = hotaVersion > 4;
|
||||||
result.levelHOTA6 = hotaVersion > 5;
|
result.levelHOTA6 = hotaVersion > 5;
|
||||||
|
result.levelHOTA7 = hotaVersion > 6;
|
||||||
|
|
||||||
result.artifactsBytes = 21;
|
result.artifactsBytes = 21;
|
||||||
result.heroesBytes = 23;
|
result.heroesBytes = 23;
|
||||||
|
@ -69,9 +69,12 @@ public:
|
|||||||
bool levelWOG = false;
|
bool levelWOG = false;
|
||||||
bool levelHOTA0 = false;
|
bool levelHOTA0 = false;
|
||||||
bool levelHOTA1 = false;
|
bool levelHOTA1 = false;
|
||||||
|
bool levelHOTA2 = false;
|
||||||
bool levelHOTA3 = false; // 1.6.0
|
bool levelHOTA3 = false; // 1.6.0
|
||||||
|
// level 4 - not released publicly?
|
||||||
bool levelHOTA5 = false; // 1.7.0
|
bool levelHOTA5 = false; // 1.7.0
|
||||||
bool levelHOTA6 = false; // 1.7.1
|
bool levelHOTA6 = false; // 1.7.1
|
||||||
|
bool levelHOTA7 = false; // 1.7.2
|
||||||
};
|
};
|
||||||
|
|
||||||
VCMI_LIB_NAMESPACE_END
|
VCMI_LIB_NAMESPACE_END
|
||||||
|
@ -168,7 +168,7 @@ void CMapLoaderH3M::readHeader()
|
|||||||
features = MapFormatFeaturesH3M::find(mapHeader->version, hotaVersion);
|
features = MapFormatFeaturesH3M::find(mapHeader->version, hotaVersion);
|
||||||
reader->setFormatLevel(features);
|
reader->setFormatLevel(features);
|
||||||
|
|
||||||
if(hotaVersion > 0)
|
if(features.levelHOTA1)
|
||||||
{
|
{
|
||||||
bool isMirrorMap = reader->readBool();
|
bool isMirrorMap = reader->readBool();
|
||||||
bool isArenaMap = reader->readBool();
|
bool isArenaMap = reader->readBool();
|
||||||
@ -181,7 +181,7 @@ void CMapLoaderH3M::readHeader()
|
|||||||
logGlobal->warn("Map '%s': Arena maps are not supported!", mapName);
|
logGlobal->warn("Map '%s': Arena maps are not supported!", mapName);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(hotaVersion > 1)
|
if(features.levelHOTA2)
|
||||||
{
|
{
|
||||||
int32_t terrainTypesCount = reader->readUInt32();
|
int32_t terrainTypesCount = reader->readUInt32();
|
||||||
assert(features.terrainsCount == terrainTypesCount);
|
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);
|
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();
|
int32_t townTypesCount = reader->readUInt32();
|
||||||
int8_t allowedDifficultiesMask = reader->readInt8Checked(0, 31);
|
int8_t allowedDifficultiesMask = reader->readInt8Checked(0, 31);
|
||||||
@ -203,6 +203,14 @@ void CMapLoaderH3M::readHeader()
|
|||||||
if (allowedDifficultiesMask != 0)
|
if (allowedDifficultiesMask != 0)
|
||||||
logGlobal->warn("Map '%s': List of allowed difficulties (%d) is not implemented!", mapName, allowedDifficultiesMask);
|
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
|
else
|
||||||
{
|
{
|
||||||
@ -745,13 +753,15 @@ void CMapLoaderH3M::readMapOptions()
|
|||||||
|
|
||||||
if(features.levelHOTA1)
|
if(features.levelHOTA1)
|
||||||
{
|
{
|
||||||
// Unknown, may be another "sized bitmap", e.g
|
int32_t combinedArtifactsCount = reader->readInt32();
|
||||||
// 4 bytes - size of bitmap (16)
|
int32_t combinedArtifactsBytes = (combinedArtifactsCount + 7) / 8;
|
||||||
// 2 bytes - bitmap data (16 bits / 2 bytes)
|
|
||||||
// potentially - combo_artifact_count / combo_artifacts
|
for (int i = 0; i < combinedArtifactsBytes; ++i)
|
||||||
[[maybe_unused]] uint8_t unknownConstant = reader->readUInt8();
|
{
|
||||||
assert(unknownConstant == 16);
|
uint8_t mask = reader->readUInt8();
|
||||||
reader->skipZero(5);
|
if (mask != 0)
|
||||||
|
logGlobal->warn("Map '%s': Option to ban specific combined artifacts is not implemented!", mapName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(features.levelHOTA3)
|
if(features.levelHOTA3)
|
||||||
@ -1235,10 +1245,11 @@ CGObjectInstance * CMapLoaderH3M::readMonster(const int3 & mapPosition, const Ob
|
|||||||
|
|
||||||
if (features.levelHOTA5)
|
if (features.levelHOTA5)
|
||||||
{
|
{
|
||||||
[[maybe_unused]] int8_t unknownA = reader->readInt8();
|
int8_t unknownA = reader->readInt8();
|
||||||
[[maybe_unused]] int32_t unknownB = reader->readInt32();
|
int32_t unknownB = reader->readInt32();
|
||||||
assert(unknownA == 0);
|
|
||||||
assert(unknownB == 0);
|
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;
|
return object;
|
||||||
@ -2466,6 +2477,7 @@ EQuestMission CMapLoaderH3M::readQuest(IQuestObject * guard, const int3 & positi
|
|||||||
case EQuestMission::HOTA_MULTI:
|
case EQuestMission::HOTA_MULTI:
|
||||||
{
|
{
|
||||||
uint32_t missionSubID = reader->readUInt32();
|
uint32_t missionSubID = reader->readUInt32();
|
||||||
|
assert(missionSubID < 3);
|
||||||
|
|
||||||
if(missionSubID == 0)
|
if(missionSubID == 0)
|
||||||
{
|
{
|
||||||
@ -2482,6 +2494,14 @@ EQuestMission CMapLoaderH3M::readQuest(IQuestObject * guard, const int3 & positi
|
|||||||
guard->quest->mission.daysPassed = reader->readUInt32() + 1;
|
guard->quest->mission.daysPassed = reader->readUInt32() + 1;
|
||||||
break;
|
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;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@ -2588,16 +2608,22 @@ CGObjectInstance * CMapLoaderH3M::readTown(const int3 & position, std::shared_pt
|
|||||||
|
|
||||||
event.computerAffected = reader->readBool();
|
event.computerAffected = reader->readBool();
|
||||||
event.firstOccurrence = reader->readUInt16();
|
event.firstOccurrence = reader->readUInt16();
|
||||||
event.nextOccurrence = reader->readUInt8();
|
event.nextOccurrence = reader->readUInt16();
|
||||||
|
|
||||||
reader->skipZero(17);
|
reader->skipZero(16);
|
||||||
|
|
||||||
if(features.levelHOTA5)
|
if(features.levelHOTA5)
|
||||||
{
|
{
|
||||||
[[maybe_unused]] int32_t allowedDifficulties = reader->readInt32();
|
[[maybe_unused]] int32_t allowedDifficulties = reader->readInt32();
|
||||||
[[maybe_unused]] int32_t hota_level_7b = reader->readInt32();
|
[[maybe_unused]] int32_t hota_level_7b = reader->readInt32();
|
||||||
[[maybe_unused]] int32_t hota_amount = 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
|
// New buildings
|
||||||
@ -2669,17 +2695,20 @@ void CMapLoaderH3M::readEvents()
|
|||||||
}
|
}
|
||||||
event.computerAffected = reader->readBool();
|
event.computerAffected = reader->readBool();
|
||||||
event.firstOccurrence = reader->readUInt16();
|
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 difficulties = reader->readInt32();
|
||||||
[[maybe_unused]] int32_t unknownA= reader->readInt32();
|
[[maybe_unused]] int32_t unknownA= reader->readInt32();
|
||||||
[[maybe_unused]] int32_t unknownB= reader->readInt32();
|
[[maybe_unused]] int32_t unknownB= reader->readInt32();
|
||||||
[[maybe_unused]] int16_t unknownC= reader->readInt16();
|
[[maybe_unused]] int16_t unknownC= reader->readInt16();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
map->events.push_back(event);
|
map->events.push_back(event);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user