The next few paragraphs might be a bit technical, but I have an interest/‘ethics’ question for authors below.
For the past year or so I’ve been working on and off on a Recursive descent parser - Wikipedia for choicescript, mostly for my own curiosity and learning. I’ve reached a point now where I have a one to one representation of the majority of what the language can do in a control flow graph, meaning I can start to do some basic forms of static analysis on any choicescript game as a whole.
I’ve got something that will generate a ‘guide’ for a choicescript game, basically a summary of every choice block + what variables change, and what can change. Additionally I make some rough assumptions about what stats can possibly be at different points of a game (ie. when stats change or are evaluated with an *if).
The Question
My primary concern with just publishing everything as MIT now is author interest. On one hand it may be a valuable way to debug choicescript and understand choice flow especially on larger games, but on the other this may conflict with the sold guides that some authors have opted for.
I’d like to hear from authors here, on that point. Either below or in a dm if you’d like me to generate a guide for your wip.
Example for Choice of the Dragon (spoilers):
choice-of-dragons-guide.md · GitHub ← This is a nice rendered version with clickable links, below is raw for on-site viewing. It uses markdown, but this isn’t a requirement.
Snippet For the Opening Two Choices
## <a id="choice-1"></a>Choice 1 [HUB] — startup (purchased)
> …at you. His horse pounds at the ground, carrying the heavily armored warrior as if he were a child's doll. The knight sets his lance to attack you.
>
> How do you defend yourself, O mighty dragon?
1. **I take to the air with a quick beat of my wings.**
- `brutality %- 10 [50 → 45–50]`
- → [Choice 2](#choice-2)
2. **I knock the knight from his horse with a slap of my tail.**
- `cunning %+ 10 [50 → 50–55]`
- → [Choice 2](#choice-2)
3. **I rush into his charge and tear him to pieces with my claws.**
- `brutality %+ 10 [50 → 50–55]`
- → [Choice 2](#choice-2)
4. **A puff of my fiery breath should be enough for him.**
- `disdain %+ 10 [50 → 50–55]`
- → [Choice 2](#choice-2)
5. **Restore a saved game.** [if choice_save_allowed]
- *(no variable changes)*
- → [Choice 1](#choice-1)
## <a id="choice-2"></a>Choice 2 — startup (victory)
> Do you finish him off, victorious dragon?
1. **Of course! How dare he attack me?**
- `brutality %+ 10 [45–55 → 45-60]`
2. **I let him live to warn others of my immense power.**
- `infamy %+ 15 [50 → 50–58]`
3. **Eh. Now that the threat is ended, he is beneath my concern.**
- `infamy %+ 10 [50 → 50–55]`
- `disdain %+ 10 [50–55 → 50-60]`
Later Snippet
## <a id="branch-split-73"></a>Branch Split 73 — clutchmate
- *if infamy > 70:* → [Choice 75](#choice-75)
- *else:* → [Choice 74](#choice-74)
## <a id="choice-74"></a>Choice 74 [HUB] — clutchmate (victory)
> You have defeated Axilmeus. He is still alive, but you have beaten him and he will be unable to offer serious resistance. What do you do with him now?
1. **Axilmeus is too great a threat to leave alive, but he is worthy of a quick and painless death.**
- `cunning %- 20 [4-98 → 3-78]`
- `brutality %- 20 [3-98 → 2-78]`
- `clutchmate_alive false [false → false]`
2. **Like a cat playing with a mouse, I will make Axilmeus suffer before he dies.**
- *if disdain > 60:*
- `clutchmate_alive true [false → true]`
- `cunning %+ 10 [4-98 → 14-98]`
- `brutality %+ 10 [3-98 → 13-98]`
- `disdain %+ 15 [61-99 → 67-99]`
- `infamy %+ 10 [32-78 → 39-80]`
- *else:*
- `clutchmate_alive false [false → false]`
- `brutality %+ 30 [3-98 → 32-99]`
- `cunning %+ 20 [4-98 → 23-98]`
- `disdain %- 10 [4-99 → 4-89]`
- `infamy %+ 30 [32-78 → 52-85]`
3. **Axilmeus must leave my territory, never to return, but he can live.**
- `clutchmate_alive true [false → true]`
- `brutality %- 30 [3-98 → 2-69]`
- `cunning %- 15 [4-98 → 3-83]`
- `infamy %- 20 [32-78 → 26-78]`
## <a id="choice-75"></a>Choice 75 — heroes
> …a traveling party of adventurers in town. The people are already calling them "heroes," telling tales of their past deeds.
>
> Do-gooders like these can be very dangerous. What do you want to do?
1. **Gather information about them.**
- `cunning %+ 10 [3-98 → 3-98]`
- `disdain %- 10 [4-99 → 4-99]`
- → [Choice 85](#choice-85)
2. **Challenge them to a duel.**
- *(no variable changes)*
- → [Choice 76](#choice-76)
3. **Kidnap a princess to lure them out.**
- *(no variable changes)*
- → [Choice 81](#choice-81)
4. **Scare them off.**
- *(no variable changes)*
- → [Branch Split 86](#branch-split-86)
5. **Ignore them.**
- `disdain %+ 30 [4-99 → 4-99]`
- → [Branch Split 79](#branch-split-79)
---
### Path: Challenge them to a duel. *(from [Choice 75](#choice-75), converges at [Choice 87](#choice-87))*
## <a id="choice-76"></a>Choice 76 — heroes (challenge)
> Are you really going to fight them directly on the field of battle?
1. **Yes.**
- `cunning %- 20 [3-98 → 2-78]`
- `brutality %+ 10 [2-99 → 12-99]`
- *if brutality > 60:*
- `infamy %+ 15 [26-85 → 37-87]`
- `wealth - 500 [2000-12000 → 1500-11500]`
- *else:*
- `wounds + 1 [0–2 → 1-3]`
- `infamy %- 30 [26-85 → 18-60]`
- `wealth - 2000 [2000-12000 → 0-10000]`
- → [Choice 87](#choice-87)
2. **No, I'm luring them into a trap.**
- `cunning %+ 20 [3-98 → 22-98]`
- `brutality %- 10 [2-99 → 2-89]`
- *if brutality < 40:*
- `infamy %+ 10 [26-85 → 33-87]`
- `wealth - 500 [2000-12000 → 1500-11500]`
- *else:*
- `wounds + 1 [0–2 → 1-3]`
- `infamy %- 30 [26-85 → 18-60]`
- `wealth - 2000 [2000-12000 → 0-10000]`
- → [Choice 87](#choice-87)
---
### Path: Scare them off. *(from [Choice 75](#choice-75), converges at [Choice 87](#choice-87))*
## <a id="branch-split-77"></a>Branch Split 77 — heroes
- *if infamy > 70:* → [Choice 87](#choice-87)
- *else:* → [Choice 78](#choice-78)
## <a id="choice-78"></a>Choice 78 — heroes
> …a brave paladin in shining white armor, challenges you to a duel. She is flanked by a wizard of some sort, as well as a priest of the goddess of war and a bard.
>
> Will you accept the challenge?
1. **Yes.**
- *if brutality > 60:*
- `infamy %+ 15 [26-85 → 37-87]`
- `wealth - 500 [2000-12000 → 1500-11500]`
- *else:*
- `wounds + 1 [0–2 → 1-3]`
- `infamy %- 30 [26-85 → 18-60]`
- `wealth - 2000 [2000-12000 → 0-10000]`
- → [Choice 87](#choice-87)
2. **No, lure them into a trap.**
- *if brutality < 40:*
- `infamy %+ 10 [26-85 → 33-87]`
- `wealth - 500 [2000-12000 → 1500-11500]`
- *else:*
- `wounds + 1 [0–2 → 1-3]`
- `infamy %- 30 [26-85 → 18-60]`
- `wealth - 2000 [2000-12000 → 0-10000]`
- → [Choice 87](#choice-87)
---
### Path: Ignore them. *(from [Choice 75](#choice-75), converges at [Choice 87](#choice-87))*
## <a id="branch-split-79"></a>Branch Split 79 — heroes
- *if infamy < 30:* → [Choice 87](#choice-87)
- *else:* → [Choice 80](#choice-80)
## <a id="choice-80"></a>Choice 80 — heroes
> …a brave paladin in shining white armor, challenges you to a duel. She is flanked by a wizard of some sort, as well as a priest of the goddess of war and a bard.
>
> Will you accept the challenge?
1. **Yes.**
- *if brutality > 60:*
- `infamy %+ 15 [26-85 → 37-87]`
- `wealth - 500 [2000-12000 → 1500-11500]`
- *else:*
- `wounds + 1 [0–2 → 1-3]`
- `infamy %- 30 [26-85 → 18-60]`
- `wealth - 2000 [2000-12000 → 0-10000]`
- → [Choice 87](#choice-87)
2. **No, lure them into a trap.**
- `cunning %- 25 [3-98 → 2-98]`
- `brutality %- 25 [2-99 → 2-99]`
- `wounds + 1 [0–2 → 1-3]`
- `infamy %- 30 [26-85 → 18-60]`
- `wealth - 2000 [2000-12000 → 0-10000]`
- → [Choice 87](#choice-87)
---
### Path: Kidnap a princess to lure them out. *(from [Choice 75](#choice-75), converges at [Choice 87](#choice-87))*
## <a id="choice-81"></a>Choice 81 — heroes (kidnap)
> Let's be honest. Are you kidnapping a princess for tactical reasons, or are you kidnapping a princess just because you like kidnapping princesses?
1. **It's not like that! It's purely strategic!**
- *(no variable changes)*
2. **A little of column A, a little of column B.**
- *(no variable changes)*
3. **Mmmm…princesses…**
- *(no variable changes)*
## <a id="choice-82"></a>Choice 82 — heroes (princess)
> …by air. You rip off the roof, snatch the princess, and fly away chortling.
>
> Bound securely in your domain, the princess offers you vast riches if you set her free. Do you accept her offer?
1. **Yes.**
- `cunning %- 50 [3-98 → 2-98]`
- `infamy %- 30 [26-85 → 18-85]`
- → [Choice 87](#choice-87)
2. **No.**
- *(no variable changes)*
- → [Choice 83](#choice-83)
## <a id="choice-83"></a>Choice 83 — heroes (heroes_arrive)
> …the heroes arrive. Their leader, a brave paladin in shining white armor, challenges you to a duel. She is flanked by a wizard of some sort, as well as a priest of the goddess of war and a bard.
1. **Accept their challenge.**
- *(no variable changes)*
- → [Choice 76](#choice-76)
2. **Kill them on the spot.**
- *if brutality > 60:*
- `infamy %+ 15 [26-85 → 37-87]`
- `wealth - 500 [2000-12000 → 1500-11500]`
- *else:*
- `wounds + 1 [0–2 → 1-3]`
- `infamy %- 30 [26-85 → 18-60]`
- `wealth - 2000 [2000-12000 → 0-10000]`
- → [Choice 87](#choice-87)
3. **Kill and eat the princess before their very eyes.**
- *(no variable changes)*
- → [Choice 84](#choice-84)
The general idea is that you can make use of this tool to help map out games, what your possible variable ranges are on all playthroughs (not mean/median, but min/max). It should also provide decent error reporting of errors across the entirety of the program similar to quick/random test, but I’ve not developed this very much. You could for instance upload to cogdemos, and run this to double check none of changes you’ve made will generate errors for users on some obscure path you wrote – where you missed a *goto or made an impossible *if in your 400k word wip.
The codebase itself is written in typescript to take advantage of the node installations authors have for choicescript, and to embed in websites if that ends up being direction others are interested in. Currently I’ve left the cfg and generation parts of it unpublished incase the sentiment is generally negative, but the parser is available here:
It’s all here:
GitHub - M3ales/choicescript-tree: Recursive Descent Parser for choicescript · GitHub .
