From 36d75698f115c98573db8af9a61856b200fcc4d2 Mon Sep 17 00:00:00 2001 From: josch Date: Sat, 21 Jun 2014 14:50:18 +0200 Subject: [PATCH] add some more things --- decompress.py | 70 + h3c_and_h3m_formats/H3C_SoD_Template.bt | 143 ++ h3c_and_h3m_formats/H3M_SoD_Template.bt | 734 +++++++ h3c_and_h3m_formats/Heroes3/hstring.bt | 15 + .../Heroes3/object/artefact.bt | 18 + .../Heroes3/object/dwellings.bt | 30 + h3c_and_h3m_formats/Heroes3/object/grail.bt | 4 + h3c_and_h3m_formats/Heroes3/object/monster.bt | 24 + .../Heroes3/object/pandorabox.bt | 44 + .../Heroes3/object/resource.bt | 5 + .../Heroes3/object/scientist.bt | 9 + .../Heroes3/object/spellscroll.bt | 4 + h3c_and_h3m_formats/Heroes3/object/town.bt | 57 + h3c_and_h3m_formats/Heroes3/objects.bt | 9 + .../Heroes3/secondaryskills.bt | 4 + .../Heroes3/special_victory.bt | 39 + h3c_and_h3m_formats/h3m_description.TXT | 1005 +++++++++ image_viewer.py | 40 + lodextract.py | 52 + lodlist.py | 19 + logo.svg | 1801 +++++++++++++++++ logo_alt.svg | 102 + 22 files changed, 4228 insertions(+) create mode 100644 decompress.py create mode 100644 h3c_and_h3m_formats/H3C_SoD_Template.bt create mode 100644 h3c_and_h3m_formats/H3M_SoD_Template.bt create mode 100644 h3c_and_h3m_formats/Heroes3/hstring.bt create mode 100644 h3c_and_h3m_formats/Heroes3/object/artefact.bt create mode 100644 h3c_and_h3m_formats/Heroes3/object/dwellings.bt create mode 100644 h3c_and_h3m_formats/Heroes3/object/grail.bt create mode 100644 h3c_and_h3m_formats/Heroes3/object/monster.bt create mode 100644 h3c_and_h3m_formats/Heroes3/object/pandorabox.bt create mode 100644 h3c_and_h3m_formats/Heroes3/object/resource.bt create mode 100644 h3c_and_h3m_formats/Heroes3/object/scientist.bt create mode 100644 h3c_and_h3m_formats/Heroes3/object/spellscroll.bt create mode 100644 h3c_and_h3m_formats/Heroes3/object/town.bt create mode 100644 h3c_and_h3m_formats/Heroes3/objects.bt create mode 100644 h3c_and_h3m_formats/Heroes3/secondaryskills.bt create mode 100644 h3c_and_h3m_formats/Heroes3/special_victory.bt create mode 100644 h3c_and_h3m_formats/h3m_description.TXT create mode 100755 image_viewer.py create mode 100644 lodextract.py create mode 100644 lodlist.py create mode 100644 logo.svg create mode 100644 logo_alt.svg diff --git a/decompress.py b/decompress.py new file mode 100644 index 0000000..6ff93a9 --- /dev/null +++ b/decompress.py @@ -0,0 +1,70 @@ +#!/usr/bin/python + +import zlib, os +import struct + +import Image, ImageDraw + +lod = open("H3bitmap.lod") +lod.seek(8) +files_count = struct.unpack("i", lod.read(4))[0] +files=[] +for file in range(2745,2793): + lod.seek(92+(file*32)) + name = lod.read(16).split("\0")[0] + offset = struct.unpack("i", lod.read(4))[0] #offset + size_orig = struct.unpack("i", lod.read(4))[0] #size_original + type = struct.unpack("i", lod.read(4))[0] #type + size_comp = struct.unpack("i", lod.read(4))[0] #size_compressed + + lod.seek(offset) + + if size_comp: + pcx = zlib.decompress(lod.read(size_comp)) + else: + pcx = lod.read(size_orig) + + if type == 16: + size = struct.unpack("i", pcx[:4])[0] + width = struct.unpack("i", pcx[4:8])[0] + height = struct.unpack("I", pcx[8:12])[0] + print file, name, width, height + + im = Image.new("RGBA", (width, height)) + draw = ImageDraw.Draw(im) + bla=[] + for i in range(256): + bla.append((ord(pcx[12+size+i*3]),ord(pcx[12+size+i*3+1]),ord(pcx[12+size+i*3+2]))) + + for i in range(size): + a =ord(pcx[12+i]) + if bla[a] == (0,255,255): + draw.point((i-int(i/width)*width,int(i/width)), fill=(0,0,0,0)) + else: + draw.point((i-int(i/width)*width,int(i/width)), fill=bla[a]) + im.save(' '.join([str(file),name]), "PNG") + elif type == 17: + size = struct.unpack("i", pcx[:4])[0] + width = struct.unpack("i", pcx[4:8])[0] + height = struct.unpack("I", pcx[8:12])[0] + print file, name, width, height + + im = Image.new("RGB", (width, height)) + draw = ImageDraw.Draw(im) + + for i in range(size/3): + if ord(pcx[12+i*3]) == 0 and ord(pcx[13+i*3]) == 255 and ord(pcx[14+i*3]) == 255: + draw.point((i-int(i/width)*width,int(i/width)), fill=(0,0,0,0)) + else: + draw.point((i-int(i/width)*width,int(i/width)), fill=(ord(pcx[12+i*3]),ord(pcx[13+i*3]),ord(pcx[14+i*3]))) + im.save(' '.join([str(file),name]), "PNG") + elif type in (1, 2, 64, 65, 66, 67, 68, 69, 70, 71, 73, 79, 80, 96): + print file, name + file = open(' '.join([str(file),name]), "w") + file.write(pcx) + file.close() + else: + print i, name, type + sys.exit("not supported %d"%type) + +lod.close() diff --git a/h3c_and_h3m_formats/H3C_SoD_Template.bt b/h3c_and_h3m_formats/H3C_SoD_Template.bt new file mode 100644 index 0000000..3480ed3 --- /dev/null +++ b/h3c_and_h3m_formats/H3C_SoD_Template.bt @@ -0,0 +1,143 @@ +//-------------------------------------- +//--- 010 Editor v2.1.3 Binary Template +// +// File: H3C SoD Template +// Author: crackedmind +// Revision: 001 +// Purpose: just for fun :) +//-------------------------------------- +#include "heroes3/hstring.bt" +#include "heroes3/secondaryskills.bt" + +struct Header { + uint32 magic; // 05 00 00 00 - AB + // 06 00 00 00 - SoD + // ?? ?? ?? ?? - RoE + + uchar map_number; // CampText.txt + hstring name; + hstring description; + uchar canPlayerChooseDifficult; + uchar whatMusic; // CmpMusic.txt, start from 0 +}; + +struct ScenarioTravel { + uchar whatHeroKeep; // bit 1 - expirience + // bit 2 - primary skills + // bit 3 - secondary skills + // bit 4 - spells + // bit 5 - artefacts + + uchar whatMonstresHeroKeep[19]; + uchar whatArtifactsHeroKeep[18]; + + uchar startOptions; // 01 - start bonus + // 02 - traveling hero + // 03 - hero options + + if ( startOptions == 1 ) { + uchar playerColor; + uchar bonusCount; + local int i; + for ( i = 0; i < bonusCount; i++ ) { + uchar bonusType; + + switch(bonusType){ + case 0: //spell + uint16 heroName; //0xFDFF - most powerfull hero + // other names from hotraits.txt + uchar spell; + break; + case 1: // monster + uint16 heroName; //0xFDFF - most powerfull hero + // other names from hotraits.txt + + uint16 monsterType; + uint16 count; + case 2: // building + // TODO + break; + case 3: + uint16 heroName; //0xFDFF - most powerfull hero + // other names from hotraits.txt + + uint16 artefact; + break; + case 4: // spell scroll + uint16 heroName; //0xFDFF - most powerfull hero + // other names from hotraits.txt + + uchar spell; + break; + case 5: // primary skills + uint16 heroName; //0xFDFF - most powerfull hero + // other names from hotraits.txt + + uchar primarySkills[4]; + break; + case 6: // secondary skills + uint16 heroName; //0xFDFF - most powerfull hero + // other names from hotraits.txt + + secskill_tag secskill; + break; + case 7: // resource + uchar type; // 0 - wood, 1 - Mercury + // 2 - ore, 3 - sulfur + // 4 - crystal, 5 - gem + // 6 - gold, FD - wood+ore + // FE - mercury+sulfur+crystal+gem + uint32 count; + break; + }; + } + } else if ( startOptions == 2 ) { + uchar count; + + local uchar i; + for ( i = 0; i < count; i++) { + uchar whichPlayer; // player color + uchar fromWhatScenario; + } + } else if ( startOptions == 3 ) { + uchar heroesCount; // max is 3 + local uchar i; + + for (i =0; i < heroesCount; i++ ) { + uchar playerColor; + uint16 hero; // FF FF is random + } + } +}; + +struct Scenario { + hstring map_name; + uint32 packedMapSize; + uchar preconditionRegion; // if equal to 0, then no region + uchar regionColor; + uchar difficult; + + hstring regionText; + + struct ScenarioProlog { + uchar isProlog; + if ( isProlog == 1 ) { + uchar prologVideo; // from CmpMovie.txt + uchar prologMusic; // from CmpMusic.txt + hstring prologText; + } + } prolog; + ScenarioProlog epilog; + + ScenarioTravel travel; +}; + +Header header; + +if ( header.magic != 0x00000006 ) { + Warning( "File is not a Heroes III SoD Company file. Template stopped." ); + return -1; +} + +// here must be a loop, iterations == map regions number, but it's hardcoded feature :( +Scenario scenario; \ No newline at end of file diff --git a/h3c_and_h3m_formats/H3M_SoD_Template.bt b/h3c_and_h3m_formats/H3M_SoD_Template.bt new file mode 100644 index 0000000..8822000 --- /dev/null +++ b/h3c_and_h3m_formats/H3M_SoD_Template.bt @@ -0,0 +1,734 @@ +//-------------------------------------- +//--- 010 Editor v2.1.3 Binary Template +// +// File: H3M SoD Template +// Author: CrackedMind +// Revision: 019 +// Purpose: just for fun :D +// +// History: 003 - add "player commands" interpretation +// 004 - fix map identification +// 005 - add "free heroes" block interpretation +// 006 - add "artefacts" block interpretation +// 007 - add "spells", "secondary skill" and "rumors" blocks +// 008 - add "hero options" block +// 009 - change some interpretation of some variables +// add landscape block +// 010 - add "objects" inerpretation +// 011 - add "artefact", "monster", "grail", "pandora box" attributes +// 012 - add "spell scroll", "resource" attributes +// 013 - add "dwellings", "shipyard", "scientist", "random artefacts", "random monsters" attributes +// change many "if" blocks to one big switch :) +// 014 - add "random dwellings", "shrines (1-3)" +// 015 - some refactoring +// add "town", "event", attributes +// 016 - some more refactoring (split to modules) +// add "ocean bottle", "sign", "prophet" (almost complete) attributes +// 017 - add "hero", "prison", "random hero", "prophet" (complete) attributes +// 018 - add "mine", "witch's hut", "hero placeholder" (almost complete) attributes +// fix "town", PLAYERS_ATTRIBUTES struct +// 019 - add global events +// add "lighthouse", "quest guard", "abandoned mine" (2 types) +// add "garrison", "special dwellings" (all types of golems & elementals) +// fix "random dwellings" +//-------------------------------------- +// TODO: hero placeholder (defined hero), take more info about "junk" bytes +// +#include "heroes3/hstring.bt" +#include "heroes3/special_victory.bt" +#include "heroes3/secondaryskills.bt" +#include "heroes3/objects.bt" + +struct BASIC_PARAMETRES { + int magic_header; + char junk; + uint32 size; + char under; + + hstring name; + hstring description; + + char difficult; + char levelLimit; +}; + +struct PLAYER_ATTRIBUTES { + char isHuman; + char isComputer; + char behavior; // 0-Random, 1-Warrior, 2-Builder, 3-Explorer + char isCityTypesOpt; + short cityTypes ;; + char randomCity; + char mainCity; + + if ( mainCity == 1 ) { + char generateHero; + uchar city[4]; // 0 - city type, 1-3 coords + } + + uchar random_hero; + uchar hero_type; + + + if ( hero_type != 0xFF ) { + uchar hero_portret; + hstring hero_name; + } + char junk; + uint heroes_count; + if ( heroes_count > 0 ) { + struct Hero_tag { + uchar portret; + hstring name; + }; + Hero_tag hero[heroes_count] ; + } +}; + +struct SpecialLossConditions { + uchar id; + + if ( id != 0xFF ) { + if ( id == 0x00 || id == 0x01 ) { + uchar coord[3]; + } + else if ( id == 0x02 ) + ushort days; + } +}; + +struct Teams { + uchar commands_count; + + if ( commands_count > 0 ) { + uchar commands[8]; + } +}; + +struct FreeHeroes { + uchar free_heroes[20]; + uchar junk[4]; + uchar heroes_count; + + if (heroes_count > 0) { + struct tuned_tag { + uchar heroID; + uchar heroPortrait; + hstring hero_name; + + uchar players; + } tuned[heroes_count] ; + } + + uchar junk2[31]; +}; + +struct Artefacts { + uchar artefacts[18] ; +}; + +struct Spells { + uchar spells[9] ; +}; + +struct SecSkills { + uchar skills[4] ; +}; + +struct Rumors { + uint32 total_rumors; + + if ( total_rumors > 0 ) { + struct Rumor_tag { + + hstring rumor_name; + + hstring rumor_text; + } rumors[total_rumors] ; + } +}; + +struct HeroOptions_enabled { + uchar isExp; + + if ( isExp == 1 ) + uint32 exp; + + uchar isSecSkill; + + if ( isSecSkill == 1 ) { + uint32 skills_count; + + secskill_tag secskills [skills_count]; + } + + uchar isArtefacts; + + if ( isArtefacts == 1 ) { + ushort headID; + ushort shouldersID; + ushort neckID; + ushort rightHandID; + ushort leftHandID; + ushort trunkID; + ushort rightRingID; + ushort leftRingID; + ushort legsID; + ushort misc1ID; + ushort misc2ID; + ushort misc3ID; + ushort misc4ID; + ushort machine1ID; + ushort machine2ID; + ushort machine3ID; + ushort machine4ID; + ushort magicbook; + ushort misc5ID; + + ushort knapsack_count; + + if ( knapsack_count > 0 ) + ushort knapsackID[knapsack_count]; + } + + uchar isBiography; + + if (isBiography == 1) + hstring biography; + + uchar gender ; + + uchar isSpells; + + if ( isSpells == 1 ) + uchar spells[9] ; + + uchar isPrimarySkills; + + if ( isPrimarySkills == 1 ) { + uchar attack; + uchar defence; + uchar power; + uchar knowledge; + } +}; + +struct HeroOptions { + local int i; + + for (i = 0; i < 156; i++) { + uchar enable; + + if ( enable == 1 ) + HeroOptions_enabled options; + } +}; + +struct LandCell { + uchar surfaceID; + uchar surfacePattern; + uchar riverID; + uchar riverPattern; + uchar roadID; + uchar roadPattern; + uchar mirroring ; +}; + +struct Object { + hstring filename; + uchar passability[6]; + uchar actions[6]; + ushort landscape; + ushort land_edit_groups; // for editor + uint32 object_class; + uint32 object_number; + uchar object_group; + uchar isOverlay; + uchar junk[16]; +}; + +struct ObjectOptions { + uchar coord[3]; // x, y, z; + uint32 objectID; + uchar junk[5]; +}; + +struct ObjectShrine { + uint32 spellID; +}; + +struct ObjectEvent { + ObjectPandora event; + uchar players; + uchar isAICan; + uchar disableAfterFirstDay; + uint32 junk; +}; + +struct ObjectSign { + hstring text; + uint32 junk; +}; + +struct ObjectProphet { + uchar quest; + + switch(quest) { + case 0: + break; + case 1: + uint32 level; + break; + case 2: + uchar offence; + uchar defence; + uchar power; + uchar knowledge; + break; + case 3: + uint32 heroID; + break; + case 4: + uint32 monsterID; + break; + case 5: + uchar art_quantity; + ushort arts[art_quantity]; + break; + case 6: + uchar creatures_quantity; + if ( creatures_quantity > 0 ) { + GuardTag creatures[creatures_quantity]; + } + break; + case 7: + uint32 resources[7]; + break; + case 8: + uchar heroID; + break; + case 9: + uchar player_color; + break; + }; + + uint32 time_limit; // FF FF FF FF - no limit + hstring quest_begin; + hstring quest_inprocess; + hstring quest_end; + + uchar reward; + + switch(reward) { + case 0: + break; + case 1: + uint32 exp; + break; + case 2: + uint32 spell_points; + break; + case 3: + uchar morale; + break; + case 4: + uchar lucky; + break; + case 5: + uchar resID; + uint32 res_quantity; + break; + case 6: + uchar priSkillID; + uchar priSkillBonus; + break; + case 7: + uchar secSkillID; + uchar secSkillLevel; + break; + case 8: + ushort artID; + break; + case 9: + uchar spellID; + break; + case 10: + ushort creatureID; + ushort creatureQuantity; + break; + }; + + char junk[2]; +}; + +struct ObjectHero { + uint32 heroID; + uchar color; + uchar hero; // FF - random + + uchar isName; + + if ( isName == 1 ) + hstring name; + + uchar isExp; + + if ( isExp == 1 ) + uint32 exp; + + uchar isPortrait; + + if ( isPortrait == 1) + uchar portrait; + + uchar isSecondary; + + if ( isSecondary == 1 ) { + uint32 skills_quantity; + if ( skills_quantity > 0 ) + secskill_tag skills[skills_quantity]; + + } + + uchar isCreature; + if ( isCreature == 1 ) + GuardTag creatures[7]; + + uchar creaturesFormation; + + uchar isArtefacts; + + if ( isArtefacts == 1 ) { + ushort headID; + ushort shouldersID; + ushort neckID; + ushort rightHandID; + ushort leftHandID; + ushort trunkID; + ushort rightRingID; + ushort leftRingID; + ushort legsID; + ushort misc1ID; + ushort misc2ID; + ushort misc3ID; + ushort misc4ID; + ushort machine1ID; + ushort machine2ID; + ushort machine3ID; + ushort machine4ID; + ushort magicbook; + ushort misc5ID; + + ushort knapsack_count; + + if ( knapsack_count > 0 ) + ushort knapsackID[knapsack_count]; + } + uchar zoneRadius; + + uchar isBiography; + + if ( isBiography == 1 ) + hstring biography; + + uchar gender ; + + uchar isSpells; + if ( isSpells == 1 ) { + uchar spells[9] ; + } + + uchar isPrimary; + if ( isPrimary == 1 ) { + uchar offence; + uchar defence; + uchar power; + uchar knowledge; + } + + uint32 unknown[4]; +}; + +struct ObjectHeroPlaceholder { + uchar color; + uchar type; +}; + +struct ObjectMine { + uint32 color; +}; + +struct ObjectWitchHut { + uint32 secskills ; +}; + +struct globalEvent { + hstring name; + hstring text; + + int32 resources[7]; + + uchar players_affected; + uchar human_affected; + uchar ai_affected; + + ushort day_of_first_event; + ushort event_iteration; + + char junk[16]; +}; + +struct ObjectQuestionGuard { + uchar quest; + + switch(quest) { + case 0: + break; + case 1: + uint32 level; + break; + case 2: + uchar offence; + uchar defence; + uchar power; + uchar knowledge; + break; + case 3: + uint32 heroID; + break; + case 4: + uint32 monsterID; + break; + case 5: + uchar art_quantity; + ushort arts[art_quantity]; + break; + case 6: + uchar creatures_quantity; + if ( creatures_quantity > 0 ) { + GuardTag creatures[creatures_quantity]; + } + break; + case 7: + uint32 resources[7]; + break; + case 8: + uchar heroID; + break; + case 9: + uchar player_color; + break; + }; + + uint32 time_limit; // FF FF FF FF - no limit + hstring quest_begin; + hstring quest_inprocess; + hstring quest_end; +}; + +struct ObjectGarrison { + uint32 color; + GuardTag guards[7]; + uchar undeleteSoldiers; + uint32 junk[2]; +}; + +struct ObjectAbandonedMine { + uchar resources ; + uchar junk[3]; +}; + +string genderRead(uchar &gend) { + string s; + if ( gend == 0 ) + SPrintf(s, "%s", "male"); + else if ( gend == 1 ) + SPrintf(s, "%s", "female"); + else if ( gend == 0xFF ) + SPrintf(s, "%s", "by default"); + return s; +} + +// +// !!! entrypoint !!! +// + +BASIC_PARAMETRES bp; + +// Check for header +if( bp.magic_header != 0x0000001C ) +{ + Warning( "File is not a Heroes III SoD Map. Template stopped." ); + return -1; +} + +PLAYER_ATTRIBUTES red; +PLAYER_ATTRIBUTES blue; +PLAYER_ATTRIBUTES tan; +PLAYER_ATTRIBUTES green; +PLAYER_ATTRIBUTES orange; +PLAYER_ATTRIBUTES purple; +PLAYER_ATTRIBUTES teal; +PLAYER_ATTRIBUTES pink; + +SpecialVictoryConditions svc ; +SpecialLossConditions slc ; + +Teams cmd; + +FreeHeroes fh; + +Artefacts arts; +Spells sp; +SecSkills ss; + +Rumors rumors; +HeroOptions options; + +LandCell ground[bp.size*bp.size] ; + +if ( bp.under == 1 ) + LandCell underground[bp.size*bp.size]; + +uint32 objects_count; + +if ( objects_count > 0 ) + Object objects[objects_count] ; + +uint32 tunedobj_count; +local int i; +if ( tunedobj_count > 0 ) { + for ( i = 0; i < tunedobj_count; i++ ) { + ObjectOptions obj; + + switch(objects[obj.objectID].object_class) + { + case 5: + case 65: + case 66: + case 67: + case 68: + case 69: + ObjectArtefact artefact; + break; + + case 6: + ObjectPandora pandora; + break; + + case 17: + case 20: + case 42: //lighthouse + ObjectDwelling dwelling; + break; + + case 26: + ObjectEvent localevent; + break; + + case 33: + case 219: + ObjectGarrison garrison; + break; + + case 34: + case 70: + ObjectHero hero; + break; + case 62: + ObjectHero hero; + break; + + case 36: + ObjectGrail grail; + break; + + case 53: + switch(objects[obj.objectID].object_number) { + case 7: + ObjectAbandonedMine abandoned; // bit0 - mercury, 1 - ore, 2 - sulfur, + break; // bit3 - crystal, 4 - gem, 5 - gold + default: + ObjectMine mine; + break; + } + break; + + case 54: + case 71: + case 72: + case 73: + case 74: + case 75: + case 162: + case 163: + case 164: + ObjectMonster monster; + break; + + case 76: + case 79: + ObjectResource res; + break; + + case 81: + ObjectScientist scientist; + break; + + case 83: + ObjectProphet prophet; + break; + + case 87: + ObjectShipyard shipyard; + break; + + case 88: + case 89: + case 90: + ObjectShrine shrine; + break; + + case 91: + case 59: + ObjectSign sign; + break; + + case 93: + ObjectSpell spell; + break; + + case 98: + case 77: + ObjectTown town; + break; + + case 113: + ObjectWitchHut whut; + break; + + case 215: + ObjectQuestionGuard qguard; + break; + + case 216: + ObjectGeneralRandomDwelling dwelling; + break; + case 217: + ObjectLevelRandomDwelling dwelling; + break; + case 218: + ObjectTownRandomDwelling dwelling; + break; + case 220: + ObjectAbandonedMine abandoned; + break; + }; + } +} + +uint32 gevents_quantity; + +globalEvent gevents[gevents_quantity] ; + +uchar main_junk[124]; diff --git a/h3c_and_h3m_formats/Heroes3/hstring.bt b/h3c_and_h3m_formats/Heroes3/hstring.bt new file mode 100644 index 0000000..f698c9e --- /dev/null +++ b/h3c_and_h3m_formats/Heroes3/hstring.bt @@ -0,0 +1,15 @@ +typedef struct { + uint32 str_len; + + if ( str_len > 0 ) + char str[str_len]; +}hstring ; + +string hstringRead (hstring &str) { + string s; + if ( str.str_len > 0 ) + SPrintf( s, "%s", str.str ); + else + return "empty"; + return s; +} \ No newline at end of file diff --git a/h3c_and_h3m_formats/Heroes3/object/artefact.bt b/h3c_and_h3m_formats/Heroes3/object/artefact.bt new file mode 100644 index 0000000..ab679e3 --- /dev/null +++ b/h3c_and_h3m_formats/Heroes3/object/artefact.bt @@ -0,0 +1,18 @@ +struct ObjectArtefact { + uchar isText; + + if ( isText == 1 ) { + hstring text; + + + uchar isGuards; + + if ( isGuards == 1 ) { + struct GuardTag { + ushort GuardID; + ushort GuardCount; + } Guards[7]; + } + uchar junk[4]; + } +}; \ No newline at end of file diff --git a/h3c_and_h3m_formats/Heroes3/object/dwellings.bt b/h3c_and_h3m_formats/Heroes3/object/dwellings.bt new file mode 100644 index 0000000..d7def45 --- /dev/null +++ b/h3c_and_h3m_formats/Heroes3/object/dwellings.bt @@ -0,0 +1,30 @@ +struct ObjectDwelling { + uint32 owner; // FF - nobody +}; + +struct ObjectShipyard { + ObjectDwelling shipyard; +}; + +struct ObjectGeneralRandomDwelling { + uint32 owner; + uint32 junk; + if (junk == 0 ) + ushort towns; + + uchar minlevel; + uchar maxlevel; +}; + +struct ObjectLevelRandomDwelling { + uint32 owner; + uint32 junk; + if ( junk == 0 ) + ushort towns; +}; + +struct ObjectTownRandomDwelling { + uint32 owner; + uchar minlevel; + uchar maxlevel; +}; \ No newline at end of file diff --git a/h3c_and_h3m_formats/Heroes3/object/grail.bt b/h3c_and_h3m_formats/Heroes3/object/grail.bt new file mode 100644 index 0000000..9e52af3 --- /dev/null +++ b/h3c_and_h3m_formats/Heroes3/object/grail.bt @@ -0,0 +1,4 @@ +struct ObjectGrail { + char radius; + uchar junk2[3]; +}; \ No newline at end of file diff --git a/h3c_and_h3m_formats/Heroes3/object/monster.bt b/h3c_and_h3m_formats/Heroes3/object/monster.bt new file mode 100644 index 0000000..cdaca9d --- /dev/null +++ b/h3c_and_h3m_formats/Heroes3/object/monster.bt @@ -0,0 +1,24 @@ +struct ObjectMonster { + uint32 monsterID; + ushort monsters_count; // if 0, then random + uchar mood; + uchar isTreasureOrText; + + if ( isTreasureOrText == 1 ) { + hstring text; + + uint32 wood; + uint32 mercury; + uint32 ore; + uint32 sulfur; + uint32 crystal; + uint32 gem; + uint32 gold; + ushort artefactID; + } + + uchar monsterNeverRunAway; // 1 - yes, 0 - no + uchar monsterDontGrowUp; // 1 - yes, 0 - no + + uchar junk2[2]; +}; \ No newline at end of file diff --git a/h3c_and_h3m_formats/Heroes3/object/pandorabox.bt b/h3c_and_h3m_formats/Heroes3/object/pandorabox.bt new file mode 100644 index 0000000..c7bbe4d --- /dev/null +++ b/h3c_and_h3m_formats/Heroes3/object/pandorabox.bt @@ -0,0 +1,44 @@ +struct ObjectPandora { + ObjectArtefact art; + uint32 exp; + int32 spell_points; + char morals; + char luck; + + int32 wood; + int32 mercury; + int32 ore; + int32 sulfur; + int32 crystal; + int32 gem; + int32 gold; + + uchar offence; + uchar defence; + uchar power; + uchar knowledge; + + uchar secskills; + + if ( secskills > 0 ) { + secskill_tag sec_skills [secskills]; + } + + uchar artefacts; + + if ( artefacts > 0 ) { + ushort artID[artefacts]; + } + + uchar spells; + if ( spells > 0 ) { + uchar spellID[spells]; + } + + uchar monstres_count; + + if ( monstres_count > 0 ) { + GuardTag monstres[monstres_count]; + } + uchar junk3[8]; +}; \ No newline at end of file diff --git a/h3c_and_h3m_formats/Heroes3/object/resource.bt b/h3c_and_h3m_formats/Heroes3/object/resource.bt new file mode 100644 index 0000000..9f0fa8b --- /dev/null +++ b/h3c_and_h3m_formats/Heroes3/object/resource.bt @@ -0,0 +1,5 @@ +struct ObjectResource { + ObjectArtefact res; + uint32 quantity; + uchar junk[4]; +}; \ No newline at end of file diff --git a/h3c_and_h3m_formats/Heroes3/object/scientist.bt b/h3c_and_h3m_formats/Heroes3/object/scientist.bt new file mode 100644 index 0000000..1f87265 --- /dev/null +++ b/h3c_and_h3m_formats/Heroes3/object/scientist.bt @@ -0,0 +1,9 @@ +struct ObjectScientist { + uchar bonus_type; // FF - Random + union { + uint32 primaryID; + uint32 secondaryID; + uint32 spellID; + } bonus; + uchar junk2[3]; +}; \ No newline at end of file diff --git a/h3c_and_h3m_formats/Heroes3/object/spellscroll.bt b/h3c_and_h3m_formats/Heroes3/object/spellscroll.bt new file mode 100644 index 0000000..f1d6348 --- /dev/null +++ b/h3c_and_h3m_formats/Heroes3/object/spellscroll.bt @@ -0,0 +1,4 @@ +struct ObjectSpell { + ObjectArtefact spell; + uint32 spellID; +}; \ No newline at end of file diff --git a/h3c_and_h3m_formats/Heroes3/object/town.bt b/h3c_and_h3m_formats/Heroes3/object/town.bt new file mode 100644 index 0000000..6e2419e --- /dev/null +++ b/h3c_and_h3m_formats/Heroes3/object/town.bt @@ -0,0 +1,57 @@ +struct ObjectTown { + char junk[4]; + uchar owner; + + uchar isName; + + if ( isName == 1 ) + hstring name; + + uchar isGuard; + + if (isGuard == 1 ) + GuardTag guards[7]; + + uchar formation; // 00 - standalone, 01 - group + + uchar isBuildings; + + if ( isBuildings == 1 ) { + uchar built[6]; + uchar active[6]; + } else { + uchar isFort; + } + + uchar mustSpells[9]; + uchar canSpells[9]; + + uint32 event_quantity; + + if ( event_quantity > 0 ) { + struct TownEvent { + hstring event_name; + hstring event_text; + + int32 wood; + int32 mercury; + int32 ore; + int32 sulfur; + int32 crystal; + int32 gem; + int32 gold; + + uchar players_affected; + uchar human_affected; + uchar ai_affected; + + ushort day_of_first_event; + ushort event_iteration; + uint32 junk[4]; + uchar buildings[6]; + ushort creatures[7]; + uint32 junk2; + } events[event_quantity] ; + } + uint32 junk3; +}; \ No newline at end of file diff --git a/h3c_and_h3m_formats/Heroes3/objects.bt b/h3c_and_h3m_formats/Heroes3/objects.bt new file mode 100644 index 0000000..893e28d --- /dev/null +++ b/h3c_and_h3m_formats/Heroes3/objects.bt @@ -0,0 +1,9 @@ +#include "heroes3/object/monster.bt" +#include "heroes3/object/artefact.bt" +#include "heroes3/object/grail.bt" +#include "heroes3/object/pandorabox.bt" +#include "heroes3/object/spellscroll.bt" +#include "heroes3/object/resource.bt" +#include "heroes3/object/town.bt" +#include "heroes3/object/dwellings.bt" +#include "heroes3/object/scientist.bt" \ No newline at end of file diff --git a/h3c_and_h3m_formats/Heroes3/secondaryskills.bt b/h3c_and_h3m_formats/Heroes3/secondaryskills.bt new file mode 100644 index 0000000..e77c3f8 --- /dev/null +++ b/h3c_and_h3m_formats/Heroes3/secondaryskills.bt @@ -0,0 +1,4 @@ +struct secskill_tag { + uchar skillID; + uchar skillLevel; +}; \ No newline at end of file diff --git a/h3c_and_h3m_formats/Heroes3/special_victory.bt b/h3c_and_h3m_formats/Heroes3/special_victory.bt new file mode 100644 index 0000000..499a6c4 --- /dev/null +++ b/h3c_and_h3m_formats/Heroes3/special_victory.bt @@ -0,0 +1,39 @@ +struct SpecialVictoryConditions { + uchar id; + + if ( id != 0xFF ) { + char canStandardEnd; + char canComputer; + } + + if ( id == 0x00 ) { + struct svc_acqSpecArt_tag { + char artID; + } svc_acqSpecArt; + } else if ( id == 0x01 ) { + struct svc_accCreatures_tag { + ushort creatureID; + DWORD creatureCount; + }svc_accCreatures; + } else if ( id == 0x02 ) { + struct svc_accRes_tag { + char resID; + DWORD resCount; + } svc_accRes; + } else if ( id == 0x03 ) { + struct svc_upgSpecTown_tag { + uchar coord[3]; + char hall_level; + char castle_level; + } svc_upgSpecTown; + } else if ( id == 0x04 || id == 0x05 || id == 0x06 || id == 0x07 ) { + uchar coord[3]; + } else if ( id == 0x08 || id == 0x09) { + // no more data + } else if ( id == 0x0A ) { + struct svc_tranSpecArt_tag { + uchar artID; + uchar coord[3]; + } svc_tranSpecArt; + } +}; \ No newline at end of file diff --git a/h3c_and_h3m_formats/h3m_description.TXT b/h3c_and_h3m_formats/h3m_description.TXT new file mode 100644 index 0000000..b0b95e6 --- /dev/null +++ b/h3c_and_h3m_formats/h3m_description.TXT @@ -0,0 +1,1005 @@ +╔ ╦ ╦ ╦ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ╦ ╦ ╦ ╗ + + ║ ║ ║ ║ ║ ║ ║ ║ + + ║ ║ ║ ║ format description cards for the game Heroes of Might and Magic III ║ ║ ║ ║ + + ║ ║ ║ ║ (C) Oleg Antoshkiv 2:4623 / 55.37 @ fidonet.org ║ ║ ║ ║ + + ║ ║ ║ ║ (C) Stanislav Ershov (supplement for SoD) ║ ║ ║ ║ + + ║ ║ ║ ║ (who will complement add your name here) ║ ║ ║ ║ + + ╚ ╩ ╩ ╩ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ╩ ╩ ╩ ╝ + + + + Warning: file cards (*. h3m) zapakovany archiver GZIP + + + + + + Legend: + + The first number indicates the size of the element. + + + + 1 (length of the element in bytes + + ├ ─ 1 (these elements are present only at certain values + + └ ─ 1 (previous element, the number of them also may be different + + + + * (Length element is listed in the previous items + + ??? (Appointment is not known, in parentheses default value + + (???) (Change element does not affect the game + + + +█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ + +The main parameters █ █ █ █ card + +█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ + + + + Description Length (code) + + + + 4 Id format + + 0E 00 00 00 - RoE + + 15 00 00 00 - AB + + 1C 00 00 00 - SoD + + 1??? Set in the (01), when the card is present at least one + + hero. + + 4 height and width cards in the boxes (square map) + + 1 0-one-card, 1-Two + + 4 The name card in bytes + + * Name cards + + 4 length description of the map + + * Map Description + + 1 The complexity of maps (0-Easy ,1-Normal ,2-Hard ,3-Expert ,4-Impossible) + + + +█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ + +Attributes players █ █ █ █ + +█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ + + + + Here are the parameters of all the players in this order: + + Red, Blue, Tan, Green, Orange, Purple, Teal, Pink + + + + For each player has a sequence of bytes: + + 1 Limiting the level of skill heroes + + 1 Can play cheloovek: 1 - YES, 0 - NO + + 1 Can play computer: 1 - YES, 0 - NO + + 1 Behavior: 0-Random, 1-Warrior, 2-Builder, 3-Explorer + + 1 Configured whether what cities owns a player + + 2 What types of cities player owns: Bit = 1 - owns, Bit = 0 - does not speak + + Bit0 Castle + + Bit1 Rampart ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╖ + + Bit2 Tower │ if the player owns Random Town, ║ + + Bit3 Inferno │ it is believed that he owns ║ + + Bit4 Necropolis │ all kinds of cities ║ + + Bit5 Dungeon ╘ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ╝ + + Bit6 Stronghold + + Bit7 Fortress + + Bit8 Conflux + + 1 Well in whether a player Random Town: 1-Yes, 0-NET + + 1 Chief Town player: 1-DA 0-NET + + ├ ─ 1 Is a hero + + ├ ─ 1 Type cities: FF - Random town, the remaining match 0 - Castle, etc. + + ├ ─ 1 X-coordinate of the castle + + ├ ─ 1 Y-coordinate of the castle + + └ ─ 1 Z-coordinate of the castle + + + + + +█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ + +Available heroes █ █ █ █ player + +█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ + + + + 1 Does Random Hero: 1-Yes, 0-Net + + 1 Hero Tip from 00 to 7F (all have 128 types of heroes) + + │ (if FF - hero no) and the following bytes are not available: + + ├ ─ 1 room faces the hero (all have 128 types) + + │ (if FF - mug Standard) + + ├ ─ 4 length of the name hero (if 0, it is not - the standard) + + ├ ─ # name of the hero + + ├ ─ 1 debris (not noticed that he is influenced by that, always either 00 or + + │ other values of Balde) + + └ ─ 4 number of heroes from the player + + └ ─ # + + ├ ─ 1 ID hero + + ├ ─ 4 length of the name hero + + └ ─ # name of the hero + + + +█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ + +█ █ Special Victory Condition █ █ + +█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ + + + + 1 Does Special Victory Condition: + + │ ■ FF - NET + + │ ■ 00 - Acquire a specific artifact + + │ ■ 01 - Accumulate creatures + + │ ■ 02 - Accumulate resources + + │ ■ 03 - Upgrade a specific town + + │ ■ 04 - Build the grail structure + + │ ■ 05 - Defeat a specific Hero + + │ ■ 06 - Capture a specific town + + │ ■ 07 - Defeat a specific monster + + │ ■ 08 - Flag all creature dwelling + + │ ■ 09 - Flag all mines + + │ ■ 0A - Transport a specific artifact + + + + ■ Acquire a specific artifact + + ├ ─ 1 is also possible to a normal ending: 1-Yes, 0-Net (not) + + ├ ─ 1 Is Available for PC + + └ ─ 1 ID artifact + + + + ■ Accumulate creatures + + ├ ─ 1 is also possible to a normal ending: 1-Yes, 0-Net + + ├ ─ 1 Is Available for PC: 1-Yes, 0-Net + + ├ ─ 2 ID unit + + └ ─ Number 4 + + + + ■ Accumulate resources + + ├ ─ 1 is also possible to a normal ending: 1-Yes, 0-Net + + ├ ─ 1 Is Available for PC: 1-Yes, 0-Net + + ├ ─ 1 resource ID: ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╖ + + │ │ 0 - Wood 4 - Crystal ║ + + │ │ 1 - Mercury 5 - Gems ║ + + │ │ 2 - Ore 6 - Gold ║ + + │ │ 3 - Sulfur ║ + + │ ╘ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ╝ + + └ ─ Number 4 + + + + ■ Upgrade a specific town + + ├ ─ 1 is also possible to a normal ending: 1-Yes, 0-Net + + ├ ─ 1 Is Available for PC: 1-Yes, 0-Net (???) + + ├ ─ 1 X-coordinate of the city + + ├ ─ 1 Y-coordinate of the city + + ├ ─ 1 Z-coordinate of the city + + ├ ─ 1 Hall Level: 0-Town, 1-City, 2-Capitol + + └ ─ 1 Castle Level: 0-Fort, 1-Citadel, 2-Castle + + + + ■ Build the grail structure + + ├ ─ 1 is also possible to a normal ending: 1-Yes, 0-Net (???) + + ├ ─ 1 Is Available for PC: 1-Yes, 0-Net (???) + + ├ ─ 1 X-coordinate of the city + + ├ ─ 1 Y-coordinate of the city + + └ ─ 1 Z-coordinate of the city + + + + ■ Defeat a specific Hero + + ├ ─ 1 is also possible to a normal ending: 1-Yes, 0-Net (???) + + ├ ─ 1 Is Available for PC: 1-Yes, 0-Net (???) + + ├ ─ 1 X-coordinate hero + + ├ ─ 1 Y-coordinate hero + + └ ─ 1 Z-coordinate hero + + + + ■ Capture a specific town + + ├ ─ 1 is also possible to a normal ending: 1-Yes, 0-Net (???) + + ├ ─ 1 Is Available for PC: 1-Yes, 0-Net (???) + + ├ ─ 1 X-coordinate of the city + + ├ ─ 1 Y-coordinate of the city + + └ ─ 1 Z-coordinate of the city + + + + ■ Defeat a specific monster + + ├ ─ 1 is also possible to a normal ending: 1-Yes, 0-Net + + ├ ─ 1 Is Available for PC: 1-Yes, 0-Net (???) + + ├ ─ 1 X-coordinate of the city + + ├ ─ 1 Y-coordinate of the city + + └ ─ 1 Z-coordinate of the city + + + + ■ Flag all creature dwelling + + ├ ─ 1 is also possible to a normal ending: 1-Yes, 0-Net + + └ ─ 1 Is Available for PC: 1-Yes, 0-Netz + + + + ■ Flag all mines + + ├ ─ 1 is also possible to a normal ending: 1-Yes, 0-Net + + └ ─ 1 Is Available for PC: 1-Yes, 0-Net + + + + ■ Transport a specific artefact + + ├ ─ 1 is also possible to a normal ending: 1-Yes, 0-Net (???) + + ├ ─ 1 Is Available for PC: 1-Yes, 0-Net + + ├ ─ 1 ID artifact + + ├ ─ 1 X-coordinate of the city + + ├ ─ 1 Y-coordinate of the city + + └ ─ 1 Z-coordinate of the city + + + +█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ + +█ █ Special loss condition █ █ + +█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ + + + + 1 Does Special Loss Condition + + │ ■ FF - None + + │ ■ 00 - Lose a specific town + + │ ■ 01 - Lose a specific hero + + │ ■ 02 - Time expires + + + + ■ Lose a specific town + + ├ ─ 1 X-coordinate of the city + + ├ ─ 1 Y-coordinate of the city + + └ ─ 1 Z-coordinate of the city + + + + ■ Lose a specific hero + + ├ ─ 1 X-coordinate hero + + ├ ─ 1 Y-coordinate hero + + └ ─ 1 Z-coordinate hero + + + + ■ Time expires + + └ ─ 2 Days + + + +█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ + +█ █ Teams (Teams) █ █ + +█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ + + + + 1 Number of teams, 0 - no team + + │ + + │ If teams do not, the following 8 bytes missing: + + │ + + ├ ─ No. 1 team for Red (red) + + ├ ─ No. 1 team for the Blue (blue) + + ├ ─ No. 1 team for the Tan (brown) + + ├ ─ No. 1 team for the Green (Green) + + ├ ─ No. 1 team for the Orange (orange) + + ├ ─ No. 1 team for the Purple (purple) + + ├ ─ No. 1 team for the Teal (blue) + + └ ─ No. 1 team for Pink (pink) + + + +█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ + +Free heroes █ █ █ █ + +█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ + + + + 20 bytes. In a game there all 156 types of characters in these 16 bytes + + Provides information about whether this is a hero in the game or not + + (to avoid the simultaneous presence of the same heroes) + + + + If the hero prescribed in the "heroes of available players, respectively, then banned + + to hire. + + + + In each byte of information on 8 heroes + + (bit = 0 - hero busy bits = 1 - the hero is free) + + + + Number of bytes - Tip hero + + + + 00 - Knight + + 01 - Cleric + + 02 - Ranger + + 03 - Druid + + 04 - Alchemist + + 05 - Wizard + + 06 - Demoniac + + 07 - Heretic + + 08 - Death Knight + + 09 - Necromancer + + 0a - Overlord + + 0b - Warlock + + 0c - Barbarian + + 0d - Battle Mage + + 0e - Beastmaster + + 0f - Witch + + 10 - Special Interests + + 11 - Elementalist + + 12 - ext. heroes (Mutare, Mutare Dreyk, etc.) + + 13 - ext. heroes (Mutare, Mutare Dreyk, etc.) + + + + 4 empty + + + + 1 Number of configured heroes + + # + + ├ ─ 1 ID hero + + ├ ─ 1 portrait of a hero + + ├ ─ 4 length of the name hero + + ├ ─ # name of the hero + + └ ─ 1 for any players available for recruitment (bit field) FF - for all + + + +█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ + +█ █ ?????? █ █ + +█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ + + + + 31 bytes filled 00 (probably reserved for new versions?) + + (in all standard maps, and campaigns like too) + + + +█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ + +█ █ █ █ Random Artifacts + +█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ + + + + 18 bytes. The game of all, there are many artifacts:) + + bit = 0 - artifact may fall + + bits = 1 - artifact can not fall + + + +█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ + +█ █ Rumors █ █ + +█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ + + + + Number 4 Rumors + + │ + + ├ ─ 4 The name 1-on Rumor + + ├ ─ # Name 1 st Rumor + + ├ ─ 4 lengths 1 st Rumor + + ├ ─ # 1 st Rumor + + │ + + ├ ─ 4 The name of 2-nd Rumor + + ├ ─ # Name 2 nd Rumor + + ├ ─ 4 length 2 nd Rumor + + ├ ─ # 2 nd Rumor + + . ... (and well before the end of all Rumors) + + + +█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ + +█ █ █ █ Settings heroes + +█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ + + Extras. set of heroes (experience, primary and secondary skills, artifacts, + + spells) + + + + 1 byte (repeated 156 times as much as the characters in the game) if 0, then + + │ trail. None bytes) + + ├ ─ 1 set whether Experience + + │ └ ─ 4 experience + + ├ ─ 1 there are secondary skills + + │ └ ─ 4 Number of skills + + │ ├ ─ 1 identifier skill + + │ └ ─ 1 level of skill (0 - DOS, 1 - DWP, 2 - Export) + + ├ ─ 1 there are artifacts + + │ ├ ─ 2 ID artifact to the head (FF FF - min. Default) + + │ ├ ─ 2 shoulders + + │ ├ ─ 2 neck + + │ ├ ─ 2 right hand + + │ ├ ─ 2 left hand + + │ ├ ─ 2 SARS + + │ ├ ─ 2 of the ring + + │ ├ ─ 2 Left kol'co + + │ ├ ─ 2 feet + + │ ├ ─ 2 Miscellaneous 1 + + │ ├ ─ 2 Miscellaneous 2 + + │ ├ ─ 2 Others 3 + + │ ├ ─ 2 different 4 + + │ ├ ─ 2 machine 1 + + │ ├ ─ 2 machine 2 + + │ ├ ─ 2 machine 3 + + │ ├ ─ 2 machine 4 + + │ ├ ─ 2 magic book + + │ ├ ─ 2 different 5 + + │ └ ─ 2 Number of things in backpack + + │ └ ─ # + + │ └ ─ 2 ID art + + ├ ─ 1 set whether biography + + │ └ ─ 4 length biography + + │ └ ─ # biography + + ├ ─ 1 set whether sex character + + │ └ ─ 1 floor (FF - by default, 00 - man, 01 - baba) + + ├ ─ 1 are whether spelly + + │ └ ─ 9 bit field, which is spelly + + └ ─ 1 are whether the primary skills + + ├ ─ 1, meaning an attack + + ├ ─ 1 value protection + + ├ ─ 1 meaning + + └ ─ 1 znachanie knowledge + + + +█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ + +█ █ █ █ map land + +█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ + + + + Size: (razmer_karty) ^ 2 * 7 + + (Description more) + + + +█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ + +█ █ █ █ map underground + +█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ + + + + Size: (razmer_karty) ^ 2 * 7 + + If the card is a one, then this section is not available. + + (Description more) + + + +█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ + +█ █ Format maps of land and underground █ █ + +█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ + + + + The first byte - codes of: + + 00 - Dirt (brown) (0F 3F 50) (RGB color map) + + 01 - Sand (light yellow) (8F CF DF) + + 02 - Grass (dark green) (00 40 00) + + 03 - Snow (white) (C0 C0 B0) + + 04 - Swamp (light green) (6F 80 4F) + + 05 - Rough (tawny) (30 70 80) + + 06 - Subterranean (red) (30 80 00) + + 07 - Lava (dark gray) (4F 4F 4F) + + 08 - Water (blue) (90 50 0F) + + 09 - Rock (black) (00 00 00) + + + + The second byte - Patterns of (them very much) + + + + Third byte - the type of stream: + + 01 - Clear + + 02 - Icy + + 03 - Muddy + + 04 - Lava + + + + Fourth bytes - configuration of the river: + + ┌ ─ ─ ─ ┐ + + 00, 01, 02, 03 - 4 variant segment │ ╔ ═ ╡ + + ┌ ─ ╥ ─ ┐ └ ─ ╨ ─ ┘ + + 04 - segment ╞ ═ ╬ ═ ╡ + + └ ─ ╨ ─ ┘ ┌ ─ ─ ─ ┐ + + 05, 06 - 2 option segment ╞ ═ ╦ ═ ╡ + + └ ─ ╨ ─ ┘ + + ┌ ─ ╥ ─ ┐ + + 07, 08 - 2 option segment │ ╠ ═ ╡ + + └ ─ ╨ ─ ┘ + + ┌ ─ ╥ ─ ┐ + + 09, 0A - 2 option segment │ ║ │ + + └ ─ ╨ ─ ┘ + + ┌ ─ ─ ─ ┐ + + 0B, 0C - 2 option segment ╞ ═ ═ ═ ╡ + + └ ─ ─ ─ ┘ + + + + The fifth byte - the type of roads: + + 01 - Dirt + + 02 - Gravel + + 03 - Cobblestone + + + + Sixth bytes - configuration of the road: + + ┌ ─ ─ ─ ┐ + + 00,01,02,03,04,05 - 6 options segment │ ╔ ═ ╡ + + └ ─ ╨ ─ ┘ + + ┌ ─ ╥ ─ ┐ + + 06, 07 - 2 option segment │ ╠ ═ ╡ + + └ ─ ╨ ─ ┘ + + ┌ ─ ─ ─ ┐ + + 08, 09 - 2 option segment ╞ ═ ╦ ═ ╡ + + └ ─ ╨ ─ ┘ + + ┌ ─ ╥ ─ ┐ + + 0A, 0B - 2 option segment │ ║ │ + + └ ─ ╨ ─ ┘ + + ┌ ─ ─ ─ ┐ + + 0C, 0D - 2 option segment ╞ ═ ═ ═ ╡ + + └ ─ ─ ─ ┘ + + ┌ ─ ─ ─ ┐ + + 0E - segment │ ║ │ + + └ ─ ╨ ─ ┘ + + ┌ ─ ─ ─ ┐ + + 0F - segment │ ═ ═ ╡ + + └ ─ ─ ─ ┘ + + ┌ ─ ╥ ─ ┐ + + 10 - segment ╞ ═ ╬ ═ ╡ + + └ ─ ╨ ─ ┘ + + + + + + Seventh bytes - sets the mirror cells + + + + The value of bits: 76543210 + + - CcBbAa (bits labeled '-' can be any) + + + + a - includes a mirror image segment of land on the vertical axis + + A - includes a mirror image segment of land on the horizontal axis + + (Not all of the land operates mirror). + + b - includes a mirror image segment of the river on the vertical axis + + B - includes a mirror image segment of the river on the horizontal axis + + c - includes a mirror image segment of road on the vertical axis + + C - includes a mirror image segment of road on the horizontal axis + + + + + +█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ + +█ █ Attributes objects standing on the map █ █ + +█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ + + + + Here are the characteristics of objects standing on the map + + including castles and heroes (except the earth, rivers and roads) + + as well as events (Events) - those that are located on the map, and + + Global Events (set in "Map Specifications") + + + + 4 Number of sites on the map (immediately propisyvayutsya 2 facility, which + + │ never shown on the map, for which it is not clear) + + └ ─ # (from objects.txt) + + ├ ─ 4 length of Sprite + + ├ ─ # name Sprite + + ├ ─ 6 cells which fields are not passable, back to the lower-right corner + + │ bit = 1 - passable + + │ bit = 0 - not passable + + ├ ─ 6 active cells (overlaid on top of not passable cell) + + │ bit = 1 - cell activated + + │ bit = 0 - not active + + ├ ─ 2 on what type of terrain can be put + + │ bit0 - water + + │ bit1 - lava + + │ bit2 - underground + + │ bit3 - stones + + │ bit4 - swamp + + │ bit5 - snow + + │ bit6 - grass + + │ bit7 - sand + + │ bit8 - dirt + + ├ ─ 2 in a group of landscapes will be added to object to the editor + + │ similar to previous + + ├ ─ 4 class facility + + ├ ─ 4 Units + + ├ ─ 1 team sites (Editor) + + │ 1 - the city of 2 - Monsters 5 - Treasures + + │ 3 - heroes 4 - artifacts + + ├ ─ 1 will be raspolagatsya object on the object or the object + + └ ─ 16 m (still at the site observed 0) this in no objects.txt + + + + 4 Number of sites on the map + + └ ─ # + + └ ─ + + + +█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ diff --git a/image_viewer.py b/image_viewer.py new file mode 100755 index 0000000..6ca9b45 --- /dev/null +++ b/image_viewer.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python + +import pyglet + +images = [ + pyglet.image.load("puzzle/cas/%d PuzCas%02d.pcx"%(i+2745, i)) for i in xrange(20) +] + +bin = pyglet.image.atlas.TextureBin() +images = [bin.add(image) for image in images] + +window = pyglet.window.Window(800,600) +image = pyglet.resource.image('interface/3178 Puzzle.pcx') +image1 = pyglet.resource.image('interface/153 AResBar.pcx') + +@window.event +def on_draw(): + window.clear() + image.blit(0, 0) + image1.blit(3, 3) + images[0].blit(7,414) + images[1].blit(7,402) + images[2].blit(7,412) + images[3].blit(7,359) + images[4].blit(7,264) + images[5].blit(7,49) + images[6].blit(16,527) + images[7].blit(22,49) + images[8].blit(70,49) + images[9].blit(72,285) + +@window.event +def on_key_press(symbol, modifiers): + if symbol == pyglet.window.key.Q: + pyglet.app.exit() + +pyglet.gl.glEnable(pyglet.gl.GL_BLEND) +pyglet.gl.glBlendFunc(pyglet.gl.GL_SRC_ALPHA, pyglet.gl.GL_ONE_MINUS_SRC_ALPHA) + +pyglet.app.run() diff --git a/lodextract.py b/lodextract.py new file mode 100644 index 0000000..d68d7be --- /dev/null +++ b/lodextract.py @@ -0,0 +1,52 @@ +#!/usr/bin/python + +import zlib, os +import struct + +import Image, ImageDraw +import StringIO + +lod = open("H3bitmap.lod") +lod.seek(8) +files_count = struct.unpack("i", lod.read(4))[0] +files=[] +for file in range(32,33): + lod.seek(92+(file*32)) + name = lod.read(16).split("\0")[0] + offset = struct.unpack("i", lod.read(4))[0] #offset + size_orig = struct.unpack("i", lod.read(4))[0] #size_original + type = struct.unpack("i", lod.read(4))[0] #type + size_comp = struct.unpack("i", lod.read(4))[0] #size_compressed + + lod.seek(offset) + + if size_comp: + pcx = zlib.decompress(lod.read(size_comp)) + else: + pcx = lod.read(size_orig) + + if type == 16: + size = struct.unpack("i", pcx[:4])[0] + width = struct.unpack("i", pcx[4:8])[0] + height = struct.unpack("I", pcx[8:12])[0] + print size, width, height + im = Image.fromstring("L", (width, height), pcx[12:12+size]) + im.putpalette(pcx[12+size:12+size+768]) + im.save(' '.join([str(file),name]), "PNG") + if type == 17: + size = struct.unpack("i", pcx[:4])[0] + width = struct.unpack("i", pcx[4:8])[0] + height = struct.unpack("I", pcx[8:12])[0] + print size, width, height + im = Image.fromstring("RGB", (width, height), pcx[12:12+size]) + im.save(' '.join([str(file),name]), "PNG") + elif type in (1, 2, 64, 65, 66, 67, 68, 69, 70, 71, 73, 79, 80, 96): + print file, name + file = open(' '.join([str(file),name]), "w") + file.write(pcx) + file.close() + else: + print i, name, type + sys.exit("not supported %d"%type) + +lod.close() diff --git a/lodlist.py b/lodlist.py new file mode 100644 index 0000000..ed9b479 --- /dev/null +++ b/lodlist.py @@ -0,0 +1,19 @@ +#!/usr/bin/python + +import struct +from sys import argv + +lod = open(argv[1]) +lod.seek(8) +files_count = struct.unpack("i", lod.read(4))[0] +files=[] +for file in xrange(files_count): + lod.seek(92+(file*32)) + name = lod.read(16).split("\0")[0] + offset = struct.unpack("i", lod.read(4))[0] #offset + size_orig = struct.unpack("i", lod.read(4))[0] #size_original + type = struct.unpack("i", lod.read(4))[0] #type + size_comp = struct.unpack("i", lod.read(4))[0] #size_compressed + print name + +lod.close() diff --git a/logo.svg b/logo.svg new file mode 100644 index 0000000..3c87590 --- /dev/null +++ b/logo.svg @@ -0,0 +1,1801 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + RENAISSANCE + + + + + + RENAISSANCE + + + + + + diff --git a/logo_alt.svg b/logo_alt.svg new file mode 100644 index 0000000..e98ac72 --- /dev/null +++ b/logo_alt.svg @@ -0,0 +1,102 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + +