Modding GearHead Caramel: Create Your Own Adventure, Part One

Contents of the ghcaramel user directory.

One of the great new features of GearHead Caramel is the ability to add your own content that will automatically be loaded and used by the game. If you check your ghcaramel user folder (which should be located in your home directory) you’ll see a bunch of folders for content, designs, and images. Today I’m going to show you how to create your own adventure module.

The content for GearHead Caramel is written in Python, as is the entire game, so it would be helpful to know a bit about the language. It would also be helpful to download the GearHead Caramel source code so you can reference all the tools available and see how the current adventure modules do things. Step one is to create a new Python file in the content folder; I’m naming my new adventure “pirates_of_east_sea.py”.

Source code for Pirates of the East Sea,

You can download this file from Dropbox. Just place it in your content folder and it will be loaded when you start GearHead Caramel. I’ll go through the source line by line and explain what each section does. First, we have the import section:

import gears
from pbge.plots import Plot, Adventure, NarrativeRequest, PlotState
import pbge
from pbge.dialogue import Offer,ContextTag
from game import teams,ghdialogue
from game.ghdialogue import context
import pygame
import random
from game.content.ghwaypoints import Exit
from game.content.plotutility import AdventureModuleData
import game
from game.content import plotutility

This part just loads the Python modules and objects that are going to be used in this adventure. You have full access to all the bits of GearHead Caramel, as well as external libraries like PyGame. You don’t need to know what any of this does right now, but in case you are curious: pbge is the “Polar Bear Game Engine” package; it contains a lot of utilities and base classes for making an isometric RPG. gears is the package that defines the GearHead construction and combat rules. game is the package that contains the user interface bits and adventure content. After it is loaded, the module we’re writing now will be placed under game.content.ghplots.pirates_of_east_sea. The module name is determined by the file name, so if you change the filename to something else the module name will also change.

class EastSeaPiratesScenario( Plot ):
    LABEL = "SCENARIO_PIRATES_OF_THE_EAST_SEA"
    active = True
    scope = True

Next, we define a class for our new adventure. All of the narrative content in GearHead Caramel is contained in Plot classes; EastSeaPiratesScenario is defined as a subclass of Plot, so it inherits all of the regular Plot methods + properties and is able to define its own methods and properties.

The LABEL property is used to locale Plots of a given type. Since there is only one Plot of this type, we want the LABEL to be unique.

The active property determines whether or not this plot this plot is currently active. Seems obvious now that I’ve typed it out. Anyhow, Plots can be turned on or off like a light switch.

The scope property tells the game where this Plot’s methods might get called. If True, this means that the Plot has global scope and can be called from anywhere in the campaign world.

For now, it’s okay to just think of LABEL, active, and scope as magic. That is to say, you can use the words but you don’t need to understand them. We’ll come back to these words later on when we do need to use them.

    ADVENTURE_MODULE_DATA = AdventureModuleData(
        "Pirates of the East Sea",
        "Go fight pirates in Namok.",
        (158, 5, 10), None,
    )

Next we define another property for our EastSeaPiratesScenario class: ADVENTURE_MODULE_DATA. This property marks this Plot as the base of an adventure module, and provides some data that gets passed to the scenario chooser when you start a new campaign.

The AdventureModuleData class takes four parameters: a name, a description, the date of this adventure (in year, month, day format), and the name of an image file to use in the scenario menu. In this case I don’t have an image for this adventure so I just pass None. If you want to add one, the scenario menu image should be a 280px x 500px png (the same aspect ratio as a VHS cassette). You can place it in the ghcaramel/image folder.

    def custom_init( self, nart ):
        self.ADVENTURE_MODULE_DATA.apply(nart.camp)

        # Create a city scene.
        team1 = teams.Team(name="Player Team")
        team2 = teams.Team(name="Civilian Team", allies=(team1,))
        myscene = gears.GearHeadScene(50, 50, "Namok City", player_team=team1, civilian_team=team2,
                                      scale=gears.scale.HumanScale, is_metro=True,
                                      faction=gears.factions.TerranFederation,
                                      attributes=(
                                      gears.personality.GreenZone, gears.tags.City, gears.tags.SCENE_PUBLIC),
                                      exploration_music='airtone_-_reCreation.ogg')

        # Create a scene generator
        myscenegen = pbge.randmaps.CityGridGenerator(myscene, game.content.gharchitecture.HumanScaleGreenzone(),
                                                     road_terrain=game.content.ghterrain.Flagstone)

        # Register the city scene and the metro data
        self.register_scene(nart, myscene, myscenegen, ident="METROSCENE")
        self.register_element("METRO", myscene.metrodat)

