Showing posts with label KoDP. Show all posts
Showing posts with label KoDP. Show all posts

21 December 2015

Treasure

As I mentioned in the last post, I am trying to make as much of the game data-driven as possible. Treasures are a good case in point.

King of Dragon Pass has 133 treasures in the latest version. The exact number matters for saved games (in other words, adding treasures changes the file format). Each treasure has specific code somewhere in the code to implement it — sometimes more than once, to handle battle treasures, source, or reference. This is of course a lot of code to write and test, and it makes it difficult to add treasures. We can do better.

Six Ages has the advantage of being the second time we’ve done this. The treasures are fairly similar in behavior to KoDP, with effects like

.mood+=3 on any Hunting win
+1 on tests vs Skepticism
characters gain +1 on Magic and Diplomacy tests where the player chose them as testee
increase q by 1 on any win vs. Duel
heal d4 sickened each Earth Season

The first four are patterns that are repeat frequently (with different skills or oppositions). The fifth is unique, but is best handled by a script that runs each Earth Season checking for the specific treasure (rather than KoDP’s approach of putting this in C++).

Here's how the first two can be specified:

{key = 1037, name = "Happy Hunting Ground",
summary = "Dirt that improves mood when hunting goes well",
onWin = {"Hunting", "mood", 3},
pool = TRADE},

{key = 1041, name = "Golden Drinking Cup",
summary = "Helps overcome skeptical minds",
modifiers = { Skepticism = 1 },
pool = EXPLORATION},

Obviously there needs to be code that checks for the onWin slot when a test is won, and the modifiers slot when a test is made. But that code then handles a wide variety of treasures.

Treasures now have unique keys, so it’s easy to add new ones. And the pool slot makes it simple to specify that a player might obtain the treasure by trading with another clan, or by exploring.

Combined with scene tagging, it’s also much easier to implement a treasure like KoDP’s Iron Spike, which included the effect

gain +1 to all tests made during Scenes R137, R163, R166, R181 and R200

If this treasure were in Six Ages, the effect would be specified

modifiers = {["@troll"] = 1 },

which means it would work for any new troll scenes, not just those created at the time the treasure was created.

Of course, nothing about this approach precludes custom code. But it massively reduces it, so only unusual treasures will need it.

10 September 2015

Data Based

I’m trying to make Six Ages easier to create and (hopefully) expand, compared to King of Dragon Pass. One way developers do this is to turn code into data. This can make it much easier to add new content without cracking open the code.

I was about to implement exploration at home, which presented a good opportunity to do this. In King of Dragon Pass when you explore without moving the exploration marker, this code determines what can happen. If we add a new possibility (or have to remove one), the code has to change in several places.

In Six Ages, this is reduced to four lines of code (which actually handles the default case which is not shown for King of Dragon Pass), and this data. New items can be added (or removed) trivially, which is good because I have not yet written all of the new scripts.

Note that the code specific to exotic goods doesn’t exist any longer either. Similar lines are now in scripts, which is a similar push to move code into scripts. (Scripts are still code, but a much more limited form, and much more specific to the game.)

Exploration in arbitrary places also uses data, though it’s a little more complex (and integrated with the map metadata).

While the data-driven approach is easier, it’s worth noting that there can still be bugs caused by data. In this case, listing a script that doesn’t exist would be bad, and there’s no easy way to catch that, since this list is in a Lua file, and the script is in an OSL file. However, it’s easy enough to write a unit test.

13 July 2015

Unit Testing

One of the deep secrets of King of Dragon Pass is that we shipped a buggy program in 1999. No, not the normal sort of low priority issues, or bugs rare enough you didn’t find them in QA or beta testing. KoDP relies on its scripting language to execute interactive scenes, and there is a serious bug in the OSL interpreter.

Luckily, there’s a workaround: the logging we put in to help debug OSL masked the bug. So instead of shipping the “release version,” we shipped the “debug version.” (This sort of issue is not unique to KoDP, by the way.)

This was actually something I forgot when I converted the game to iOS. (Looking back at my notes, I may have rediscovered this a day after releasing for iOS…) And I ended up making the same decision. It works in debug, so ship debug.

It turned out that even with debugging output turned on, there were a few extremely rare situations where the bug would surface. I believe I found and fixed some of those, but with tools, interpreter, and save files all revolving around the original implementation of lists, it was hard to make enough changes to be certain. And this was tricky code.

