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).
Pictures?
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…