Using probability in a skill check with *choice and *rand

So, at the moment the skill checks most of the times work this way.

In the startup file you create your skill, let’s say:

*create strength 50

And then in the scene file you have your check, let’s say:

*choice
   # Use brute strength
      *if strength >= 75
         You smash the goblin's head.
      *else
         The goblin guts you.

I wanted to introduce probability, so if (let’s say) your strength is 45 and the check is 75 your will not automatically fail, but you will have a probability of success based on your skill level. In this case 60%.

I think I worked out a way, but if you think you can write it better (or I missed the target entirely and deluded myself), please do tell me.

This I what I did.

In the startup file I wrote:

*create dieroll 0

*create strength 45

Then in a scene I wrote:

*choice
   # Use brute strength
      *rand dieroll 0 100
      *if dieroll =< ((strength/75)*100)
         You smash the goblin's head.
      *else
         The goblin guts you.

What do you think of it?

2 Likes

That’s a good idea to be honest.

Just a general tip, use rand before the page you’ll actually use the value, because if the player goes to the stats page and back, or closes the app, the page will reload and the rand will throw a different value.

The lesser than or equal to sign is inverted. The correct way is <=.

You can also write it all in one line if you don’t mind longer lines of code.

*if ((strength >= 75) or (dieroll <= ((strength/75)*100))) 
  ... 

Seems to make that it does what you want it to do. If your strength is 45 and you need to make a check for 75 your check would be so that you make the check 60% of the time.

It might get a bit frustrated for a player to have it like this for every skill check I imagine (depending on the game). I was thinking about ways to get a check only on the missing skill but will have to get back to you tomorrow as it is the weekend :wink:

I think it is a good idea to use always. Sometimes, despite the author’s best efforts, it’s not always clear which skill is being checked, or the player thinks they have enough of a skill to pass the test only to fail. I know I’ve fallen for that a lot and it’s frustrating.

This way you always have at least a chance.


Thinking about it, you only need the second check:

*if (dieroll <= ((strength/75)*100))
  ... 

If strength is 75 or more it’s a chance of 100% success. So you don’t need to check it in the first place if you’ll check it anyways.

It’s less code you have to write overall.


Edit:

I see you were already doing that. My bad. :sweat_smile:

Great idea! I’ll steal it!

So do you think it should be done one time for each scene at best? I mean you open a new scene(chapter), you execute the command and for that entire scene you’ll have that dieroll’s value?

I should have copy pasted it instead of writing it at the moment lol

My main intention was to use it as an invisible “safety net”. You go always for your best skill, but in case you miss the right choice you have still a chance. I think it could be worked to be a standalone system, but the way the story progress should be reimagined.

Lol thanks. Go ahead! :laughing:

1 Like

I’d probably go with: *if ((strength >=75) or (dieroll <=60))

1 Like

No. Just the page before you actually use the value. That way, it can regenerate the value as many time, but only one will be used.

Example. Instead of this:

Do, this:

*rand dieroll 0 100
*choice
   # Use brute strength
      *if (dieroll <= ((strength/75)*100))
         You smash the goblin's head.
      *else
         The goblin guts you.

The random number is generated on the page with the choice, but its value is only used on the next page, inside the choice child (option’s body), depending on the player’s choice.

Do that every time you use *rand. In your original code, I could see the text:

You smash the goblin’s head.

Then go to the stats page to check if my stats changed, and when I came back I could be seeing the other outcome:

The goblin guts you.

Because when ChoiceScript renders the page again it calculates everything again. It’s not “fixed”. Generally it’s not a problem, because every operation evaluates the same every time, except for *rand.


The thing is it won’t always be 60%. It varies relative to the difference between your skill points and the threshold checkpoint.

So, (dieroll <= ((strength/75)*100)) is actually more appropriate.

2 Likes

There is an underlying philosophical issue here, which is whether the goal of the game/story is to always get the reader to a successful ending (in which case, it’s a story) or whether they find their forward path blocked (temporarily or permanently) if the wrong choices are made, in which case it’s a game.

If it’s a game, no safety net is warranted because the risk of losing is part of the game.

