initial commit

This commit is contained in:
josch 2014-06-26 09:29:46 +02:00
commit 1f5fffe76a
4 changed files with 1402 additions and 0 deletions

26
bf.py Executable file
View file

@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
class bf(object):
def __init__(self,value=0):
self._d = value
def __getitem__(self, index):
return (self._d >> index) & 1
def __setitem__(self,index,value):
value = (value&1L)<<index
mask = (1L)<<index
self._d = (self._d & ~mask) | value
def __getslice__(self, start, end):
mask = 2L**(end - start) -1
return (self._d >> start) & mask
def __setslice__(self, start, end, value):
mask = 2L**(end - start) -1
value = (value & mask) << start
mask = mask << start
self._d = (self._d & ~mask) | value
return (self._d >> start) & mask
def __int__(self):
return self._d

802
h3m.py Executable file
View file

@ -0,0 +1,802 @@
# -*- coding: utf-8 -*-
"""
copyright 2008 - Johannes 'josch' Schauer <j.schauer@email.de>
copyright 2010 - Remigiusz 'Enleth' Marcinkiewicz <enleth@enleth.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
import gzip
import struct
import chardet
import binascii
#from guess_language import guessLanguage
from lxml import etree
from lxml import objectify
from bf import bf
from h3m_ids import *
def edet(string):
e = chardet.detect(string)
if e["encoding"] in h3m_encoding_quirks:
e["encoding"] = h3m_encoding_quirks[e["encoding"]]
return e
def extract(filename):
h3m_data = gzip.open(filename)
r = lambda s: struct.unpack(s,h3m_data.read(struct.calcsize(s)))
E = objectify.ElementMaker(annotate=False)
try:
vver = h3m_versions[r("<I")[0]]
except KeyError:
raise ValueError("Invalid game version or not a HoMM 3 map")
if vver == "WoG":
raise NotImplementedError("WoG maps not supported yet")
(vhas_players, vsize, vunderground) = r("<BIB");
if vunderground not in [0,1]:
raise ValueError("Underground specifier not in [0,1]")
vunderground = str(bool(vunderground))
m = E.map(version=vver,size=str(vsize),underground=vunderground)
m.append(E.conversion_metadata())
(vlength, ) = r("<I")
if vlength>30:
raise ValueError("Map name longer than 30 characters, possibly an invalid file")
vname = h3m_data.read(vlength)
enc = edet(vname)
vname = vname.decode(enc["encoding"])
m.append(E.name(vname))
m.conversion_metadata.append(E.encoding(enc["encoding"],entity="/map/name[0]",confidence=str(enc["confidence"])))
(vlength, ) = r("<I")
vdesc = h3m_data.read(vlength)
enc = edet(vdesc)
vdesc = vdesc.decode(enc["encoding"])
m.append(E.description(vdesc))
m.conversion_metadata.append(E.encoding(enc["encoding"],entity="/map/description[0]",confidence=str(enc["confidence"])))
try:
vdifficulty = h3m_diffictulties[r("<B")[0]]
except KeyError:
raise ValueError("Invalid map difficulty value")
m.append(E.difficulty(vdifficulty))
if m.xpath("/map/@version")[0] in ["AB", "SoD", "WoG"]:
(vmax_level,) = r("<B")
if vmax_level==0:
vmax_level = "Unspecified"
else:
vmax_level = "Unspecified"
m.append(E.max_level(vmax_level))
m.append(E.players())
#player info
for pnum in h3m_player_colors:
(vis_human, vis_computer) = r("<BB")
if vis_human not in [0,1] or vis_computer not in [0,1]:
raise ValueError("Invalid player type specifiers %#04x and %#04x" % (vis_human, vis_computer))
if vis_human == 0 and vis_computer == 0:
#player is disabled, skipping garbage
if m.xpath("/map/@version")[0] == "RoE":
h3m_data.read(6)
elif m.xpath("/map/@version")[0] == "AB":
h3m_data.read(12)
elif m.xpath("/map/@version")[0] in ["SoD", "WoG"]:
h3m_data.read(13)
m.players.append(E.player(color=h3m_player_colors[pnum],type="Disabled"))
continue
if vis_human == 1 and vis_computer == 1:
player_type = "Both"
elif vis_human == 1:
player_type = "Human"
else:
player_type = "Computer"
player = E.player(color=h3m_player_colors[pnum],type=player_type)
try:
vai_type = h3m_ai_types[r("<B")[0]]
except KeyError:
raise ValueError("Invalid AI type")
player.append(E.ai(vai_type))
if m.xpath("/map/@version")[0] in ["SoD", "WoG"]:
(venforce_alignment,) = r("<B")
if venforce_alignment not in [0,1]:
raise ValueError("Invalid alignment enforcement specifier %#04x" % venforce_alignment)
venforce_alignment = str(bool(venforce_alignment))
else:
venforce_alignment = "Unspecified"
valignments = bf(r("<B")[0])
if m.xpath("/map/@version")[0] in ["AB", "SoD", "WoG"]:
(vconflux,) = r("<B")
if vconflux not in [0,1]:
raise ValueError("Invalid Conflux specifier %#04x" % vconflux)
if vconflux == 1:
valignments[8] = 1
(vrandom_alignment,) = r("<B")
if vrandom_alignment not in [0,1]:
raise ValueError("Invalid random alignment specifier %#04x" % vrandom_alignment)
if vrandom_alignment == 1:
valignments[9] = 1
alignments = set()
for i in range(0,10):
if valignments[i] == 1:
alignments.add(h3m_alignments[i+1])
player.append(E.alignment(', '.join(alignments),enforced=venforce_alignment))
(vmain_town,) = r("<B")
if vmain_town not in [0,1]:
raise ValueError("Invalid main town specifier %#04x" % vmain_town)
if vmain_town:
if m.xpath("/map/@version")[0] in ["AB", "SoD", "WoG"]:
(vmain_town_generate_hero, vmain_town_unknown1) = r("<BB")
vmain_town_unknown1 = ("%#04x" % vmain_town_unknown1)
m.conversion_metadata.append(E.unknown1(vmain_town_unknown1,player_color=h3m_player_colors[pnum]))
if vmain_town_generate_hero not in [0,1]:
raise ValueError("Invalid main town hero generation specifier %#04x" % vmain_town_generate_hero)
vmain_town_generate_hero = str(bool(vmain_town_generate_hero))
else:
vmain_town_generate_hero = "Unspecified"
vmain_town_unknown1 = "Unspecified"
vcoords = r("<BBB")
player.append(E.main_town("%d,%d,%d" % vcoords, generate_hero=vmain_town_generate_hero, unknown1=vmain_town_unknown1))
(vgenerate_random_hero, vmain_hero) = r("<BB");
if vgenerate_random_hero not in [0,1]:
raise ValueError("Invalid random hero generation specifier %#04x" % vgenerate_random_hero)
vgenerate_random_hero = str(bool(vgenerate_random_hero))
player.append(E.generate_random_hero(vgenerate_random_hero))
if vmain_hero != 0xFF:
(vmain_hero_portrait, ) = r("<B")
if vmain_hero_portrait == 0xFF:
vmain_hero_portrait = "Standard"
else:
vmain_hero_portrait = str(vmain_hero_portrait)
(vlength, ) = r("<I")
vmain_hero_name = h3m_data.read(vlength)
player.append(E.main_hero(str(vmain_hero),portrait=vmain_hero_portrait,name=vmain_hero_name))
if m.xpath("/map/@version")[0] in ["AB", "SoD", "WoG"]:
(vhero_placeholders,vheroes_count) = r("<BI")
player.append(E.hero_placeholders(vhero_placeholders));
if vheroes_count > 0:
player.append(E.heroes())
for i in range(vheroes_count):
(vhero_portrait, ) = r("<B")
if vhero_portrait == 0xFF:
vhero_portrait = "Standard"
else:
vhero_portrait = str(vhero_portrait)
(vlength, ) = r("<I")
vhero_name = h3m_data.read(vlength)
player.heroes.append(E.hero(portrait=vhero_portrait,name=vhero_name))
m.players.append(player)
#special victory condition
(vvictory_condition,) = r("<B")
try:
vvictory_condition = h3m_victory_conditions[vvictory_condition]
except KeyError:
raise ValueError("Invalid special victory condition %#04x" % vvictory_condition)
if vvictory_condition != "None":
(vvictory_allow_normal, vvictory_apply_to_computer) = r("<BB")
if vvictory_allow_normal not in [0,1]:
raise ValueError("Invalid normal victory specifier %#04x" % vvictory_allow_normal)
if vvictory_apply_to_computer not in [0,1]:
raise ValueError("Invalid special victory for computer specifier %#04x" % vvictory_apply_to_computer)
vvictory_allow_normal = str(bool(vvictory_allow_normal))
vvictory_apply_to_computer = str(bool(vvictory_apply_to_computer))
m.append(E.special_victory_condition(type=vvictory_condition, allow_normal=vvictory_allow_normal, apply_to_computer=vvictory_apply_to_computer))
if vvictory_condition == "Acquire artifact":
(vvictory_artifact_id,) = r("<B")
try:
vvictory_artifact_id = h3m_artifact_types[vvictory_artifact_id]
except KeyError:
raise ValueError("Invalid special victory artifact id %#04x" % vvictory_artifact_id)
m.special_victory_condition.append(E.artifact(vvictory_artifact_id))
if m.xpath("/map/@version")[0] in ["AB", "SoD", "WoG"]:
(vvictory_artifact_unknown2,) = r("<B")
vvictory_artifact_unknown2 = ("%#04x" % vvictory_artifact_unknown2)
m.special_victory_condition.append(E.unknown2(vvictory_artifact_unknown2))
m.conversion_metadata.append(E.unknown2(vvictory_artifact_unknown2))
elif vvictory_condition == "Accumulate creatures":
(vvictory_creature_id,vvictory_creature_quantity) = r("<BI")
try:
vvictory_creature_id = h3m_creature_types[vvictory_creature_id]
except KeyError:
raise ValueError("Invalid special victory creature id %#04x" % vvictory_creature_id)
m.special_victory_condition.append(E.creature(vvictory_creature_id,quantity=str(vvictory_creature_quantity)))
elif vvictory_condition == "Accumulate resources":
(vvictory_resource_type, vvictory_resource_quantity) = r("<BI")
try:
vvictory_resource_type = h3m_resource_types[vvictory_resource_type]
except KeyError:
raise ValueError("Invalid special victory resource type %#04x" % vvictory_resource_type)
m.special_victory_condition.append(E.resource(vvictory_resource_type,quantity=str(vvictory_resource_quantity)))
elif vvictory_condition == "Upgrade town":
raise NotImplementedError
elif vvictory_condition in ("Build Grail", "Defeat hero", "Capture town", "Defeat monster"):
vcoords = r("<BBB")
m.special_victory_condition.append(E.location("%d,%d,%d" % vcoords))
elif vvictory_condition in ("Flag all dwellings", "Flag all mines"):
pass
elif vvictory_condition == "Transport artifact":
raise NotImplementedError
else:
raise NotImplementedError
#special loss condition
(vloss_condition,) = r("<B")
try:
vloss_condition = h3m_loss_conditions[vloss_condition]
except KeyError:
raise ValueError("Invalid special loss condition %#04x" % vloss_condition)
if vloss_condition != "None":
m.append(E.special_loss_condition(type=vloss_condition))
if vloss_condition in ("Lose town", "Lose hero"):
vcoords = r("<BBB")
m.special_loss_condition.append(E.location("%d,%d,%d" % vcoords))
elif vloss_condition == "Time limit":
(vloss_days,) = r("<H")
m.special_loss_condition.append(E.days(str(vloss_days)))
else:
raise NotImplementedError
#Teams
(vteam_count, ) = r("<B")
if vteam_count > 0:
#print dict(zip(range(0,8),r("<8B")))
vteams = r("<8B")
for pnum in range(0,8):
if m.xpath("/map/players/player[@color=$color]/@type",color=h3m_player_colors[pnum])[0] != "Disabled":
m.xpath("/map/players/player[@color=$color]",color=h3m_player_colors[pnum])[0].append(E.team(str(vteams[pnum])))
#guess_str = m.xpath("/map/name")[0].text + ' ' + m.xpath("/map/description")[0].text
#print guessLanguage(guess_str)
if m.xpath("/map/@version")[0] == "RoE":
vavailable_heroes = r("<16s")[0]
else:
vavailable_heroes = r("<20s")[0]
vunknown3 = "0x"+binascii.hexlify(r("<4s")[0])
m.conversion_metadata.append(E.unknown3(vunknown3))
if m.xpath("/map/@version")[0] in ["SoD", "WoG"]:
(vdisposed_heroes,) = r("<B")
if vdisposed_heroes != 0:
raise NotImplementedError("Disposed heroes not implemented")
vunknown4 = "0x"+binascii.hexlify(r("<31s")[0])
m.conversion_metadata.append(E.unknown4(vunknown4))
if m.xpath("/map/@version")[0] == "AB":
vavailable_artifacts = r("<17s")[0]
elif m.xpath("/map/@version")[0] in ["SoD", "WoG"]:
vavailable_artifacts = r("<18s")[0]
if m.xpath("/map/@version")[0] in ["SoD", "WoG"]:
vavailable_spells = r("<9s")[0]
if m.xpath("/map/@version")[0] in ["SoD", "WoG"]:
vavailable_skills = r("<4s")[0]
(vrumors_count,) = r("<B");
vunknown5 = "0x"+binascii.hexlify(r("<3s")[0])
m.conversion_metadata.append(E.unknown5(vunknown5))
for rnum in range(vrumors_count):
(vlength, ) = r("<I")
vrumor_name = h3m_data.read(vlength)
enc = edet(vrumor_name)
vrumor_name = vrumor_name.decode(enc["encoding"])
#m.conversion_metadata.append(E.encoding(enc["encoding"],entity="/map/rumor[@name='']",confidence=str(enc["confidence"])))
(vlength, ) = r("<I")
vrumor_text = h3m_data.read(vlength)
enc = edet(vrumor_text)
vrumor_text = vrumor_text.decode(enc["encoding"])
m.append(E.rumor(vrumor_text,name=vrumor_name))
#m.conversion_metadata.append(E.encoding(enc["encoding"],entity="/map/description[0]",confidence=str(enc["confidence"])))
#(map_data["heroes_count"], ) = struct.unpack("<B", h3m_data.read(1))
#if map_data["heroes_count"] > 0:
#map_data["free_heroes"] = []
#for i in range(map_data["heroes_count"]):
#(hero_id, ) = struct.unpack("<B", h3m_data.read(1))
#(hero_portrait, ) = struct.unpack("<B", h3m_data.read(1))
#(name_length, ) = struct.unpack("<I", h3m_data.read(4))
#hero_name = h3m_data.read(name_length)
#(hero_players, ) = struct.unpack("<B", h3m_data.read(1))
#map_data["free_heroes"].append({"id": hero_id, "portrait":hero_portrait, "name":hero_name, "players":hero_players})
#hero options
#for i in range(156):
#(hero_enable, ) = struct.unpack("<B", h3m_data.read(1))
#if hero_enable == 1:
#(isExp, ) = struct.unpack("<B", h3m_data.read(1))
#if isExp == 0x01:
#(exp, ) = struct.unpack("<I", h3m_data.read(4))
#(isSecSkill, ) = struct.unpack("<B", h3m_data.read(1))
#if isSecSkill == 0x01:
#(skills_count, ) = struct.unpack("<I", h3m_data.read(4))
#for i in range(skills_count):
#(skill_id, ) = struct.unpack("<B", h3m_data.read(1))
#(skill_lvl, ) = struct.unpack("<B", h3m_data.read(1))
#(isArtifact, ) = struct.unpack("<B", h3m_data.read(1))
#if isArtifact == 0x01:
#raise NotImplementedError
#(isBiography, ) = struct.unpack("<B", h3m_data.read(1))
#if isBiography == 0x01:
#(length, ) = struct.unpack("<I", h3m_data.read(4))
#biography = h3m_data.read(length)
#(gender, ) = struct.unpack("<B", h3m_data.read(1))
#(isSpells, ) = struct.unpack("<B", h3m_data.read(1))
#if isSpells == 0x01:
#spells = struct.unpack("<9B", h3m_data.read(9))
#(isPrimarySkills, ) = struct.unpack("<B", h3m_data.read(1))
#if isPrimarySkills == 0x01:
#(attack, defense, power, knowledge) = struct.unpack("<4B", h3m_data.read(4))
if m.xpath("/map/@version")[0] in ["SoD", "WoG"]:
vunknown6 = "0x"+binascii.hexlify(r("<156s")[0])
m.conversion_metadata.append(E.unknown6(vunknown6))
map_size = int(m.xpath("/map/@size")[0])
upper_terrain = [[] for i in range(map_size)]
#read upper world
for i in range(map_size**2):
x = i%map_size
y = (i-x)/map_size
upper_terrain[y].append(r("<7B"))
#read underworld
if m.xpath("/map/@underground")[0] == "True":
lower_terrain = [[] for i in range(map_size)]
for i in range(map_size**2):
x = i%map_size
y = (i-x)/map_size
lower_terrain[y].append(r("<7B"))
(vdef_count, ) = r("<I")
print vdef_count
defs = []
for i in range(vdef_count):
(vlength, ) = r("<I")
vdef_filename = h3m_data.read(vlength)
#the biggest object is 8x6 tiles big - this is an array that maps
#passability to each of this tiles with bits 1 passable, 0 not passable
#we store a set with all not passable tiles
print vdef_filename
vdef_passability = r("<6B") #passability
vdef_passability = frozenset([(8-x,6-y) for x in range(8)
for y, p in enumerate(vdef_passability)
if not (p >> x) & 1])
vdef_accessibility = r("<6B") #passability
vdef_accessibility = frozenset([(8-x,6-y) for x in range(8)
for y, p in enumerate(vdef_accessibility)
if not (p >> x) & 1])
h3m_data.read(2) #landscape
h3m_data.read(2) #land_edit_groups
(vdef_type,vdef_subtype,vdef_groups,vdef_underlay ) = r("<IIBB")
h3m_data.read(16) #junk
return m
(vobj_count, ) = r("<I")
map_data["tunedobj"] = []
for i in range(map_data["tunedobj_count"]):
(x, y, z) = struct.unpack("<3B", h3m_data.read(3))
(object_id, ) = struct.unpack("<I", h3m_data.read(4))
#print x,y,z,object_id,
junk = h3m_data.read(5) #junk
#if junk != "\x00\x00\x00\x00\x00":
# for c in junk:
# print("%02d"%ord(c), end=' ')
# break
#print i, map_data["objects"][object_id]["filename"],
#print map_data["objects"][object_id]["class"]
map_data["tunedobj"].append({"id":object_id, "x":x, "y":y, "z":z})
if object_id in (0,1):
pass
elif map_data["objects"][object_id]["class"] == 53:
if map_data["objects"][object_id]["number"] == 7:
h3m_data.read(4)
else:
h3m_data.read(4)
elif map_data["objects"][object_id]["class"] in (76, 79):
(isText, ) = struct.unpack("<B", h3m_data.read(1))
if isText == 0x01:
(length, ) = struct.unpack("<I", h3m_data.read(4))
text = h3m_data.read(length)
(isGuards, ) = struct.unpack("<B", h3m_data.read(1))
if isGuards == 0x01:
for i in range(7):
(guard_id, guard_count) = struct.unpack("<HH", h3m_data.read(4))
h3m_data.read(4) #junk
(quantity, ) = struct.unpack("<I", h3m_data.read(4))
h3m_data.read(4) #junk
elif map_data["objects"][object_id]["class"] in (34, 70, 62):
(hero_id, color, hero) = struct.unpack("<IBB", h3m_data.read(6))
(isName, ) = struct.unpack("<B", h3m_data.read(1))
if isName == 0x01:
(length, ) = struct.unpack("<I", h3m_data.read(4))
name = h3m_data.read(length)
(isExp, ) = struct.unpack("<B", h3m_data.read(1))
if isExp == 0x01:
(exp, ) = struct.unpack("<I", h3m_data.read(4))
(isPortrait, ) = struct.unpack("<B", h3m_data.read(1))
if isPortrait == 0x01:
(portrait, ) = struct.unpack("<B", h3m_data.read(1))
(isSecSkill, ) = struct.unpack("<B", h3m_data.read(1))
if isSecSkill == 0x01:
(skills_count, ) = struct.unpack("<I", h3m_data.read(4))
for i in range(skills_count):
(skill_id, ) = struct.unpack("<B", h3m_data.read(1))
(skill_lvl, ) = struct.unpack("<B", h3m_data.read(1))
(isCreature, ) = struct.unpack("<B", h3m_data.read(1))
if isCreature == 0x01:
for i in range(7):
(guard_id, ) = struct.unpack("<H", h3m_data.read(2))
(guard_count, ) = struct.unpack("<H", h3m_data.read(2))
(creaturesFormation, ) = struct.unpack("<B", h3m_data.read(1))
(isArtifact, ) = struct.unpack("<B", h3m_data.read(1))
if isArtifact == 0x01:
(headID, shouldersID, neckID, rightHandID, leftHandID,
trunkID, rightRingID, leftRingID, legsID, misc1ID, misc2ID,
misc3ID, misc4ID, machine1ID, machine2ID, machine3ID,
machine4ID, magicbook, misc5ID) \
= struct.unpack("<19H", h3m_data.read(38))
(knapsack_count, ) = struct.unpack("<H", h3m_data.read(2))
if knapsack_count > 0:
for i in range(knapsack_count):
(knapsackID, ) = struct.unpack("<H", h3m_data.read(2))
(zoneRadius, ) = struct.unpack("<B", h3m_data.read(1))
(isBiography, ) = struct.unpack("<B", h3m_data.read(1))
if isBiography == 0x01:
(length, ) = struct.unpack("<I", h3m_data.read(4))
biography = h3m_data.read(length)
(gender, ) = struct.unpack("<B", h3m_data.read(1))
(isSpells, ) = struct.unpack("<B", h3m_data.read(1))
if isSpells == 0x01:
spells = struct.unpack("<9B", h3m_data.read(9))
(isPrimarySkills, ) = struct.unpack("<B", h3m_data.read(1))
if isPrimarySkills == 0x01:
(attack, defense, power, knowledge) = struct.unpack("<4B", h3m_data.read(4))
h3m_data.read(16) #unknown
elif map_data["objects"][object_id]["class"] in (17, 20, 42):
(owner, ) = struct.unpack("<I", h3m_data.read(4))
elif map_data["objects"][object_id]["class"] == 93:
(isText, ) = struct.unpack("<B", h3m_data.read(1))
if isText == 0x01:
(length, ) = struct.unpack("<I", h3m_data.read(4))
text = h3m_data.read(length)
(isGuards, ) = struct.unpack("<B", h3m_data.read(1))
if isGuards == 0x01:
for i in range(7):
(guard_id, guard_count) = struct.unpack("<HH", h3m_data.read(4))
h3m_data.read(4) #junk
(spell_id, ) = struct.unpack("<I", h3m_data.read(4))
elif map_data["objects"][object_id]["class"] == 216:
(owner, ) = struct.unpack("<I", h3m_data.read(4))
(junk, ) = struct.unpack("<I", h3m_data.read(4))
if junk == 0x00:
(towns, ) = struct.unpack("<H", h3m_data.read(2))
(minlevel, maxlevel, ) = struct.unpack("<2B", h3m_data.read(2))
elif map_data["objects"][object_id]["class"] in (54, 71, 72, 73, 74, 75, 162, 163, 164):
(monster_id, ) = struct.unpack("<I", h3m_data.read(4))
(monster_count, ) = struct.unpack("<H", h3m_data.read(2))
(mood, ) = struct.unpack("<B", h3m_data.read(1))
(isTreasureOrText, ) = struct.unpack("<B", h3m_data.read(1))
if isTreasureOrText == 0x01:
(length, ) = struct.unpack("<I", h3m_data.read(4))
text = h3m_data.read(length)
(wood, mercury, ore, sulfur, crystal, gem, gold, artefactID) \
= struct.unpack("<7IH", h3m_data.read(30))
(mosterNeverRunAway, ) = struct.unpack("<B", h3m_data.read(1))
(monsterDontGrowUp, ) = struct.unpack("<B", h3m_data.read(1))
h3m_data.read(2) #junk
elif map_data["objects"][object_id]["class"] in (98, 77):
h3m_data.read(4) #junk
(owner, ) = struct.unpack("<B", h3m_data.read(1))
(isName, ) = struct.unpack("<B", h3m_data.read(1))
if isName == 0x01:
(length, ) = struct.unpack("<I", h3m_data.read(4))
name = h3m_data.read(length)
(isGuard, ) = struct.unpack("<B", h3m_data.read(1))
if isGuard == 0x01:
for i in range(7):
(guard_id, guard_count) = struct.unpack("<HH", h3m_data.read(4))
(formation, ) = struct.unpack("<B", h3m_data.read(1))
(isBuildings, ) = struct.unpack("<B", h3m_data.read(1))
if isBuildings == 0x01:
build = struct.unpack("6B", h3m_data.read(6))
active = struct.unpack("6B", h3m_data.read(6))
else:
(isFort, ) = struct.unpack("<B", h3m_data.read(1))
mustSpells = struct.unpack("<9B", h3m_data.read(9))
canSpells = struct.unpack("<9B", h3m_data.read(9))
(eventQuantity, ) = struct.unpack("<I", h3m_data.read(4))
if eventQuantity > 0:
for i in range(eventQuantity):
(length, ) = struct.unpack("<I", h3m_data.read(4))
event_name = h3m_data.read(length)
(length, ) = struct.unpack("<I", h3m_data.read(4))
event_text = h3m_data.read(length)
(wood, mercury, ore, sulfur, crystal, gem, gold,
players_affected, human_affected, ai_affected,
day_of_first_event, event_iteration) \
= struct.unpack("<7I3B2H", h3m_data.read(35))
h3m_data.read(16) #junk
buildings = struct.unpack("<6B", h3m_data.read(6))
creatures = struct.unpack("<7H", h3m_data.read(14))
h3m_data.read(4) #junk
h3m_data.read(4) #junk
elif map_data["objects"][object_id]["class"] in (5, 65, 66, 67, 68, 69):
(isText, ) = struct.unpack("<B", h3m_data.read(1))
if isText == 0x01:
(length, ) = struct.unpack("<I", h3m_data.read(4))
text = h3m_data.read(length)
(isGuards, ) = struct.unpack("<B", h3m_data.read(1))
if isGuards == 0x01:
for i in range(7):
(guard_id, guard_count) = struct.unpack("<HH", h3m_data.read(4))
h3m_data.read(4) #junk
elif map_data["objects"][object_id]["class"] in (33, 219):
(color, ) = struct.unpack("<I", h3m_data.read(4))
for i in range(7):
(guard_id, guard_count) = struct.unpack("<HH", h3m_data.read(4))
(undeleteSoldiers, ) = struct.unpack("<B", h3m_data.read(1))
h3m_data.read(8)
elif map_data["objects"][object_id]["class"] == 87:
(owner, ) = struct.unpack("<I", h3m_data.read(4))
elif map_data["objects"][object_id]["class"] == 83:
(quest, ) = struct.unpack("<B", h3m_data.read(1))
if quest == 0x00:
pass
elif quest == 0x01:
(level, ) = struct.unpack("<I", h3m_data.read(4))
elif quest == 0x02:
(offence, defence, power, knowledge) = struct.unpack("4B", h3m_data.read(4))
elif quest == 0x03:
(hero_id, ) = struct.unpack("<I", h3m_data.read(4))
elif quest == 0x04:
(monster_id, ) = struct.unpack("<I", h3m_data.read(4))
elif quest == 0x05:
(art_quantity, ) = struct.unpack("<B", h3m_data.read(1))
for i in range(art_quantity):
(art, ) = struct.unpack("<H", h3m_data.read(2))
elif quest == 0x06:
(creatures_quantity, ) = struct.unpack("<B", h3m_data.read(1))
for i in range(creatures_quantity):
(guard_id, ) = struct.unpack("<H", h3m_data.read(2))
(guard_count, ) = struct.unpack("<H", h3m_data.read(2))
elif quest == 0x07:
resources = struct.unpack("7I", h3m_data.read(28))
elif quest == 0x08:
(hero_id, ) = struct.unpack("<B", h3m_data.read(1))
elif quest == 0x09:
(player, ) = struct.unpack("<B", h3m_data.read(1))
else:
raise NotImplementedError
if quest:
(time_limit, ) = struct.unpack("<I", h3m_data.read(4))
(length, ) = struct.unpack("<I", h3m_data.read(4))
quest_begin = h3m_data.read(length)
(length, ) = struct.unpack("<I", h3m_data.read(4))
quest_running = h3m_data.read(length)
(length, ) = struct.unpack("<I", h3m_data.read(4))
quest_end = h3m_data.read(length)
(reward, ) = struct.unpack("<B", h3m_data.read(1))
if reward == 0x00:
pass
elif reward == 0x01:
(exp, ) = struct.unpack("<I", h3m_data.read(4))
elif reward == 0x02:
(spell_points, ) = struct.unpack("<I", h3m_data.read(4))
elif reward == 0x03:
(morale, ) = struct.unpack("<B", h3m_data.read(1))
elif reward == 0x04:
(lucky, ) = struct.unpack("<B", h3m_data.read(1))
elif reward == 0x05:
(resID, ) = struct.unpack("<B", h3m_data.read(1))
(res_quantity, ) = struct.unpack("<I", h3m_data.read(4))
elif reward == 0x06:
(priSkillID, ) = struct.unpack("<B", h3m_data.read(1))
(priSkillBonus, ) = struct.unpack("<B", h3m_data.read(1))
elif reward == 0x07:
(secSkillID, ) = struct.unpack("<B", h3m_data.read(1))
(secSkillBonus, ) = struct.unpack("<B", h3m_data.read(1))
elif reward == 0x08:
(artID, ) = struct.unpack("<H", h3m_data.read(2))
elif reward == 0x09:
(spellID, ) = struct.unpack("<B", h3m_data.read(1))
elif reward == 0x0A:
(creatureID, ) = struct.unpack("<H", h3m_data.read(2))
(creatureQuantity, ) = struct.unpack("<H", h3m_data.read(2))
else:
raise NotImplementedError
h3m_data.read(2) #junk
elif map_data["objects"][object_id]["class"] in (91, 59):
(length, ) = struct.unpack("<I", h3m_data.read(4))
text = h3m_data.read(length)
h3m_data.read(4) #junk
elif map_data["objects"][object_id]["class"] == 113:
(secSkills, ) = struct.unpack("<I", h3m_data.read(4))
elif map_data["objects"][object_id]["class"] in (88, 89, 90):
(spellID, ) = struct.unpack("<I", h3m_data.read(4))
elif map_data["objects"][object_id]["class"] == 215:
(quest, ) = struct.unpack("<B", h3m_data.read(1))
if quest == 0x00:
pass
elif quest == 0x01:
(level, ) = struct.unpack("<I", h3m_data.read(4))
elif quest == 0x02:
(offence, defence, power, knowledge) = struct.unpack("4B", h3m_data.read(4))
elif quest == 0x03:
(hero_id, ) = struct.unpack("<I", h3m_data.read(4))
elif quest == 0x04:
(monster_id, ) = struct.unpack("<I", h3m_data.read(4))
elif quest == 0x05:
(art_quantity, ) = struct.unpack("<B", h3m_data.read(1))
for i in range(art_quantity):
(art, ) = struct.unpack("<H", h3m_data.read(2))
elif quest == 0x06:
(creatures_quantity, ) = struct.unpack("<B", h3m_data.read(1))
for i in range(creatures_quantity):
(guard_id, ) = struct.unpack("<H", h3m_data.read(2))
(guard_count, ) = struct.unpack("<H", h3m_data.read(2))
elif quest == 0x07:
resources = struct.unpack("7I", h3m_data.read(28))
elif quest == 0x08:
(hero_id, ) = struct.unpack("<B", h3m_data.read(1))
elif quest == 0x09:
(player, ) = struct.unpack("<B", h3m_data.read(1))
else:
raise NotImplementedError
if quest:
(time_limit, ) = struct.unpack("<I", h3m_data.read(4))
(length, ) = struct.unpack("<I", h3m_data.read(4))
quest_begin = h3m_data.read(length)
(length, ) = struct.unpack("<I", h3m_data.read(4))
quest_running = h3m_data.read(length)
(length, ) = struct.unpack("<I", h3m_data.read(4))
quest_end = h3m_data.read(length)
elif map_data["objects"][object_id]["class"] == 36:
(radius, ) = struct.unpack("<B", h3m_data.read(1))
h3m_data.read(3) #junk
elif map_data["objects"][object_id]["class"] == 220:
(resources, ) = struct.unpack("<B", h3m_data.read(1))
h3m_data.read(3) #junk
elif map_data["objects"][object_id]["class"] == 217:
(owner, towns) = struct.unpack("<II", h3m_data.read(8))
if towns==0x00:
(towns,) = struct.unpack("<H", h3m_data.read(2))
elif map_data["objects"][object_id]["class"] == 218:
(owner, minlvl, maxlvl) = struct.unpack("<IBB", h3m_data.read(6))
elif map_data["objects"][object_id]["class"] == 81:
(bonus_type, primaryID) = struct.unpack("<BI", h3m_data.read(5))
h3m_data.read(3) #junk
elif map_data["objects"][object_id]["class"] == 6:
(isText, ) = struct.unpack("<B", h3m_data.read(1))
if isText == 0x01:
(length, ) = struct.unpack("<I", h3m_data.read(4))
text = h3m_data.read(length)
(isGuards, ) = struct.unpack("<B", h3m_data.read(1))
if isGuards == 0x01:
for i in range(7):
(guard_id, guard_count) = struct.unpack("<HH", h3m_data.read(4))
h3m_data.read(4) #junk
(exp, spell_points, morals, luck, wood, mercury, ore, sulfur,
crystal, gem, gold, offence, defence, power, knowledge) = \
struct.unpack("<IIBBIIIIIIIBBBB", h3m_data.read(42))
(secSkills, ) = struct.unpack("<B", h3m_data.read(1))
if secSkills > 0:
for i in range(secSkills):
(skill_id, skill_lvl) = struct.unpack("<BB", h3m_data.read(2))
(artefacts, ) = struct.unpack("<B", h3m_data.read(1))
if artefacts > 0:
for i in range(artefacts):
(artID, ) = struct.unpack("<H", h3m_data.read(2))
(spells, ) = struct.unpack("<B", h3m_data.read(1))
if spells > 0:
for i in range(spells):
(spellID, ) = struct.unpack("<B", h3m_data.read(1))
(monsters, ) = struct.unpack("<B", h3m_data.read(1))
if monsters > 0:
for i in range(monsters):
(guard_id, guard_count) = struct.unpack("<HH", h3m_data.read(4))
h3m_data.read(8) #junk
elif map_data["objects"][object_id]["class"] == 26:
(isText, ) = struct.unpack("<B", h3m_data.read(1))
if isText == 0x01:
(length, ) = struct.unpack("<I", h3m_data.read(4))
text = h3m_data.read(length)
(isGuards, ) = struct.unpack("<B", h3m_data.read(1))
if isGuards == 0x01:
for i in range(7):
(guard_id, guard_count) = struct.unpack("<HH", h3m_data.read(4))
h3m_data.read(4) #junk
(exp, spell_points, morals, luck, wood, mercury, ore, sulfur,
crystal, gem, gold, offence, defence, power, knowledge) = \
struct.unpack("<IIBBIIIIIIIBBBB", h3m_data.read(42))
(secSkills, ) = struct.unpack("<B", h3m_data.read(1))
if secSkills > 0:
for i in range(secSkills):
(skill_id, skill_lvl) = struct.unpack("<BB", h3m_data.read(2))
(artefacts, ) = struct.unpack("<B", h3m_data.read(1))
if artefacts > 0:
for i in range(artefacts):
(artID, ) = struct.unpack("<H", h3m_data.read(2))
(spells, ) = struct.unpack("<B", h3m_data.read(1))
if spells > 0:
for i in range(spells):
(spellID, ) = struct.unpack("<B", h3m_data.read(1))
(monsters, ) = struct.unpack("<B", h3m_data.read(1))
if monsters > 0:
for i in range(monsters):
(guard_id, guard_count) = struct.unpack("<HH", h3m_data.read(4))
h3m_data.read(8) #junk
(players, isAICan, disableAfterFirstDay) = struct.unpack("<BBB", h3m_data.read(3))
h3m_data.read(4) #junk
try:
(gevents_count, ) = struct.unpack("<I", h3m_data.read(4))
for i in range(gevents_count):
(length, ) = struct.unpack("<I", h3m_data.read(4))
name = h3m_data.read(length)
(length, ) = struct.unpack("<I", h3m_data.read(4))
text = h3m_data.read(length)
h3m_data.read(7*4) #resources
(players_affected, ) = struct.unpack("<B", h3m_data.read(1))
(human_affected, ) = struct.unpack("<B", h3m_data.read(1))
(ai_affected, ) = struct.unpack("<B", h3m_data.read(1))
(day_of_first_event,) = struct.unpack("<H", h3m_data.read(2))
(event_iteration,) = struct.unpack("<H", h3m_data.read(2))
h3m_data.read(16) #junk
except:
print("d'ough...'")
h3m_data.read(124) #junk
return map_data

563
h3m_ids.py Executable file
View file

@ -0,0 +1,563 @@
# -*- coding: utf-8 -*-
h3m_versions = {0x0E:"RoE", 0x15:"AB", 0x1C:"SoD", 0x33:"WoG"}
h3m_diffictulties = {0:"Easy", 1:"Normal", 2:"Hard", 3:"Expert", 4:"Impossible"}
h3m_player_colors = {0:"Red", 1:"Blue", 2:"Tan", 3:"Green", 4:"Orange", 5:"Purple", 6:"Teal", 7:"Pink"}
h3m_encoding_quirks = {"ISO-8859-2":"Windows-1250"}
h3m_ai_types = {0:"Random", 1:"Warrior", 2:"Builder", 3:"Explorer"}
h3m_alignments = {1:"Castle", 2:"Rampart", 3:"Tower", 4:"Inferno", 5:"Necropolis", 6:"Dungeon", 7:"Stronghold", 8:"Fortress", 9:"Conflux", 10:"Random"}
h3m_victory_conditions = {0:"Acquire artifact", 1:"Accumulate creatures", 2:"Accumulate resources", 3:"Upgrade town", 4:"Build Grail", 5:"Defeat hero", 6:"Capture town", 7:"Defeat monster", 8:"Flag all dwellings", 9:"Flag all mines", 10:"Transport artifact", 0xFF:"None"}
h3m_loss_conditions = {0:"Lose town", 1:"Lose hero", 2:"Time limit", 0xFF:"None"}
h3m_resource_types = {0:"Wood", 1:"Mercury", 2:"Ore", 3:"Sulfur", 4:"Crystal", 5:"Gems", 6:"Gold"}
h3m_terrain_types = {0:"Dirt", 1:"Desert", 2:"Grassland", 3:"Snow", 4:"Swamp", 5:"Rough", 6:"Subterraean", 7:"Lava", 8:"Water", 9:"Rock"}
h3m_hero_types = {
# Knights
0:"Orrin",
1:"Valeska",
2:"Edric",
3:"Sylvia",
4:"Lord Haart",
5:"Sorsha",
6:"Christian",
7:"Tyris",
# Clerics
8:"Rion",
9:"Adela",
10:"Cuthbert",
11:"Adelaide",
12:"Ingham",
13:"Sanya",
14:"Loynis",
15:"Caitlin",
# Rangers
16:"Mephala",
17:"Ufretin",
18:"Jenova",
19:"Ryland",
20:"Thorgrim",
21:"Ivor",
22:"Clancy",
23:"Kyrre",
# Druids
24:"Coronius",
25:"Uland",
26:"Elleshar",
27:"Gem",
28:"Malcom",
29:"Melodia",
30:"Alagar",
31:"Aeris",
# Alchemists
32:"Piquedram",
33:"Thane",
34:"Josephine",
35:"Neela",
36:"Torosar",
37:"Fafner",
38:"Rissa",
39:"Iona",
# Wizards
40:"Astral",
41:"Halon",
42:"Serena",
43:"Daremyth",
44:"Theodorus",
45:"Solmyr",
46:"Cyra",
47:"Aine",
# Demoniacs
48:"Fiona",
49:"Rashka",
50:"Marius",
51:"Ignatius",
52:"Octavia",
53:"Calh",
54:"Pyre",
55:"Nymus",
# Heretics
56:"Ayden",
57:"Xyron",
58:"Axsis",
59:"Olema",
60:"Calid",
61:"Ash",
62:"Zydar",
63:"Xarfax",
# Death Knights
64:"Straker",
65:"Vokial",
66:"Moandor",
67:"Charna",
68:"Tamika",
69:"Isra",
70:"Clavius",
71:"Galthran",
# Necromancers
72:"Septienna",
73:"Aislinn",
74:"Sandro",
75:"Nimbus",
76:"Thant",
77:"Xsi",
78:"Vidomina",
79:"Nagash",
# Overlords
80:"Lorelei",
81:"Arlach",
82:"Dace",
83:"Ajit",
84:"Damacon",
85:"Gunnar",
86:"Synca",
87:"Shakti",
# Warlocks
88:"Alamar",
89:"Jaegar",
90:"Malekith",
91:"Jeddite",
92:"Geon",
93:"Deemer",
94:"Sephinroth",
95:"Darkstorn",
# Barbarians
96:"Yog",
97:"Gurnisson",
98:"Jabarkas",
99:"Shiva",
100:"Gretchin",
101:"Krellion",
102:"Crag Hack",
103:"Tyraxor",
# Battle Mages
104:"Gird",
105:"Vey",
106:"Dessa",
107:"Terek",
108:"Zubin",
109:"Gundula",
110:"Oris",
111:"Saurug",
# Beastmasters
112:"Bron",
113:"Drakon",
114:"Wystan",
115:"Tazar",
116:"Alkin",
117:"Korbac",
118:"Gerwulf",
119:"Broghild",
# Witches
120:"Mirlanda",
121:"Rosic",
122:"Voy",
123:"Verdish",
124:"Merist",
125:"Styg",
126:"Andra",
127:"Tiva",
# Planeswalkers
128:"Pasis",
129:"Thunar",
130:"Ignissa",
131:"Lacus",
132:"Monere",
133:"Erdamon",
134:"Fiur",
135:"Kalt",
# Elementalists
136:"Luna",
137:"Brissa",
138:"Ciele",
139:"Labetha",
140:"Inteus",
141:"Aenain",
142:"Gelare",
143:"Grindan",
# Extension Heroes
144:"Sir Mullich",
145:"Adrienne",
146:"Catherine",
147:"Dracon",
148:"Gelu",
149:"Kilgor",
150:"Lord Haart",
151:"Mutare",
152:"Roland",
153:"Mutare Drake",
154:"Boragus",
155:"Xeron"}
h3m_artifact_types = {
0:"Spell book",
1:"Spell Scroll",
2:"Grail",
3:"Catapult",
4:"Ballista",
5:"Ammo Cart",
6:"First Aid Tent",
7:"Centaur Axe",
8:"Blackshard of the Dead Knight",
9:"Greater Gnoll's Flail",
10:"Ogre's Club of Havoc",
11:"Sword of Hellfire",
12:"Titan's Gladius",
13:"Shield of the Dwarven Lords",
14:"Shield of the Yawning Dead",
15:"Buckler of the Gnoll King",
16:"Targ of the Rampaging Ogre",
17:"Shield of the Damned",
18:"Sentinel's Shield",
19:"Helm of the Alabaster Unicorn",
20:"Skull Helmet",
21:"Helm of Chaos",
22:"Crown of the Supreme Magi",
23:"Hellstorm Helmet",
24:"Thunder Helmet",
25:"Breastplate of Petrified Wood",
26:"Rib Cage",
27:"Scales of the Greater Basilisk",
28:"Tunic of the Cyclops King",
29:"Breastplate of Brimstone",
30:"Titan's Cuirass",
31:"Armor of Wonder",
32:"Sandals of the Saint",
33:"Celestial Necklace of Bliss",
34:"Lion's Shield of Courage",
35:"Sword of Judgement",
36:"Helm of Heavenly Enlightenment",
37:"Quiet Eye of the Dragon",
38:"Red Dragon Flame Tongue",
39:"Dragon Scale Shield",
40:"Dragon Scale Armor",
41:"Dragonbone Greaves",
42:"Dragon Wing Tabard",
43:"Necklace of Dragonteeth",
44:"Crown of Dragontooth",
45:"Still Eye of the Dragon",
46:"Clover of Fortune",
47:"Cards of Prophecy",
48:"Ladybird of Luck",
49:"Badge of Courage",
50:"Crest of Valor",
51:"Glyph of Gallantry",
52:"Speculum",
53:"Spyglass",
54:"Amulet of the Undertaker",
55:"Vampire's Cowl",
56:"Dead Man's Boots",
57:"Garniture of Interference",
58:"Surcoat of Counterpoise",
59:"Boots of Polarity",
60:"Bow of Elven Cherrywood",
61:"Bowstring of the Unicorn's Mane",
62:"Angel Feather Arrows",
63:"Bird of Perception",
64:"Stoic Watchman",
65:"Emblem of Cognizance",
66:"Statesman's Medal",
67:"Diplomat's Ring",
68:"Ambassador's Sash",
69:"Ring of the Wayfarer",
70:"Equestrian's Gloves",
71:"Necklace of Ocean Guidance",
72:"Angel Wings",
73:"Charm of Mana",
74:"Talisman of Mana",
75:"Mystic Orb of Mana",
76:"Collar of Conjuring",
77:"Ring of Conjuring",
78:"Cape of Conjuring",
79:"Orb of the Firmament",
80:"Orb of Silt",
81:"Orb of Tempestuous Fire",
82:"Orb of Driving Rain",
83:"Recanter's Cloak",
84:"Spirit of Oppression",
85:"Hourglass of the Evil Hour",
86:"Tome of Fire Magic",
87:"Tome of Air Magic",
88:"Tome of Water Magic",
89:"Tome of Earth Magic",
90:"Boots of Levitation",
91:"Golden Bow",
92:"Sphere of Permanence",
93:"Orb of Vulnerability",
94:"Ring of Vitality",
95:"Ring of Life",
96:"Vial of Lifeblood",
97:"Necklace of Swiftness",
98:"Boots of Speed",
99:"Cape of Velocity",
100:"Pendant of Dispassion",
101:"Pendant of Second Sight",
102:"Pendant of Holiness",
103:"Pendant of Life",
104:"Pendant of Death",
105:"Pendant of Free Will",
106:"Pendant of Negativity",
107:"Pendant of Total Recall",
108:"Pendant of Courage",
109:"Everflowing Crystal Cloak",
110:"Ring of Infinite Gems",
111:"Everpouring Vial of Mercury",
112:"Inexhaustible Cart of Ore",
113:"Eversmoking Ring of Sulfur",
114:"Inexhaustible Cart of Lumber",
115:"Endless Sack of Gold",
116:"Endless Bag of Gold",
117:"Endless Purse of Gold",
118:"Legs of Legion",
119:"Loins of Legion",
120:"Torso of Legion",
121:"Arms of Legion",
122:"Head of Legion",
123:"Sea Captain's Hat",
124:"Spellbinder's Hat",
125:"Shackles of War",
126:"Orb of Inhibition",
127:"Vial of Dragon Blood",
128:"Armageddon's Blade",
129:"Angelic Alliance",
130:"Cloak of the Undead King",
131:"Elixir of Life",
132:"Armor of the Damned",
133:"Statue of Legion",
134:"Power of the Dragon Father",
135:"Titan's Thunder",
136:"Admiral's Hat",
137:"Bow of the Sharpshooter",
138:"Wizard's Well",
139:"Ring of the Magi",
140:"Cornucopia",
141:"Magic Wand", # WoG artifact
142:"Gold Tower Arrow", # WoG artifact
143:"Monster's Power", # WoG artifact
144:"Highlighted Slot", # Not an actual artifact, internal use only
145:"Artifact Lock", # Not an actual artifact, internal use only
146:"Axe of Smashing", # WoG Commander artifact
147:"Mithril Mail", # WoG Commander artifact
148:"Sword of Sharpness", # WoG Commander artifact
149:"Helm of Immortality", # WoG Commander artifact
150:"Pendant of Sorcery", # WoG Commander artifact
151:"Boots of Haste", # WoG Commander artifact
152:"Bow of Seeking", # WoG Commander artifact
153:"Dragon Eye Ring", # WoG Commander artifact
154:"Hardened Shield", # WoG Commander artifact
155:"Slava's Ring of Power", # WoG Commander artifact
156:"Warlord's banner", # WoG artifact
157:"Crimson Shield of Retribution", # WoG artifact
158:"Barbarian Lord's Axe of Ferocity", # WoG artifact
159:"Dragonheart", # WoG artifact
160:"Gate Key", # WoG artifact
161:"Blank Helmet", # Blank artifact
162:"Blank Sword", # Blank artifact
163:"Blank Shield", # Blank artifact
164:"Blank Horned Ring", # Blank artifact
165:"Blank Gemmed Ring", # Blank artifact
166:"Blank Neck Broach", # Blank artifact
167:"Blank Armor", # Blank artifact
168:"Blank Surcoat", # Blank artifact
169:"Blank Boots", # Blank artifact
170:"Blank Horn"} # Blank artifact
h3m_creature_types = {
0:"Pikeman",
1:"Halberdier",
2:"Archer",
3:"Marksman",
4:"Griffin",
5:"Royal Griffin",
6:"Swordsman",
7:"Crusader",
8:"Monk",
9:"Zealot",
10:"Cavalier",
11:"Champion",
12:"Angel",
13:"Archangel",
14:"Centaur",
15:"Centaur Captain",
16:"Dwarf",
17:"Battle Dwarf",
18:"Wood Elf",
19:"Grand Elf",
20:"Pegasus",
21:"Silver Pegasus",
22:"Dendroid Guard",
23:"Dendroid Soldier",
24:"Unicorn",
25:"War Unicorn",
26:"Green Dragon",
27:"Gold Dragon",
28:"Gremlin",
29:"Master Gremlin",
30:"Stone Gargoyle",
31:"Obsidian Gargoyle",
32:"Stone Golem",
33:"Iron Golem",
34:"Mage",
35:"Arch Mage",
36:"Genie",
37:"Master Genie",
38:"Naga",
39:"Naga Queen",
40:"Giant",
41:"Titan",
42:"Imp",
43:"Familiar",
44:"Gog",
45:"Magog",
46:"Hell Hound",
47:"Cerberus",
48:"Demon",
49:"Horned Demon",
50:"Pit Fiend",
51:"Pit Lord",
52:"Efreeti",
53:"Efreet Sultan",
54:"Devil",
55:"Arch Devil",
56:"Skeleton",
57:"Skeleton Warrior",
58:"Walking Dead",
59:"Zombie",
60:"Wight",
61:"Wraith",
62:"Vampire",
63:"Vampire Lord",
64:"Lich",
65:"Power Lich",
66:"Black Knight",
67:"Dread Knight",
68:"Bone Dragon",
69:"Ghost Dragon",
70:"Troglodyte",
71:"Infernal Troglodyte",
72:"Harpy",
73:"Harpy Hag",
74:"Beholder",
75:"Evil Eye",
76:"Medusa",
77:"Medusa Queen",
78:"Minotaur",
79:"Minotaur King",
80:"Manticore",
81:"Scorpicore",
82:"Red Dragon",
83:"Black Dragon",
84:"Goblin",
85:"Hobgoblin",
86:"Wolf Rider",
87:"Wolf Raider",
88:"Orc",
89:"Orc Chieftain",
90:"Ogre",
91:"Ogre Mage",
92:"Roc",
93:"Thunderbird",
94:"Cyclops",
95:"Cyclops King",
96:"Behemoth",
97:"Ancient Behemoth",
98:"Gnoll",
99:"Gnoll Marauder",
100:"Lizardman",
101:"Lizard Warrior",
102:"Gorgon",
103:"Mighty Gorgon",
104:"Serpent Fly",
105:"Dragon Fly",
106:"Basilisk",
107:"Greater Basilisk",
108:"Wyvern",
109:"Wyvern Monarch",
110:"Hydra",
111:"Chaos Hydra",
112:"Air Elemental",
113:"Earth Elemental",
114:"Fire Elemental",
115:"Water Elemental",
116:"Gold Golem",
117:"Diamond Golem",
118:"Pixie",
119:"Sprite",
120:"Psychic Elemental",
121:"Magic Elemental",
122:"NOT USED (attacker)",
123:"Ice Elemental",
124:"NOT USED (defender)",
125:"Magma Elemental",
126:"NOT USED (3)",
127:"Storm Elemental",
128:"NOT USED (4)",
129:"Energy Elemental",
130:"Firebird",
131:"Phoenix",
132:"Azure Dragon",
133:"Crystal Dragon",
134:"Faerie Dragon",
135:"Rust Dragon",
136:"Enchanter",
137:"Sharpshooter",
138:"Halfling",
139:"Peasant",
140:"Boar",
141:"Mummy",
142:"Nomad",
143:"Rogue",
144:"Troll",
145:"Catapult (specialty X1)",
146:"Ballista (specialty X1)",
147:"First Aid Tent (specialty X1)",
148:"Ammo Cart (specialty X1)",
149:"Arrow Towers (specialty X1)",
150:"Supreme Archangel",
151:"Diamond Dragon",
152:"Lord of Thunder",
153:"Antichrist",
154:"Blood Dragon",
155:"Darkness Dragon",
156:"Ghost Behemoth",
157:"Hell Hydra",
158:"Sacred Phoenix",
159:"Ghost",
160:"Emissary of War",
161:"Emissary of Peace",
162:"Emissary of Mana",
163:"Emissary of Lore",
164:"Fire Messenger",
165:"Earth Messenger",
166:"Air Messenger",
167:"Water Messenger",
168:"Gorynych",
169:"War zealot",
170:"Arctic Sharpshooter",
171:"Lava Sharpshooter",
172:"Nightmare",
173:"Santa Gremlin",
174:"Paladin (attacker)",
175:"Hierophant (attacker)",
176:"Temple Guardian (attacker)",
177:"Succubus (attacker)",
178:"Soul Eater (attacker)",
179:"Brute (attacker)",
180:"Ogre Leader (attacker)",
181:"Shaman (attacker)",
182:"Astral Spirit (attacker)",
183:"Paladin (defender)",
184:"Hierophant (defender)",
185:"Temple Guardian (defender)",
186:"Succubus (defender)",
187:"Soul Eater (defender)",
188:"Brute (defender)",
189:"Ogre Leader (defender)",
190:"Shaman (defender)",
191:"Astral Spirit (defender)",
192:"Sylvan Centaur",
193:"Sorceress",
194:"Werewolf",
195:"Hell Steed",
196:"Dracolich"}

11
mapread.py Executable file
View file

@ -0,0 +1,11 @@
# -*- coding: utf-8 -*-
import h3m
from lxml import etree
import sys
#from guess_language import guessLanguage
map = h3m.extract(sys.argv[1])
#print guessLanguage(map["map_desc"])
print etree.tostring(map,pretty_print=True,xml_declaration=True,encoding="UTF-8")