Ren'Py dynamic responses

Hysocs

Newbie
Mar 5, 2024
17
8
I'm currently working on a game and have developed a compliment system. At present, you can give an NPC a compliment. Right now, there are three compliments, and each has five responses based on stat values (e.g., if the NPC has high lust or low love, etc.). I plan to make it more complex by adding an anger stat that decreases over time. When you give a compliment, I use complex math to determine if the compliment succeeds or fails. It's essentially a percentage change that varies based on stats. However, during my playtesting, I'm finding some issues. Initially, I set a 10% chance for the compliment to succeed, and if it does, the NPC responds, and depending on the compliment, it increases the stats, boosting your chances for the next compliment to succeed. If it fails, it increases the anger stat, lowering your odds, and this stat decreases over time. During testing, I found you can get really unlucky and have it fail non-stop, so I reverted to a simpler system where if it's above a certain stat, it succeeds 100% of the time. However, this leads to metagaming and choosing the same compliment to spam stats higher. I want to use the dynamic system, but I'm thinking of making dynamic thresholds per NPC for the success rate (like if the NPC is difficult, she will always hate your compliments, etc.), but I don't know what the best approach is, especially since this is only one of my planned 15 interaction systems. Merging them to flow nicely will be challenging if it gets more complicated.

You guys play games, so what would you prefer—a dynamic percentage-based system or a simpler system where, for instance, there are ten compliments and depending on the NPC's personality, some succeed and others fail? One might like gaming, and another might not, and this could lead to pulling from a list of generic replies that don’t base responses on the current mood or stats.

It's going to be a sandbox game, so the only character lore you'll get is from interactions. Therefore, I personally think I need to squeeze in as much information as possible in the responses.
 

Winterfire

Forum Fanatic
Respected User
Game Developer
Sep 27, 2018
4,939
7,254
During testing, I found you can get really unlucky and have it fail non-stop
How did you do the testing? Rollback will always display the same random value to avoid cheating, you can change that, but then it'd be pointless.
 

Hysocs

Newbie
Mar 5, 2024
17
8
How did you do the testing? Rollback will always display the same random value to avoid cheating, you can change that, but then it'd be pointless.
I just set it up in a way that allows me to spam the compliment and see the result in the console with every press. This could be due to how I'm handling success or failure. I could use weights, similar to my NPC movement system, but I don't really think it's an issue. The main problem I'm encountering, as with any RNG system, is that players can feel cheated if their luck is bad.
 

Winterfire

Forum Fanatic
Respected User
Game Developer
Sep 27, 2018
4,939
7,254
for instance, there are ten compliments and depending on the NPC's personality, some succeed and others fail?
This is the best solution imho. Gives the player the chance to learn behaviours, and it doesn't make much sense for the same character to enjoy a compliment but hate it the next day.
 

Hysocs

Newbie
Mar 5, 2024
17
8
This is the best solution imho. Gives the player the chance to learn behaviours, and it doesn't make much sense for the same character to enjoy a compliment but hate it the next day.
Thank you for the feedback. I am considering implementing a hybrid system where the NPCs accept specific compliments, and their responses are influenced by their current stats. This way, the reactions won't be completely random and will reflect the NPCs' emotional state. However, I anticipate potential issues, such as responses becoming repetitive if a stat like 'lust' is maxed out, causing NPCs to always respond in a horny manner. Since it's a sandbox game, I'm thinking of making all stats decay over time. The only way to maintain them would be through dating the NPCs, at which point the stats will cap at 500 (out of 1000). This prevents players from exploiting the system by using a 'meta compliment' on every NPC. To manage the stat decay, players will need to focus on one NPC at a time until they start dating them. This could encourage building a harem one relationship at a time. Does this sound appealing or would it get annoying?
 

Winterfire

Forum Fanatic
Respected User
Game Developer
Sep 27, 2018
4,939
7,254
Thank you for the feedback. I am considering implementing a hybrid system where the NPCs accept specific compliments, and their responses are influenced by their current stats. This way, the reactions won't be completely random and will reflect the NPCs' emotional state. However, I anticipate potential issues, such as responses becoming repetitive if a stat like 'lust' is maxed out, causing NPCs to always respond in a horny manner. Since it's a sandbox game, I'm thinking of making all stats decay over time. The only way to maintain them would be through dating the NPCs, at which point the stats will cap at 500 (out of 1000). This prevents players from exploiting the system by using a 'meta compliment' on every NPC. To manage the stat decay, players will need to focus on one NPC at a time until they start dating them. This could encourage building a harem one relationship at a time. Does this sound appealing or would it get annoying?
No, doesn't sound too different from how NPCs are handled in Harvest Moon, as long as they don't decay too quickly at a too high rate.
 
  • Like
Reactions: Hysocs

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Respected User
Donor
Jun 10, 2017
10,130
14,809
During testing, I found you can get really unlucky and have it fail non-stop,
Welcome to the wonderful world of probabilities.