If it’s a story, then no need to use *dieroll etc, just have them beat the goblin every time (including by making sure their strength stat is high enough from previous choices before encountering the goblin).

In other words, what’s the point of having a 40% fail rate (with random dieroll) for a reader without the necessary strength stat?

How does losing the fight with the goblin help the reader enjoy the story?

2 Likes

It doesn’t have to be that way. We can’t know without the inner core dynamics.

For example, I had a project similar one time. You were a magician in training in a world where magic can be very difficult to perform without the time for rituals.

If a fight was dire you could cast a wild spell (random die chance of bad consequences) for instance, you can be cursed. Or maybe the spell makes your hair green or the enemy can turn into a statue.

1 Like

Using *rand makes it sound more like a TTRPG to me, since there’s an element of chance when you roll a dice in Dungeons and Dragons or w/e. Dumb luck, rather than a scripted win/lose is very gamey, imo—like button mashing to a win against the hardest boss.

Speaking of, I think it would be cool to actually have two win checks. The “proper” one, where *if (strength >=75), you win because skill. And *elseif (dieroll <= ((strength/75)*100)) references that you fluked it somehow.

This already works both ways.

If your strength is 75 or more your probability of success is 100%. No need to have strength >= 75.

I understand that the maths is the exact same, this is just about adding optional text variation. As a player, if I somehow beat the Minotaur with 10 strength, I’d like the how to be referenced. Otherwise it might feel like there’s no jeopardy at all, when there is.

  • The game would check if you meet the >=75 threshold first. If you do, great, you get your success text about you being an awesome godly being.
  • If you don’t meet that threshold, it checks if you have chance on your side, but the chance check is still as hard, since it also relies on a relation of 75 strength. You pass that, the text says your opponent fell and you got the killing blow while they were distracted.
  • You fail both those, then you get your fail text.

I used *elseif to illustrate you’d only see one passage or another.

5 Likes

Ah now I see it. It’s a sort of flavour/customisation, I’ve seen it before in some CoG games when a skill check has three possible outcomes (good, bad, bitter good).

I intended the thing more as a safety check especially for the late game, but your implementation is feasible as well.

I’ll grant I’m much more inclined to the “book” side of gamebook. But I don’t think it has to be black or white. After all, even video games let you choose the difficulty level. Yes, it’s a design choice and they are all valid. Personally I prefere a story centered game than a skill centered game.


That’s a good piece of advice.

If I somehow beat the minotaur with a chance of 10%, you could add the text that even you (the MC) doesn’t know how, or something like that. Makes the player aware that there’s a distinction on winning by skill and winning by luck.


Generally, and iirc it’s part of CoG’s guideline for their choice of games, when you do a skill check you don’t increase the same skill. This is to avoid a feedback-loop. So choices are broken into “training” (when a choice increases the skill) and “testing” (when a skill is checked in a win/loose dynamic). By the way, those are just how I call them, nothing official, :joy:.

With your system you could have a skill increase if the player wins by luck, which feels realistic while avoiding the reinforcement feedback-loop. It encourages exploring other choices even late in the game because I still have a chance, albeit smaller. It adds a safety net and minimizes frustration… Thinking about it, it should just be standard practice. :joy:

1 Like

To summarize what people said then the original code would change in something like this.

In the startup file.

*create dieroll 0
*create strength 45

And in the scene file.

*rand dieroll 0 100
*choice
   # Use brute strength.
   	*if strength >= 75
   		You smash the goblin's head.
   			*goto successful_event
   	*elseif (dieroll <= ((strength/75)*100))
   		The goblin trips and kills himself.
   			*goto lucky_event
   	*else
   		The goblin guts you.
   			*goto failed_event

Where we have three possible outcomes. *if when our skill is enough of its own, *elseif when our skill is not enough but it gives us a chance, *else when even luck is against us.

Then regarding *goto lucky_event we could put under that label a reward or a penalty for not having won the skill check proper, or both. Something like a slight skill raise for a reward and/or a slight relatioship drop (if an eventual party member saw us) as a penalty.

2 Likes