Ironfist's Technical Capabilities


This originated as an E-mail sent to the project-ironfist Google Group in April 2016.

 

Resource tooling:

 

Graphics:

 

HoMM II uses the "ICN" sprite archive file format for most of its graphics, which consists of a set of independent images. It has a 216 color palette, with certain color codes reserved for "color cycling," meaning that it will alternate between certain colors every few frames. There are also "colors" for semitransparency to give things shadows.

 

We have a usable converter to and from ICN files, written by Grayface, athough it doesn't support the compression allowed by this format, and only supports some color cycling. We also have tools that can map images outside the HoMM II palette into the nearest color of the palette, allowing us to reasonably import outside graphics as stopgaps.

 

For terrains, it uses the .TIL tileset files. I do not know this file format, but we nonetheless have tools written by Grayface for working with them.

 

HoMM II also uses some .BMP files which are not standard bitmaps. I am not aware of anyone having figured out how to work with these, mainly because I haven't looked very hard.

 

HoMM II uses the proprietary Smacker format for its video. My previous attempt to obtain Smacker's documentation from the vendor failed.  I know at least one other modding project that needed to replace Smacker for its video needs.

 

Sound:

 

HoMM II allows both .XMI (extended MIDI) music as well as Redbook (i.e.: audio CD format) music. I have not worked with .XMI files successfully, but there has been stuff written on XMI files; I'm unsure if HoMM II's XMI files are the same as those.

 

CyberPhreak has begun work on something replacing the game's Redbook audio with .OGG/MP3 files, allowing us to finally hear the true soundtrack without having a physical CD in.

 

For sounds, HoMM II uses headerless .WAV files; they can be manipulated with any audio program such as Audible. http://projectironfist.pbworks.com/w/page/68304751/Adding%20and%20Editing%20Sounds

 

GUIs:

 

HoMM II implements its own GUI system inspired by the Windows API. The workings of its GUI system have been mostly reverse-engineered. Each GUI consists of a collection of widgets, manually laid out using exact pixel values, and manipulated programmatically.  Every game window is first loaded from ".BIN" GUI file, which just gives a collection of widgets and their starting values. This format has been completely reverse-engineered. We have h2guiview.exe, a fairly primitive reader for these files, but do not have an editor.

 

In the one case we've added a GUI, for the edit town window in the map editor, we did it by replacing the existing GUI with one using Windows forms. This is much more appropriate for an editor.

 

Other:

 

"Creature frame information" files describe the animations of a creature. They have been completely reverse-engineered, and we have tools to work with them: http://projectironfist.pbworks.com/w/page/57740979/Controlling%20Creature%20Animation

 

There are a couple of miscellaneous data files used by HoMM II for things such as procedural graphics generation (e.g.: the "Holy Word" spell); these have not been reverse-engineered.

 

Archiving: We have a fairly satisfactory mechanism of creating the .AGG files used by HoMM II. The game is modified so that it will first load assets from ironfist.agg, allowing us to replace the original games assets by just distributing that one file. The main limitation of this file format is its limitation to the "8+3" style DOS filenames. It also lacks compression.

 

 

Other files:

 

Both the HoMM II map and savegame file formats have been reverse-engineered. They are fairly ugly binary formats.

 

We have begun modifying the savegame format to a more-maintainable XML-based format. Namely, we've added sections to save scripting information (see below), and moved information about heroes into XML -- this was done so that we could add new spells to the game, as the existing format only allows heroes to know 66 spells.

 

So far, we've avoided modifying the HoMM II map format by putting things in scripts instead. For example, the "ShareVision" function, which causes one player to see everything another player does, is perhaps more naturally expressed as an editor setting (similar to allies).

 

We have also added the "creatures.xml" file (see "Creatures" section), as well as the SCRIPTS folder for Lua scripts.

 

Map Editor

 

The map editor has been fairly minimally modified. We fixed a few bugs in the original map editor, and replaced the "Edit Town" window with a new one which is a bit easier-to-use and allows giving a town the new Ironfist cretaures. We have made it possible to add new objects to the map editor, and have added the new Ironfist creatures; however, these are still hardcoded into the editor.

 

Perhaps the most important part of the map editor is the 500+ line PlaceOverlay function, which places an object on the map, and includes a lot of special cases for e.g.: setting the faction field of a town. After a lot of work, I have cleaned up the decompiled code and moved it into Ironfist. This opens the path for being able to add objects with special map-editor behavior, such as towns.

 