If you toss a coin, there's 50% chance to get one result or another. But if you toss that coin 100 time, the probability for you to get a straight suit of tail then head repeated 50 times, is nearly the same than the probability to get 100 times head or 100 times tail.
So, obviously, when you're trying to apply this to something more than a pure binary value, the probability to get a fair spreading is even lower.

And there's no answer to that problem, or more precisely no simple answer.
Professional games that feel randomized are in fact based on weighted decision trees. Things that (globally) looks likes this:
  • Weight 1 choice 1 [condition set 1]
  • Weight 1 choice 2 [condition set 2]
  • Weight 2 choice 3 [condition set 3]
Therefore, the choice is at most done with a random( 4 ), with a value of 1 mean "choice 1", while a value of 2 mean "choice 2", and 3-4 mean "choice 3". Yet, only when all the condition set are validated.
Then, starting there, you follow the selected branch, and repeat the same process until you reach a decision.

Like at each level the possibility for a choice to appear or not is conditioned, while the randomization is always done on a small value, it ensure a better spreading, and the computer don't looks like it's spamming the same pattern again and again.
If you take a game like Mortal Kombat by example, the most basic approach would have three levels. One based on the player health, one based on the opponent health, and one based on the last move made by the player.
So, even considering that you repeat the same move during all the fight, the possibility to see your opponent do the same move two time in a row will be relatively low, because your health and his will not stay long in the correct range.

But, as I implied, it's not something easy to implement.


For your problem, I would probably go with a randint( 4 ) compared to a computed float value.
A compliment would starts with 50% chance of success, therefore a value of 2, and would be adjusted by adding/removing each elements expressed as float percent (weighted or not).

Let's say that there's 3 possible compliments (small, medium, big), the first step would be: trigger += compliment weight / 3.0, what would add 0.3, 0.6 or 1
Then I would subtract the anger (that have a max value of 50) with a weight of 2: trigger -= ( anger / 50.0 ) * 2. This would remove between 0 and 2
Then the decision is made with success = ( randint( 4 ) + 1 ) >= trigger.

A big compliment when there's no anger would lead to a value of 3, and therefore a 75% chance of success.
A big compliment with some anger would lead to a value between 2 and 2.9, what would lead to 50% chance of success
A big compliment with full anger would lead to a value of 1, what leave 25% chance of success.
A small compliment with full anger would lead to a value of 0.3, so no chance of success.

If you want to have a possibility of 100% chance of success, then also double the compliment weight.
A big compliment with no anger would then have a value of 4, what would always succeed. This while a small compliment with full anger would have a value of 0.6, what would still always fail.
 
  • Like
Reactions: Hysocs

osanaiko

Engaged Member
Modder
Jul 4, 2017
2,111
3,394
Hysocs I didn't read all the other replies especially AnneO because i am grumpy today. :p

But sounds like you need "simulated randomness".

This is a design that has been used by game devs since the earliest days of console gaming.

Basically, instead of doing a random check every time which can result in a string of failures and piss off the player, you use the "bag of tokens" technique.

Create a "bag of tokens" with a known count of "win" and "lose" tokens in it. You shuffle the order of the tokens in the bag, and each time you check the result, you take one token out. Once the bag is empty, you refill it and reshuffle the order.

If the proportion of win vs lose tokens is 3-2, then the worst possible sequence of "lose" is four in a row:

W-W-W-L-L (shuffle) L-L-W-W-W

However the typical case feels much more "fair" to the player - 2 or 3 wins in a row to every 1-2 loses in a row.

In this way, the game result still feels random to the player, but they can't get stuck by a bad "run of luck".
 

Hysocs

Newbie
Mar 5, 2024
17
8
Hysocs I didn't read all the other replies especially AnneO because i am grumpy today. :p

But sounds like you need "simulated randomness".

This is a design that has been used by game devs since the earliest days of console gaming.

Basically, instead of doing a random check every time which can result in a string of failures and piss off the player, you use the "bag of tokens" technique.

Create a "bag of tokens" with a known count of "win" and "lose" tokens in it. You shuffle the order of the tokens in the bag, and each time you check the result, you take one token out. Once the bag is empty, you refill it and reshuffle the order.

If the proportion of win vs lose tokens is 3-2, then the worst possible sequence of "lose" is four in a row:

W-W-W-L-L (shuffle) L-L-W-W-W

However the typical case feels much more "fair" to the player - 2 or 3 wins in a row to every 1-2 loses in a row.

In this way, the game result still feels random to the player, but they can't get stuck by a bad "run of luck".
Thanks for the advice. I ended up with a weird hybrid approach using weights. I needed to make it dynamic so I could adjust the weighting differently per interaction, so I created a config-type system where each interaction can have set weights, etc. Though this system is a little overkill because most interactions will always succeed after they succeed the first time. They can also always succeed if certain conditions are met, like if the NPC has seen them naked, etc. And these interactions are locked to a limited amount daily.
 
  • Like
Reactions: osanaiko