Back in 1997, we were very concerned about size (on disk and in memory) so we went to a lot of trouble to make lists (of clans, people, tribes) very compact. In retrospect, we committed one of the cardinal sins of programming: premature optimization. It was a noble goal, but at the start of the Six Ages implementation, I looked at KoDP saved games. Out of 1549 saved variables, 8 were lists. So compact storage was completely unnecessary. Lists are used far more frequently than they’re saved (for example, in picking a random clan from a list of neighbors who don’t hate you), so correct behavior was really the key.

While I didn’t really want to rewrite part of the game that was basically working, there was no guarantee that it would continue to (mostly) work with a whole new game. So Six Ages has a new implementation of the scripting language, from the bottom up. This supports new features, but is also an attempt to get it to work correctly in all situations.

So how do you guarantee correct behavior in a complex program? At one level, you can’t — or if you could, it would take too long to prove. But you can write code to test your code. The new implementation of OSL needed unit tests. (The original game had none — it would have been very unusual in the late 1990s.)

Various testing methodologies are big in business software (often combined with build automation), and a sign of a quality open source project is having tests. But it can be tricky to test games. There are ways to deal with randomness, but specifying a situation (like having exactly one non-hating neighbor, the right mix of advisors, or a raid history) or expected behavior for a multi-stage interactive scene can be tricky. And a lot of a game is its user interface, which poses its own testing challenges. Fortunately, while a game as a whole can be difficult to test, subsystems can be tested. The scripting language is just such a system. And even better, the handling of lists requires no testing tricks.

All tests pass!
While I didn’t really use test-driven development, I did start writing unit tests very early, and once in a while did write the test first (specifying correct behavior) and then the code. And when I find a bug in the low-level code, I’ll add a test to make sure the bug is actually fixed, and not reintroduced by later changes. Looking back at the development diary, I see comments like
  • Working on iteration. Hooray for unit tests.
  • And glad I made a unit test, it looks like I need to add a copy of the treasure if I’m mutating them
  • Again, hooray for unit tests. Did it for children, since that’s a kind of complex thing. And it caught a problem with setGoods: too.
  • Oops, that type broke stuff. Hooray for unit tests!
Next post, even more automated testing. (The previous post discussed some of the design changes in OSL.)

06 July 2015

Scripting Changes

King of Dragon Pass’s interactive scenes are the core of the game, and at their heart is the Opal Scripting Language (OSL). Since Six Ages will follow in the tradition of KoDP, it too will rely on OSL.

Or would it? OSL has some limitations, and I considered switching to Lua, which is a much more powerful scripting language (and widely used in games). If I was going to have to rework OSL (see below), why not just move to a well-known and reliable language? In the end, I decided to stick with OSL. Its syntax was designed around the needs of KoDP-style scenes, which makes it easier to convert from an author’s script to a runnable script. And OSL scripts can be saved saved in a single file but loaded individually, which didn’t fit the Lua model. (This is likely to be important on memory-constrained mobile devices.) Finally, I already had an OSL compiler and interpreter.

They just needed updating. One of the biggest problems was that the number of scripts and variables had to be known when a game was saved. This made adding new content difficult. This meant some significant changes under the hood to allow for future growth.

I also wanted to make scripting easier to use. It was already safe (in that problems with a script were very unlikely to crash the game), but you sometimes needed to jump through hoops to work within the syntax or implementation details (you could only get the properties of some variables, not all). Placeholders could be easier: <duel/fight> rather than <d2:duel/fight>. And could allow nesting: <it was not {t}’s fault/{t} was blameless>. Or even allow music to change in the middle of a scene.

Another usability improvement would be to allow scripts to run other scripts, or to check the scene queue.

A few small changes would allow the clan questionnaire to be a script, rather than custom-coded. And we could tag scenes, for example to make sure they appeared at random at the right dramatic phase.
scene: scene_1Friendmaking
scene001, left, [CouldBefriend <> 0], @Diplomacy, @actOne, @staple, mayRepeat
music: "CouldBeGood"
[SceneUsed(scene_1Friendmaking)] {
  f = false
} else {
  # Never been used, so this must be the start of the game
  f = true
}
And there was another reason to rework OSL, which I’ll get into next time.

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

19 December 2014

Concept Art Continues

King of Dragon Pass had great art, but we’re trying to go even better with the concept art for Six Ages. As I said last time, we’re trying to be cool and distinctive, which weren’t explicit goals in King of Dragon Pass. And of course, we now have the excellent art from the Guide to Glorantha to live up to.

