Treasures

Like King of Dragon Pass, Six Ages will include magical treasures. They’re Gloranthan (they were in the original White Bear & Red Moon game, and lots more in the subsequent Nomad Gods), and they are a useful reward and fun to collect.

And they’re essentially all unique, which is great as a player but less wonderful as a developer.

As a developer, I want treasures to be easier to work with this time. KoDP had some annoying limits on how many there were (adding a treasure meant breaking the file format of saved games), which was an obvious thing to improve. But KoDP had the implementation of treasures scattered everywhere. Basically, each treasure needed specific C++ code, plus it might have to be listed in an IsBattleTreasure or TreasureThe (it’s “Vinga’s Comb,” not “the Vinga’s Comb”) function.

First, we designed as many as possible with script tags in mind. In other words, Robin Laws would describe a treasure’s effects as “+1 to Bargaining and Diplomacy in scenes tagged @outlanders.” Then, I’d specify treasures as Lua data like

modifiers = { Bargaining = 1, Diplomacy = 1 },
requires = { "@outlanders" }

so there’s no treasure-specific code. Compare to KoDP having to insert lines like

case code_Leadership:
    if (ourClan->HaveTreasure(kRingMadeFromVingkotsCrown))
        skill++;

Part of the advantage is that the details of the treasure effect are all in one place, next to metadata (such as name, description, value, use of “the,” and whether a treasure needs to be chosen in battle).

The data-driven approach also handles things like “mood+=13 on any Food win”

onWin = {"Food", "mood", 13},

Combat has some additional complexity, so “+1 Combat when raided by elves” is the Lua table

battle = { type = type_Raid, defender = true, opponentStereotype = "aldryami", bonus = 1 },

To summarize: we tried to design to a number of patterns, wrote general-purpose code to handle the patterns, and then specify how a treasure slots into the pattern with Lua data.

Of course, magic doesn’t always fit a pattern, so we can run an OSL script

everyTurn = "fragment_MostaliMill"

or have a script check for a treasure

