Modding Starter Guide

This document is not yet complete.

The first few sections of this page discuss the merits of modding compared to other so-called solutions. Feel free to skip those if you are already convinced. While you wait for me to complete the page, you can visit Voyager's excellent guide, or go back to the main Starcraft section to peruse other resources.

Why even mod?

Game modification ('modding') involves editing functions that are normally out of an end user's reach. For Starcraft, modding generally refers to anything that requires more than what the editors are capable of. A more stringent definition may include EUDs and any of the other myriad features provided by SCMDraft 2, a third-party map editor by SuicidalInsanity.

Regardless of which description you find suitable, modding isn't just an encouraged activity among fans and developers of custom content, it's expected. A map or campaign without a mod component is seen as well below the baseline of what is possible with the engine, especially with the amount of documentation and examples available. You learn far more when you take up the task of modding, and will be rewarded with a project that justifies its existence beyond the result of a conventional hobby, thus attaining something resembling objective fulfillment.

In short, if you take your Starcraft project seriously, you'll be modding on 1.16.1. It is indeed more involved and challenging than mapping alone, but nothing worth doing is easy.


Short for extended unit deaths, EUDs are a hacky workaround to many of the engine's limits. They disable several essential features like savegames and the 'set next scenario' trigger action, making it a foregone conclusion that you'll be avoiding them for singleplayer projects. They also fall short of what is possible with GPTP and other external plugins, making them too limited for almost all cases.

The cream of the crop of EUD-enabled maps are tantamount to gimmicks and multiplayer arcade games, all of which would benefit from a mod component to properly add any and all desired functions. The only saving grace of EUDs is that they don't require a different exe file to be launched, and so they can be distributed through, but to hold your project back in the name of accessibility is to embrace a trope so tired that it's not even worth my derision anymore.

1.16.1 vs 1.2

Though this is true of all patches following 1.16.1, the "remastered" parent patch (1.2) absolutely destroyed the ability to make sweeping changes to Starcraft's engine. Though some functions are possible through the work of Neiv, graphical edits range from arduous to impossible, and the vast majority of changes that require plugins are impossible on the platform due to the change in location of memory addresses.

Worse still, nearly every patch breaks mod files, requiring them to be patched by the author and redownloaded by the user. That alone is far worse than having to use iccup or some other third-party gateway in order to play 1.16.1 multiplayer, as it extends even to singleplayer use, making 1.2 even less accessible than its older cousin, and even more annoying to work with.


I make no bones about the fact that modding Starcraft is unreasonably difficult at times. This document assumes you are content to put up with all of the platform's quirks and annoyances, or work to solve them yourself as best you can. Despite its legions of shortcomings, 1.16.1 is still the best custom content platform when it comes to RTS titles, and it has the most robust set of documentation and fellow modders that are more than willing to share their knowledge and time to assist you in your endeavors.

Though you may find some fleeting success using EUDs or modding on remastered, there are no alternatives that even come close to offering you what 1.16.1 can. This is the one true path, as was foretold. Prickle your penises and get ready to mod, and remember to gain my contact info if you run into trouble.


1.16.1 installation guide
SCMDraft 2

Starter Tasks

The following sections detail steps on how to do common modding tasks.

Creating a custom unit

Required tools:
  • PyMS
    • PyDAT
    • PyICE
    • PyGRP
    • PyMPQ
    • PyTBL
  • Firegraft
  • GPTP + Visual Studio 2010
  • Photoshop (or other image processor)
  • Audition 1.5 (or other audio processor)

The plan
We're going to make BAETYLUS, an inside-joke unit I made for mapcrap S2E05. In this tutorial, we'll be doing the following:

  • Change stats and weapon
  • Change graphic and animation
  • Change sound set
  • Add custom regeneration rules
  • Add to a structure's command card

Step 1
Changing the unit's stats and weapon
Open PyDAT and create a copy of units.dat and weapons.dat by clicking 'save as' (Ctrl+Alt+A) in the Units, Weapons, Flingy, and Images tabs. You'll do this every time you want to make a new set of changes for another mod to ensure that you don't overwrite the game's standard files.

In Units, under Basic, go to the Sarah Kerrigan entry and change her HP to 222, shields to 111, and enable shields with the checkbox. Feel free to modify her build cost if you want to adjust how expensive it is to repair her.