Looking back at the original KoDP art, we had only 11 concept sketches, from two artists. For Six Ages, we’ve asked for 72, and have three concept artists. Partly this is because the KoDP concept art only portrayed the Orlanthi settlers (although the game ended up showing 7 other human cultures, plus a couple of historical ones). Glorantha is full of different people, and we might as well figure out what they look like up front.

The team has assembled an extensive set of art reference, drawing from the web as well as printed sources, in a number of languages. (Our shared Dropbox folder is over half a gigabyte.) I borrowed a couple more Osprey books from my brother-in-law, and bought a few more (thanks in part to some good suggestions). A few library books were disappointing only because First Ancient History already included the same illustrations. I also found a few other useful books in my personal library, which I had forgotten about.

We should be wrapping up before the end of the year, and I hope to show you a little of the work in a future post.

20 November 2014

Concept Art Goals

Like King of Dragon Pass, Six Ages is is going to portray a number of Gloranthan cultures. Many of them have not been well documented, so we need to come up with some art guidelines.

I’m asking a few artists to come up with concept sketches. Here are the goals:
  • Look cool (this is a fantasy game)
  • Look distinctive (ideally you can tell from a screen shot that it’s Six Ages)
  • Support the story (players need to identify who is who from the picture, so different groups need to be recognizable)
  • Look realistic (it should feel like these are real people living real lives; many fantasy art staples like chainmail bikinis wouldn’t work)
  • Not just a transplanted Earth culture (it’s totally fine to draw on Scythians or Hittites, but if so that should only be one element of the design)
  • Fit the setting (Six Ages is set in Glorantha, and needs to be compatible with the license)
  • Be acceptable in the iOS App Store (the Minoans had no problems with an open bodice, but Apple would. Guide to Glorantha doesn’t have the same restrictions, and can portray people living in warm climates wearing appropriate lack of clothing.)
To help my own imagination, and to provide reference as needed, I ordered a bunch of Osprey books. They tend to be a bit military-focused, but have great reconstructions with lots of detail. The books cover the time period of 5000 BC-1500 AD, so we can definitely mix & match as needed.

Many of these books came out since we did King of Dragon Pass, which had its own collection of Osprey references (which I’ve also dug back into).

It’s too bad the Tessloff books aren’t easy to get in the USA, So lebten sie zur Zeit der Wikinger was a great reference for daily life (we used it for King of Dragon Pass), and I suspect they have others that would be helpful.

For that matter, am I missing any other Iron Age or Bronze Age visual references?

P.S. I ended up ordering a few more references. The Mayas book (which is not an Osprey) may actually have the same content as a Tessloff edition.

28 October 2014

The Saga Begins

Fifteen years ago, A Sharp’s first game went on sale. King of Dragon Pass was a unique blend of interactive storytelling and resource management, set in the mythical world of Glorantha.

In fifteen years, there has never been another game like it. King of Dragon Pass had its own influences, and has influenced other games. But nothing else interwove stories of politics, culture, and individuals, and tied them together with a living world of magic.

We are now working on a successor, with the working title Six Ages.

Over the years, lots of people asked for a sequel of some sort. The obvious follow-up would be a game that was just King of Dragon Pass with new scenes. I know that some players would be pleased with that, but that never felt like enough. If I’m going to work on something for over a year, the project needs to have at least some novel twist. (It doesn’t have to be as groundbreaking as King of Dragon Pass, which I believe was the first storytelling strategy game!) Over the years I toyed with some ideas, but nothing seemed like it would work. Finally, a few months ago, I had an inspiration.

Unfortunately, I can’t tell you much. Partly that’s because development is still in the early stages. Mostly it’s because Six Ages is an ambitious project, and won’t be released for well over a year. A lot can change in development. And right now, there’s nothing interesting to show anyway.

But I can say that the game will consist of meaningful story choices tied together by the economic challenges facing a small community. It will be set in Glorantha and draw from its rich cultures and mythology. And it’s intended to be highly replayable.

And I’m excited that I will again be working with writer and game designer Robin D. Laws, and artists Jan Pospíšil (who did illustrations for King of Dragon Pass) and Pat Ward (who I worked with at Shenandoah Studio). And when the game is further along, Liana Kerr will again be doing QA.

Over the coming months, we will be posting more, both here and on Twitter @SixAges. Anything of a more permanent nature will be on the game’s web site.