How to find and install a mod (If all you want to do is play a mod, this is the only section you need to read!)
1. Click the "Mods" button on the save slot screen.
2. Select "Browse Steam Workshop" from the list and click "okay."
This will open Steam Workshop in the Steam browser (we've had trouble with using Steam Overlay). It might take a few seconds for the Steam browser to respond.
3. In Steam Workshop, find a mod you like and click on it.
This will open the Workshop page for that mod.
4. Click "subscribe."
You are now "subscribed" to this mod. When you return to the game, the game will try to download and install all subscribed mods.
5. Go back to the game, open the mod menu, click "Browse local Queue", and click "okay."
6. After synching with Steam, the game asks if you want to download your subscribed mods. Click "yes."
Your mod will download and install automatically, then appear in your queue.
7. To play this mod, simply click "Play."
7. If you are the author of this mod, additional options will appear:
Click "Edit" to view the mod's source files on your computer, and "Update" to push your latest changes to to Steam Workshop.
1. Introduction & Terminology for n00bs
So, you want to make a mod for Defender’s Quest. This guide will show you how. First, a warning - there are currently no specialized tools or editors for making Defender’s Quest mods. You’ll be doing almost everything using simple text and image editors.
NOTE: This guide is a work in progress. Many of the sections are stubs and still need to be filled out. Also, mod functionality has not been robustly tested, and might need a few more patches to bring it up to speed. I’ll need some help from adventurous modders to test the limits of the system.
SPOILER ALERT: If you’re poking around in the game’s data files, you will come across spoilers! This guide talks about these files in great detail, so it will also contain lots of spoilers. Play the game first if you don’t want to be spoiled!
1.0 Terminology for n00bs
Feel free to skip this section and refer back to it later as necessary.
You don’t need any programming experience to make a Defender’s Quest mod, but throughout this documentation I will be using some light programming jargon, as well as some terminology specific to Defender’s Quest. Here’s a quick rundown:
Defender’s Quest Jargon:
TD-RPG: This means “Tower Defense Role Playing Game” and was the original code-name for the project.
Labels vs. Variables: A label is the piece of text that we display to the player in game and is consistent with the game’s theme and story. Often we’ll have an internal representation of that thing in game data that goes by some other name, sometimes similar, sometimes completely different, and often has no relation to the game’s theme, it’s just a mechanical word for our own use. This internal representation is called a “variable.” The following entry is a good example.
Mcguffin: Although Azra’s character class is displayed as “Librarian” in game, her character class is referred to throughout the code and game data as “mcguffin.” This is because she is the “Tower Defense McGuffin”, ie the thing you have to arbitrarily defend.
Unazra: The mysterious sorceress, Tletl-Metzli, was originally named “unazra” while we were coming up with a name for her, and this is what she’s referred to in game data. Her character class is “antimcguffin.”
Gold/scrap: Scrap is the in-game label for money, but in data the variable is simply “gold.” Defender vs. Character: The members of your party are your characters, and the units you place in battle are defenders. This distinction is pretty subtle, but I throw it in as a heads-up for when you see me use one or the other term.
A character is an object that holds a party member’s data, basically, and a defender is the in-battle representation for that character. Azra is also a “defender” in this sense.
Creature: In battle, the word “creature” means either a defender or an enemy. So, when I say something like “creatures can take damage” I mean, “defenders or enemies can take damage.” Casual/Normal/Advanced/Extreme: The battle challenge labels are “casual”, “normal”, “advanced,” and “extreme,” but internally the variables are “casual”, “easy”, “medium,” and “hard.”
Alternate Mcguffin: In the final battle, Zelemir shows up as a support character and alternate target for the enemies and is thus an “alternate mcguffin.” When Unazra shows up, she is sometimes an alternate mcguffin (the final sidequest) but usually simply a substitute mcguffin for Azra.
String: Some text, i.e, a ‘string” of letters, numbers, or other characters between quote marks. Not the stuff you tie up packages with.
Examples: “this_is_a_string”, “this is also a string”, “aNdIAmaStringT00!!!11110mgroflcopter”
Boolean: A value that is either true or false.
Byte: Eight “bits” of memory, where a bit is a number that can store only a zero or a one. A byte can store any number between 0 and 255, or 256 values in total.
Hexadecimal: Regular numbers are base 10, so “10” means “ONE ten + ZERO ones.” Binary numbers are base 2, so “10” means “ONE two + ZERO ones.”
Hexadecimal numbers are base 16, so “10” means “ONE sixteen + ZERO ones.” Since you can go higher than ten for a single digit in Hexadecimal you need extra characters to display those values. So, you use letters of the alphabet. “A” means ten, “B” means eleven, etc, up to “F” which means fifteen. So, “1B” in Hexadecimal means “ONE sixteen + ELEVEN ones,” or 27 in decimal.
The only reason I go into this much detail is because color values are often expressed in Hexadecimal. So, on a computer, a single pixel on the screen is defined by three numbers, each specifying the amount of red, green, and blue light. These three values are the red, green, and blue color “channels.”
Take the color magenta. On a computer, magenta is made by mixing the maximum amount of red and blue light, with no green light. So, one byte (0-255) is used for each color “channel.”
Magenta = Red(255) + Green(0) + Blue(255). In Hexadecimal, 255 is written as “FF”. (FIFTEEEN sixteens + FIFTEEN ones) = (15x16 + 15) = (240+15) = 255.
So Magenta = Red(FF) + Green(00) + Blue(FF).
Usually you stick those three bytes together: FF00FF, and to let the computer know that’s a hexadecimal number rather than a regular string, you put “0x” in front. So magenta is commonly expressed as “0xFF00FF” in Hexadecimal.
24-bit vs.32-bit color As you might have guessed, the 3 bytes of a pixel equals 24 bits. So, that’s where the word “24-bit color” comes from - 24-bit pixels. So what does “32-bit color” mean? Well, sometimes you want pixels that are partially transparent. To do this, you add one more “channel,” the “alpha channel,” where alpha means transparency. In a 32-bit pixel value, the first byte is the transparency value, where 0 means “fully transparent” and 255 means “fully visible.”
So 0xFFFF00FF would be completely visible magenta, and 0x88FF00FF would be half-transparent magenta, and 0x00FF00FF would be completely invisible magenta, the same as not drawing anything at all.
Throughout the mod data, if you see me using only six letters for a color, (not counting the “0x” prefix) then I’m using 24-bit color and you don’t have to worry about transparency. This is the RGB format - the first byte is red, then green, then blue. If I’m using 8 letters for a color, it’s in a place where I need transparency, so I’m using 32-bit color. This is the ARGB format - the first byte is alpha (transparency), then red, then green, then blue.
........ Creating Your First Mod
Before we get into anything fancy, let’s start by making a really simple mod.
Start Defender’s Quest and click “start.”
Click on the “Mod” button in the lower right hand corner.
Select “create new mod”
Enter a name
Wait for the files to export
Close Defender’s Quest
What’s happening: Defender’s Quest comes with a set of default assets and data embedded into the game itself. When you create a mod, it exports all of this information as loose files that you can modify. Then, you can load these changed files back into the game as a “mod,” or modification.
When the export is complete, it will display where you can find your new mod’s containing folder on your computer. This is the mod’s “root” directory, and we’ll refer back to it throughout this article.
Now that there’s a folder for it, here’s the basics of modding:
Go to your mod’s root directory on your computer
Change some of the files
Start Defender’s Quest
Click on the “Mod” button
Select “load existing mod”
Select your mod’s root directory
The game will load in all those assets, then restart the game. This time, it will be using your data instead of the game’s default assets. That’s the basics of creating a mod!
........ File System Overview
Mods are simply a collection of data and graphic files organized in a certain structure. When you’re running a mod, any time the game needs a certain asset it will first look in your mod for the file. If it doesn’t find it, it will revert to the default version of that file.
Example:You can create a valid mod that consists of nothing but a single sprite sheet graphic of Azra with a blue dress instead of a purple one. When the game looks for Azra’s spritesheet, it will load your changed version, and Azra will have a blue dress in battle. Whenever the game looks for anything else, it won’t find the file in your mod, so it will use the default version of that file instead, so your mod will be exactly the same as the normal game, except Azra will have a blue dress.
When you export a mod for the first time, you can specify how much data you want to include. Since large graphic files can take a long while to export (particularly cutscene and background assets), if you don’t feel like changing those in your mod, it’s best to stick with just data, or just data and sprites. If you later decide you do want to make changes to those heavier graphicd files, you can always add them later, but you’ll need to get the filenames and folder structure right. In this case it’s best to do a separate full graphics-and-everything export to a new mod folder with a different name, and then copy over the missing assets. This way, you can avoid overwriting your existing work.
Below is the structure of a fully-exported mod that contains all the game’s data.
The root directory contains:
These folders: cutscenes/ ← cutscene data, graphics, and effects fonts/ ← bitmap fonts gfx/ ← all non-cutscene graphics maps/ ← level data & image maps tables/ ← .csv tables for character classes, etc
These files: data_bonus.xml ← bonus challenge levels data_credits.xml ← credits list data_defender.xml ← defender classes, colors, spells, animations data_defender_skills.xml ← defender skill trees data_effects.xml ← effect animations (damage, bleed, etc) data_enemy.xml ← enemy stats, animations, attacks, etc data_enemy_plus.xml ← New Game+ enemies data_fake_save.xml ← save file for “test” games data_game_progression.xml ← triggers, quests, plotlines data_game_progression_demo.xml ← same, but for the demo version data_heroes.xml ← hero character start information data_hotkeys.xml ← hotkey layouts data_items.xml ← items: weapons, armor, skulls, etc. data_journal.xml ← journal entries data_journal_style.xml ← journal formatting data_names.xml ← name bank for random names data_recruit.xml ← starting recruit information data_tips.xml ← tips for the tips menu settings.xml ← information about this mod
cutscenes\scripts.xml ← cutscene scripts cutscenes\scripts_demo.xml ← same, but for the demo version cutscenes\puppet_shows.xml ← “puppet show” scripts (animated sprites) cutscenes\backgrounds\ ← background art for cutscenes/towns cutscenes\characters\ ← character art for cutscenes cutscenes\characters\light\ ← lighting effects for characters in cutscenes
maps\index.xml ← game index (very important!) maps\index_demo.xml ← same, but for the demo version maps\<level_id>.png ← image map for level maps\<level_id>.xml ← data file for level
tables\exp.csv ← global character levelup table tables\recruit.csv ← new recruit cost table tables\<class_name>.xml ← character class stats table
Next, we'll dig into the various data files and explaining how they work.
2. Core Data Files and INDEX.XML
As you can see from the previous section, there’s a lot of data files! Fortunately, the most important data is in only a few of them. These are the “core” data files, and they’ll be the ones we’ll talk about first.
This tag specifies which kinds of tiles are considered “legal” for defenders to stand on. To add new types of legal terrain, just add a line like the one below in between the opening and closing tags for “legal_terrain.”
If you add a tileset with a corresponding filename, and then use it in a battle, defenders will be able to stand on it.
The “id” attribute in the tag is a “reference” to a specific tileset. When you reference an id like this somewhere in the data, the game will expect to find a correspondingly named file in a specific location.
In this case, by mentioning “yellow_brick_road” as a legal tileset for defenders to stand on, the game will be looking for a corresponding graphic asset called “tile_yellow_brick_road.png”
If you pop on over to the gfx\tiles\ you’ll see a lot of graphics files. This is where the different tilesets you’re referencing are stored. We’ll get back to creating battle maps later, this is just a quick aside to show you how referencing works.
Anyways, back to index.xml.
Overworld Terrain (tilesets)
After the <legal_terrain> tag, you’ll see a <tiles> tag.
These are the tilesets used for the overworld. The default=”dirt” attribute in the opening tag specifies what the bottom-most tileset is.
NOTE: The dark=”grey_dirt” attribute is no longer used, it’s an artifact from when we used to have a light-world / dark-world kind of thing going on that we later scrapped.
Within the <tiles> tag are a list of <tile> tags. Each of these specifies a pixel color in hexadecimal format (rgb), a tile id (value) and a layer number (layer). So, in this example, the overworld has a dirt layer on the bottom, then sand, then grass, then water, then black_stone, then creep, then sewage. All of the tilesets for these layers can be found in gfx\tiles\, but unlike normal battle tiles they start with the prefix “tile_overworld_” instead of just “tile_.” So the overworld grass tile will be “tile_overworld_grass.png.”
The overworld is created by looking up several image maps and turning them into tile layers. These image maps are stored in the maps/ folder, and have the format overworld_<tile_id>.png
So if you go to that folder, you should find files like overworld_sand.png, which specifies where all the sand is. The game will look for pixels that match the value in the corresponding <tile> tag, so for sand, it’s a kind of dark yellow (0x808000). Any other pixel value in that file is treated as empty space.
When designing the overworld, I usually have one master .psd file setup with each tileset as a separate layer, each set to “lighter color” so that the pixel color shows through and the black becomes transparent. This way I can see how the layers will look stacked together. When I’m done, I save each layer as a separate png.
........ Overworld Features
The next tag is <features>. This is a collection of specific art pieces that are placed around the overworld, and is used for things like towns, the cliffs surrounding the pit, the coliseum, the desert fortress, etc.
Here’s an example: <feature shown="true" id="pitwalls_nw" _x="0" _y="0"/>
This defines a feature, with the id of “pitwalls_nw” at location (0,0) - the top-left corner of the map, and makes it visible (“shown”) by default. The game will look for a corresponding piece of art, feature_pitwalls_nw.png, in the gfx/tiles folder, when it tries to draw the overworld.
Features can be modified by game triggers - specifically, their visibility can be changed. For instance, the town of Karsk is burned to the ground early in the game. This is accomplished by starting the game with two different versions of the town’s graphic feature, one visible, and one invisibile.
After Karsk is burned in the story, its associated map pearl is disabled, the first feature is hidden, and the second one is shown. We’ll get into how to do that when we cover map triggers.
You’ll notice that there is an “@a” appended to both of the above id’s. If you just want to place a feature down somewhere, you just give it the same id as the graphic you want to show (without the “feature_” prefix), so in this case, you could just have written id=”karsk”.
However, if you need to target that feature with a game trigger later on, you’ll want to give it a suffix starting with “@.” This is because you might have multiple features of the same basic graphic id, and you need to differentiate between which one you want to target. The “@” symbol is used as a separator between the id and suffix in this case.
I think you can use just about anything as the suffix, but I would stick to single-character lowercase latin letters just to be safe.
By default, features will be drawn above tileset terrain but below “map pearls” (the shiny red, blue, purple, and yellow spheres that specify locations) as well as the small white dots that connect them. If you want to draw a feature above these things, set the “over” attribute to “true.”
This draws the stairs and gate for the monastery above the connecting map dots.
NOTE: For boolean values in data files to work correctly, make sure you ALWAYS do it like this: <tag boolean=”true”/>
Ie, all lowercase, one word, spelled out as “true.” Never use “TRUE”, “True”, “trUe”, or “1”. None of those will work. Also, for any boolean attribute in an XML tag, if you don’t specify any value, it will be the same as setting it to false.
So this: <feature shown=”true” id=”mountain_gate@A” _x=”533” _y=”318”/>
Is exactly the same as this: <feature shown=”true” id=”mountain_gate@A” _x=”533” _y=”318” over=”false”/>
Finally, sometimes you want to draw a feature that is sometimes visible and sometimes not depending on where the user is on the map. This is a great way to make ceilings for caves and large buildings - we use this for the desert fortress, for instance. Here’s how you do it:
Setting “touch_hide” to “true” means that when the map marker (Azra’s overworld sprite) is at a certain location, the feature will be shown, and when it’s somewhere else, the feature will be hidden. You enter data for “show_range” the same way you specify a range of pages to be printed on a printer, using numbers separated by commas and dashes.
The above example will show the feature when Azra is on any pearls between 15 and 28, as well as 48, 49, 50, and 54. These happen to be all of the pearls inside of the desert fortress, so the user sees the ceiling disappear when they go “inside” and re-appear when they leave.
The high-numbered pearls added to the end are the sidequests and special locations that were added in the New Game+ expansion, after #’s 29-47 had already been defined for other purposes outside of the fortress. We’ll touch more on this when we get to game_progress.xml and triggers.
........ Map Pearls
“Map pearls” represent locations on the overworld that you can visit. All of the pearls are listed in the <pearl_data> tag.
Here’s an example: <pearl id="0" level="The Half-Way World" level_id="1_1_where_am_i" description="Lost and alone, $MCG finds herself caught between life and death." _x="70" _y="90" _type="battle" />
Let’s spell out the relevant attributes:
id=”0” ← numerical id, reference level=”The Half-Way World” ← title displayed to the player level_id=”1_1_where_am_i” ← string id, alternate reference description=”Lost and alone...” ← description displayed to the player _x=”70” ← x coordinate on map _y=”90” ← y coordinate on map _type=”battle” ← whether this is a battle, town, etc.
NOTE: You’ll notice that the x, y, and type attributes all have a leading underscore, “_”. Don’t leave this off! It’s required for map pearls.
I’m unfortunately not consistent about this. In other places you’ll find x/y attributes without the underscore - but whatever format I’m using in a given place, you should follow the same, as that’s what the game will expect.
The reason I used an underscore is that there are a lot of variables in the game called “x” “y” and “type”, and I wanted to avoid tripping up against those reserved keywords in the code when I accessed them from the XML. On second thought this probably just made thing more confusing, but the game engine expects it now, so there you go.
There are two ways that levels get referenced - by numerical id, and by string id. The first level’s numerical id is 0 (zero), and it’s string id is “1_1_where_am_i.” Both of these will be used in different locations to refer back to this pearl. For instance, the “touch_hide” attribute of overworld features that you read about in the previous section uses numerical id’s to specify specific map pearls.
The string id can be anything, as long as it’s unique and you use it throughout the game. Originally, the string id’s were supposed to describe the act and “scene” of the level, as well as its title, but over the course of development we changed the number of acts from 4 to 7, and changed many of the titles.
However, by that point we already had a bunch of other data file hooked up already and referencing the old string id’s, so it wasn’t worth the risk of changing everything. So that’s why levels in act 7 are named things like “4_1_blah_blah” and the last level is “12_4_final” (we didn’t originally know how many acts we would have, so when I created the final level way in advance I put in the far-flung act “12” scene “4” - way more than we would need. Again, confusing, I know.)
Okay, whatever. On to explaining things.
There are several kinds of pearls you can put on the map. Here are the legal values for “_type:”
“battle” ← A normal battle. Default color is red. “place” ← A non-battle location. Usually means “town.” Default color is blue. “sidequest” ← Special battle type. Default color is purple.
There are some extra optional attributes you can specify, too:
button_text lets you specify exactly what goes on the button. The default for battles is “BATTLE” and the default for towns is “TOWN.” Sometimes, you might have a “town” location that’s not really a town in terms of story, such as Ozimal’s prison or the Dragon’s lair. This is how you specify an alternate name.
sub_type is currently only used for the hermits in NG+. The only value it recognizes is “upgrade” and I think that’s what makes it turn the pearl gold instead of blue.
optional is used to flag a battle as not required to beat the game. This way, NG+ will be unlocked even if you never play this battle. We only use this for “The Way Out” in the default campaign.
suppressed keeps a pearl from showing up on the map, even if it’s been unlocked in game progress, etc. We use this to temporarily hide a feature we’re not quite finished with yet that we can release later, but still have the triggers for it work correctly. When we remove the suppression the location will automatically appear in save files that have fulfilled the requirements for showing it. I doubt you’ll ever have to use this.
Now, just setting up all your pearls in the index file will not make them appear on the map. By default, all pearls are invisible and none of them are connected to one another. Triggers in data_game_progression.xml will do all of the work of making pearls appear as you beat battles, which we’ll get to in a minute.
The next few sections, <battle_screen_data>, <overworld_data>, and <party_screen_data>, contain tutorials that show up in those various screens. We’ll skip those sections for now and come back to them later, when we cover tutorials in general. For now, scroll down to the <town_data> tag.
You can usually buy weapons, armor, recruit characters, and trigger sidequests from towns. Here’s an example of a typical town:
This is the entry for the monastery. The “id” attribute is the string id for the town (used to reference it throughout the game), and the “name” attribute is what’s displayed to the player on the town screen.
Inside the opening and closing tags for the town, there are various sub-tags.
Equipment for Sale
First, there’s a list of weapon tags, one for each type of weapon offered.
This town sells swords, specifically swords level 2, 3, and 5, which you can look up in data_items.xml - these are “Metal Shiv,” “Rusty Sword,” and “Iron Sword”, respectively. The “lvl” attribute specifies which items are available in the normal game, and “plus_lvl” indicates what’s for sale in NG+. (An item’s “level” is simply a unique numerical id). If no weapon tags are found, the town will not show the “weapons” button.
Prices are set in data_items.xml, and are always the same for every town, since the price is tied to the item, not the store. Armor is handled exactly like weapons, except you start with the word “armor” instead.
These tags are pretty self explanatory - they simply mention which defender classes can be recruited here. If none are found, the town will not show the “recruit” button.
Next, we have the “talk” tag:
All this does is specify the string id of a cutscene (defined in cutscenes/scripts.xml) to play when the button is pressed. Cutscenes are one of the many events that can set off a trigger, and in data_game_progression.xml we’ve set it up so that watching one of these cutscenes will unlock the corresponding sidequest on the map. We’ll show you how to do that later.
Just setting up the talk tag is not enough to make the talk button appear in a town, because it is disabled by default. You must also specify a trigger through data_game_progression.xml that “unlocks” the town cutscene. In the default campaign, we use this to make these town cutscenes only appear in NG+ mode, and often only after you’ve visited a town for the first time.
We’ll talk more about this when we get to progress and plot triggers.
By default, towns will look for an art file that matches their string id in the cutscenes/backgrounds/ folder, with the prefix “back_”. So the town with the string id “ghost_town” will look for a background file named “back_ghost_town.png” You can also specify a specific file if you want, however:
Next, we had a specific situation in the Treasure Chamber with the special sword, “Evni.” This is the only unique item that is ever sold in a store (you can set an item as unique in data_items.xml). When an item in a store is “unique,” it will not show up for sale if it detects you already have it in your inventory. However, in NG+ you can upgrade Evni, which basically just deletes the old Evni and replaces it with Evni+, which is actually a different item as far as the game engine is concerned. So, it was possible to buy Evni, upgrade it to Evni+, then go back and buy Evni again!
To fix this, we added the following tag to the dragon’s lair:
So, this extra tag will not show sword #13 (Evni) if you already have sword #19 (Evni+). For those of you less experienced with XML, note that the <weapon> tag has been split into an opening and closing tag. If you are not adding children to a tag, you usually end it with a “/>” rather than a “>”.
The following examples are equivalent:
<weapon attribute=”blah” thing=”whatever”/> (open and close the tag on one line)
<weapon attribute=”blah” thing=”whatever”> </weapon> (open and close thetag in two lines)
However, the second example lets you add child tags, such as <dont_show/>, which we’ve done above.
Special Case 2: Hermits and Upgrades
Here’s an example of one of the “Hermit” towns in NG+, where you can upgrade unique items for better ones.
I believe all the hermit towns in NG+ are identical except for backgrounds. What’s special here is that we have two new attributes: upgrade and replace.
If upgrade is set to “true”, then the store instead becomes an upgrade shop rather than a normal store. Rather than looking for the lvl tag to see what’s for sale, it interprets the content of the lvl tag as items that it can upgrade for you. Since hermit towns only show up in NG+ for the default campaign, we of course use plus_lvl in this case. (Theoretically you could put upgrade shops in a normal mode game, though I’ve never tested that).
So, if you have any of the swords with a level equal to 4,6,8,10,12, or 13 (all the unique swords in data_items.xml), they will show up in the store. It will only show the items on the list that are actually in your inventory. In the default campaign, upgrades cost skulls, but this is handled in data_items.xml rather than here- we just fiddle with the price settings for the upgraded versions of the items. And as you can guess, the “replace” attribute specifies which items the store will offer as upgrades for the original list. The order of both lists matter!
<weapon type="sword" upgrade="true" plus_lvl="4,6,8,10,12,13" replace="14,15,16,17,18,19"/> This means that sword 4 becomes sword 14, 6 becomes 15, 8 becomes 10, etc. We’ve set things up so that 4 is Blood-Feud Kopal and 14 is Blood-Feud Kopal+, etc, so it feels like you’re “upgrading” the item.
Technically speaking, you could just use this as a way to swap one item for a completely different one, and use scrap instead of skulls, but again, we’ve never tested using the system in that way. Also, I’m not sure if this system will work with non-unique items, there might be some code in the engine that specifically expects things to be unique.
Special Case 3: Strange Monument
This town is unlike any of the others, in case you couldn’t tell :) This is an unfinished feature that we’re still working on, so I won’t waste any time writing about it right now as it could change in the future, and it’s suppressed in the game anyway for now.
And just to be clear, the code sequences are redacted on purpose, in my version of the data they actually have meaningful information there, the engine just scrubs that out on export so that modders wouldn’t spoil the secrets before the feature comes out :)
........ Battle Rewards
The next tag in index.xml is <reward_data>. This is where you specify what rewards the player gets for beating battles on different settings. First off, let’s talk about the various challenge levels. Although they’re displayed in-game as Casual, Normal, Advanced, and Extreme, internally they are called casual, easy, medium, and hard.
This is because the internal names came naturally to us as programmers, but we later wanted to give better signals to players about where they should start, and we were afraid that if the default difficulty setting, “Normal,” were instead displayed as “Easy,” some players would be tempted to skip it right away (and get their butts kicked). That said, the internal references are casual, easy, medium, hard, rather than what you see in-game.
Here’s another place where I’m not always consistent - in some places I use “med” for medium and in others I spell it out as “medium.” Just follow whatever standard I’m using in a given file and location. In most places in the engine I treat “med” and “medium” as synonyms, but I can’t guarantee that.
With that out of the way, let’s look at how these work.
This is the third battle in the game. diff means difficulty, or the challenge level, win_type is the reward’s particular victory condition and can be either “normal” or “perfect”, type means the kind of reward, and value is generally a number if xp/gold, or a specific item id if the type is “item.”
You’ll notice there is no entry for “casual.” Casual rewards are automatically generated, and are always half the reward for “easy” (ie, normal). We never reward anything other than gold or xp for “easy” challenges, so rewarding an item for easy challenges will probably cause the casual reward to break because it assumes a numerical reward it can copy and cut in half.
You’ll also notice that the most basic reward, beating the level on “easy” with win_type “normal” (ie, just passing without a perfect) will reward “progress” with no value given. This is a special value that technically does nothing by itself, but will display to the user that beating the level will unlock the next location on the map. Actual map progression/unlocking is handled in data_game_progression.xml.
These are the legal values for “type”:
type=”progress” value ignored type=”xp” value = amount of xp type=”gold” value = amount of money type=”item” value = item type, level, and amount type=”finish” value = cutscene to display type=”finish_puppet” value = cutscene + puppet show to display
So, progress, xp, and gold are pretty simple to understand. “item” bears a little explaining. The correct format is “<class>_<type>_<level>_<count>”. First is the item’s class. There are two item classes: weapons, and armor. Every item is in one of these two classes, even weird things like books (technically classified as weapons) and skulls (technically classified as armor). Next is item type, which is a word like “sword”, “bow”, “skull”, “light” (for light armor), etc. Next is item level, which is just the item’s numerical id. Finally, the last underscore and value is optional and specifies count, or how many copies of the item to give.
So, this would give 3 stone shivs to the player: type=”item” value=”weapon_sword_1_3”
And this would give 1 Brigandine: type=”item” value=”armor_heavy_10”
Books and skulls are special cases that don’t behave like normal items in terms of how they’re equipped, but they can be awarded just like any other item. More on this later.
Next, let’s talk about the “finish” and “finish_puppet” values you can specify as a reward. This is how you specify an end-of-game cutscene. So, for pearl #36, ie, “The Way Out,” instead of awarding “progress”, just beating the level ends the game with the cutscene “ending_4_6_outro.”
For the final battle, the reward is “finish_puppet” which means, don’t just play a cutscene, but also play a puppet show. A “puppet show” is a short animated sequence using sprites. We currently only use this for the final sequence where Zelemir and/or Bakal permanently cross over to the “other side” to confront Eztli-Tenoch. We’ll go into how puppet shows work and are specifically triggered later, for now, just know that in terms of setting a reward it’s basically the same as triggering a cutscene.
What’s more relevant is how to trigger different ones depending on the outcome of the battle. Right now this is set up specifically to deal only with the situation we coded where you have a final battle with a mcguffin (Azra) and an alternate mcguffin (Zelemir).
<reward pearl_id = "40" diff="easy" win_type="normal" type="finish_puppet" value="ending_zelemir_unscathed|ending_zelemir_wounded|ending_zelemir_dead|ending_zelemir_unscathed|ending_zelemir_wounded|ending_zelemir_dead" /> Let’s unpack that a bit:
At the end we have a really long value string, with six cutscene id’s separated by a vertical pipe character, “|”. These six cutscene id’s are specified in a specific order, and correspond to the six possible outcomes of the final battle. Those outcomes are, in order:
A - Perfect++ (Azra unharmed, Zelemir unharmed) B - Perfect+ (Azra unharmed, Zelemir wounded) C - Perfect (Azra unharmed, Zelemir dies)
D - Passed++ (Azra wounded, Zelemir unharmed) E - Passed+ (Azra wounded, Zelemir wounded) F - Passed (Azra wounded, Zelemir dies)
You’ll notice that there’s only 3 different cutscenes, and the outcomes for A, B, and C, are respectively also applied to outcomes D, E, and F. So basically, in terms of which cutscene to show, this data setup doesn’t care whether Azra gets wounded or not in terms of which ending you get, the only variable that makes a difference is whether Zelemir is unscathed, is wounded, or dies. We could have very easily made six different unique endings with the above setup, but we felt three was enough.
There’s one other possible ending - game over, which only happens if you lose the final battle. The trigger for showing a cutscene on failure is specified in the level data itself, rather than here (don’t ask me why I did it that way, that’s apparently how it’s set up). We’ll cover that later.
This whole example of showing specific cutscenes in response to specific battle outcomes is a hacked-together special case just for dealing with the final level. Generally speaking, if you just want to show a cutscene after beating a battle, or even responding to whether you got a perfect or just a pass, you would do that through generic game progress triggers in data_game_progression.xml, not through crazy reward parameters.
........ Tutorial Levels & NewGame+ Rewards
One last thing - you’ll notice the first two battles only have rewards specified for beating them on “easy.” Whenever you don’t specify “med” or “hard” challenge rewards, it assumes the level is a tutorial, which changes a few things. First of all, it uses the small scroll menu that doesn’t let you choose a difficulty option. Second, it doesn’t display any stars on the map for that level, and it also tells the star-counting algorithm to ignore this level in terms of calculating overall stars earned. (Since no star is shown on the map, no star is counted for this level).
Be careful - the game is only set up to handle battles with a full set of rewards, or ones that only have “easy” rewards (ie, tutorials). If you specify “med” but not “hard”, or anything else that’s unexpected, the game might choke on your data. Furthermore, we recommend against offering challenge rewards other than simple progress for tutorials because none of that is displayed to the player.
New Game+ Rewards
After the <reward> tags you’ll notice a bunch of <plus_reward> tags. These are exactly the same as the normal rewards, except these are the ones that will be loaded for a New Game+.
And that’s it for index.xml! That’s probably one of the most complicated files in the game, so now we’ll move onto something a bit simpler.
3. Defender Data
Two main files contains all the information that defines character classes, both in and out of battle.
<level_cap> - defines the level cap. Very simple. <class_data> - all the character classes in the game <graphic_data> - corresponding graphics & animations for each character class <color_data> - color sets for recruiting this class <pallete_data> - pallete sets referenced in color_data <swatch_data> - color swatches referenced in pallete_data
<hidden_flavors> - which attack flavors should be hidden* <defender> - entry for a defender and all of their skills
*ie, flavors that shouldn't show up in the interface anywhere, such as "physical", so you don't get nonsense like "Hits and PHYSICALS a single target for 10 dmg."
The "id" value is very important. This is the universal string handle by which you'll refer to Berserkers throughout the game. This has nothing to do with the displayed name, which is specified under "name."
Note: You'll notice that "$CLASS_BERSERKER" looks like some weird code thing rather than the word "Berserker", which is how it appears in game. That's because this is a localization flag. I'll cover that in more details later, but the short version is this: whenever the game sees a localization flag like this, it will replace it with the corresponding definition in the currently selected language. So, in the English localization files, there's a definition for "$CLASS_BERSERKER" which is "Berserker."
The culture tag I believe is ignored, part of some discarded feature we never wound up using.
The graphic id is very important - this string associates this class with a graphic definition which is supplied below the class definitions.
The cost value I believe is ignored, I should remove that sometime. The game looks up the summon/boost costs for each defender from the data tables.
The sex id is ignored, we were originally going to supply both male and female versions of each class but we were barely able to finish the regular set of sprites so we cut the feature.
The equip values specify what kind of items this class can equip. These values should correspond to the type values you define in data_items.xml. If a class cannot equip weapons or armor, you should put "none" as the value.
For the range tag, you can specify minimum & maximum range distance. Generally you want the minimum value to be "0" except for when you want a dead zone inside, like rangers have.
You can also specify shape, the legal values are:
"circle" - standard circular range. If min is not 0, will have a dead zone.
"box" - square range. If min is not 0, I don't think it will create a dead zone.
"double_circle" - dual range, like dragons use. Min range specifies boundary
The "type" value I think is just for display purposes in the character class overviews in the interface. The legal values are "ranged", "melee", and "ultimate", and I don't think case matters. I *think* all it does is append "$TYPE_" to the front, and then show the localized text. So I think you could specify your own types, but you'd have to create corresponding localization entries.
The attack tag is definitely ignored. Why is that even still in there? Game design is messy :P
The blurb specifies the text that you see in the recruit screen, as well as various other places where it describes the class. Again, this is localized.
The mcguffin has some extra stuff. First of all, in the equip section her armor is listed as "none" but a weapon_2 value is defined. Azra can equip 2 books, and books are technically classified as weapons. By specifying a weapon_2 value and "none" for armor, it overrides the armor slot with a second weapon slot. You can do the same thing with an armor_2 value, but then you need to set weapon to "none."
Next, the Mcguffin has spells (as does the Sorceror and AntiMcguffin)
num: the spell slot. 6 spells maximum, so values go from 0-5
id: the handle of the spell, should be linked to a skill
cost: the base casting cost of the spell. I think this value is overridden by whatever is in data_defender_skills.xml for this spell
x,y,z: these are three variables that affect various aspects of the spell. Again, I believe these are overridden in data_defender_skills.xml
txt: the description, shown to the player. Localized. The corresponding texts in data_defender.csv will have "$X", "$Y", and "$Z" in them, and will be replaced at run-time with the actual values.
Please note that spells were one of the earliest features coded in the game, and to a large degree are still hard-coded. You can define normal defender attacks in almost any way, but spells are among the least flexible. You can mostly only change and tweak the existing spells rather than come up with entirely new ones. For instance, if you create new spell ids, they might not work at all when you try to cast them as the game explicitly looks for "lightning," etc.
The <graphic_data> tag specifies how defenders look and animate. The class_id should match the definition you have specified in the class tag. So a class with id "mcguffin" should have a graphic id of "mcguffin" and there should be a corresponding graphic with class_id "mcguffin" and so on.
<gfx> tag This tag specifies a graphic FILE. You can have up to two of these, one to specify the hero graphic, and one to specify the generic graphic.
id - "hero" or "generic"
name - the filename. "mcguffin_hero" means "gfx/defenders/mcguffin_hero.png"
width/height - frame size of the battle sprite / icon
big_w/big_h - frame size of the "big", party screen icon
off_x/off_y - offsets to nudge the sprite into place correctly
Then there's a list of animations for each character. First, I'll explain the structure of the anim tag, then what animations are expected for each character.
id - the reference id for the animation.
looped - whether it should loop continuously or just play once and stop
framerate - frames per second
Within the anim tag there will also be a list of frames. These start with an index of 0, and you just list them one by one inside the animation.
For the mcguffin, the following animations are expected:
idle_overworld - plays on the overworld sprite
idle_down - the default idle pose for battle.
spell_down - when a spell is cast
spell_big_down - when a "big" spell is cast
hit_down - when mcguffin is hit
death_down - when mcguffin is killed (don't think it actually gets to play, but should exist)
Notice most end with "_down." That's because in battle, the character's facing is applied to the end of the animation that's supposed to play, and the mcguffin only ever faces down. So the game will tell her to play the "spell" animation, or "spell_big" animation, and then that will resolve to "spell_down" and "spell_big_down", etc.
Antimcguffin and sorceror are just copies of the mcguffin, so their stuff is largely the same. Let's look at the berserker.
The berserker has TWO <gfx> tags, since you can recruit generic berserkers in addition to Slak: <gfx id="hero" name="berserker_hero" width="64" height="64" big_w="130" big_h="130" off_x="-3" off_y="40"/> <gfx id="generic" name="berserker_generic" width="64" height="64" big_w="130" big_h="130" off_x="-3" off_y="40"/>
The only real difference is that two different files are referenced.
Non-mcguffin defenders have a *lot* more animations. They will have four animations for each of their active (attack) skills, with the suffix "_up", "_down", "_left", and "_right", except for special cases like "summon" and "boost" that only ever face down.
Each defender expects these animations:
skillname_(up/down/left/right) (for each skill)
Idle is what they are doing when they're just standing in battle and have no attacks cooled down yet. Ready is what they look like when an attack is available.
"Sweet" frames. The last thing about animations is "sweet" frames. Early on we just had the attacks resolve at the end of the animation, but this looks ugly. You want the hit to happen right when the sword is being slashed, not after the recovery animation. So, we let you specify a "sweet" frame to indicate where the hit should happen.
<frame value="4"/> <sweet value="4"/> <!--this is where the hit is--> <frame value="5"/> <frame value="6"/> </anim>
You put the "<sweet>" tag in with your animation, and give it a value matching the frame you want to be "sweet." I usually write it on the same line as the frame I'm making 'sweet', but you can put it on the next line and it will work the same. Just make sure they're next to each other and the values match.
The way these "sweet" frames are interpreted depends on the attack. You should only specify as many sweet frames as their are hits in the attack. So slash should have exactly one sweet frame, and double hit should have exactly two. If you specify too many or too few, it won't break but it might create weird results. If you don't specify any sweet frames, all the hits will happen simultaneously at the end of the attack.
........ Character Colors
Setting up recolorable sprites
Take a look at this image:
I'm using the head as an example because it's small. In Defender's Quest, all sprites that can be recolored (mostly defenders and enemies) have a vertical row of pixels in the upper left hand corner of the image. When this image is loaded, it scans the first 20 vertical pixels or so to read the image's "pallete" and then deletes those pixels.
When you put a color in this pallete, it gives the game the ability to color-swap these out later. So, open up data_defender.xml and take a look at the <color_data> tag again.
What's happening here is that we're saying the berserker has 12 custom colors in all. When you are in the color customization interface, you can pick a color swatch to set, say, the character's hair, or skin color. What's actually happening is that you are selecting 2, 3, or 4 colors at once - when you click on brown skin, for instance, it's picking a hilight, midtone, and shadow color, and it winds up changing 3 colors on the character.
The "h" "m" "s" and "s2" values correspond to "hilight", "midtone", "shadow", and "shadow2". So any given color swatch can provide 4 distinct color shades.
Each "feature" entry lets you specify a "feature" of the character that can be recolored, and then you define which colors in the master sprite are affected by that.
So, for instance, in the "eye" feature, the midtone value of the selected swatch will replace the color specified in index 2 - the third color from the top of the pallete column in the sprite. Notice the other values are all "-1", which means they're ignored.
For the "skin" feature, the hilight gets put into color index 7, the midtone in index 6, the shadow in index 5, and the second shadow is ignored.
The "pallete" value in the feature references which set of colors is available to the user to choose from for this color feature, and those palletes are defined below this section in data_defender.xml
Features like "outline" and "weapon" are intentionally ignored by the engine, but they might be necessary. If forget why they're there.
Color palletes The palletes are pretty simple to define: you just specify a list of swatch ids. For instance, we have three different palletes which specify the range of skin tones for each of our game's cultures:
The ash have the most diverse range, the quaid are universally pale, and the nomad have a small range of reds, tans, and browns. Fun fact: when you click on the class tabs in the character customization screen, it will generate a random character from a specific culture. So, it will first select ash, nomad, or quaid, and then based on that will select color traits only from those respective palletes. If you hit the "random" buttons it will use the full pallete set available to the user and will ignore cultural limitations (so you can have a quaid name with dark skin, or a nomad name with blue eyes, etc).
Color Swatches The color swatches themselves can be specified, of course.
This is pretty simple. You specify colors in hexadecimal format, and specify values for the hilight, midtone, shadow, and second shadow. You can use photoshop's color picker to give you the hexadecimal values of colors if you want to do this visually.
Skills are at the very heart of defender's quest.
There's two basic kinds: passive skills, or TRAITS, and active skills/attacks, or TECHNIQUES.
Each character will have exactly 5 TECHNIQUES, except for Azra, who has 6 spells that take the place of techniques. Each character also has a varying number of traits, except for Azra, who has none.
Each <defender> tag will reference the class id, and then have a list of <skill> tags.
name - the reference id for the skill. Used all over the place.
type - legal values are "attack" for a technique or "passive" for a trait
posture - legal values are "offense" and "defense" and is mostly cosmetic (red vs. blue)
The sub tags are:
reqs - requirements to unlock
flavor - list of flavors associated with the skill
graphic - associated graphics/animations
graphic_pos - offset values (if necessary)
info - very important, specifies almost everything about the skill
stats - provides a table of stat values for each skill point invested
<reqs> Requirements. "level" specifies which level the character must be at to unlock this skill, "skill" specifies what skill is a prerequisite for this (put "none" if none), and "skill_lvl" specifies how many points you need in the prerequisite to unlock it.
<flavor> Each flavor tag specifies a "flavor" that can be applied to the skill. Flavors modify attacks in various ways. Most skills will have boring flavors like "physical" and "melee" that are (mostly) descriptive. These generally don't do anything special other than identify the source of damage, in case a creature is strong/weak against it, etc. Some attacks, however, have flavors like "chill" and "burn" that do cool stuff.
All flavors specified here are ALWAYS ON for this attack. They may be modified and/or replaced by traits, or by the stats table, but otherwise whatever is specified here will always show up on the attack.
See the "Damage Flavors" section below for more about flavors.
The remaining tags will also be discussed in the following sections.
........ Damage Flavors
One of the central features of the Defender’s Quest battle system is the concept of a damage “flavor.” Simply put, a flavor is some kind of quality associated with damage that does something interesting. The “something” depends on the flavor. For instance, when a creature takes damage from an attack that also has a poison flavor, they will get the “poison” status effect and start taking damage over time.
Some damage flavors don’t normally do anything by themselves, and are only there to categorize the source of the damage, such as “physical,” or “magic.” This is so things like special armor can respond to specific kinds of attacks, etc.
Damage flavors can have various properties, specifically:
flavor (the string id of the flavor, ie, “poison”)
amount (some number, interpretation depends on flavor)
time (number of seconds it will last)
rate (value between 0-1, chance of it occurring)
So, you could have something like this:
When this flavor is applied to an attack, there is a 75% chance that the victim will take 50% of the attack’s original damage every second for 10 seconds. Since flavors can have wildly different effects, the exact interpretation of the various parameters often varies wildly as well. Often many of the attributes have no meaning for a certain flavor (such as “time” for things like “armor_break”) and are just ignored.
Here is a full list of damage flavors and what they do:
burn Damage over time. Just like poison except it mutually cancels with chill/freeze, and is removed if an enemy walks into water. amt=0.25,t=10,rate=0.75:75% means, chance of “Deal 25% of original damage every second for 10 seconds.”
poison Damage over time. see above
ever_poison Just like poison, but always lasts forever. Ignores time value. Not used in game
bleed Multiplies damage of incoming attacks. amt=0.25 means “Damage taken multiplier becomes 125%”
ever_bleed Bleed that lasts forever. Not used in game
blinded Target gets “blind” status, with a reduced chance of hitting their targets. amt=0.75 means “Blinded victim’s chance to hit = 75%”
disease Target can’t regenerate while diseased. Not used in game
inspire Target gets “inspired” status, dealing additional damage with every hit. NOTE: This flavor only goes on “healing” attacks that healers target defenders with. amt=1.10 means “Damage given multiplier is 110%”
inspired_hit This flavor is automatically applied to the attacks by defenders who are currently “inspired.” Behaves very much like a critical hit. The status effect sets the rate for this flavor to 1.0. amt=1.10 means “Damage given multiplier is 110%” time = ignored
stun Target can’t move. Exactly like freeze, except nothing cancels it.amt = ignored, time = duration
single_stun Exactly like stun, but can only be applied to a given target once per battle.Not used in game
chill Slows a target by a specified amount. Canceled by burn. amt=0.4 means “Target’s speed becomes 60% of normal”
slow Slows a target. Just like chill, except nothing cancels it.
freeze Exactly like stun, except canceled by burn.
light Only affects “dark” enemies. It temporarily removes their shroud, making them easier to hit, and causes the attack with this flavor to deal more damage (again, only vs. dark enemies). amt=1.2 means “Deal 120% damage against dark enemies.”
area Descriptive, does nothing by itself All area effect attacks, as well as splash regions of splash attacks, have this flavor.
magic Descriptive... Ice mage and healer attacks have this flavor, as do all of Azra’s and all enemys’ spells.
physical Descriptive... All attacks that aren’t magic have this flavor.
melee Descriptive... This flavor triggers counter-attacks and porcupine damage.
ranged Descriptive... All arrows
physical-ranged Descriptive... Rather than have the game check against things “physical” and “ranged” separately, we just created combination flavors for when we wanted to check for something specific. Worms in NG+ have a high rate of dodge versus this flavor, which basically means “arrows.”
undodgeable Makes the target skip their evasion check when resolving this attack. All parameters are ignored
reduce_health Used in Zelemir’s “decimate” spell. amount=0.9 means “reduce health to 10%” It reduces you to exactly that, and if you are below that amount, it will not do anything. Ie, this attack can’t kill you by itself.
armor_pierce Ignore a certain amount of armor when calculating damage. amount is multiplied against the attack’s damage to get the number of armor points ignored. So 100 DMG + armor pierce(amount=0.4), will ignore 40 points of armor.
armor_ignore Ignores armor altogether. All parameters ignored.
armore_break Removes a certain amount of armor permanently. amount of armor removed calculated the same way as for armor_pierce
critical Damage is greater than normal amount=2.2 means “Damage multiplier is 220%”
knock_back Knocks an enemy back by a certain number of map squares. amount=1.0 means “Knock back by 1 square length”. 1 square is 40x40 pixels
auto_kill same as devour, but without the “nom” Not used in game.
devour If target health is below a certain value, it dies immediately. amount=0.1 means “if target is below 10% health, NOM!”
strike_through Attack can pierce (ie, keep going) and hit up to a certain number of targets amount=3 means “can hit up to 3 targets”
de_invincible Removes invincibility from affected target before applying damage. Used in the “right hand” battle, when Zelemir attacks the super cultist - his lightning spell has “de-invincible” applied to it.
psi_burn Reduces the amount of PSI gained from killing affected enemy. amt=0.25 reduces PSI reward from target by (proportional_damage) x (25%)*
*psi_burn is complicated and needs further explaining. Basically, the higher the amount of psi_burn in an attack’s flavor, the less PSI an enemy hit with it will give when it dies.
Azra has lightning with Damage(100) Azra strikes an Enemy(HP = 100, PSI_REWARD = 10) with lightning.
If the lightning has psi_burn flavor (amount = 1.0): Enemy gives 0.0 PSI, all of it was burned away. Lightning dealt 100% of the enemy’s health. Flavor burned up 100% of its PSI
If the lightning has psi_burn flavor (amount = 0.25): Enemy gives 7.5 PSI, 25% of it was burned away. Lightning dealt 100% of the enemy’s health. Flavor burned up 25% of its PSI
If the enemy instead had 200 HP: After one strike, enemy will give 8.75 PSI when it dies. Lightning dealt 50% of the enemy’s health. Flavor burned up 12.5% of its PSI
After two strikes, enemy will give 7.5 PSI when it dies (which is now) Lightning dealt another 50% of the enemy’s health Flavor burned up another 12.5% of its PSI
Damage Flavors vs. Status Effects
Keep in mind, flavors are closely related to but not the same thing as status effects! So, the “poison” flavor gives the corresponding “poison” status effect to anything that attack touches. Likewise, the “inspire” flavor gives the “inspired” status effect to anything that attack touches.
So if you make a sword that has the “inspire” flavor or something, it will make all the enemies it hits become inspired, making them deal more damage to you! Be careful about these things :)
........ Attack Skills, "Techniques", part 1
Attack skills, or "techniques", are the abilities your characters use in battle, and are tied to specific boost levels.
The best way to understand these is to look at how the skills work in the normal game, and then compare that to their definitions in data_defender_skills.xml. These are heavily data driven, so you can do all kinds of crazy stuff here.
There are a few basic components to a technique definition:
info tag - specifies all the basic properties
stats table - specifies stats and properties that change with skill levels
graphic info - specifies how the attack looks
effects - (optional) if it has any sort of effect (usually just for AOE/Splash projectiles)
flavors - (optional) if it has any default flavors
<info> This tag specifies almost all the relevant information for a skill, and unlike the other tags it's not super self-documenting, as just looking at the data files doesn't give you a full picture of everything it can do. This is probably the most important part of technique documentation.
Here are the most important attributes you can specify in the <info> tag. There are others, but they only work when using certain types so we'll discuss them then.
NOTE: If an attribute is not present in the info tag, it's the same as it being present with the value "false"
anim - the id of the animation that plays when this attack is used NOTE: put ":repeat" at the end of the animation to repeat the same animation for each attack
sfx - the id of the sound effect* played when this attack is used
sfx_each - if the skill has more than one attack, play this sfx for each attack instead of the normal sfx. This is timed to the "sweet" frames, if any.
splash_sfx - if a splash attack, the sound effect to play when the splash damage effect is created. Not sure if this is actually used.
sfx_end - the sfx to play for the last attack used. Not sure if this is used?
heal - "minor" or "major". If present, makes the attack a heal technique and minor/major drives what effect to play on healed targets.
type - the skill's basic archetype. See more below.
speed - how fast the attack's collision projectile moves
shape - I'm not sure if this is actually even used
priority - if multiple techs are available, highest priority is used first.
single_target - true:all attacks apply to ONE target. false:spread attacks out over multiple targets
hitall - true:each attack hits EVERYTHING in range. false: each attack hits only one enemy.
random_targets - not sure if this is used?
strike_through - supposed to make attack pierce through multiple targets. Not sure it's used, the preferred way to do this now is to add a "strike_through" flavor.
counter - if true, works as a counter-attack. Attack will launch in response to a melee attack, which is immediately dodged, and triggers this attack.
retarget - true:attack will find a new target if the original one dies while en route.
orthogonal - true:makes the projectile "straighten out" along major axis lines. Useful for piercing attacks
*See the audio section for how to play multiple random variants of the same basic sound effect
"type" is the single most important attribute specified above. This lets you specify the attack's basic archetype, such as ' type="guided_projectile" '.
Legal technique types:
"spell" - the skill is a mcguffin spell
"guided_melee" - basic melee attack (there is no "unguided_melee")
"guided_projectile" - basic projectile attack, has "homing"
"spread_projectile" - spreads out multiple shots in one burst, no homing
"unguided_projectile" - unguided projectile, no homing
"heal_attack_all" - heals all friends in range, hurts all enemies in range (ie, Zeal)
"splash_projectile" - a projectile that does splash damage, like dragon's "fireball"
Melee Attacks All melee attacks use the "guided_melee" type. Basically, any targeted enemy in the character's range (or melee range if they have dual-range) will be hit by a melee attack as soon as it is fired.
If you want to hit one target multiple times, specify single_target="true" and set num_attacks in the stats table to a value higher than one. If you want to spread several attacks out over multiple targets, use single_target="false" with multiple num_attacks. Specifying hitall="true" will basically give you an AOE melee attack.
Projectiles Projectiles come in three varieties - guided, unguided, and spread. If guided or unguided, multiple attacks will result in multiple projectiles, and single_target=true/false will determine whether that all goes to one enemy or fired around more generously. Giving this attack a "strike_through" flavor will let it pierce a number of targets up to the "amount" value. Using "spread_projectile" as the type will fire a number of shots equal to the number of attacks, all at once.
Splash attacks (AOE) Splash attacks are a bit of a misnomer, and can be confused with splash projectiles. In truth, "splash" by itself means an AOE attack. I'm not 100% sure on this, but I think the "splash" type makes it automatically just hit everything in melee range. So any values for hitall and single_target should be ignored.
The exception is if you set a value for the heal attribute. If you set heal="minor" or "major" it will make this a healing skill, and single_target="true" will make it a single-target heal tech, like aid. Setting single_target="false" and hitall="true" will make it heal everyone in range, like "group_heal."
Splash projectiles These are guided projectiles that explode on contact with splash damage. The splash damage is specified in the stats table, and note that any flavors applied to the main skill will be moved to the splash effect, so all enemies affected by the splash will be hit with that flavor.
Heal/Attack All This is a special case, only used for Zeal. It's basically an AOE attack that heals all friends in range and harms all enemies in range.
........ Attack Skills, "Techniques", part 2
Stats Table The stats table is much like the <info> tag, letting you specify a bunch of attributes, including optional ones, for your technique. However, these let you specify stats that change in value as the technique has more skill points assigned to it.
I think the number of points the player can put into a skill is entirely determined by how many stats entries you create, but I haven't tested that robustly.
Here are the basic attributes you can specify in the stats table.
level = what skill level this stat definition is for. (0 means you don't have the skill, so 1 is minimum)
attack_mult = damage is calculated as (attack_mult * final_attack_stat), and the final attack stat does include item, buff, and boost bonuses. So a value of 0.10 means the tech does 10% of your attack stat, 1.0 means 100% of your attack stat, etc. If this is a heal technique, this is how much HP is restored instead.
dmg_mult = only used for "heal_attack_all" type attacks. Since attack_mult is reinterpreted as healing amount for heal attacks, you need to also specify the damage dealt to enemies. dmg_mult takes this role in this special case.
cooldown = how many seconds it takes for the attack to cool down. The character's speed and boost stat will modify this base value.
num_attacks = how many hits this attack can dish out. This gets interpreted in various ways depending on the values of single_target, hitall, and the type of the attack.
<flav>_amount = modifies a default flavor's amount value. "<flav>" represents the flavor id, so in practice you'd see "stun_amount" or "chill_amount", etc.
<flav>_time = same, but the time value
<flav>_rate = same, but the rate value
splash_mult = what % of the attack's final damage is dealt as splash damage to surrounding targets
radius = size of the splash damage radius, or the AOE radius.
Flavors You can specify a default flavor for the attack by putting a <flavor> tag down. "type" will define its id, and amount/time/rate values should also be given. If you don't specify any flavor values in the stats table, these values will always apply to the attack, regardless of skill level. If values are specified in the stats table, those will be used instead.
Graphics The <graphic> tag is usually for specifying a projectile image for projectile attacks.
The ice mage uses an actual graphic on the "ice ball" attack, and that looks like this: <graphic id="ice_ball" width="24" height="24" off_x="0" off_y="0" framerate="8"/>
Specify the file id, so that references "gfx/effects/ice_ball.png".
Projectile graphics will usually call for some additional tags: This lets you specify the animation loop: <graphic_anim> <frame value="0"/> <frame value="1"/> <frame value="2"/> <frame value="1"/> </graphic_anim>
NOTE: you can have an animated projectile, or one that rotates, but NOT both.
You can also specify some positioning so that the projectile appears from the correct location: <graphic_pos> <zoff x="0" y="40"/> <left x="-30" y="-7"/> <right x="25" y="-7"/> <up x="9" y="-10"/> <down x="-9" y="-8"/> </graphic_pos>
The left/right/up/down tags should be pretty obvious - offsets for where the projectile should appear based on the character's animation facing, but what is zoff? Well, it lets you mess with stacking. All objects on screen have x and y positions, and a derived z position which is : (y * screen_width + x). The "z" position is used to calculate which enemy goes in front of another, and higher z wins. zoff lets you add adjustments to how their z offset is calculated, so you can properly position a projectile AND make sure it stacks correctly.
Note that splash and AOE will need a splash effect animation. You specify those like this: <effects time="0.5"> <effect id="explode_big" chance="1"/> <effect id="explode_medium" chance="1"/> <effect id="explode_small_long" chance="1"/> <effect id="explode_small" chance="1"/> <effect id="explode_tiny" chance="1"/> </effects>
The time attribute specifies how long the effect lasts, and each <effect> tag specifies an effect animation that is part of the splash effect. These all correspond to ids for effects defined in data_effects.xml. You can specify a "chance" value for each one which defines the random weights assigned to each one. The values are all totaled and then normalized, so in the above example each one has a 20% chance of appearing. If you want to shift things towards "explode_big", you could set that weight to 2, or keep it at 1 and lower the other weights.
What about melee attacks? They don't use projectiles, but the game engine still needs to generate some sort of collision object, and it uses a "fake" projectile for that, that simply is invisible. "bignull" is the default "fake projectile" for all melee attacks. It's a 60x60 image that says "null" on it and is always invisible in game. There's also a smaller variant, "null" that's 20x20.
........ Passive Skills, "Traits"
Traits are much simpler than techniques.
As far as I can tell, there are only two valid "type" values for traits, "flavor" and "stat_boost".
Flavor augments Most passive traits just add new flavors to your attacks. This sounds pretty simple, but can do all kinds of interesting new things for your characters.
Specifying this is really simple: <info type="flavor" flav="poison" attack="all" />
Now this stat will give "poison" to all attacks, and you specify the amount/time/rate values in the stats table like so:
You can also specify the id of an attack instead of "all", and the flavor will only be added to that specific attack.
Stat boost This one's even simpler.
You identify the stat to boost: <info type="stat_boost" stat="range" />
And specify how much in the stats table: <stats level="1" amount="0.20" /> <stats level="2" amount="0.30" /> <stats level="3" amount="0.40" /> <stats level="4" amount="0.50" />
NOTE: the amount is the TOTAL BONUS at that skill level, it's doesn't cumulatively add all the previous ones.
........ Mcguffin's Skills, Spells
Spells are mostly hard-coded and kind of hacky. If you try to create your own from scratch it probably won't work, though you can probably edit/tweak the existing ones.
Mcguffin Spells don't have anything in the info tag other than the type, which is "spell."
You can specify default flavors for the spell, though how that gets interpreted depends on the spell.
The stats table works like it does for techs/traits, but there are three very important values that only work for spells. These are:
x - the value for the "x" variable in the spell.
y - the value for the "y" variable in the spell
z - the value for the "z" variable in the spell
<var>_stat - lets you add a portion of one of the mcguffin's stats to the corresponding variable. So x_stat="attack" will add a portion of Azra's attack to the x variable.
<var>_add - this is the multiplier to use with <var>_stat. So x_stat="attack" and x_add="0.5" will add 50% of Azra's attack stat to base x value.
The _stat / _add thing is useful if you want a spell that can grow with the character's level, so lightning grows stronger as Azra grows stronger, not just based on raw skill points. Additionally, if you were to give Azra a weapon that buffs her attack stat, that would help in this case, too.
Note that most of the spells don't have any graphics or effects data - this is because they are largely all hard-coded. Sorry about this :/
Note: if you're going to provide an <effects> tag, you also need to supply a <graphic> tag, even if the id is just "null" to force the loader to grab the effects.
Also note that in the regular game, the Mcguffin has a skill called "explosion" with the type "fake_attack". This is there for crystals and other things to pull a stock explosion effect from, and if its not defined your game will likely break.
Special Case hacks - Sorcerer / Antimcguffin In the normal game, Zelemir can show up on your side as a "friend," which is a computer-controlled defender that you have no control over. Since he's not the mcguffin, his spells are interpreted as a hybrid of a technique and a spell - basically, they work like mcguffin spells, but are triggered according to the regular defender cooldown cycle, with a few tweaks.
Each of zelemir's spells has a "chance" value added to the stats table - whenever the cooldown bar fills up, there's a random roll against chance to see if he actually uses the spell. So cooldown="14" and chance="0.25" means there's a 25% chance of using lightning-z every 14 seconds.
I believe Zelemir, or any "friend" type character, has their level and skills set in the battle definition. I'm not entirely sure.
Note that zelemir has a lot of info values specified to make the hack work with the regular game logic. This "friend" feature is *SERIOUSLY* hacky. I have no idea what would happen if you put in regular skills and whatnot here. Use this at your own risk.
Even more of a brutal hack is the Antimcguffin, because she can show up as BOTH a computer-controlled "friend", AND as a replacement mcguffin for Azra, so her skills must be able to be interpreted in both directions.
So... basically just look at their data entries in the default game. Also beware, this will probably blow up in your face if you make too many changes. Best of luck!
At its core, each battle is defined by two main files:
The png file specifies the battle’s basic visual layout, and the xml file specifies data, how to interpret the colors in the png file, what tilesets to use, and lots of other things.
There are two basic ways to design a battle map. Simple mode, and Layered mode. Let’s deal with simple mode first.
Simple Battle Setup
Simple battles are created by setting up a 15x15 pixel PNG file. Here’s an example of the first level, 1_1_where_am_i.png:
By itself, this image is meaningless. We need to create some data to tell the game how to interpret it.
The “default” attribute of the main <tiles> tag specifies the undermost tile layer. “default_fade” is not used anymore, it’s a relic of an abandoned feature.
The <size> tag specifies that a tile (one quarter of a square) should be 20 pixels. Theoretically the game is set up to deal with multiple tile sizes, but I am pretty dang sure the code now makes so many assumptions that battles consist of 40x40 squares using underlying tilesets of 20x20 pixels that anything else will probably make it choke and explode.
The <start> tag specifies a spawn portal for the enemies. The “rgb” attribute refers to the pixel color in the image map where the spawn portal will be. You should have exactly one pixel in your image map that is this exact color. If you have more than one, I’m not sure what the behavior will be - it will probably just pick the first one it finds to be the portal.
You can have multiple <start> tags, one for each spawn portal, and you should assign them simple “id” values - I recommend “a,b,c,d”, etc. I think the game supports up to five spawn locations. In this case, the one and only spawn portal on the map is the magenta pixel.
Next is the <end> tag, this is Azra’s location. In this case, the cyan pixel.
Next, we define our various tile layers. First is the “blue sand” layer, which is white (0xFFFFFF). Any white pixels found in the image will be considered part of the “blue sand” tileset.
However, we don’t just want a boring tileset, we’d also like little variable pieces on top, like bushes, shrubs, little skulls, cacti, etc - just visual noise to break up the monotony. To do this, we specify an additional pixel color that still counts as part of the tileset, but tells the game to consider drawing little random bits on those squares.
We add the <doodad> tag for “blue_sand” and set its color to “0xAAAAAA”, or light grey. If you look at the image map, the white and light grey pixels will all be blue sand, but only the light grey pixels will have a chance of doodads appearing on them.
We then do the same with the “blue stone” and “dark_cliff” layers. blue_stone uses medium grey and dark grey for its tile and doodad pixels, and dark_cliff uses red and maroon for its tile and doodad pixels.
Please note that the layer=”0” bit doesn’t actually do anything, it’s just a leftover artifact. The order in which you specify the tile layers is the order that the game will draw them in, so dark_cliff will show up on top of blue_stone, on top of blue_sand, on top of grey_dirt. layer=”3” and the like is completely ignored.
So - what about the path the enemies walk on? This is always black (0x000000), and its tileset will be the default one.
In Simple Mode, the game will try to “auto-layer” the various tilesets. It does this by extending the bottom-most layers so that it looks like they continue on underneath the layers drawn on top of them. This usually works, but on some levels it looks weird and you need a bit more manual control. This is where Layering comes in.
NOTE: Although the definable area in a battle is 15x15 squares, the topmost row is where the enemy wave bar is shown, and so it’s not advisable to put anything there except impassable terrain. That’s what we do, at any rate.
........ Layered Battle Setup
This is what a “layered” battle image map looks like. The basic idea is that you build the map just the way you normally would, but afterwards, you separate each tile layer out by itself and draw it exactly the way you want.
First and foremost, you should specify your start and end point pixels only on the “ZEROth” layer, ie, the first 15x15 pixels. Each layer after that should be another 15x15 square, with only black pixels and the tile color (not the doodad color!) for that layer. Any color that is not the same as the main tile color will be ignored on this layer.
These extra layers must be placed in the exact same order you specify them in your level’s xml file.
Which squares are “doodad” squares will be determined by looking at the”ZEROth” layer, so put that information there. In the extra layers, draw out exactly how you want the tileset to look when layered. This way, you can get things to layeri in exactly the way you want.
The final tileset layout positions will be determined by the extra layers, and which square counts as what tile type will be determined by compositing them together (ie, whatever tileset is on top at that square location is what tile type it is for legal/illegal tile counting purposes).
This section will talk about how to create cutscene content. For information on trigger cutscenes, see the next section, "Game Progression & Triggers."
Cutscenes are defined in cutscenes/scripts.xml, and are defined by <scene> tags, which can be quite large and complicated.
The basic structure of a <scene> tag is:
scene attributes (name, title, background, etc)
<enter> (character enters)
<exit> (character exits)
<line> (character delivers a line)
<swap> (swap character image/pose)
<background> (change background image)
<music> (change music)
<narration> - present a special "narration" slide - ie, big fancy intro text
<sfx> - play a sound effect
<set_offset> - set offset for a character image before it appears
name - id for the cutscene, referenced elsewhere (in triggers, etc)
title - displayed title to the player
background - id for the background image
music - id for the music file
act / scene - values to display for act and scene
foreground_left / foreground_right - id for foreground image. Snapped to left/right edge of screen
<enter> tag This makes a character enter the screen.
"image" is the image id of the character,
"side" is which side they enter from (legal values = left/right/mid_left/mid_right). Left/right makes them enter from and stay on the left or right side, and mid_left/mid_right makes them enter from one or the other side and then stay in the middle of the screen. I think only one character can be in the middle at once.
"instant" specifies whether the character appears immediately, or transitions in normally.
fade="true" lets you make a character fade in from being transparent, rather than sliding in.
If a character enters from "mid_left" or "mid_right" you want to specify the offset, so you should supply midX and midY values.
The exit tag is almost identical to the <enter> tag, but you don't have to supply an image. Also, you can specify "both" to make both sides exit at once.
This tag governs talking. You should specify a speaker name. If you want to reference a character's actual name rather than hard text, use this format : "$ABC" where ABC are the first three letters of the class id (when defining classes make sure the first three letters for each are unique). The name will be replaced with that of that class' hero.
If you want to use a character's name within a line, use the same flag format, but put an asterisk (*) at the beginning of the line to tell the game to look for flags. You can also specify line breaks with "$N". Note that you won't see any of this in scripts.xml, as it's all been localized and you'll find the actual line content in scripts.csv in the localization data.
TODO: bubble positioning, etc.
TODO: all this <swap> tag <background> tag <music> tag <narration> tag <sfx> tag <set_offset> tag