In Advanced, make her mechanical by ticking the appropriate checkbox. Leave her organic so she can be repaired by SCVs and healed by medics.

In Graphics, give her the Terran Advisor portrait so she looks her robotic self when clicked on.

In AI Actions, untick the two boxes in the middle of the section. This will let AI use her in attack and defense forces.

Under Basic, click the 'Jump ->' button next to the unit's weapon entry. This will take you directly to the weapon entry used by the unit.

Adjust the damage to 6, bonus to 4, cooldown to 6, type to normal, and range to 160. This gives her a very fast attack suitable for a mission made in four hours. We could also make her deal splash damage if we wanted, by setting the explosion to 'splash (radial)' or 'splash (enemy)', and setting the radii to whatever we wanted, but we'll leave that for another unit.

Under Weapon Display, set the behavior to Fly & Follow Target, the graphics to ID 162 - Venom (Unused Zerg Weapon), the X offset to 5, the Y offset to 2, and the launch spin to 48. The last few fields control the position and behavior of the missile as it spawns, allowing it to look like it's coming from the barrel of the rifle rather than the center of the attacker's graphic.

In a perfect world, we'd use an attack overlay instead of managing the position of the missile through offsets, to make sure it spawned at precisely the right pixel for each direction of the attack animation. We don't yet have the luxury of infinite overlays, so we'll save that for another time.

Click the 'Jump ->' button next to the weapon's graphics entry to jump to the Venom flingy.Increase the acceleration to make the attack more responsive. I put it at 1800, so it should reach its top speed significantly faster.

Click the 'Jump ->' button next to the flingy's sprite entry, then again next to the sprite's image entry. This will take you to the image entry used by the weapon's flingy's sprite. By this point you should be getting somewhat familiar with how these entities are linked within the game files.

All we're doing here is setting the function (under Drawing Properties) to Hallucination. This will make the venom attack blue when used in-game. Note that some of the remappings crash, and not all of them are documented within PyDAT itself.

That's all we need PyDAT for right now, but keep it open. You'll use it to reference entity IDs as we progress through the tutorial.

Step 2
Changing the unit's graphic and animation
In order for your unit to feel truly unique, you should give it a custom graphic. Many assets are linked in the Starcraft section, but for the purposes of the tutorial we'll make our own using Photoshop. I use CS6, but most versions should be fine, and you should be able to get by if you're familiar with other software like Krita or GIMP 2 and prefer to use those. Even if you've never used Photoshop before, this tutorial should bring you up to speed for editing Starcraft graphics.

I also recommend downloading the MPQ rip so you have access to Starcraft's visual and aural assets. You can also extract them yourself with PyMPQ or WinMPQ.

If we go to images.dat in PyDAT and search for Sarah Kerrigan, we can see that her graphic is called 'ughost.grp', located in the terran section of the graphics. Open stardat's rip or MPQ and go to 'unit\terran\ughost.grp'. Make a copy of that file and move it to your modding workspace. Open the file with PyGRP, select 'Units.pal' from the palette section, and select 'Single BMP, framesets' from the dropdown menu, as shown in the image below. Select all frames at once by clicking on a frame and pressing Ctrl+A. Extract the frames (Ctrl+E) to your workspace, and keep PyGRP open.

Now that you have all of her frames exported into a single image, recoloring them should be trivial. Open the extracted image in your image processor and zoom in to a comfortable level. Go to image -> adjustments -> replace color, set the hue to +95, select 'add to sample', and begin adding her hair pixels to the replace color profile. Scroll around to make sure you've nabbed them all, or some pixels may remain unchanged. Since her hair shares some colors with her muzzle flash, I recommend adding it to the sample as well, even if it looks a little odd.

Once you're done, save the replace color profile in case you need to reuse or edit it later, and press 'OK'. Go to image -> mode -> RGB color, then go to image -> mode -> indexed color. Under the 'Palette' dropdown menu, select 'custom', select 'load', and select GameBasic.act from your list of palettes. This will repalette the image using the standard palette used by most of Starcraft's assets, so some colors may mush together. Save the modified image and close your image processor.In PyGRP, scroll to the bottom of the list, and take note of the last frame number. That number plus 1 is the exactly number of frames in the grp. Make sure you have all frames selected and press delete to remove them. Import the edited image and when PyGRP asks you for the number of frames, enter 221. Save your changes to your copy of ughost.grp, and close PyGRP.