Next, we define a custom_init method (method is just a fancy name for a function attached to a class). This is the method that gets called when a Plot is initialized; we will use this to create all the scenes and other things we need this plot to create.

The first thing we do is apply the ADVENTURE_MODULE_DATA to the campaign. Just take my word on it for now.

Next, we create a city scene. We need two teams to begin with: one for the player character and another for the city’s civilians. This will act as a default team when characters are placed in the city.

The GearHeadScene class takes a whole lot of parameters. First it needs a width and height (50×50), then a name, the teams, the scale… is_metro=True marks this scene as the base for a metropolis. Then the city faction is defined, it’s given some attributes, and the exploration music is set.

The city also needs a map generator, and that’s defined next. You can look through pbge.randmaps and game.content.gharchitecture to see various types of map generators and options.

Finally, the scene object gets joined to the map generator object using the register_scene method. This method also assigns the scene an element name, “METROSCENE”. We will learn more about elements next time. The metrodat property of the scene gets registered under the element name “METRO”.

       # Create the entry/exit point.
        myroom = self.register_element("_ENTRY_ROOM", pbge.randmaps.rooms.Room(3, 3, anchor=pbge.randmaps.anchors.south),
                                        dident="METROSCENE")
        mygate = self.register_element("MISSION_GATE", Exit(
            name="To The Docks", desc="You stand before the Namok waterfront. The southern docks are used for terrestrial shipping.",
            anchor=pbge.randmaps.anchors.middle,plot_locked=True
        ), dident="_ENTRY_ROOM")


        # Record the scene/entrance in the campaign.
        nart.camp.home_base = (myscene, mygate)
        nart.camp.scene = myscene
        nart.camp.entrance = mygate

        return True

We need a place for the player character to enter this scene. So, next we add a room to “METROSCENE” and add an Exit waypoint to that room.

The campaign object needs to know about our scene and waypoint, so we manually set the scene and entrance of the campaign to the objects we just created. The home_base property of the campaign tells where to go if the party gets entirely wiped out. We set this to our newly created scene and entrance as well.

The custom_init method returns True to let the plot initializer know that everything went according to plan. We have now created an empty city scene with an entrance point, but there are a few more methods to define before it’s completely usable.

    def METROSCENE_ENTER(self, camp):
        # Deal with recovery of incapacitated/dead lancemates+mecha
        etlr = plotutility.EnterTownLanceRecovery(camp, self.elements["METROSCENE"], self.elements["METRO"])
        
    def MISSION_GATE_menu(self, camp, thingmenu):
        thingmenu.add_item("Exit this adventure.", self._end_adventure)

    def _end_adventure(self, camp):
        camp.eject()

The METROSCENE_ENTER method is called whenever the player enters the scene “METROSCENE”. Scenarios in GearHead Caramel have to deal with dead/incapacitated lancemates manually. Fortunately, there’s an EnterTownLanceRecovery class in plotutility that should be appropriate for most situations.

The MISSION_GATE_menu method adds a menu item to the Exit waypoint we created above. In this case, the added menu item calls the _end_adventure method if selected.

And that’s it! We now have a fully functional (if somewhat boring) adventure module. You can run GearHead Caramel and it will be waiting for you in the scenario menu.

GearHead Caramel scenario menu with "Pirates of the East Sea" scenario present.

There’s nothing but an empty city scene, and nothing to do but exit the scenario, but it works. You can use this py file as a starting point for creating your own adventures. In the next tutorial, we’ll add some actual content.

An empty city map with a lone bored cavalier wandering around.

GearHead Caramel v0.612

CNA-15 Century mecha from GearHead.

I’ve just uploaded GearHead Caramel v0.612. This is just a quick bugfix release- I accidentally broke GH1 character import in v0.611. Also, I added the CNA-15 Century mecha from GH1 and GH2.

You can download it from GitHub, Patreon, or buy it from itch.io. If you are using the itch.io app your install of GearHead Caramel should automatically update… I hope. This is my first time using the itch.io Butler system.

GearHead Caramel on itch.io

Title screen of GearHead Caramel showing a dielancer mecha.

I’ve just uploaded GearHead Caramel to itch.io. Its price there is $10, but you will still be able to download the game from GitHub for free. Think of it as a throwback to 1990s shareware. I hope that if you enjoy the game you will consider buying it to support development.

If all goes well, later on I would like to upload all three GearHead games to Steam. I plan to use the 3D models I’m currently making to fill in all the missing mecha sprites from GH1 and GH2.

GearHead Caramel v0.611

I’ve just uploaded GearHead Caramel v0.611 to GitHub. You can download the binaries from there or from Patreon.

Modding GearHead Caramel: How to Make Portrait Bits

Picture shows a head and arms in the Gimp image editor.