CyberPhreak suggested using the fheroes2 editor instead, and it's worth having a look at it soon. It barely existed the last time I looked at it. My main concern is whether it can duplicate the original editor's fairly-complicated behavior for laying out pleasant-looking terrain tiles, which was one of the main reasons I chose to mod the original editor instead of e.g.: modifying the HoMM III editor to output HoMM II maps.

 

(For those who don't know, fheroes2 is an attempted reimplementation of HoMM II from scratch, currently ~10 years in the making. It's fairly impressive, although there are a lot of ways it's subtly different from the original Heroes II which I'm too nice to elaborate on.)

 

Code Tooling

 

The most important part of Ironfist is the "Revitalize" system for modifying binaries almost as easily as if we had their source code. I've written on it extensively, e.g.: http://projectironfist.pbworks.com/w/page/57731943/Interacting%20with%20the%20Original%20Code

 

The main part of Revitalize is a script for converting the output of our reverse-engineering work in IDA into a .asm file which can be used by the Microsoft Macro Assembler (MASM) with special macros that allow us to easily redefine parts. Quite a number of people have successfully learned to mod the game's code using this system, several of whom did it without talking to us. I personally find this workflow fairly pleasant, although not as pleasant as if we had the original code.

 

We do want to keep heroes2.asm and editor2.asm updated as we perform reverse-engineering. Usually this just consists of renaming things. Because regenerating the file is annoying and requires a small amount of manual work (and would be fairly laborious to automate due to the particularities of the IDA API), we try not to do it very often.

 

Parts of the Codebase

 

A general rule of thumb: modifying the game's logic and behavior is easier than modifying its GUI and graphics. So, making a creature that can walk over certain obstacles in battle = relatively easy (even though we haven't reverse-engineered the pathfinding code); changing the combat system so that you con move a creature one step at a time like in the King's Bounty games = hard.

 

Resources

 

Code for dealing with resource files is the most reverse-engineered part of the system. The resourceManager in particular has been 100% converted into Ironfist code, allowing us to modify it freely. We in general have great liberty in modifying resource code.

 

Scripting

 

Ironfist's most powerful addition is the scripting system, allowing much greater variety in custom maps, and hopefully in the future allowing custom spells and artifacts. The design is laid out in http://projectironfist.pbworks.com/w/page/65959884/Basics%20of%20Scripting .

 

Generally, the scripting integration is lightly sprinkled throughout the codebase, where we often just insert a single line of code to call a callback function inside your lua script.

 

Creatures

 

Creatures have been heavily worked on. We have replaced the game's hardcoded creature table with the creatures.xml file, which makes it easy to modify and add creatures. We have reverse-engineered and built tooling for virtually all aspects of dealing with creatures: see http://projectironfist.pbworks.com/w/page/54023699/Adding%20and%20Editing%20Creatures . The main exception is missiles: some additional work would need to be done to allow us to add new archer creatures and give them a custom projectile. Another exception: a little more work would be needed to add more creatures that cost resources other than gold.

 

Creature abilities were implemented in the original game as a small set of general abilities, plus a bunch of creature specific special cases. The former have been converted into our new system, and we are now able to easily add new abilities such as the harpy's strike-and-return ability and expose them to creature creators. The special-cased unique creature abilities are still largely hardcoded (e.g.: "if (creatureId == titan) then immune_to_mind_spells"); ideally, we'd slowly convert them into our new extensible system as desired. I see in the Tales of Enroth code that DraggonFantasy played with trying to make it so that any creature could have the hydra's ability.

 

Creatures have a one-byte code; adding more than 256 creatures would take some major rewriting. We are very far from this limit.

 

Artifacts

 

The artifact system is fairly simple: heroes have a list of artifacts, and the game is littered with code like "if (hero_has_ligthning_rod()) then lightning_bolt_damage *= 1.25". 

 

We have added one new artifact, the Pandora's Box. Adding more new artifacts should be as simple as creating a single graphic and then finding the part of the code to modify. It would be nice to have a design where new artifacts could be added purely by scripting, so that editing the game's code is not required to have a new artifact.

 

If we want to change the artifact system, such as allowing heroes to have more than 14 artifacts or (controversial!) carry artifacts and not use them, probably the hardest thing to change would be the GUI.

 

Artifiacts have a one-byte code; adding more than 256 artifacts would take some major rewriting. We are far, but less far, from this limit.

 

Spells

 