Let's increase BAETYLUS's speed. Open PyICE and open the default iscript.bin by pressing Ctrl+D. If you're using framework as the base for your mod, you can make a copy of its iscript.bin and edit that instead.Find the Sarah Kerrigan entry. In iscript entries, she's ID 77. In units, she's ID 16. Open her entry (Ctrl+E) and note the list of headers that refer to blocks of code depending on what action the image is taking. Find 'SarahKerriganWalking' block towards the bottom of the script. For every instance of the 'move' opcode, change its value from 4 to 5. Save the entry, close it, and save your iscript.bin. You can close PyICE after that.

Step 3
Changing the unit's sound set
Back in PyDAT, in Units, go to Sounds. Note that BAETYLUS doesn't have a ready sound. We can rectify this by pointing to an unused sound and replacing that in our MPQ. I used 665, an unused Zealot sound.

We'll take note of the other sound filenames, since we'll need to replace them with our own. In stardat, go to sound\terran\kerrigan and make a copy of all the files. You can omit UKeDth01, since it's unused. We'll edit the others in Audition 1.5 to take on a more robotic tone. We should also replace UKeWht00, since it makes reference to Kerrigan by name.

Once you have the files loaded in Audition, go to Delay Effects -> Echo. A simple duo of presets I use as part of my Dragoon voice editing will work fine for a robotic sound. You can find them in the images below, and copy their effects on your own screen. Save them as presets in case you want to use them later.

Since echoing can add volume and threaten peaks, we should normalize the sound file to 90% before applying our effects. Go to Amplitude -> Normalize and set the % to 90, then apply your echoes. You can normalize it to 99% or 100% after if you like. Once you've applied these effects to all of the sound files and save them, you can look for a replacement file for UKeWht00 and a ready line.

In the campaign rip on the Starcraft page, I chose terran05\wav\T5B03uke.wav as a replacement line and cut out everything but 'Get straight to the point'. I ran the file through a few FFT filters to make it sound like the voice was coming through a radio, and added background static to make it fit in with the other sounds.

For the ready line, I combined bits of terran11\wav\TBM01uke.wav and terran08\wav\T8M40uke.wav to make her say "I don't need this again." The files already had static in the background, so all I had to do was edit them to sound echoey.

You can find the wavs I made here, or make your own. Once you've finished, you can close Audition and move on to the next step.

Step 4
Add the unit to a structure's command card and change its strings
Let's make BAETYLUS trainable at the Command Center. Open Firegraft and either create a new exe or open a copy of Framework.exe.

Under Button Sets, find Command Center (ID 81), right-click on the SCV entry, and make a copy. Set its Position to 2, Icon to 16, Disabled string to 611, Enabled string to 612, Condition Variable to 16, and Action Variable to 16. It'll look like the image below when you're finished.

Click the '->' arrow next to the Sarah Kerrigan entries in the Condition Variable and Action Variable fields to be brought to the Dat Requirements list for her. Tick 'Used', and add five requirements (Ctrl+Insert). Fill them out until they look like the image does. This will allow her to be trainable if the structure is the Command Center, the structure isn't constructing an addon or lifted off, and the player has an Academy. You can get the same result by copying the Firebat's requirements and changing Barracks to Command Center.

Keep Firegraft open. In PyTBL, open Framework's stat_txt.tbl, or the default one if you aren't using Framework (Ctrl+D). Find Sarah Kerrigan's text entry. The first class is the unit's name and displays when selected in-game. The second class, 'Ghost' in this case, displays in the editor only. The third class determines where in the editor the unit is organized. Changing it to 'Ground Units' would sort it alongside the Marine and Firebat if we used our modified files in SCMDraft. Note that all strings end in '<0>'; this is an end-of-string character, which tells the game to read the next set of characters as a new string.

Change the first class to BAETYLUS, and leave the rest. Then, run a search for 'C-10' and change the second entry named 'C-10 Canister Rifle' to 'Ophiuchus Blaster', the name of BAETYLUS's weapon. This changes what's displayed when you hover over the weapon icon in the unit info panel. Note that there are no other classes in this section; those only exist for certain strings, and weapon names are not among them.

