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”.
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.
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.