User:Kernelmethod/Sandbox

From Caves of Qud Wiki
Revision as of 21:26, 19 September 2023 by Kernelmethod (talk | contribs) (Add note about the Blue Ctesiphus tutorial)
Jump to navigation Jump to search

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 books that function as 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.

Getting started

TODO:

  • Setting up development environment
  • Where to find game files.
  • Player.log
  • How to perform a wish
  • The _Quickstart game option

Prerequisites:

  • Have played through a good chunk of Qud

Basic concepts

XML

  • What is XML?
  • Tags vs attributes

Wishes

Creating a mod

  • Adding new mod with manifest.json to the Mods/ folder.
  • At the end of this section, modders should have a no-op mod that appears in their mods list.
{
    "id": "Pyovya_SnapjawMage",
    "title": "Snapjaw Mages!",
    "description": "Adds the new Snapjaw Mage creature to Caves of Qud.",
    "version": "0.1.0",
    "author": "Pvovya",
    "tags": "Creature",
    "PreviewImage": "preview.png"
}
SnapjawMage
├── manifest.json
└── preview.png

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 great hero of the snapjaws." />
    <part Name="Render" DisplayName="snapjaw mage" Tile="Assets_Content_Textures_Creatures_sw_snapjaw_warrior.bmp" ColorString="&amp;O" DetailColor="Y" />
  </object>
</objects>

Before I did 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 a new snapjaw like the one below show up:

(IMAGE HERE, INCLUDING DESCRIPTION OF SNAPJAW)

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.
  • 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:

DOWNLOAD LINK FOR NEW TILE

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

Now, 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 when you spawn a snapjaw hero, it'll look something like this:

IMAGE

Cool! Now let's fill out some more details about our new creature.

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" />

Minor details

TODO

<property Name="Role" Value="Artillery" />

TODO

<tag Name="DynamicObjectsTable:Snapjaws" />
<tag Name="AggregateWith" Value="Pyovya_SnapjawMage_Snapjaw Mage" />

FINAL VERSION OF CREATURE XML BEFORE GOING TO THE NEXT SECTION

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. Under your definition of the Pyovya_SnapjawMage_Snapjaw Mage creature in Creatures.xml, add two new creatures:

<?xml version="1.0" encoding="utf-8" ?>
<objects>
  <object Name="Pyovya_SnapjawMage_Snapjaw Mage" Inherits="Snapjaw">
    <!-- All of the stuff that you added in the previous section... -->
    <tag Name="BaseObject" Value="*noinherit" />
  </object>
</objects>

TODO

<?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>

Notice how we've used the Inherits attribute here. We're using our original snapjaw mage creature, Pyovya_SnapjawMage_Snapjaw Mage, 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>

TODO: explain syntax for changing text color.

TODO: explain what's going on in the <mutation> tag.

Now we'll make some similar changes to our ice mages: we'll change their detail 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>

TODO:

  • Inherit from the Snapjaw Hero
  • Add mutations, change colors

Proof-of-concept:

<?xml version="1.0" encoding="utf-8" ?>
<objects>
  <object Name="Pyovya_SnapjawMage_Snapjaw Mage" Inherits="Snapjaw">
    <part Name="Description" Short="Tussocks of fur dress skin stretched over taut muscle." />
    <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" />

    <property Name="Role" Value="Artillery" />
    <tag Name="DynamicObjectsTable:Snapjaws" />
    <tag Name="AggregateWith" Value="Pyovya_SnapjawMage_Snapjaw Mage" />
    <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" />
  </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" />
  </object>
</objects>

Creating new items

TODO: magical tome of fire + magical tome of ice

Proof-of-concept:

<?xml version="1.0" encoding="utf-8" ?>
<objects>
  <!-- Weapons -->
  <object Name="Pvovya_SnapjawMage_Magic Tome" Inherits="BaseMissileWeapon">
    <part Name="Description" Short="A magical tome." />
    <part Name="Physics" Weight="1" UsesTwoSlots="true" Category="Missile Weapon" />
    <part Name="Commerce" Value="200" />

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

  <object Name="Pvovya_SnapjawMage_Fire Tome" Inherits="Pvovya_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" Skill="Rifle" AmmoChar="f" ShotsPerAction="1" AmmoPerAction="1" ShotsPerAnimation="1" WeaponAccuracy="0" />
    <part Name="CooldownAmmoLoader" Cooldown="10" Readout="true" ProjectileObject="Pvovya_SnapjawMage_FireTomeProjectile" />

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

  <object Name="Pvovya_SnapjawMage_Ice Tome" Inherits="Pvovya_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" Skill="Rifle" AmmoChar="FR" ShotsPerAction="1" AmmoPerAction="1" ShotsPerAnimation="1" WeaponAccuracy="0" />
    <part Name="CooldownAmmoLoader" Cooldown="10" Readout="true" ProjectileObject="Pvovya_SnapjawMage_IceTomeProjectile" />

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

  <!-- Projectiles -->
  <object Name="Pvovya_SnapjawMage_FireTomeProjectile" Inherits="TemporaryProjectile">
    <part Name="Render" DisplayName="{{R|stream of flame}}" ColorString="&amp;R" />
    <part Name="Projectile" BasePenetration="8" 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>

  <object Name="Pvovya_SnapjawMage_IceTomeProjectile" Inherits="TemporaryProjectile">
    <part Name="Render" DisplayName="{{C|streak of ice}}" ColorString="&amp;B" />
    <part Name="Projectile" BasePenetration="4" BaseDamage="1d4" Attributes="Cold NonPenetrating" 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>

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.

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.