code: fragment_SacredTime
[HaveTreasure('bowlOfUnity)] {
    # .magic +=1 each Sacred Time if Expansiveness>0

Not quite as good as pure data but better than requiring code.

Quasi-Treasures

A treasure is now a way to encapsulate a conditional modifier. I started to notice another pattern, where player choice could result in a modifier. Rather than come up with a new scheme, I just made new treasures. (I called them quasi-treasures because they act like treasures but don’t look like treasures. Notably, they don’t appear in lists of treasures in the user interface.) In fact, one of the examples above is actually a quasi-treasure.

Treasures are typically gained permanently and quasi-treasures often go away after a certain number of years (for example, the visiting priest’s blessing lasts five years). This can be handled by the normal GainTreasure/LoseTreasure functionality (i.e. just queue a script to run in five years that executes the LoseTreasure function).

malletOfPlentyPictures?

We discussed showing treasures, and Jan mocked up a treasure illustration. However, I decided against a visual representation. It’s a lot of work just designing what dozens of treasures look like, let alone getting all the pictures. More importantly, it would increase the difficulty of adding new treasures in an update (which we did twice in KoDP, despite the hassle), since they would need pictures.

So this is the only place you’ll see the mallet…

Art Styles

One of the ways that Six Ages is following in the footsteps of its predecessor is to use very distinct art styles for different purposes. Here’s a brief look at the directions we’re going.

The Distant Past

HealerAlthough we debated a variety of styles, in the end we decided to stick with a “woodcut” look to represent things that took place a long time ago (i.e. for the clan questionnaire). I found our artist because she had a show at the gallery a few blocks away. Here’s a look at a Gods War event by Damara Kaminecki.

The Present

Troll tradersKeeping the ink and watercolor style for the bulk of the illustrations, which are set in the here-and-now, was not really questioned. We did consider different nuances, and Jan Pospíšil did a few test pieces. There are a number of artists working in this style — this is one of Jan’s early pieces, which helped establish the tone. (Note that the trolls are awake early, since the sun has not fully set.)

The Otherworld

Blue DragonThe world of the gods is key to a game set in Glorantha, and we again wanted a look that was very different from the mundane world. We didn’t have any preconceptions, though once again we were drawn to Magic: The Gathering artists. But we ended up going with a local artist, who has a distinctive style. Here’s Michelle Lockamy’s take on a Gloranthan archetype, the blue dragon.

So It Is Written

Rune of writingThe game just hit an important milestone: our writer/designer Robin D. Laws has completed his work. All of the interactive scenes and myths are written.

This doesn’t mean the game is almost done. If I recall correctly, Robin also finished his work on King of Dragon Pass well before anyone else. But it does shift gameplay development into a refinement phase.

Other aspects of the game have only barely started, such as music and a tutorial. And there’s still a lot of art to draw.

And it’s possible we’ll need a few new scenes, though someone else will likely write them.

A very approximate guess as to how much Robin has written is 400,000 words. (The scene compiler outputs a text file with all the strings, which we will be spell checking. This file contains 402,293 words, though some of these are names of music or other aspects of implementation.) That’s as much as ten short novels!

While you’re waiting to read Robin’s work in Six Ages, you can check out some of his other recent work, which has been nominated for ENnies Awards.

Sweeps Week

s235-pencils-cropSince essentially all of the game’s scenes have been written and coded, I figured it’s time to start sweeping.

“Sweep” is the term we use when we find an issue, and realize that it could apply to every scene in the game.

For example, the bug report

I noticed a [q > 4] which is probably not possible

is something that could affect any scene. So today I searched every script (i.e. swept the code) for similar patterns (e.g. [q = 4] was also a problem, because in rare cases, the special variable q can indeed be set to 5).

And the task

Tag @cattleWard for Cattle Ward blessing

meant I had to go through every script and see if the blessing (“Protects our cattle herds from predators”) was relevant. If so, the script needed the tag. Going through everything, I realized that the description actually needed to change, to “Protects our cattle herds from raids and predators.”

The sweep that’s had the biggest impact has been

Sweep to be sure ChooseLeader is followed by a leader test

In other words, if you pick a leader, then it’s that leader’s Bargaining or Combat that will be used to overcome opposition. We had tried to catch these cases, but missed a few. And this was by far the most brute force sweep, since ChooseLeader is very common.

It looks like there are about 15 of these in our bug tracker, and about half are done. I expect to finish them this week.

 

Scene Tags

Since Six Ages is our second iteration of a storytelling game, I wanted to make sure it would be easier to do certain things. Being able to categorize scenes was something that was easy to improve on, since in King of Dragon Pass, everything was a special case. For example, when we wanted to make sure you got to deal with tribal disputes when you were a king, we had to list them all.

switch (COpal::DieRoll(4)) {
 case 1:
 scene = scene_R397TradeDispute;
 break;

case 2:
 scene = scene_R398MagicalDispute;
 break;

case 3:
 scene = scene_R399PoliticalDispute;
 break;

case 4:
 scene = scene_218ComplainORama;
 break;
}

This was fragile — scene_218ComplainORama was actually a fairly late addition in version 2.x, and I had to make sure that it was included in that code.

Likewise any news that was considered a random rumor had to be listed. This at least was data instead of being buried in C++ code, but it was still separate from the actual news.

SceneIDT CScene::gRumors[] = {
 news_FF13MoreChaos,
 news_FF14LessChaos,
 news_FF15MoreUndead,
 news_FF16LessUndead,

So I came up with the idea of tagging scenes. Here’s what the OSL documentation says:

Tags begin with @. They can be any word (e.g. @help, @hurt, @tutorial, @actThree, @endgame, @notEnd, @codeTrigger, @frequent, @infrequent). Tags can be purely informational, only a few have predefined meanings. Feel free to invent tags. Tags could be used when triggering scenes at random. (For example, if the player is doing poorly, there could be an increased chance of an @help scene. If the player is very wealthy, it might be time for an @hurt scene.)

So there could be an @kingly tag and an @rumor tag. Implementing a random rumor can start with something like

rumors = [self scriptsWithTag: @"rumor" ofType: type_News];

which searches all scripts for the tag (also choosing only news scripts). A typical rumor will include the tag

news: news_R14Quake
@rumor
speaker: WhoHasHighestSkill(ClanMembers, 'magic)
text: I don’t have to tell you about the earthquake, since everyone felt it.

Most of the tags are indeed invented (usually by Robin Laws as he writes scenes). To help check on consistency, the scene compiler outputs a report of tag usage, which lets us make sure it’s consistently @dwarves and not sometimes @mostali or @dwarfs. A few are used internally (e.g. @nameEntry marks a script that needs a name field added to the UI), but most of these let us control the story.

For example, Robin can create a scene where you perform anti-dwarf magic and write, “Scenes tagged @dwarves do not trigger 30 + q seasons,” which can be coded

DisableTag("@dwarves") 
t = "@dwarves"
w = 30 + q
triggerWithValue code_EnableTag t w

(This takes 4 lines instead of two because of some limitations in the OSL scripting language.) A typical dwarf-related scene would then be tagged

scene: scene_37DwarfTrade
scene037, left, random, @dwarves, @trade, mayRepeat

The arbitrary tags also help implement the magic system. For example, a magical effect can be defined as

{
 name = "Elf Friend", tag = "@elves",
 explanation = "Helps our dealings with the Aldryami"
}

which gives a bonus to any scene that has been properly tagged. One of the tasks to do once all scenes are coded is to verify the tagging for magical blessings that depend on it.

Robin extended the idea with what I call dynamic tags. For example, he came up with a scene which could have a variety of outsiders. So he wrote, “scene gains tag @dwarves.” The implementation is

AddSceneTag(ThisScene, "@dwarves")

Obviously, making sure a scene has the right tag for a random outsider is important when there are blessings that are tied to tags.

I’m also making use of tags to help ensure correctness. For example, sometimes a scene wants to trigger another scene years later, but perhaps a character in the scene is off exploring when the time falls due. We handle this by triggering a code fragment, which can handle whether the character is exploring, died, or whatever. This sort of check is usually added once we start testing, and it would be nice to make sure that we caught every place that triggered the delayed scene. So the scene compiler makes sure that any scene marked @triggerFromCode can’t be triggered directly (but only from a code fragment tagged @triggeringCode).

And our unit test that runs every script simply runs them in an arbitrary order. Scenes may rely on having been run in a particular order, so the unit test may need to do setup that would have happened in normal execution. So there are tags like @unitTestWithClan and @unitTestWithPerson. This isn’t necessarily an exact match for normal execution, but it works for this level of brute force testing.

By the way, the @help/@hurt idea is not implemented at the moment. I’m not sure if it will be, but the flexible tagging system makes it easy to add at any time.

Sacred Time Recap

Several King of Dragon Pass players requested a way to see what their Sacred Time allocations of clan magic were. In most cases, advisors will remind you on the relevant screen (especially in version 2, which added a lot of advice to the management screens). For example, in the Magic screen, if you put points into Quest magic, someone will have the advice “We prepared for a quest during Sacred Time. Our chance of success is good” (assuming it’s not trumped by some other circumstances).

Magic ScreenWhen I began Six Ages, I wanted to have a centralized place to see everything. Until recently, it didn’t seem like it would fit. Then Robin Laws suggested showing some other information, and I realized that the Sacred Time allocations could be added as well. (The slider lets you choose to see the gods, or the new other information.)

Concept Inspiration

Raven ConceptSomewhere along the line, Jan Pospíšil drew a concept sketch that I liked, but that didn’t seem right for a member of the player’s clan (which was the original thought).

Recently, Robin Laws and I were going over the interactive scenes that are currently in the game, and figuring out what was lacking. He came up with a new scene that seemed like it perfectly fit the sketch.

So the scene is now written and coded, and we’ll be doing a full illustration based on the quick design. Sometimes good concept ideas never make it into the game, but I’m glad this one can.

Testing In Bulk

Like King of Dragon Pass, Six Ages is a large, complex game. That means that during development, there will be a lot of bugs.

Graph of scenes written, coded, testedThe best way to find them is to start testing early. I like to start QA as early as possible, once there’s a runnable game. For example, we can start the process of making sure every interactive scene works.

We have a really good QA tester, but like KoDP, there are a lot of scenes, with a lot of branches. One of the process improvements over KoDP is that we have a way to brute force test every response of every scene. This is only a supplement to human testing. It can make sure nothing crashes, but can’t find typos or situations where the wrong person is mentioned. But it does mean we don’t waste QA’s time with testing something that isn’t fully implemented.

Some bugs have patterns. If one scene has a problem after the player has made a major story choice, it’s likely that others will too. I usually track these in our bug database as a “sweep,” meaning once all the scenes are coded, we will have to search the code for possible occurrences. We still report fix bugs as we go, and when this situation came up again in a scene, I decided to try out an idea: change the brute-force testing to set up the story situation, and then run the brute-force test. Bingo! Ten failures. Or, ten places that a person doesn’t have to either read code and see what’s going on (in a code sweep), or write up a bug report (manual testing).

Last night I got a bug report about a scene failing when there was no chief. So I decided to do another brute-force test. This found a lot of problems in scenes that had not yet been tested.

Unfortunately, the brute-force testing of every branch of every scene takes about two minutes (and getting worse, as we code more scenes). So while I probably should run each brute-force variant, for now I’m relegating them to occasional situations. But I’m definitely going to look for more places to do this.

Thumbnails

When we work with illustrators, we’re still using much the same process as we did with King of Dragon Pass. We first get a thumbnail sketch to figure out the basic layout of the illustration, then get a more refined pencil sketch. We’ve also been reviewing an inked version, and then a colored version. Some of these terms are no longer as literal as they were back in the 1990s (more artists are using a digital process, so there may not be actual pencils or ink pens involved), but the same basic idea of refinement is the same.

One thing I’ve found a bit different in this project is what different artists consider as a thumbnail. I had never seen color used in a thumbnail before, but two artists have done so. And some of the thumbnails are very polished.

A few artists will also produce a lot of alternatives (in one case, a thumbnail was so different that it generated a new scene).

Here’s a representative sample, from five of our artists.

  

I chose these to show the range of detail. Some of these may not actually end up in the game. But they’re all perfectly good thumbnails that start the process of illustrating an interactive scene.

Header Runes

The runes in the header correspond to the seven personal skills in the game. They’re slightly different than in King of Dragon Pass, since we won’t have quite as big an emphasis on farming. Animals and Plants have been combined into a single skill, Food. And since it’s a clan-level game, we added Diplomacy as an explicit skill, rather than just averaging Bargaining and Leadership. (Bargaining, Combat, Leadership, and Magic are the same. Custom is renamed to Lore to reflect a wider use.)Trade, Death, Harmony, Man, Mastery, Truth, Magic

Most of the skills had fairly obvious runes (Combat = Death, Magic = Magic), but the Food skill gave me trouble until I remembered this:

ManMan rune
Meaning: Mortal humanoids
This Rune represents the humanoid shape, and is common among all intelligent humanoid races. Some other races interpret it as “slave” or “food”.

HeroQuest Glorantha, p. 17