Search for 'Merc Gunship', and change the string to what you see in the image below. Change the next string to 'b<1>Deploy BAETYLUS (<3>B<1>)<0>'. Note that the first class is not shown in game, but corresponds to the hotkey the player can press instead of clicking the button. This is also highlighted towards the end of the string.

Save your changes to stat_txt.tbl and close PyTBL.

Step 5
Define new regeneration rules
Let's lower the energy cost of cloak for BAETYLUS. To do this, we'll dive into GPTP. Make a copy of Framework's plugin source and open the project file in Visual Studio 2019. Once you have the project file open, go to 'Source Files\subfolders\update_unit_state.cpp' and scroll down to find the function that spends cloak energy.

First, we'll remove the line with 'unit->id == UnitId::Hero_SarahKerrigan ||'. Then we'll make a new case especially for her. Just above the last 'else', write:
if (unit->id == UnitId::Hero_SarahKerrigan)
cloakingEnergyCost = 6;

Now that we've edited our file, we need to tell GPTP to use it. Once your file looks like the above image, save it, and go to 'Source Files\initialize.cpp'. Scroll down until you find 'hooks::injectUpdateUnitState();'. Add a mass comment (** */ **) to the end of the preceding line, and close it after the command. It should look like the image below when you're done.

These are all the changes we need to make cloak cost less for BAETYLUS. Go to Build -> Configuration Manager and configure the plugin to build as a Release version, then go to Build -> Clean, and finally Build -> Build. Once Visual Studio is finished building your plugin, you can go to your plugin source folder, go to Release\patch\', find GPTP.qdp. and copy it to your workspace.

In Firegraft, go to Plugins, and under MPQDraft Plugins, hit 'Add'. Find your GPTP.qdp, add it to your exe, and save. You're now ready for the final step - testing!

Step 6
Add our files and test
Save your changes in Firegraft, and close the program. Open your Firegraft exe in PyMPQ and begin adding your files like so.

  • our .dat files should be imported under 'arr\'
  • our graphic should be imported under 'unit\terran\'
  • our iscript.bin should be imported under 'scripts\'
  • our sound files should be imported under 'sound\terran\kerrigan\', except PZeRag00, which should have 'sound\protoss\zealot\'

Once that's done, we can launch our mod and test our changes. You'll need to test it in a map where Kerrigan is enabled in map settings, which should be most maps since she's not normally trainable. Everything should work properly, but if you run into issues, double check your filenames and paths in PyMPQ, and cross reference your changes with the images in this tutorial. You can look at my working example if you need to compare your files to the ones I made.

Giving a unit an air attack

Required tools:
  • PyMS
    • PyDAT
    • PyICE
    • PyMPQ
  • Firegraft

The plan
We're going to give the Terran Siege Tank an air attack. This one is super easy. In this tutorial, we'll be doing the following:

  • Change unit weapon links and weapon targets
  • Declare an air attack animation

Step 1
Change unit weapon links and weapon targets
We'll start with modifying units.dat and weapons.dat. Open PyDAT and create a copy of those two files using 'save as'.

In Units, under Basic, go to the Siege Tank Turret (Siege Mode) entry and set its air weapon to 27, and its air max hits to 1.

Click the 'Jump ->' button next to one of the weapon links to navigate to weapons.dat, and under Target Flags, tick the 'Air' tickbox.

That's it for our work in PyDAT. We can save and exit.

Step 2
Declare an air attack animation
In PyICE, we'll open the default iscripts.bin file ('CTRL+D') and save a copy of it using 'save as'. Then using the right-most column, we'll navigate to the Tank Turret entry (ID 31), select it with left-click, and open it ('CTRL+').All we need to do here is declare an air attack animation so the game knows what frames to play when the unit attacks an air target. In this case, we can simply copy the declarations from the GndAttkInit, GndAttkRpt, and GndAttkToIdle fields, and paste them over the '[NULL]' declarations in the AirAttkInit, AirAttkRpt, and AirAttkToidle fields. Notably, there is no unique GndAttkRpt animation - it's identical to GndAttkInit.

And we're done! We'll create a fresh exe with Firegraft ('CTRL+N') and save it, add our changed files with PyMPQ (.dat files with the 'arr\' prefix, iscript.bin with the 'scripts\' prefix), and test our changes. You can also refer to my working example if you run into trouble.