The game's spell code has been heavily reverse-engineered. While there are a number of regular subsystems, such as for spells which modify a creature and have a certain duration, and for spells whose animation is some sprite animation, on the whole the spell system is fairly complex, with lots of custom code for each spell -- including procedural graphics. 

 

We can add new spells. We have modified the savegame format to accomodate this. We have modified the game setup code so that Ironfist spells can appear in mage guilds, although I believe they still cannot appear at shrines.

 

We have added one new spell, the Awareness spell, as a proof of concept.  Adding a new adventure-map spell should be only as difficult as coding it up and creating the graphics. Adding a new combat spell will be a little bit harder, as we still need to translate the decompiled combatManager::DoSpell code into readable C++; it implements behavior such as Eagle Eye (heroes learning spells they see others cast) in one monolithic function. Also, procedural graphics code is scary (i.e.: is usually fairly unreadable after decompiling).

 

We have not modified the map editor to allow you to place Ironfist spells on spell scrolls.

 

Spells have a one-byte code; adding more than 256 spells would take some major rewriting. We are very far from this limit. 

 

Skills

 

The secondary-skill system is fairly simple, with a number of tables giving things such as the probability of receiving a secondary skill, and every hero having a list of secondary skills known and their level. Secondary skills are implemented as custom checks like "if (hero_has_archery_skill) then damage *= 1.1" . Conceptually, it should be easy to add a new secondary skill up to 256 skills, although we haven't tried. If we want to allow heroes to know more than 8 skills, probably the hardest thing to do would be to modify the GUI.

 

Secondary skills have a one-byte code; adding more than 256 secondary skills would take some major rewriting. This will never happen. There are currently about 13 skills. 

 

Primary skills are also simple, although I've yet to a see any proposals for modifying the primary skill system.

 

Combat

 

The combat code has been heavily reverse-engineered. We have been able to modify it for things such as the harpy's strike-and-return ability or to create new creatures at the start of battle for the Pandora's box. Sergei thinks our Lua scripting is presently good enough to be able to do interesting combat things like have a creature split in two every time it's attacked, and is currently trying to build this.

 

In general, modifying things that happen during combat is relatively easy. On the other hand, the combat code is very, very heavily intertwined with graphics. So, trying to simulate combat to implement a better AI would be fairly prohibitive.

 

Adventure Map

 

The adventure map data structures have been heavily reverse-engineered. It's a fairly ugly design. We should have the capabilities for doing things such as changing map objects at runtime (we have a new scripting call for this), but it's not pleasant. The "late overlay" system for placing multiple objects on a map tile is kinda complicated, and I constantly have to review it to remember how it works.

 

One notable thing is that the game only allows 128 codes for different kinds of map objects. The Price of Loyalty expansion already pushed past this, and did an ugly hack that involved giving many different objects the same code. We'll probably have an easier time building our own data structures that attach additional data to each map cell, rather than modifying the existing ones.

 

The adventure map code itself (pushing buttons, moving heroes) has been less reverse-engineered. We have, however, been able to do things like modify map events (notably, to remove the need to remember passwords for border guards).

 

Factions

 

A faction is a bunch of discrete things: a hero, its battle form, its adventure map graphics, its stats (incl. secondary skills), hero portraits, a new town map object, new creatures, a new town screen, wiring together the town and its town screen and its creatures, making things be appropriately randomly generated with the map, etc. Overall, I believe each of these pieces is fairly simple, but we've only done a few of the pieces.

 

Adding a new hero's stats is fairly easy.

 

We have the capabilities to give a hero a new faction and give him a new battle form; we did this for the Cyborg. We have yet to make it so that he uses new adventure-map graphics. We have done most of the work needed to add a new hero or town to the map editor (the PlaceOverly function stuff).

 

We have not fully reverse-engineered the town screen code, although I have a good idea of what's involved in creating a custom town screen.

 

For comparison, until Horn of the Abyss, I'm told every HoMM III mod that added a new faction did it by replacing an existing one.

 

GUI

 

Programming HoMM II GUIs is still fairly difficult. First, I don't think the system is very well designed. Second, we don't have a good GUI editor. Third, GUI code tends to be filled with lots of constants corresponding to IDs in the GUI files; we don't have a good way of connecting these to our code. Nontheless, the GUI system is fairly completely reverse-engineered.

 

Other

 

Things that have not been reverse-engineered much include: multiplayer/networked play, the game's AI, the campaign system, anything involving the title screen/main menu, and pathfinding (how heroes/creatures move).