Updated version of this post is in OP, but maybe this can still help.
- How to port a mod to Blast
So you want to port your mod to Blast, eh? Well, here's how to do it. Look inside the base/ folder. This is where Blast takes the preraws from and compiles them and puts them into raw/, where DF can read them. But as you see, that base/ folder is already filled with a mod (namely the standard base, which is discussed in another tutorial). You don't really want that, since you already have your own mod. Luckily, there's a folder named base_clean/ too. Rename that folder to base/ and put the old base/ folder somewhere else. Now this base_clean/ also contains a mod, but don't worry, it's the simplest mod imaginable, it's just the vanilla raws and an empty base.pm file. Just replace those vanilla raws with your own raws (objects/ to objects/, graphics/ to graphics/), and you've already almost ported your mod to Blast. There's only one step remaining, and that's to check for special characters, namely curly braces, semicolons and @ symbols, which have special functionality in Blast. You'll probably only need those for comments or [TILE:] definitions, so it should be really easy to remove them or replace them with their ANSI code symbols 123, 125 or 32 respectively. That should be perfectly enough for any mods that work without a launcher, which is all the mods except Masterwork DF as of the time of this writing. Now if you want to compile your mod, just run blast.pl or blast.cmd, and it will build all your raws from your base.
- How to make a mod with Blast
You have four choices when making new mods with Blast:
1) Making a standalone mod, starting with Vanilla files:
Pick either base/ or base_clean/ as a starting point. Rename your choice to base/ and start modifying its contents. If you choose base_clean/, you'll get totally unmodified Vanilla raws to work with. If you choose base/, you'll have a Blastified version of the vanilla raws, which will evaluate to (almost) exactly the vanilla raws when compiled, but the uncompiled raws will look quite different and are structured to make modifying them easier.
2) Making an extendable mod:
Same as step 1, but this you'll want to follow the guidelines on how to make mods extendable, see below. It's probably easier for you if you start with base/, since base/ is already written to be extendable.
3) Making a compatible Vanilla extension:
Write an add-on to base/: Copy and rename the clean/ add-on in the addons/ folder and start editing it. See the how-to on writing add-ons for more details.
4) Making a compatible extension to an extendable base mod:
Write an add-on to the mod you want to extend: Same as step 3), but you want to make sure that your base/ is the mod you want to extend. See the how-to on writing add-ons for more details.
- How to compile your mod
Just run blast.pl or blast.cmd, and everything gets compiled automatically and a new raw/ folder is built from scratch. Compilation information and any warnings or errors will be written to the console (if you're running from console), and also to blast_log.txt in case someone asks you for an error report.
- How to use a template
The basic template call syntax is {IDENTIFIER;ARG1;ARG2...}. This will call the template named IDENTIFIER and pass it all the ARGs. The template does something with those ARGs (and maybe with some internal memory too), and it will return a string that is put in place of the template call. Note that leading and trailing whitespace in the ARGs is ignored, so you can nicely format template calls with lots of argument. Note that ARGs are allowed to contain template calls themselves, and the argument list will not be split by semicolons that are in such template calls. Note that the internal templates are not parsed when passed in arguments to the surrounding template, so the surrounding template may decide for itself when, where and how often to parse those internal templates.
Look at blast_doc/templates.txt to see a documentation of the standard templates included in Blast.
- How to define a template for your mod
There are two ways to define templates for your mod. The first way is to define a Perl subroutine in base.pm (or addon.pm if you're writing an add-on), and to register it to Blast. Here's an example base, containing exactly one template definition:
package base;
my $adventure_tiers = 0;
sub newAdventureTier {
$adventure_tiers += 1;
return "[ADVENTURE_TIER:$adventure_tiers]";
}
$TEMPLATES{'#ADVENTURE_TIER'} = \&newAdventureTier;
1;
There. We assigned a reference to a subroutine into %base::TEMPLATES, under the name of "#ADVENTURE_TIER".
This template we defined here is now available in your base as {#ADVENTURE_TIER}. Every time this template is called, it will be given the parameters that the template call comes with, split by all semicolons that aren't contained in any internal braces, and is expected to return a string it will be replaced by. This template, as we defined it now, ignores all parameters and just returns a new [ADVENTURE_TIER:X] tag with the next higher number than the previous call, starting with 1. The # at the start of the template name indicates that it is a post-template, which means that it is called in the last phase of assembly, after all pretemplates and main templates (those without a # at the beginning) have already run.
Note the lines at the beginning and end of this file. The first line sets the file's namespace, which should be "base" for the base mod, and NAME for an add-on called NAME. That final line there tells Perl that this file was run correctly.
Let's see this in action. Here's an example situation.
...
[ITEM_IMPROVEMENT_MODIFIER:RINGS_HANGING:64]
[ITEM_IMPROVEMENT_MODIFIER:BANDS:384]
[ITEM_IMPROVEMENT_MODIFIER:SPIKES:384]
{#ADVENTURE_TIER}
[FRIENDLY_COLOR:1:0:1]
[DEFAULT_SITE_TYPE:CAVE_DETAILED]
[LIKES_SITE:CAVE_DETAILED]
...
Now let's see what it evaluates to after being run through Blast:
...
[ITEM_IMPROVEMENT_MODIFIER:RINGS_HANGING:64]
[ITEM_IMPROVEMENT_MODIFIER:BANDS:384]
[ITEM_IMPROVEMENT_MODIFIER:SPIKES:384]
[ADVENTURE_TIER:1]
[FRIENDLY_COLOR:1:0:1]
[DEFAULT_SITE_TYPE:CAVE_DETAILED]
[LIKES_SITE:CAVE_DETAILED]
...
Useful, don't you think? Makes you stop needing to worry about adventure tier collisions. Imagine all the stuff you can make much more easy with this mechanic.
The other way to define templates is simply to use the TEMPLATE template, defined in the standard library. This method doesn't require any knowledge of Perl, but it is substantially less powerful. It is mainly used to write short macros, which are still insanely useful as automated copy-pasting (and it's much easier to make changes too). Let's see an example of this:
[OBJECT:ITEM]
{!TEMPLATE;@@FOOD;id;name;value=2;
[ITEM_FOOD:%id]
[NAME:%name]
[VALUE:%value]
}
{@@FOOD;@ITEM_FOOD_SANDWICH;sandwich}
{@@FOOD;@ITEM_FOOD_BAGEL;bagel;3}
{@@FOOD;@ITEM_FOOD_BURGER;burger;4}
There. This is a whole preraw file which works perfectly. First thing to note is all the @ symbols. These get translated to namespace identifiers in the first stage of compilation, and they are basically shorthands for namespaces. Single @ symbols will expand to a prefix unique to the base/addon the file belongs to, double @ symbols will expand to a prefix unique to the file they are in, and triple @ symbols will generate a completely unique pseudorandom prefix, which seems kinda useless, but it's there if you need it. But that's not what's interesting here.
What interests us more is the template definition. The Blast standard library provides a !TEMPLATE template which can actually make other templates inside the preraws. The ! signifies that it is a pretemplate, which means that it is run in the first stage of processing, before all other templates without a ! at the beginning of the name. This {!TEMPLATE;...} call defines a new template called @@FOOD (actually, it's called base__item_food_moar__FOOD, but we don't need to know that), which takes three named parameters, inserts them into a chunk of raws, and subsequently spits out those raws. One of these parameters even has a default value.
The three other template calls all call the newly defined template @@FOOD, and they return a complete food item definition each! Let's see what this file turns into after Blast is done compiling:
item_food_moar__base
[OBJECT:ITEM]
[ITEM_FOOD:base__ITEM_FOOD_SANDWICH]
[NAME:sandwich]
[VALUE:2]
[ITEM_FOOD:base__ITEM_FOOD_BAGEL]
[NAME:bagel]
[VALUE:3]
[ITEM_FOOD:base__ITEM_FOOD_BURGER]
[NAME:burger]
[VALUE:4]
There. Doesn't that look great? The template works precisely like you would expect any macro template to work. All the %parameters are replaced by the arguments, and where there is no argument, the default value is used.
Also, you can see how the '@' expanded to 'base__', so don't get confused if the processed mod doesn't contain any @ symbols anymore.
- How to make a base mod extension-compatible
Non-Blast mods are not very extension-compatible by default, and this should be obvious to everyone who tried to write an extension to a non-Blast mod that included, say, a new item (let's say a new weapon called an ITEM_WEAPON_SWORDCHUCKS). This is because this item is only available to entities that have [WEAPON:ITEM_WEAPON_SWORDCHUCKS] in their raws, but the raws can't be modified from within the extension, which means that you can't add new items to existing entities. But this isn't your normal raws, so Blast makes this entirely possible and easy to accomplish. All the base mod has to do is provide global templates that have an influence on what code is generated in the base raw files, so that the add-on can easily register changes. The possibilities this sort of system generates are boundless, and the flexibility and ease of use of these hook templates depend only on the base modder's programming capabilities.
Let's go back to the ITEM_WEAPON_SWORDCHUCKS problem. Instead of typing up an explicit solution for this, I'll just refer you to the default mod base that comes with Blast, and show you how it solves this problem. It defines two templates very specifically for this situation: {ITEM_CLASS} and {#USES_ITEM_CLASSES}. ITEM_CLASS can register items as certain types with certain qualities, and {#USES_ITEM_CLASSES} can be given a list of types and qualities which will expand to a list of items that fit these types and qualities.
To see how this works and to get an idea of how useful this is, download Blast and have a look at entity_default.txt and the item_*.txt files.
This is the basic idea of making your mod extension-compatible: You provide some templates that can pass data to the base mod, which is later used to generate raw code with a placeholder post-template. In some cases (such as the item problem), you will want to make those post-templates available to the add-ons too, so they can have code generated in their own entities as well.
- How to write an add-on for a base mod
Let's say you want to write an add-on named insertNameHere. First, make sure you have the correct base mod installed. Then duplicate the clean/ folder you can find in addons/, name the copied folder insertNameHere. Put all your preraw files in insertNameHere/objects/ and your Perl templates in insertNameHere/addon.pl (assuming you need some). Note that addon.pl may NOT define global templates, so all the templates you put in %TEMPLATES absolutely must contain an @ symbol in their name, therefore you should use single quotes for your template name if you don't want Perl to mess with the @.
For your convenience, @s will behave differently in base files than in add-on files. In base files, @FOO will expand to base__FOO, and in the add-on insertNameHere, @FOO will expand to insertNameHere__FOO. This is mainly for ease of use of namespaces, but if you want to refer to the local namespace of a specific add-on (let's say otherName), you can write otherName@FOO and it will expand to otherName__FOO, no matter where this @ is. This doesn't really save typing, but it should increase legibility.
Finally, writing an add-on gets easier as the base expands in compatibility. If you're missing some functionality from the base you're writing an add-on to, contact the base author and work it out with them.
- How to write an add-on for vanilla DF
Follow the steps above for writing an add-on for a base mod, but use the default base/ as your base mod. It has the same content as vanilla DF, but it contains hooks and templates that make extending it easier.
For detailed documentation of all the templates provided by the vanilla base/, look in base/basedoc.txt.