15 April 2015

Dissecting the King of Dragon Pass Map

The approach we used for King of Dragon Pass’s map worked pretty well, so I expect to be using it again. If only I knew what it was…

That is, I know how the King of Dragon Pass map works, but not how to make it.

The map tracked where clans were, and what you had explored. Exploration was represented by a hexagonal grid. (Coincidentally, the hexes are the same size as the Dragon Pass board game map, or Guide to Glorantha. They’re positioned for game convenience though, and don’t try to align with any published map’s hexes.) A hex was considered explored or not. The map was drawn by first drawing the unexplored map (the memory of your ancestor’s time in Dragon Pass). Then the detailed map, masked to show only the explored hexes, is drawn on top. Finally, any labels (such as clan or tribe names) are drawn.

KoDP clan zones labelled in this zoomed-in view
Clans were positioned in one or more zones, irregular shapes that conform to the topography. At the start of the game, clans occupy contiguous zones, though occasionally this can change during play. Zone assignments weren’t completely fixed, though for example the Colymar tribe’s clans started out in one of the nine zones of the Nymie Vale. Note that there are spare zones at the northeast of the map, intended for clans that enter the game during play.

There are also zones used for exploration, so any expedition to say Snakepipe Hollow can result in the appropriate scene or news.

As data structures, zones consist of some metadata (name, whether the zone is along a river), a list of neighboring zones, positioning info, and a Windows Bitmap object defining the shape. This is all saved in a map file. Although the iOS version improved how zones are shaded, the basic data is exactly the same as the CD version we shipped in 1999.

Partly that’s because I have no idea how we made the data file! I still have a bunch of old tools (like a scene decompiler, which was used early in testing and abandoned), but nothing that creates the map. I know that Shawn Steele wrote the tool, but I don’t know how each zone was defined. Presumably there were .bmp files for each of the 122 zones, but I really don’t know for sure.

I’m currently in the middle of working on the new map, so I reviewed all the existing code (and added a quick way to visualize zones, as seen above). This post summarizes the starting point. Once the new system is done, I’ll describe what changed.

02 April 2015

Scripting

Six Ages uses the same Opal Scripting Language (OSL) that we used in King of Dragon Pass (although it’s been improved — a topic for future posts). This is a domain-specific language that’s intended to make it easy to get interactive scenes into the game. As a scripting language, it can also make it easy for someone who is not a C programmer to code game logic.

As a trivial example, here’s a response from one of the new scenes. Getting scenes from the writer to the game is not always this simple, but quite often is. OSL makes it much easier than other scripting langages (like Lua or JavaScript) to handle basic game elements like responses, saga, and text output. Its syntax is designed for the game.

Response 4: Decline.
{
saga: We declined.
sagaText: They said there were no hard feelings and went on their way.
}

One of the goals for Six Ages is to make more use of script, as opposed to custom code. King of Dragon Pass had a lot of game-specific logic in its C++ code. This basically baked in a lot of assumptions, meaning that code couldn’t easily be used in Six Ages, let alone a possible sequel or another game entirely.

The clan questionnaire in King of Dragon Pass was at least driven by data, but had its own code to show the questions, and to provide a recap of the answers. Six Ages has a similar questionnaire, but it’s a series of scripts (which allows for a lot more flexibility). The final page recaps your answers. When you start the game, KoDP ran C++ code that looked at each answer and wrote to the saga, to summarize your answers. But, we already have a script that summarizes answers — the recap page. So a slight variant of that writes the saga. No special code!

In KoDP, we seeded certain scenes (such as the first encounter with the ducks) from C++. In Six Ages, similar scenes are now seeded from the script that runs at the start of a game.

#seed this scene early; equivalent of Bull in KoDP. Season NOT Storm NOT Darkness
x = d3
[x = 1] t = NextSeaSeason
[x = 2] t = NextFireSeason
[x = 3] t = NextEarthSeason
trigger scene_6 t + 5 * d2 # Year 2 or 3

OSL is intended for this sort of thing, so this is much more compact and readable than the non-script equivalent.

In KoDP, there was special code that let you know about the Horse Spawn. Now, a similar situation is handled by the script that handles battle.

Robin Laws wanted a few standard calculations to occur in each scene. So there is now a special script that runs before any scene, that makes a number of political calculations (both external and internal).

One new script facility is intended to leverage scripts: variable watching. You can write a line like

StartWatching("debut")

and any time the variable debut changes, a script will be called (by convention, the variable newValue has the new value of the watched variable):

code: fragment_debutWillChange
[newValue = true AND debut = false] trigger news_ItHasBegin 0

This is also an advantage of creating your own language: if you need a special feature, it’s easy to add. (The disadvantage is that if you need a feature that’s in a more common scripting language, you have to add it.)