User:Kernelmethod/Sandbox: Difference between revisions

From Caves of Qud Wiki
Jump to navigation Jump to search
(Add a section on navigating the game's data files.)
m (Fix a typo)
Line 464: Line 464:
<syntaxhighlight lang="xml">
<syntaxhighlight lang="xml">
<!-- We borrow the same description that StandaloneMarkovBook uses -->
<!-- We borrow the same description that StandaloneMarkovBook uses -->
<part Name="Description" Short="Crip pages of goatskin vellum are bound into a codex." />
<part Name="Description" Short="Crisp pages of goatskin vellum are bound into a codex." />
<part Name="Physics" Weight="1" UsesTwoSlots="true" />
<part Name="Physics" Weight="1" UsesTwoSlots="true" />
<part Name="Commerce" Value="80" />
<part Name="Commerce" Value="80" />
Line 754: Line 754:
   <object Name="Pyovya_SnapjawMage_Magic Tome" Inherits="BaseMissileWeapon">
   <object Name="Pyovya_SnapjawMage_Magic Tome" Inherits="BaseMissileWeapon">
     <!-- We borrow the same description that StandaloneMarkovBook uses -->
     <!-- We borrow the same description that StandaloneMarkovBook uses -->
     <part Name="Description" Short="Crip pages of goatskin vellum are bound into a codex." />
     <part Name="Description" Short="Crisp pages of goatskin vellum are bound into a codex." />
     <part Name="Physics" Weight="1" UsesTwoSlots="true" />
     <part Name="Physics" Weight="1" UsesTwoSlots="true" />
     <part Name="Commerce" Value="80" />
     <part Name="Commerce" Value="80" />

Revision as of 18:41, 20 September 2023

Modding Tutorial: Snapjaw Mages!

Welcome! If you're looking to get started with modding Caves of Qud, this tutorial is a good place to start.

In this tutorial, we're going to add a new creature to the game -- the great and mystical snapjaw mage. Along the way we're going to be helped by my friends Rulimispruce, legendary sprouting orb and Pyovya, legendary mopango.

Sprouting orb.png < Howdy!
Mopango pilgrim.png < I'm excited!

By the end of this tutorial, you'll have created a new mod which

  • introduces two new creatures, the snapjaw fire mage and the snapjaw ice mage, and
  • introduces two new missile weapons, the tome of fire and the tome of ice.

Before you get started, you may also want to check out the Blue Ctesiphus modding tutorial on Steam. It's a little dated, but it also covers many of the concepts covered here.

This mod won't require any scripting, so you don't need to know anything about C#. However, I'd recommend that you play through a good chunk of Caves of Qud before you try your hand at modding. It's helpful to be able to refer to existing creatures and items when creating new ones.

You can find the source for the final version of the mod here: https://github.com/kernelmethod/QudMods/tree/SnapjawMage/SnapjawMage/SnapjawMage

Getting started, and basic concepts

If this is your first time modding, make sure to follow the checklist in Modding:Overview. It's particularly important that you install a text editor like VS Code. I've prepared all of the tiles that you'll need to use for this tutorial, so you don't need to familiarize yourself with a pixel editor. However, if you plan on adding new tiles in the future you should be familiar with an editor like Piskel or Aseprite.

You should also enable the following options in your game:

  • Modding > Enable Mods
  • Debug > Show quickstart option during character generation.
    • This will cause a _Quickstart option to show up when you start a new game. This option makes it very easy to create a new character and immediately start testing out your mod.

Finally, you should take a look at the page of file locations and find the following directories on your computer:

  • the "offline mods" folder; and
  • the "game data files" folder.

XML

XML (eXtensible Markup Language) is a type of markup language, which (loosely speaking) is a text-based format that can be understood by a program. Caves of Qud makes extensive use of XML for things like defining creatures, quests, items, conversations, and more. We'll be working with XML a lot throughout this tutorial, so it's helpful to have a little familiarity with XML first.

You can check out the Wikipedia page on XML if you want to learn more. Here's some basic terminology you should be familiar with: in the XML snippet below,

<foo bar="baz" />

foo is an XML tag. Meanwhile, bar is an attribute, which (in this case) has been assigned the value baz.

You may also see comments here and there. A comment consists of one or more lines of text between <!-- and -->, such as the following:

<!-- This is a comment! -->

<!--
  ... and this is also a comment!
-->

Comments don't do anything by themselves; they're just helpful for documenting things that are going on in your XML.

Wishes

Wishes are commands that can be executed in-game to perform a variety of tasks. They're very useful when modding -- you can use a wish to spawn a creature of your choice, or create an item, and a variety of other tasks. You should follow the instructions on the Wishes page to bind the wish command to a key combination.

There are a lot of useful wishes. Here are a few that I use often:

  • idkfa: puts your character in "God Mode". This makes your character immortal, and causes all attacks that penetrate to instantly kill.
  • swap: allows you to swap your body with an adjacent creature.
  • In addition, you can wish for the ID of a creature or item to spawn that creature/item. For instance, wishing for Troll King 1 will spawn Jotun, Who Parts Limbs.

Navigating the game's data files

We won't delve too deeply into Caves of Qud's data files, but it's helpful to know how to navigate through them when creating a mod. Make sure that you've found where your computer keeps the game's data files by looking at the list of file locations before continuing; it should be a subfolder called Base of a folder called StreamingAssets somewhere on your machine.

Mopango pilgrim.png < Don't modify the game's files! You could end up having to reinstall the game in order to fix a mistake.

Once you've found this folder, you should see a bunch of files with names ending in things like .bmp, .rpm, .xml, .json, and so on.

Snapjaw Mages -- Game files.webp

For this tutorial, the .xml files are the ones we're going to be the most interested in. There are a lot of these files (35 as of game version 2.0.205.63); here's a high-level overview of just a few of them:

  • Bodies.xml: in charge of defining various body parts and creature anatomies. This is useful when you want to define a new body type; for instance, the Blahajar mod defines a unique anatomy specific to sharks.
  • Conversations.xml: defines the conversational script that different creatures have.
  • Mutations.xml: data file containing all of the mutations that are available in-game.
  • ObjectBlueprints/Creatures.xml: definitions of all of the creatures that exist in Caves of Qud.
  • ObjectBlueprints/Items.xml: definitions of all of the items available in Caves of Qud.
  • Skills.xml: contains all of the skill trees provided by Caves of Qud, and abilities within those trees.
  • Quests.xml: lays out the steps and rewards for non-procedurally generated quests.

When adding new creatures and items (as in this tutorial!), we're mostly going to be interested in just ObjectBlueprints/Creatures.xml and ObjectBlueprints/Items.xml. Starting in the next section, we'll discuss what all of the bits and pieces mean in these files. Make sure you know where to find these files before you continue!

Creating a mod

Mopango pilgrim.png < Let's get started!

We'll start by creating a mod that doesn't actually do anything. To do that, go to Caves of Qud's "offline mods" folder; you can find the location of this folder for your operating system by looking at the page of file locations. Inside this folder (it should be named Mods), create a new folder called SnapjawMage. The first file we're going to create for our mod will be a manifest file; this contains metadata such as our mod's title, a description of the mod, and its version. Create a new file called manifest.json inside the SnapjawMage/ folder, and paste in the following contents:

{
    "id": "Pyovya_SnapjawMage",
    "title": "Snapjaw Mages!",
    "description": "Adds the new Snapjaw Mage creature to Caves of Qud.",
    "version": "0.1.0",
    "author": "Pyovya",
    "tags": "Creature",
    "PreviewImage": "preview.png"
}
Mopango pilgrim.png < Feel free to replace Pyovya with your own name!

We should also get a preview image for the mod. I've made one that you can use here:

https://github.com/kernelmethod/QudMods/blob/SnapjawMage/SnapjawMage/SnapjawMage/preview.png

Download this image and place it in the SnapjawMage/ folder, so that now your folder looks like this:

SnapjawMage
├── manifest.json
└── preview.png

Now start up Caves of Qud. In the splash screen, click on "Installed Mod Configuration". If everything went correctly, you should see a new "Snapjaw Mages!" mod appear in your list of installed mods:

Snapjaw Heros -- Mods List.webp

You will be returning to this screen often!

Mopango pilgrim.png < Every time you make a change to your mod, you will need to go back to this screen and activate the "Save and Reload" option (which you can do by pressing r).

Your first creature

Adding a new creature to Creatures.xml

In your mod directory, create a new folder called ObjectBlueprints/, and within that folder open up a new file in your text editor called Creatures.xml. Let's start by adding the following to Creatures.xml:

<?xml version="1.0" encoding="utf-8" ?>
<objects>
</objects>

Save this file! Before continuing, make sure your mod directory looks something like this:

SnapjawMage
├── manifest.json
├── ObjectBlueprints
│   └── Creatures.xml
└── preview.png

With that out of the way, let's start adding our new snapjaw mage to Creatures.xml:

<?xml version="1.0" encoding="utf-8" ?>
<objects>
  <object Name="Pyovya_SnapjawMage_Snapjaw Mage" Inherits="Snapjaw">
  </object>
</objects>

Let's break this down:

  • The object tag tells Qud that we want to add a new creature.
  • The Name attribute is a unique identifier for our new creature (it's not the name of the creature as it appears in-game -- we'll get to that shortly). You'll use this identifier whenever you want to wish for a new snapjaw mage.
  • The Inherits attribute says that our new creature should "inherit" all of the properties of the Snapjaw creature.
Sprouting orb.png < Hey, why'd you add the Pyovya_SnapjawMage bit to the front of the name of the creature? Why not just call it a Snapjaw Mage?
Mopango pilgrim.png < When writing a mod, it's common courtesy to prefix unique identifiers with your name, an underscore _, followed by the mod's name. This ensures that if somebody else writes their own Snapjaw Mage mod, your mod won't conflict with theirs.

So far we haven't actually added anything to our new creature; for all intents and purposes it's a plain ol' snapjaw. Let's change that by adding some parts.

Sprouting orb.png < What's a part?
Mopango pilgrim.png < A part is a special piece of code that can be added to a creature to modify its appearance, behavior, stats, and any number of other things. There are a lot of parts -- over a thousand! You won't need to worry about most of them; many of them are highly-customized bits of code written for just one or two creatures. For instance, there's a CryptSitterBehavior part that is used exclusively by crypt sitters.

We're going to add two new parts to our creature: Render and Description.

<?xml version="1.0" encoding="utf-8" ?>
<objects>
  <object Name="Pyovya_SnapjawMage_Snapjaw Mage" Inherits="Snapjaw">
    <part Name="Description" Short="A tattered robe and decaying hat are all that protect =pronouns.possessive= thin layer of grizzled fur from the forces of nature. But behind that furtive glance, =pronouns.subjective= =verb:prepare:afterpronoun= an elemental spell, deployed at a moment's notice against threats to =pronouns.objective= and =pronouns.possessive= kin. =pronouns.Subjective= =verb:understand:afterpronoun= not the power that =pronouns.subjective= =verb:wield:afterpronoun=; and that only makes =pronouns.objective= all the more dangerous." />
    <part Name="Render" DisplayName="snapjaw mage" Tile="Assets_Content_Textures_Creatures_sw_snapjaw_warrior.bmp" ColorString="&amp;O" DetailColor="Y" />
  </object>
</objects>

Before I dig into the new XML we've added, save Creatures.xml. Reload your mods, start a new game and wish for a Pyovya_SnapjawMage_Snapjaw Mage. You should see a new snapjaw like the one below show up:

Snapjaw Mages -- Initial mage.webp

Congrats! You've successfully added a snapjaw mage to your game.

Sprouting orb.png < I did?

Well, it's still a little bare-bones, but you have indeed created a new creature called a snapjaw mage and spawned it in your game! Give yourself a pat on the back, Rulimispruce.

Sprouting orb.png < *rustling noises*

Now, back to the parts that you just added:

  • The Description part changes (as you might guess) the description of the creature when you look at it.
    • You'll notice that the description includes a lot of things like =pronouns.subjective= and =verb:understand:afterpronoun=. This ensures that the game uses the correct pronouns while generating the creature's description and conjugates verbs correctly. See Modding:Grammar for more details.
  • The Render attribute changes the creature's appearance, as well as its name (as it appears in-game). This tag has the following attributes:
    • DisplayName: how the creature's name is displayed in-game.
    • Tile: a .png or .bmp ("bitmap") image that's used to display the creature. Check out Modding:Tiles for more information. In the snippet above, I just used the tile for snapjaw warriors to get us started.
    • ColorString and DetailColor: these are the primary and secondary colors used to color in the tile that you supply. You can look at Modding:Colors & Object Rendering for a full list of all of the available colors; in this case, we used O (orange) as the primary color and Y (white) as the detail color.

Using custom tiles

Instead of having our snapjaw mages look like off-color snapjaw warriors, let's add a snazzy new tile to the game to use for our mages! Just pop open a pixel editor, create a 16px x 24px black-and-white tile, save it as a --

Sprouting orb.png < I'm just a lil old sprouting orb, I don't know how to do any of those things.

Ah, alright, fair enough. Well in that case, feel free to download the tile that I've already made for you here:

https://github.com/kernelmethod/QudMods/blob/SnapjawMage/SnapjawMage/SnapjawMage/Textures/Pyovya_SnapjawMage/snapjaw_mage.png

In your mod directory, create a new folder called Textures/; in that folder, create a new subfolder called Pyovya_SnapjawMage/; and in there, create another subfolder called Creatures/. Save snapjaw_mage.png there, so that your mod folder now looks like this:

SnapjawMage
├── manifest.json
├── ObjectBlueprints
│   └── Creatures.xml
├── preview.png
└── Textures
    └── Pyovya_SnapjawMage
        └── snapjaw_mage.png

Let's change the Render part for our mages to use this new tile:

<part Name="Render" DisplayName="snapjaw mage" Tile="Pyovya_Snapjaw/snapjaw_mage.png" ColorString="&amp;O" DetailColor="Y" />

Now let's fill out some more details about our new furry friend.

Adding inventory

We'll keep adding stuff to our snapjaw mage to round them out a bit more. First of all, like any good mage, they need a walking stick and some books. Let's give them some clothes to equip while we're at it. Add the following XML to your creature:

<inventoryobject Blueprint="Walking Stick" Number="1" />
<inventoryobject Blueprint="Woven Tunic" Number="1" />
<inventoryobject Blueprint="Sandals" Number="1" />
<inventoryobject Blueprint="StandaloneMarkovBook" Number="1-2" Chance="10" />

By setting Number="1-2" and Chance="10" in that last line, we've given our mages a 10% chance of holding 1-2 books when they spawn.

Adding skills

Let's give our mage the Cudgel skill as well, so that they're a little bit better at fighting with that walking stick:

<skill Name="Cudgel" />

Changing stats

The base Snapjaw creature that we're inheriting from has really low stats, so we're going to bump up our mage's stats a little.

<stat Name="Hitpoints" Value="15" />
<stat Name="DV" Value="4" />

<!-- Raise ego to make the mage's mental mutations a little more powerful -->
<stat Name="Ego" Value="17" />

<!-- Raise willpower to reduce the cooldowns of abilities -->
<stat Name="Willpower" Value="17" />

If you've followed along up to this point, you should be ending this section with a snapjaw mage that looks like this:

Snapjaw Mages -- Mage new tile.webp

Your Creatures.xml at this point should look something like the following. Make sure that everything checks out before proceeding to the next section!

<?xml version="1.0" encoding="utf-8" ?>
<objects>
  <object Name="Pyovya_SnapjawMage_Snapjaw Mage" Inherits="Snapjaw">
    <part Name="Description" Short="A tattered robe and decaying hat are all that protect =pronouns.possessive= thin layer of grizzled fur from the forces of nature. But behind that furtive glance, =pronouns.subjective= =verb:prepare:afterpronoun= an elemental spell, deployed at a moment's notice against threats to =pronouns.objective= and =pronouns.possessive= kin. =pronouns.Subjective= =verb:understand:afterpronoun= not the power that =pronouns.subjective= =verb:wield:afterpronoun=; and that only makes =pronouns.objective= all the more dangerous." />
    <part Name="Render" DisplayName="snapjaw mage" Tile="Pyovya_SnapjawMage/snapjaw_mage.png" ColorString="&amp;O" DetailColor="Y" />

    <inventoryobject Blueprint="Walking Stick" Number="1" />
    <inventoryobject Blueprint="Woven Tunic" Number="1" />
    <inventoryobject Blueprint="Sandals" Number="1" />
    <inventoryobject Blueprint="StandaloneMarkovBook" Number="1-2" Chance="10" />

    <skill Name="Cudgel" />

    <stat Name="Hitpoints" Value="15" />
    <stat Name="DV" Value="4" />
    <stat Name="Ego" Value="17" />
    <stat Name="Willpower" Value="17" />
  </object>
</objects>

Using your creature as a base: Elemental Mages

Sprouting orb.png < Hold up a second. How is this creature a mage? It doesn't have any kind of magic spells!

I was just getting to that!

So far, we've sketched out most of the properties, skills, and stats that a snapjaw mage should have. Now we're going to create two types of mages: fire mages and ice mages. The first thing we're going to do is mark the snapjaw mage as a "base object", i.e. an object that doesn't appear in-game but which instead serves as the basis for other objects. Add the following tag to the Pyovya_SnapjawMage_Snapjaw Mage creature:

<tag Name="BaseObject" Value="*noinherit" />

Now, below your definition of the snapjaw mage in Creatures.xml, add two new creatures:

<?xml version="1.0" encoding="utf-8" ?>
<objects>
  <!--
  Skipped: the XML that defines the "Pyovya_SnapjawMage_Snapjaw Mage" creature
  -->

  <object Name="Pyovya_SnapjawMage_Fire Mage" Inherits="Pyovya_SnapjawMage_Snapjaw Mage">
  </object>

  <object Name="Pyovya_SnapjawMage_Ice Mage" Inherits="Pyovya_SnapjawMage_Snapjaw Mage">
  </object>
</objects>
Mopango pilgrim.png < Notice how we've used the Inherits attribute here. We're telling the game that our original snapjaw mage creature, Pyovya_SnapjawMage_Snapjaw Mage, should serve as a base for our fire and ice mages. As a result, our new creatures will spawn with walking sticks, have the Cudgel skill, and so on.

Referencing the Modding:Colors & Object Rendering page, we're going to change our fire mages' detail color to red. We're also going to give them the Pyrokinesis mutation:

<object Name="Pyovya_SnapjawMage_Fire Mage" Inherits="Pyovya_SnapjawMage_Fire Mage">
  <part Name="Render" DisplayName="snapjaw {{R|fire}} mage" Tile="Pyovya_SnapjawMage/snapjaw_mage.png" ColorString="&amp;O" DetailColor="R" />
  <mutation Name="Pyrokinesis" Level="1" />
</object>

The {{R|fire}} bit there says that the word "fire" should be colored red. Now we'll make some similar changes to ice mages (changing their color to cyan), and give them the Cryokinesis mutation.

<object Name="Pyovya_SnapjawMage_Ice Mage" Inherits="Pyovya_SnapjawMage_Ice Mage">
  <part Name="Render" DisplayName="snapjaw {{C|ice}} mage" Tile="Pyovya_SnapjawMage/snapjaw_mage.png" ColorString="&amp;O" DetailColor="C" />
  <mutation Name="Cryokinesis" Level="1" />
</object>

Now try wishing for a Pyovya_SnapjawMage_Fire Mage and a Pyovya_SnapjawMage_Ice Mage. You should get two creatures that appear like the ones below (and they should immediately start attacking you with Pyrokinesis and Cryokinesis):

Snapjaw Mages -- Fire and Ice.webp

Creating new items

We've now successfully added a snapjaw fire mage and a snapjaw ice mage. We're also going to give them two new missile weapons: a tome of fire and a tome of ice. These new weapons will be magical spell books that function as less powerful versions of the flamethrower and freeze ray, respectively.

Start by creating a new file Items.xml in the ObjectBlueprints/ folder:

SnapjawMage
├── manifest.json
├── ObjectBlueprints
│   ├── Creatures.xml
│   └── Items.xml
├── preview.png
└── Textures
    └── Pyovya_SnapjawMage
        └── snapjaw_mage.png
Sprouting orb.png < Does it matter whether I name my file Items.xml? And do I have to place it in the ObjectBlueprints/ directory?
Mopango pilgrim.png < Nope and nope! In fact, you can name all of your XML files whatever you want (as long as they end in .xml) and place them wherever you feel like (as long as they're in the SnapjawMage/ mod directory). The scheme that we're using here to organize our XML files is the same scheme that the game uses for its own files (the ones that you can find in the "game data files" folder), just to make the relationship between what we're writing and Caves of Qud's code a little bit clearer.

We want to create two new items -- a fire tome and and ice tome -- and we can probably guess in advance that these two items are going to have a lot of the same properties. Therefore, we're going to start the same way that we did when we were creating our mages: we'll create a base "magic tome" object, which we will later inherit from.

Add the following to Items.xml:

<?xml version="1.0" encoding="utf-8" ?>
<objects>
  <object Name="Pyovya_SnapjawMage_Magic Tome" Inherits="BaseMissileWeapon">
    <tag Name="BaseObject" Value="*noinherit" />
  </object>
</objects>

Now we need to add some parts to our new object:

<!-- We borrow the same description that StandaloneMarkovBook uses -->
<part Name="Description" Short="Crisp pages of goatskin vellum are bound into a codex." />
<part Name="Physics" Weight="1" UsesTwoSlots="true" />
<part Name="Commerce" Value="80" />

We've already seen the Description part before. The Physics part is a common part used by items to determine how much they weight, whether they are equipped in one or two slots, and what category they appear under in the inventory screen. Finally, the Commerce part defines how valuable the item is.

Let's also add a tag to the item to indicate its tier, as well as what mods it can accept (in our case, we don't want this item to be moddable):

<tag Name="Tier" Value="2" />
<tag Name="Mods" Value="" />

That should be enough for our base object. Now, let's create a fire tome and an ice tome by inherting from Pvovya_SnapjawMage_Magic Tome. While we're at it, let's add some tiles to render each of them:

<?xml version="1.0" encoding="utf-8" ?>
<objects>
  <!-- Skipped: definition of "Pyovya_SnapjawMage_Magic Tome" -->

  <object Name="Pyovya_SnapjawMage_Fire Tome" Inherits="Pyovya_SnapjawMage_Magic Tome">
    <part Name="Render" DisplayName="tome of {{R|fire}}" Tile="Items/sw_book_1.bmp" ColorString="&amp;R" DetailColor="Y" />
  </object>

  <object Name="Pyovya_SnapjawMage_Ice Tome" Inherits="Pyovya_SnapjawMage_Magic Tome">
    <part Name="Render" DisplayName="tome of {{C|ice}}" Tile="Items/sw_book_1.bmp" ColorString="&amp;C" DetailColor="Y" />
  </object>
</objects>

Using existing items as a template

Now, we know that we want these items to function like a flamethrower and freeze ray, but we probably need to iron out some more details first.

Sprouting orb.png < Do spell books use ammo?

That's a good question. If we wanted, we could set up our new missile weapons to use some kind of ammo, or pull from an energy cell. I'm actually going to go with a third option -- let's set up our tomes of fire and ice so that they don't use any kind of ammo or energy, but instead just have a plain 10-turn cooldown.

We must also figure out what kind of projectile each of these items shoots. Let's take a look at how the game defines the flamethrower and freeze ray objects. Looking at the file locations, navigate in your file browser to where the game's data files are stored. Once you're in that folder, go to ObjectBlueprints/ and open up the Items.xml file. Then search for Flamethrower and Freeze Ray; you should find the following XML for each of them.

<object Name="Freeze Ray" Inherits="BaseRifle">
  <part Name="Render" DisplayName="{{freezing|freeze}} ray" Tile="items/sw_raygun.bmp" ColorString="&amp;C" DetailColor="y" />
  <part Name="Physics" UsesTwoSlots="true" Weight="28" />
  <part Name="MissileWeapon" Skill="Rifle" AmmoChar="FR" ShotsPerAction="1" AmmoPerAction="1" ShotsPerAnimation="1" WeaponAccuracy="0" />
  <part Name="Commerce" Value="750" />
  <part Name="EnergyAmmoLoader" ChargeUse="500" ProjectileObject="ProjectileFreezeRay" />
  <part Name="EnergyCellSocket" SlotType="EnergyCell" />
  <part Name="Description" Short="Gaseous coolant billows through a chiffon tube, putting dew on the wide and planar barrel chrome. It spills out onto the air from a ice-chipped muzzle." />
  <part Name="Examiner" Complexity="5" />
  <part Name="TinkerItem" Bits="12345" CanDisassemble="true" CanBuild="true" />
  <part Name="Metal" />
  <part Name="ItemElements" Elements="ice:10" />
  <tag Name="MissileFireSound" Value="lazerMedium4" />
  <tag Name="Mods" Value="MissileWeaponMods,FirearmMods,CommonMods,RifleMods,ElectronicsMods,BeamWeaponMods" />
  <tag Name="Tier" Value="5" />
  <tag Name="DynamicObjectsTable:Guns" />
  <stag Name="Cold" />
</object>

<!-- some more item definitions later... -->

<object Name="Flamethrower" Inherits="BaseHeavyWeapon">
  <part Name="Render" Tile="items/sw_flamethrower.bmp" DisplayName="flamethrower" ColorString="&amp;R" TileColor="&amp;c" DetailColor="R"/>
  <part Name="Physics" UsesTwoSlots="true" />
  <part Name="MissileWeapon" Skill="HeavyWeapons" bShowShotsPerAction="false" NoWildfire="true" MaxRange="12" AnimationDelay="20" AmmoChar="f" ShotsPerAction="9" AmmoPerAction="1" ShotsPerAnimation="9" WeaponAccuracy="10" />
  <part Name="Commerce" Value="100" />
  <part Name="LiquidAmmoLoader" Liquid="oil" ProjectileObject="ProjectileFlamethrower" />
  <part Name="LiquidVolume" MaxVolume="32" Volume="32" StartVolume="1d32" InitialLiquid="oil-1000" />
  <part Name="LeakWhenBroken" />
  <part Name="Description" Short="A limpid fuel pump exposes ribbons of oil slick, and behind it a voltage gauge ticks. The slanted heat shield is scorched black." />
  <part Name="Examiner" Alternate="UnknownBackpack" Complexity="4" />
  <part Name="TinkerItem" Bits="0004" CanDisassemble="true" CanBuild="true" />
  <part Name="Metal" />
  <tag Name="TurretName" Value="flamethrower turret" />
  <tag Name="Tier" Value="4" />
  <tag Name="UsesSlots" Value="Back,Missile Weapon,Missile Weapon" />
  <tag Name="DynamicObjectsTable:Guns" />
  <tag Name="ReloadSound" Value="SplashStep1" />
  <tag Name="MissileFireSound" Value="flamethrower" />
  <stag Name="Heat" />
</object>

If you know a bit about each of these items, you can intuit what some of these parts do. For instance, EnergyCellSocket is clearly related to the ability to insert and use energy cells in freeze rays; LiquidAmmoLoader is somehow connected to the fact that flamethrowers run on oil.

In any case, the most important bits right now is this line from the definition of Freeze Ray:

<part Name="EnergyAmmoLoader" ChargeUse="500" ProjectileObject="ProjectileFreezeRay" />

... and this line from the definition of Flamethrower:

<part Name="LiquidAmmoLoader" Liquid="oil" ProjectileObject="ProjectileFlamethrower" />

From this, we can see that there is a ProjectileFreezeRay object that freeze rays shoot, and a ProjectileFlamethrower object that flamethrowers shoot.

To have our new items shoot these projectiles on a cooldown, we're going to add the CooldownAmmoLoader part. Here's how we'll add it to our tome of fire:

<object Name="Pyovya_SnapjawMage_Fire Tome" Inherits="Pyovya_SnapjawMage_Magic Tome">
  <part Name="Render" DisplayName="tome of {{R|fire}}" Tile="Items/sw_book_1.bmp" ColorString="&amp;R" DetailColor="Y" />
  <part Name="CooldownAmmoLoader" Cooldown="10" Readout="true" ProjectileObject="ProjectileFlamethrower" />
</object>

... and here's how we'll add it to our tome of ice:

<object Name="Pyovya_SnapjawMage_Ice Tome" Inherits="Pyovya_SnapjawMage_Magic Tome">
  <part Name="Render" DisplayName="tome of {{C|ice}}" Tile="Items/sw_book_1.bmp" ColorString="&amp;C" DetailColor="Y" />
  <part Name="CooldownAmmoLoader" Cooldown="10" Readout="true" ProjectileObject="ProjectileFreezeRay" />
</object>

We also need to add a MissileWeapon part to each of our items, and specify the sound that the item makes when it's fired. Go ahead and update Items.xml until you get the following:

<?xml version="1.0" encoding="utf-8" ?>
<objects>
  <!-- Skipped: definition of "Pyovya_SnapjawMage_Magic Tome" -->

  <object Name="Pyovya_SnapjawMage_Fire Tome" Inherits="Pyovya_SnapjawMage_Magic Tome">
    <part Name="Render" DisplayName="tome of {{R|fire}}" Tile="Items/sw_book_1.bmp" ColorString="&amp;R" DetailColor="Y" />
    <part Name="MissileWeapon" AmmoChar="f" ShotsPerAction="1" AmmoPerAction="1" ShotsPerAnimation="1" WeaponAccuracy="0" />
    <part Name="CooldownAmmoLoader" Cooldown="10" Readout="true" ProjectileObject="ProjectileFlamethrower" />

    <tag Name="MissileFireSound" Value="flamethrower" />
  </object>

  <object Name="Pyovya_SnapjawMage_Ice Tome" Inherits="Pyovya_SnapjawMage_Magic Tome">
    <part Name="Render" DisplayName="tome of {{C|ice}}" Tile="Items/sw_book_1.bmp" ColorString="&amp;C" DetailColor="Y" />
    <part Name="MissileWeapon" AmmoChar="FR" ShotsPerAction="1" AmmoPerAction="1" ShotsPerAnimation="1" WeaponAccuracy="0" />
    <part Name="CooldownAmmoLoader" Cooldown="10" Readout="true" ProjectileObject="ProjectileFreezeRay" />

    <tag Name="MissileFireSound" Value="hiss_low" />
  </object>
</objects>

You've successfully added both items to your game! You can now wish for a Pyovya_SnapjawMage_Fire Tome or a Pyovya_SnapjawMage_Ice Tome.

Adding custom projectiles

Sprouting orb.png < I burnt down all of Joppa with my tome of fire! Take that, Ualraig.

Ah, hm, yeah, maybe using the same projectile that flamethrower and freeze ray use isn't the greatest idea. Those are both mid- to late-game items, and we want our new snapjaws to be early-game enemies.

Let's fix that by creating some new projectile types that operate in the same way as ProjectileFlamethrower and FreezeRayProjectile, but are a little bit weaker. First, let's look up how these projectiles are defined in the game's data files, and then copy that over to our Items.xml. We'll rename these projectiles Pyovya_SnapjawMage_FireTomeProjectile and Pyovya_SnapjawMage_IceTomeProjectile.

<!-- Copied from ProjectileFlamethrower -->
<object Name="Pyovya_SnapjawMage_FireTomeProjectile" Inherits="TemporaryProjectile">
  <part Name="Render" DisplayName="{{R|stream of flame}}" ColorString="&amp;R" />
  <part Name="Projectile" BasePenetration="15" BaseDamage="1d2" Attributes="Heat Fire" ColorString="&amp;R" PassByVerb="whoosh" />
  <part Name="TemperatureOnHit" Amount="4d20" Max="false" OnWielderHit="true" />
  <part Name="TemperatureOnEntering" Amount="8d20" Max="false" OnWielderHit="true" />
</object>

<!-- Copied from ProjectileFreezeRay -->
<object Name="Pyovya_SnapjawMage_IceTomeProjectile" Inherits="TemporaryProjectile">
  <part Name="Render" DisplayName="{{C|energy beam}}" ColorString="&amp;B" />
  <part Name="Projectile" BaseDamage="1d4" Attributes="Cold NonPenetrating" ColorString="&amp;B" PassByVerb="crackle" />
  <part Name="TemperatureOnHit" Amount="-190" Max="false" OnWielderHit="true" />
  <part Name="TemperatureOnEntering" Amount="-190" Max="false" OnWielderHit="true" />
</object>

Let's make some changes to the penetration, base damage, and temperature changes of each of these items. Here's what I set mine to, but go ahead and try tweaking these numbers to different values:

<object Name="Pyovya_SnapjawMage_ProjectileFireTome" Inherits="TemporaryProjectile">
  <part Name="Render" DisplayName="{{R|stream of flame}}" ColorString="&amp;R" />
  <part Name="Projectile" BasePenetration="4" BaseDamage="1d4" Attributes="Heat Fire" ColorString="&amp;R" PassByVerb="whoosh" />
  <part Name="TemperatureOnHit" Amount="4d20" Max="false" OnWielderHit="true" />
  <part Name="TemperatureOnEntering" Amount="8d20" Max="false" OnWielderHit="true" />
</object>

<object Name="Pyovya_SnapjawMage_ProjectileIceTome" Inherits="TemporaryProjectile">
  <part Name="Render" DisplayName="{{C|streak of ice}}" ColorString="&amp;B" />
  <part Name="Projectile" BasePenetration="4" BaseDamage="1d4" Attributes="Cold" ColorString="&amp;B" PassByVerb="crackle" />
  <part Name="TemperatureOnHit" Amount="-4d20" Max="false" OnWielderHit="true" />
  <part Name="TemperatureOnEntering" Amount="-8d20" Max="false" OnWielderHit="true" />
</object>

Now you can change the CooldownAmmoLoader part of your tome of fire and tome of ice objects to use this new projectile.

Wrapping up

We can't forget to give our mages their new weapons! Go back to Creatures.xml, and add the following XML tag to Pyovya_SnapjawMage_Fire Mage:

<inventoryobject Blueprint="Pyovya_SnapjawMage_Fire Tome" Number="1" />

You should also add the Template:Qud chat to the Pyovya_SnapjawMage_Fire Mage's inventory:

<inventoryobject Blueprint="Pyovya_SnapjawMage_Ice Tome" Number="1" />

Going forward

Congrats! You reached the end of the tutorial!

Mopango pilgrim.png < Woohoo!
Sprouting orb.png < I'm ready to go face these mages in magical combat.

For posterity's sake, here's how our mod folder should be structured at the end:

SnapjawMage
├── manifest.json
├── ObjectBlueprints
│   ├── Creatures.xml
│   └── Items.xml
├── preview.png
└── Textures
    └── Pyovya_SnapjawMage
        └── snapjaw_mage.png

Here's what my Creatures.xml contained:

<?xml version="1.0" encoding="utf-8" ?>
<objects>
  <object Name="Pyovya_SnapjawMage_Snapjaw Mage" Inherits="Snapjaw">
    <part Name="Description" Short="A tattered robe and decaying hat are all that protect =pronouns.possessive= thin layer of grizzled fur from the forces of nature. But behind that furtive glance, =pronouns.subjective= =verb:prepare:afterpronoun= an elemental spell, deployed at a moment's notice against threats to =pronouns.objective= and =pronouns.possessive= kin. =pronouns.Subjective= =verb:understand:afterpronoun= not the power that =pronouns.subjective= =verb:wield:afterpronoun=; and that only makes =pronouns.objective= all the more dangerous." />
    <part Name="Render" DisplayName="snapjaw mage" Tile="Pyovya_SnapjawMage/snapjaw_mage.png" ColorString="&amp;O" DetailColor="Y" />

    <inventoryobject Blueprint="Walking Stick" Number="1" />
    <inventoryobject Blueprint="Woven Tunic" Number="1" />
    <inventoryobject Blueprint="Sandals" Number="1" />
    <inventoryobject Blueprint="StandaloneMarkovBook" Number="1-2" Chance="10" />

    <skill Name="Cudgel" />

    <stat Name="Hitpoints" Value="15" />
    <stat Name="DV" Value="4" />
    <stat Name="Ego" Value="17" />
    <stat Name="Willpower" Value="17" />

    <tag Name="BaseObject" Value="*noinherit" />
  </object>

  <object Name="Pyovya_SnapjawMage_Fire Mage" Inherits="Pyovya_SnapjawMage_Snapjaw Mage">
    <part Name="Render" DisplayName="snapjaw {{R|fire}} mage" Tile="Pyovya_SnapjawMage/snapjaw_mage.png" ColorString="&amp;O" DetailColor="R" />
    <mutation Name="Pyrokinesis" Level="1" />
    <inventoryobject Blueprint="Pyovya_SnapjawMage_Fire Tome" Number="1" />
  </object>

  <object Name="Pyovya_SnapjawMage_Ice Mage" Inherits="Pyovya_SnapjawMage_Snapjaw Mage">
    <part Name="Render" DisplayName="snapjaw {{C|ice}} mage" Tile="Pyovya_SnapjawMage/snapjaw_mage.png" ColorString="&amp;O" DetailColor="C" />
    <mutation Name="Cryokinesis" Level="1" />
    <inventoryobject Blueprint="Pyovya_SnapjawMage_Ice Tome" Number="1" />
  </object>
</objects>

... and here's my Items.xml:

<?xml version="1.0" encoding="utf-8" ?>
<objects>
  <!-- Weapons -->
  <object Name="Pyovya_SnapjawMage_Magic Tome" Inherits="BaseMissileWeapon">
    <!-- We borrow the same description that StandaloneMarkovBook uses -->
    <part Name="Description" Short="Crisp pages of goatskin vellum are bound into a codex." />
    <part Name="Physics" Weight="1" UsesTwoSlots="true" />
    <part Name="Commerce" Value="80" />

    <tag Name="Tier" Value="2" />
    <tag Name="Mods" Value="" />
    <tag Name="BaseObject" Value="*noinherit" />
  </object>

  <object Name="Pyovya_SnapjawMage_Fire Tome" Inherits="Pyovya_SnapjawMage_Magic Tome">
    <part Name="Render" DisplayName="tome of {{R|fire}}" Tile="Items/sw_book_1.bmp" ColorString="&amp;R" DetailColor="Y" />
    <part Name="MissileWeapon" AmmoChar="f" ShotsPerAction="1" AmmoPerAction="1" ShotsPerAnimation="1" WeaponAccuracy="0" />
    <part Name="CooldownAmmoLoader" Cooldown="10" Readout="true" ProjectileObject="Pyovya_SnapjawMage_ProjectileFireTome" />

    <tag Name="MissileFireSound" Value="flamethrower" />
  </object>

  <object Name="Pyovya_SnapjawMage_Ice Tome" Inherits="Pyovya_SnapjawMage_Magic Tome">
    <part Name="Render" DisplayName="tome of {{C|ice}}" Tile="Items/sw_book_1.bmp" ColorString="&amp;C" DetailColor="Y" />
    <part Name="MissileWeapon" AmmoChar="FR" ShotsPerAction="1" AmmoPerAction="1" ShotsPerAnimation="1" WeaponAccuracy="0" />
    <part Name="CooldownAmmoLoader" Cooldown="10" Readout="true" ProjectileObject="Pyovya_SnapjawMage_ProjectileIceTome" />

    <tag Name="MissileFireSound" Value="hiss_low" />
  </object>

  <!-- Projectiles -->
  <object Name="Pyovya_SnapjawMage_ProjectileFireTome" Inherits="TemporaryProjectile">
    <part Name="Render" DisplayName="{{R|stream of flame}}" ColorString="&amp;R" />
    <part Name="Projectile" BasePenetration="4" BaseDamage="1d4" Attributes="Heat Fire" ColorString="&amp;R" PassByVerb="whoosh" />
    <part Name="TemperatureOnHit" Amount="4d20" Max="false" OnWielderHit="true" />
    <part Name="TemperatureOnEntering" Amount="8d20" Max="false" OnWielderHit="true" />
  </object>

  <object Name="Pyovya_SnapjawMage_ProjectileIceTome" Inherits="TemporaryProjectile">
    <part Name="Render" DisplayName="{{C|streak of ice}}" ColorString="&amp;B" />
    <part Name="Projectile" BasePenetration="4" BaseDamage="1d4" Attributes="Cold" ColorString="&amp;B" PassByVerb="crackle" />
    <part Name="TemperatureOnHit" Amount="-4d20" Max="false" OnWielderHit="true" />
    <part Name="TemperatureOnEntering" Amount="-8d20" Max="false" OnWielderHit="true" />
  </object>
</objects>

Extra challenge

Before you go, here's a little challenge that you can use to test what you've learned so far. We now have mages of fire and ice; now, try creating a new snapjaw electric mage, along with a tome of electricity that shoots electric projectiles. You're free to go about this however you wish, but here are some general pointers:

  • You'll probably want to give your new mage the Electrical Generation mutation.
  • When you're creating your tome of electricity, start by having it shoot ProjectileElectroPistol; this is the projectile that is shot by an arc winder. Once you're ready, create your own version of this projectile by referring to how ProjectileElectroPistol is implemented in the game's version of ObjectBlueprints/Items.xml.

Next steps

Sprouting orb.png < What should I do if I want to start designing my own creatures?

TODO

Scratchpad

Lingering notes that will be removed before the final version:

  • How much should we discuss population tables beyond the DynamicObjectsTable tag? Should we write some more in an appendix?