Now that GearHead Caramel is in a properly playable state, I thought I should start explaining how it works. Unlike previous GearHead games, Caramel uses a portrait generator that assembles characters from component parts. Each portrait bit can be anchored to a particular spot on the portrait, can contain multiple images, and each of those images can be placed at different depths. Also, while the portrait is being constructed, a matching 64×64 pixel avatar is also built.

That’s a lot of information to dump at once, so let’s look at a specific example: por_hair_halftail.png.

A hairstyle sprite from GearHead Caramel.

This hairstyle comes in three parts. The first goes on top of the head, in front of any facial features. The second goes on top of the head but behind the ear. The third goes behind the head and the body. You will also notice that the hair is colored pure green (#000100 to #00FF00) and placed on a pure blue (#0000FF) background. Assembled, the hair looks like this:

Let’s start with the color. Most GearHead sprites come with five color channels: pure red, pure yellow, pure green, pure cyan, and pure magenta. For characters, these channels correspond to clothing, skin, hair, metal, and accent color, respectively. The pure colors are used by the color switcher to decide what color each pixel should be in the final portrait.

The easiest way to get the color channels right is to first draw your sprite in black and white, then color it using a multiply layer on top. This can be done in Gimp, Photoshop, and probably whatever graphics program you use unless it’s MS Paint. Use #FF0000, #FFFF00, #00FF00, #00FFFF, and #FF00FF as your colors on the multiply layer.

The Chameleon mecha portrait from GearHead Caramel showing how coloring can be done using the multiply layer.

Next question: How do we tell GearHead Caramel about the new portrait bit? For that, we turn to JSON. Inside the image folder there are a bunch of portrait definition files. Here’s the portrait definition for the hairstyle shown above:

Each portrait bit needs a unique name. The bit type tells the portrait generator when to use this bit; in this case, the type is “hair”, so this bit may be used whenever the portrait requests hair. Next you see definitions for each of the layers giving the image filename, anchor, offsets, depth, and frame information. After that, there’s layer information for the 64x64px avatar. The avatar layers have the same format as the portrait layers. Finally, there is a style tag. This particular hairstyle will normally only be chosen for a character with the “Feminine” tag, but you can disable style tags in the character creator and give this hairstyle to anyone you want.

I have uploaded my portrait work files and JSON definition files to Google Drive, so you can play around with them without needing to download the source code. You can place new portrait bits and JSON files in the image subfolder of your user folder (which should be “ghcaramel/” in your home directory). Please let me know if you have any questions.

GearHead Caramel v0.600: Completely Completeable

GearHead Caramel v0.600 has just been released. The big news this time around is that the DeadZone Drifter campaign now has a proper conclusion. In addition there are new skill trainers, you can buy medicine + other consumables, and you can ask potential lancemates about their skills before you hire them. The binaries for Windows, Linux, and MacOS can be downloaded from GitHub or Patreon.

Try it out and let me know what you think. Happy holidays!

Merry Christmas!

I was hoping to get the first complete release of DeadZone Drifter finished for today, but then last night while I was playing through the conclusion I found a major bug that has somehow gone unnoticed for the past year or so. Anyhow, I fixed the bug, and may or may not post a new release later today. It’s coming up soon at least!

GearHead Caramel v0.560: Kerberos Attacks!

GearHead Caramel v0.560 has been uploaded to GitHub. This one comes with some graphics upgrades, balance tweaks, and the ability to (finally!) retreat from combat… which you might need if you wander into the new Kerberos scenario.

This means things are set up nicely for me to start work on the DeadZone Drifter conclusion. I’m hoping to get the finale ready for release in December. Wish me luck.

GearHead Miniatures!

Those of you who have been following GearHead development for a while will know that I have always dreamed of having physical models of the mecha from the GearHead universe. Well, thanks to the combined magic of Blender and 3D printing, this dream has now become a reality!

Two mecha have been released so far- the Corsair and the Haiho. Three more mecha are nearly ready for release. By default, these models are at 1/300 scale (good for tabletop gaming) but you can scale them up by x2.08 to print them at 1/144 scale (most gunpla + other giant robot models).

You can order GearHead miniatures from Shapeways. If you have access to a 3D printer, you can get the STL and blend files from my itch.io shop or by becoming a Patron at the G.H. Variations level or higher. These would make wonderful Christmas presents for someone, I’m sure.

GHC v0.551: Quick Bugfix

Turns out that v0.550 crashes on a fresh install; many thanks to AmkG for reporting and fixing the problem. You can download v0.551 from GitHub. The only other change for now is that I changed the Corsair’s Heavy Rocket Pod back to 4 missiles from 5, since I’m working on a model of it for 3D printing and don’t want to change the rectangular launcher.

I will post more about the GearHead 3D models later, probably after the test prints get back.