Showing posts with label OSL. Show all posts
Showing posts with label OSL. Show all posts

15 August 2021

KoDP on the web: 50 Years of Text Games / Storylets with Casting

 Emily Short just posted

Aaron Reed’s 50 Years of Text Games has now covered King of Dragon Pass, which I strongly recommend reading: the game used techniques that we’re still very much exploring and discussing now, including elements we might now refer to as storylets with casting (that is, storylets that assign characters to particular roles). Well worth a look if you’re interested in the structure, code, or writing process of that game, or storylet games in general. 

First, Aaron did a very well researched look at King of Dragon Pass. If you’re at all interested in how we made the game (and how our effort at selling it was received), check it out.

Second, Emily’s categorization seems pretty accurate. Our scenes (a term we used because of their similarity to scenes in a play) would now be considered storylets, and they’re chock full of assignable roles. In many cases, that role is a clan (a neighbor, a rival, an ally, etc.). It can also be a character.

Often the role is a requirement for the scene to be run. The scene condition is in square brackets on the second line of this script, the actual assignment is on line 4.

scene: scene_228LetsPretend

scene228, left, [ProDragonewtOnRing AND dragonewt.knowledge <> 'unknown]

music: "CouldBeBad"

p = ProDragonewtCharacter

text: Two children have been pretending to be the god Orlanth and Aroka, the blue dragon. Somehow, their play has gone beyond pretend, and magic is gathering, almost as if they were on a heroquest.

saga: Somehow two children playing at Orlanth and Aroka started a full-blown ritual.

[ProDragonewt Priority] The children may learn draconic wisdom from this experience. [1]

[Trickster AND ProDragonewtOnRing] Good one, <p>! [1]


This is a fairly typical script. The scene is richer if there’s a named leader who can be involved, and in general, we favor choosing leaders who are on the clan ring. Players have typically had an opportunity to learn a bit about their personality (as well as have invested in them as a representative of the clan). The advisor is curious to know about the summoned dragon, and another character offers a rejoinder.

(This scene was created by Lysander Xen as part of our contest, so it’s technically not part of the version Aaron was describing. The illustration is by Jan Pospíšil.)

Note that KoDP’s spiritual successor, Six Ages, also makes use of storylets. A blog post goes into more detail. But pretty much it’s the technique we pioneered in 1997.

25 August 2013

Anatomy of a Scene

Thinking of entering the Scene Contest, but not quite sure where to start? Let’s look at the basics of scenes.

A “scene” is what we call the basic interactive situation in King of Dragon Pass. It always has an illustration and a choice of responses. In most cases, it also has advice, provided to the player by the most appropriate ring member.

Since the story arc of the long game can take multiple generations, many scenes are designed to repeat within a game. (For the farmers to be unhappy is not unusual.) Others happen only once (babies in shield don’t show up every day), or happen in response to specific situations (tribes only form once, so you only get news about this once, though hopefully in every game).

Here’s a typical scene that happens to occur in the tutorial, as coded in our scripting language. (It’s edited to show only the more interesting parts.)

scene: scene_48SoraWantsWhiteHorse
scene002, right, [sora >= 0 AND .horses > 5], mayRepeat

The second line indicates which piece of art to use (here we reuse the illustration of Sora Goodseller) and which side the text appears (in other words, usually the less interesting part of the art). Next is a condition. It doesn’t make sense for Sora to live forever, so the scene shouldn’t happen after her death. And it’s no fun being asked for a horse when you have none. Assuming the condition is met, this scene occurs randomly. Finally, this scene can repeat during a game (horses don’t live forever either). Scenes don’t repeat for a number of years, however.

Scenes start by setting the, well, scene. Here, there’s a little logic so the text flows better if she has been by before. Note that the situation is also written to the saga.

if [sora > 0] then {
text: Sora Goodseller, a trader-priestess of the talking god, Issaries, returns to trade.
} else {
text: Sora Goodseller, a trader-priestess of the talking god, Issaries, comes to trade.
}
text: In addition to the usual exchange of goods, she asks if we have any white horses.
saga: The Issaries priestess Sora Goodseller came to our clan and asked if we had any white horses to trade.
if [d3 = 1 AND .horses > 5 AND walkthrough = false] then {
w = true
h = "<d2:mare/stallion>"
text: We do have a single white <h> in our herd. Sora made an opening offer of 3 cows worth of goods.
} else {
text: Although we have some light grey horses, none can truly be called white.
saga: We had no white horses.
}

To make things more repeatable, there is a random chance of having a white horse (tracked in the variable w). (For simplicity, the tutorial never has one.)

music: "CouldBeGood"

Each scene has accompanying music relating to the situation.

And now to the responses. These may be shown depending on various conditions. In this case, whether we have a white horse or not. (Remember that the scene won’t run unless we have at least 5 horses, so the response doesn’t need an additional condition.)

[NOT w] response 2: Apologize for not having one, and throw her a feast.
{
text: Sora said that the lack of a white horse reflected poorly on neither our generosity nor our hospitality, and the feast was proof of both.
saga: Embarrassed that we had no white horse, we gave her a feast instead.
.mood += 2
.cattle -= 5
}
[w] response 3: Give her the white horse.
{
otherClan = RandomClan(KnownClans)
text: Sora inspected the horse closely, then insisted on paying for it. She seemed very pleased with the <h>, which she named Snowflower. After taking it for a ride, she told us about her visit to the <otherClan> clan, which had spoken ill of us. However, we realized it was due to a misunderstanding, and she agreed to let them know of this.
saga: We gifted Sora with a white <h>, but she insisted on paying. She helped clear up a misunderstanding with the <otherClan.plural>.
otherClan.attitude += 3
.goods += 4
.horses -= 1
}

These two responses are fairly self-contained. In response 2, we slaughter some cows for a feast, and the people’s spirits raise. Response 3 has some other consequences.

[w] response 9: Sell the white horse for a treasure.
{
text: “I have no magical treasures I can offer, I’m afraid.”
SceneContinues
}

This response doesn’t end the scene. Responses like this can make the scene a bit more complex, or allow the player to make multiple choices (such as sacrificing for magical aid before embarking on a mission).

Most scenes don’t have 9 responses! This one basically has twice as many because it needs to be interesting if you have a horse or not. Our original plan was that every scene have 5 responses. But 3 is enough. The main thing is that there shouldn’t be a response that is so obviously good that players would always pick it, or so obviously bad that they would never choose it. In the first cases, there wouldn’t really be a choice at all. In the second, we would be writing (and testing) a useless response.

Of course, it’s OK to mention other choices, as in some of the advice.

Advice:
[Animals >= 2] A horse is usually worth four cows. [46]
[Animals >= 3] A horse is usually worth four cows, but white horses are fairly rare. [4789]
[Elmal] White horses are sacred to Elmal and to his wife Redalda, the horse goddess. [0]
[Uralda] You can’t get cheese or cream from a horse. [36]
[Trickster AND NOT w] We could paint a horse white, I’ve done it before. [5]
[Daring AND NOT w] Let’s go steal her a white horse! [0]

Advice can be conditional as well. Note that the quality of the advice depends on the speaker’s Animals skill. In general, the game gives skill-based advice first, and then advice that depends on religion or personality. Also note that most of the advice includes recommended responses.

That’s the basics: situation, a few responses, advice. Scenes can be a bit more complex by asking for additional responses. Here’s one from a scene about a suitor.

response 2: “He must first prove himself worthy.”
{
saga: We required him to prove his worthiness.
NewChoices:
text: <l> asks you to name a test for <suitor>:
response Skill at arms
{
}
response Poetry
{
}
response Pig calling
{
}
response Plowing
{
}

Although the examples here are in our OSL scene language, we didn’t expect our authors to write code. Nor do we for the scene contest — just come up with the basic situation (and optionally a way to illustrate it), reasonable responses, plausible consequences, and some advice.

08 June 2013

Architecture Redux

I’ve mentioned the game’s architecture before, but understanding it helps answer some common questions, so I thought I’d draw a picture.


The game has three main divisions. In the original version, different developers were more or less responsible for each.

The user interface (the 50 or so screens and dialogs) were created for the Windows and Macintoshes of the day (that day being somewhere between 1997, when we started the project, and 1999, when it was released). We used mTropolis, a powerful multimedia development system that was discontinued over a year before the game came out.

The interactive scenes (and news) were coded in OSL (the Opal Scripting Language, or the Opal Scene Language).

The game engine, written in C++, executed the OSL code, ran the economic model (tracking cows and the effects of treasures on them), and was responsible for saving the game. It was cross-platform, running equally well on Mac OS and Windows.

When we created a new version for iOS, the basic game code and the scenes didn’t need radical change. Both were enhanced (for example, the game had more advice and supported 7 new treasures, and there were 28 new scenes) but existing code continued to work. By contrast, none of the user interface code could be used. Not that it would have mattered much, the small touch screen needed a new user interface anyway. This was a very substantial effort, and it ended up being partly duplicated for iPad and again for the 4 inch display.

There are numbers in the diagram because they suggest why the iOS version is distinct from anything else. Saved games assume a specific number of scenes and treasures. Adding more would mean substantial reworking of the C++ code. But this code had to work with mTropolis, so it’s tied to 1998 era systems. The hardware and compilers I used back then are long gone.

So that’s why the GOG Windows version can’t be updated.

Some have asked about a new Windows or Mac version, or an Android version. Since mTropolis no longer exists and UIKit is iOS-specific, any version for any other platform will require reworking the user interface (possibly with some redesign, definitely a brand new implementation). Think of it was rewriting a third of the game.

The first iOS release took about 20 calendar months. Since the C++ code didn’t need significant updating, the user interface could thus be said to be about half the code needed for that project.

Actually, there was some new C++ code, because we wanted to add Game Center achievements. Most of this would work on Mac OS X, but not on other platforms.

So unlike the original version, where it was trivial to build for both Mac and Windows, there’s a daunting amount of work to bring the game to another platform.

What we’ve done instead is reflected in those numbers: reworking the 50 screens for iPad (and soon the iPhone 5). And adding new treasures and new scenes in an update we hope to release this month.

18 March 2013

30K Sale(s)

text: We’re very pleased to let you know that our <d3:unique/distinctive/indie> game King of Dragon Pass has sold over 30000 copies in the App Store! To celebrate, we’re putting the game on sale for 30% off, for three days.
music: "WeDidIt"
price = price * 0.7 # 30% off
trigger code_SaleOver 3  # Sale ends in 3 days

Response 1: Buy Now!
.fun += 1000
.goods -= 7
text: Clan members were heard saying things such as “<d3:This is undoubtedly the best rpg game on iOS./This game is simply brilliant./I must have put in 30 hours by now.>”

Response 2: Wait 3 days for the regular price, to support the developers.
.fun += 1000
.goods -= 10
text: Clan members could be heard saying such things as: “d3:A game with more depth and heart than you can shake a stick at./Thank you dev team for such a great game that I will be playing for years to come!/Congrats to the developers on making something so different and downright fun.>”

Response 3: Send messengers to nearby clans to let them know.
foreach c in NearbyClans
c.fun += 1000
aSharp.obligations += 1
SceneContinues

Response 4: Get the Windows version on GOG.com.
text: Clan members were sad that we had no iPad, iPhone, or iPod touch. But they praised the ring for finding another way.
.fun += 999

Response 5: Ignore the opportunity.
text: Clan members shook their heads and muttered darkly about the foolish decisions their leaders were making.
.mood -= 25

Advice:
[Storytelling] Get this game. It’s tribal politics and role playing at its best. Play it as if you are in the shoes of your clan leader or as you wish yourself; whatever brings you into the world, live it. You will not regret a thing. [1234]


02 September 2012

How Many Scenes?

A long-time player recently commented about how he had just gotten an interactive event he had never seen before. This is not as surprising as it sounds, even for a player who has had the game over a year, because many events are conditional, and the raw number is such that you won’t get each one every game. But I was curious about the exact odds.

Counting

The game calls interactive events “scenes,” which is biased towards the illustrated events. There are 1624 in total, but they aren’t all story events (scenes). They can be divided into:

code: A chunk of OSL script used to set state or conditionally trigger scenes. These have names like code_InitialTribalAgreements, fragment_BeSureToHaveElection, or code_R115MiddlingPenaltyOver. None of these have any player interaction. There are 464 of these.

news: Some sort of report, given by (or relating to) a single leader. These have no illustration. Most have no interaction, but some do give player choices. A notable subset of interactive news is heroic combat during a battle. Battle results is treated as a special case, and is shown with two illustrations. News scenes have names like news_TradeRouteEnded, news_R45aGrainHeFound, mission_EmissaryBanditAttack, or battle_HesGoneBerserk. There are 462 news scenes.

scenes: Interactive events are the core of the game. They always have an illustration, and at least one leader giving advice. They have names like scene_2Trader, scene_R194WeddingCelebration, or mission_ProposeAlliance. There are 614 of these.

quests: Heroquests are essentially a special type of interactive event, with no advice. There are 84 of these.

So there are 614 scenes defined in OSL, but it’s not really accurate to call all of those interactive events. That’s because when we designed an event, we sometimes wanted to show new advice in response to player choices, or change the background music to reflect a change in situation. This was implemented as switching to a new scene. So scene_R59TheChallenge might trigger scene_R59aChallengeResult, but that’s really just one event to the player.

Luckily, we were pretty consistent about naming scenes, and by looking for that pattern (R59a as opposed to R59), there are 70 scenes that are followups within an overall event.

That leaves 544 distinct interactive events. It’s worth noting that 28 of these are new in the iOS version (25 were in version 2.0, and one is new in the upcoming 2.1).

Calculating

But, what are the odds of not getting one of the 544? All scenes are not created equally (we kept the amount of branching in the game to a minimum, but some scenes directly depend on earlier choices), and many have specific preconditions. There’s no good way to figure that, so we’ll assume each does have an equal chance of showing up. If there are 5 random events each year, the odds of not getting a specific one each year is 99.1%. How long is a game? That can vary widely, but looking at two sagas of complete long games that are in our bug tracking system 48 to 58 years. For this quick calculation, let’s call it 53. So the odds of not getting a particular scene during a game are over 61%. Now we have to figure how many games. King of Dragon Pass is highly replayable, but even a hard-core player might not play more than 12 games in a year. The odds of not getting a random scene in a year of play are thus only around 0.3%.
A (thankfully) rare scene

It turns out the scene in question was not random, however. It related to the harvest, so it could only occur in Earth season. That means each game has over a 90% chance of not getting it, and thus he had a 31% chance of not seeing it in 12 games. Except that there was another condition on the scene, so the odds of getting it plunge even more.

(The odds would be slightly different for the original Windows version, but I’ll leave that as an exercise for the reader.)

Conclusion

So what does this analysis say? I think it verifies our design goal of replay, since you will not see many scenes your first game. (And this is only talking about events, not your responses to them.) And even if you have played a dozen games, you have a pretty good chance of getting something completely new if you play one more.

Also, our marketing copy of “nearly 500 interactive scenes” is conservative, and we should have done the math before.

22 May 2012

Skills, Expanded

I wrote before about the seven skills a leader is rated in. But we wanted to support OSL code such as

test Deception(expeditionLeader) vs Crankiness d6

In other words, like many roleplaying games, people have all sorts of abilities. But seven was already a fairly large number. So we came up with the idea of composite skills. Deception is the average of Bargaining and Leadership.

Including the composite skills, a leader can be tested in
Animals
Bargaining
Combat
Custom
Deception (Bargaining + Leadership)
Diplomacy (Bargaining + Custom)
Exploring (Bargaining + Combat)
Farming (Animals + Plants)
Hunting (Animals + Combat + Plants, special for Odayla worshippers)
Leadership
Magic
Plants
Poetry (Custom + Leadership)
Prophecy (Magic + Leadership)
Strategy (Combat + Leadership) 
Note that not every attempt to compose a poem is automatically use of the Poetry skill — it would depend on the context. But without some obvious reason to do things differently, that’s how we would have coded the scene.

11 December 2011

A Skilled Leader

I’ve seen a few questions about the named leaders, so I’ll amplify a bit on what’s in the manual.

By the way, named leaders are considered nobles (thanes), and are counted as such in the Clan screen.

Each leader is rated in seven skills. These are actually numbers, but rather than report them as 3.3 or 5.12, they’re categorized
Fair
Good
Very Good
Excellent
Renowned
Heroic

Normally any skill less than Good isn’t listed, to make things easier.

In the normal course of events, leaders gradually improve, until age 50. Elders may lose their Combat edge as they get older. (Once in a while characters can lose — or gain — skill in other ways.)

So what are those skills good for?

The quality of the advice someone gives depends on their skills. For example, Vordessa (with Very Good in Animals) can probably give reasonable advice about situations involving cattle health. But someone with a Renowned skill will probably have additional insights. The game favors the best advice, so depending on the situation, Vordessa will more often be giving Combat advice (since it’s Excellent) rather than Animal-related advice.

Leaders are sometimes explicitly tested in their skills. For example, the “Uralda’s Blessing” heroquest is hard because the quester must have a good enough Combat skill to survive the biting things. Or an interactive scene may let you pick who fights a duel or acts as an emissary. Depending on the situation, the game may only let you choose from characters who are likely to succeed. For example, if you won’t succeed unless you have a good bargainer, the “pick leader” dialog will only show characters above a certain level. (What skill is tested is not always obvious, and in fact more than one skill may be important, so you might want to sort the list several ways before picking.)

Leaders are also tested when they act as the clan’s agent. When you pick a response, somebody actually has to perform (or lead) the action. For example, this OSL code

Response 5: “We will go with you, but your clan will owe us a favor.”
{
# Calculate clan relationship bonuses
test Bargaining vs. Bargaining d5 + 1 + n, bonus: b

means that the leader with the best Bargaining skill makes the test on behalf of the clan. (The second “Bargaining” indicates that certain treasures or magic come into play.)

So the skills are quite important. You want leaders on the ring who can give you good values in each of the seven skills.

On the other hand, you also want seven different religions represented on the ring. This matches Orlanth’s first ring, and thus gives magical benefit. There are also times when a leader’s religion gives you additional options, like in this OSL code

[UroxOnRing] Response 6: Conduct a ritual to sense Chaos.

So picking a clan ring is a tradeoff.

Finally, no discussion of clan leaders should leave out their personalities. Everyone is an individual, with an aptitude for poetry, hatred of elves, or a solitary streak. This will color their advice (as they can’t resist from promoting their agenda), or drive their actions. Check out any statements a leader makes when you tap them in the Reorganize dialog, or watch for trends in their advice.

02 October 2011

OSL (King of Dragon Pass scripting)

Several people asked about the scripting language used in King of Dragon Pass, OSL. This stands for Opal Scripting Language, since “Opal” was the code-name for the game. Apparently we once called it “MiniScript” (but quickly dropped that name).

Our original plans were to use a multimedia development system, mTropolis, and augment it with C++. I’m not sure if scripting was in the original plan, but if not it didn’t take long to add. Scripting languages tend to be much higher-level, are often domain-specific, and intended for use by people who aren’t programmers.

In 1997 we didn’t have a variety of existing languages to plug in. (Today I’d probably use Lua, though others might pick JavaScript or C#.) So we came up with our own. The basic idea was that a relatively non-technical author could create files that were almost valid code. I figured we were going to want to review them anyway, so I didn’t worry too much about syntax errors, or doing things that would be moderately complex.

You can see a sample of scene coding on our site (it’s too large to include here).

The main features were:

Structure
We needed to support multiple responses and advice. There are no functions, but there’s simple branching.

Tests
A core concept of the game is that most results are not certain. They require an individual to perform a deed. In game terms, this is a test. For example, one of your leaders will test their Combat ability against a dueler. Or the lawspeaker will test his Custom when arguing a case. Or a ring member will test their Poetry (a composite ability) against the surliness of the clan when trying to calm them.

Tests have two outcomes: win or lose. So OSL has those keywords. Sometimes, the degree of success matters, in which case the variable q is set to the amount the victorious side won by.

Variables
All variables are global. However, single-letter variables are reset to 0 at the beginning of a scene. Variables are easily accessible to the C++ code, and are actually one of the principal ways that the multimedia code can talk to the other portions.

Variables can contain a floating point value, a string, or refer to a person, clan, or tribe. In the latter case, specific attributes could be used (e.g. otherClan.chief or c.leadership). Variables could also hold lists of values.

Functions
We started out with special-purpose functions, often used so that script could handle interaction (such as ChooseSacrifice). But our C++ programmer, Shawn Steele, realized that we could come up with generalized list functions
c = StrongestMilitary(ClansWithPositiveAttitude(NeighboringClans))

Placeholders
All text allowed for placeholders, which would be replaced by a value
response 2: “The <survivorClan.plural> are our neighbors.”
Some of these were context-sensitive, to allow for English grammar (<him/her>). And we had a special placeholder used to vary text (to provide more repeatability).
Bargaining with bandits is <d3:giving chickens to the fox/a sign of how weak we think we are/doomed to fail>

OSL is definitely a “little language” — it’s not Turing-complete. But it serves its purpose pretty well. Robin Laws was able to describe scenes which needed very little cleanup to compile, our QA team was able to read the logic, and it helped glue the mTropolis and C++ code together.

10 September 2011

Repeatability

Many people have been wondering how repeatable the game really is. If there are only 500 scenes, what happens when you play for a week?

It’s certainly true that the same basic situations are going to recur. But we took a number of steps to help things feel fresh when they do:

No scene will randomly repeat for at least five game years.

And by then, it’s likely the context will be different. Is Dorasa still the tribal queen? Have you patched up a feud? Did you finally get fed up with your Trickster and outlaw him? Can you still afford to pay off a request for wergild? The same situation could easily have totally different ramifications. (This is one reason KoDP isn’t a pure storytelling game, but has a relationship and economic model.) And of course, in a different game, the context will certainly be different.

Most scenes have five responses. We tried to make all of them reasonable choices, so you can explore alternatives. (Even bad alternatives might end up with amusing consequences, and a single choice shouldn’t doom you.) And very often a response will test the abilities of a clan leader, and thus have either a successful or unsuccessful outcome.

A number of scenes have internal variation. For example, in one scene a ring member dies tragically. The specific ring member is random. And there are four possible deaths.

On top of that, flavor text is often randomized. Here’s some of what you see if that ring member was slain by a Chaos horror:

text: The ring gathers in sorrow around <c>, who was struck down by a weird Chaos monster <d6:that had the body of a giant snail and the head of a dragon/that looked like a deer but had the face of a troll/that had the body of a scorpion and a human head/that was hiding at the bottom of a pond/that was living inside one of our cows/that was lurking among the trees at the edge of our tula>.

Finally, if a scene logically can’t repeat within one game, it won’t.

So you could think of King of Dragon Pass as composed of a number of storytelling motifs, which it repeats in endless variation.

26 August 2010

User Choices In

As I mentioned earlier, King of Dragon Pass has a pretty wide range of interactivity during a scene. There are almost two dozen ways a script can ask the user for input. All of them are now implemented (though not exhaustively tested). The last was ChooseName, which is actually used in more than two scenes becaue there’s more than one route to a tribe. Here’s a typical one:

response 3: Pick a new name for the tribe.
{
n = "<.chief>i"
n = ChooseName("What do you call your tribe?", n)

Sliders are used in many of these functions. Here’s what ChooseWealthAndFood looks like in the game. They work pretty well on the small screen (at least for me!), and there’s generally space to show them.

There’s still more scene interaction to implement, but this is mostly running other types of interactivity from within a scene: heroquest, raid, exploration.

A note on prerelease graphics: not only is the art not final (the sliders don’t have the correct transparency), but the scene art intentionally has the highest JPEG compression, so the game loads onto a device more quickly.

13 August 2010

Lots to Do

King of Dragon Pass is a pretty big game — over 400 crisis management activities, 75 individual clan leaders, 500 hand-drawn color illustrations, 28 musical compositions. Or you can look at how many words of text are in the game: about 462,000.

But those numbers don’t really have much to do with converting the original game to iOS (the operating system of iPhone, iPod touch, and iPad). The assets can be converted to the small screen with Photoshop batch actions.

King of Dragon Pass has three parts: the game engine (written in C++), interactive scenes (written in our custom scripting language, OSL), and UI code (originally done with mTropolis). It’s the UI that needs redoing for iOS.

The game has something like 30-40 screens or dialogs (not counting help screens). All have to be redone. Many need new layout or simplification, and sliders and buttons have to be hooked up.

We also need to handle the UI for OSL functions like ChooseClan, which lets you pick a clan in the middle of an interactive scene. Here’s a quick look at where we stand so far:
Some of these are relatively rare (if I recall correctly kChooseName is used in only two scenes), but they all need to be reimplemented, and tested.