Fighting Fantasy Combat in Twine

August marks the 40th anniversary of the publication of The Warlock of Firetop Mountain, the first volume of the Fighting Fantasy series which combined elements of table-top roleplaying games and Choose Your Own Adventure style books.

Firetop Mountain is notorious for its maze. I spent many hours as a child trying to map that maze and somehow fluked my way out of it. I’ve also “played” Firetop Mountain with both of my children. My son gave up in the maze. My daughter and I got through it and even killed the Warlock, but didn’t get any treasure. I think I put them off RPGs for life.

What has this got to do with programming or continuous improvement or engineering management? Good question! I’ll get to the point.

I follow Rands’s advice in Bored People Quit: “don’t forget what it’s like to build a thing.” So I’ll try to spend some time building little things with different tools, either learning something new or improving and building on what I already know.

I’ve been curious about the Twine, a tool for making interactive fiction. How complex a gamecan you make? How hard is it to do something more than just Choose Your Own Adventure style games? I decided to have a crack at implementing the combat found in Firetop Mountain.

It turns out there are a few different story formats supported by Twine. I went with the latest version of the Harlowe story format.

Combat in the game based on dice rolls, a skill variable, and, if you want to try it, luck. For the first cut I opted to just do very basic combat against one oponent with no option to try for lucky hits or misses, and no trying to escape the fight.

I started with character generation, rolling stats for you and your opponent:

(set: $skill to 6 + (random: 1, 6))\
(set: $stamina to 12 + (random: 2, 12))\
(set: $hits to 0)\
(set: $opponent_skill to 6 + (random: 1, 6))\
(set: $opponent_stamina to 12 + (random: 2, 12))\
(set: $opponent_hits to 0)
(set: $round to 1)\
# Welcome to the Fighting Fantasy simulator
You have $skill SKILL and $stamina STAMINA. Your opponent has $opponent_skill SKILL and $opponent_stamina STAMINA.
[[Good luck!->Fight]]
view raw start.twine hosted with ❤ by GitHub

Combat in the book is a loop where you roll dice for both players and compare attack scores. Whoever has the best score takes two points of stamina off the other. The fight ends when you or your opponent run out of stamina. I implemented the same loop: each render of the fight page is one round where the attack is worked out, damage is updated and you either win, lose, or keep fighting:

(set: $round to it + 1)\
## Round $round
---
=|=
You STAMINA: $stamina HITS: $hits
=|=
Opponent STAMINA: $opponent_stamina HITS: $opponent_hits
|==|
---
(set: _attack to $skill + (random: 2, 12))\
(set: _opponent_attack to $opponent_skill + (random: 2, 12))\
(if: _attack > _opponent_attack)[(set: $opponent_stamina to it - 2)(set: $hits to it + 1)\
### You hit your opponent for 2 points of damage]
(elseif: _attack < _opponent_attack)[(set: $stamina to it -2)(set: $opponent_hits to it + 1)\
### You are hit by your opponent and take 2 points of damage!]
(else: )[
### You both probe with your swords but neither is able to land a solid hit]
(if: $stamina < 1)[The last blow does you in. [[You see black before your body hits the ground->Dead]]]
(elseif: $opponent_stamina < 1)[Your sword pierces your opponent's armour and he is run through. [[He looks surprised, then annoyed, then dead->Win]]]
(else: )[You circle each other. This match isn't done yet.
[[Keep fighting->Fight]]]
view raw fight.twine hosted with ❤ by GitHub

My amazing design skills created this user interface:

a screenshot of combat

Once I had basic combat in place I set about copying passages from the book into a new story. I started at Passage 1 and proceeded numerically, ignoring the narrative order. The combat code remained fairly generic. I incorporated trying for lucky hits and misses, and allowed players to escape a fight. I used used Harlowe’s Datamap type to encapsulate all the variables in fight, but man, that syntax got ugly fast.

After getting combat fairly reliable and copying out several dozen passages, I was pretty much done with Firetop Mountain in Twine. Could I do the whole thing? Probably. Do I want to? Nah. I’ll stick to my really dog-eared book, thanks.

Joe Mahoney's Picture

About Joe Mahoney

Joe is a software engineering leader, programmer, surf life guard, and runner who writes about and curates links covering links covering software engineering and management, career growth, continuous improvement, creativity, and productivity.

Wellington, New Zealand