Jump to content
  • Advertisement
Sign in to follow this  
int01h

Skill gaining process.

This topic is 4914 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi guys is there around some good idea about gaining a skill in a standard rpg game? I mean, i have an problem - because : 1) they rise too fast or they rise too slow. I would like it to have like that: the higher level of skill player has, the lower chances are for the skill gain (thats normal) And, the higher leve of skill player has, the higher are chances to do _skill_action. So, i was thinking around and made such code: ________[1]__________________________________ if(RAND(1,100)<=player[who].harvesting+1){ Do_harvesting_action(); } ________[2]__________________________________ tmpik=RAND(1,100); if(tmpik<100-player[who].harvesting){ ADD_Stat(player[who],POINTS,HARVESTING); } 1: It's almost impossible at the beginning of harvesting skill (1,2,3,4...) 2: it's too fast at the begining :( Any clue?, better clue?

Share this post


Link to post
Share on other sites
Advertisement
You're trying to do this with linear functions, and from your descriptions it sounds like you want non-linear functionality.

Why not have skill acquisition based upon a logarithmic function - that is, rate of increase slows down as level increases - and skill usage based upon an exponential function - that is rate of success increases as skill level increases.

Generically you could include both these cases in a sigmoid model: this is a 4-parameter model as follows:

y = min + max * (skill_level) ^ hill / (skill_level ^ hill + level_50 ^ hill)

where:

min : is the value taken by y when skill_level = 0;
(min + max) : is the asymptote that y approaches when skill_level increases
hill : is a 'gradient' type parameter that controls the steepness of the curve
level_50 : is the skill_level that gives exactly the half-way point between min and max

The easiest way to get a feel for this function is to slap it into something like excel, and see how the parameters change the shape of the curve. Then just allocate parameters to meet your requirements.

HTH,
Jim.

Edit : had a quick play around.

For skill gaining, try the reversed version of the equation above; that is:

y = max - equation_above

(I'll leave the algebra rearranging to you - there is a simple solution, but I can't remember it off the top of my head, and can't be bothered to write it out), with:

max = 50, min = 0, hill = 2, level_50 = 10

This gives you the decreasing probability of gaining a new skill point that you want.

For success, try the original equation with:

max = 100, min = 0, hill = 2, level_50 = 50

Should give the sort of curve you're after. Note that you can probably get a nicer curve for your purposes by replacing skill_level and level_50 with log(skill_level) and log(level_50) in the equation above. Then again, I'm thinking in terms of having a generally available flexible curve class - if you don't need this kind of math in your program, have a look at the exponential and logarithmic curves I mentioned above (but don't forget that probability truncates at 1).

Jim.

Edit again : clarified some of the descriptions, cos I missed a couple of things!

[Edited by - JimPrice on March 4, 2005 9:20:49 AM]

Share this post


Link to post
Share on other sites
Bff.. that's not so eZ as i thoud.
Well, simplifying that:

when user clicks on a button the harvesting rises (that's not true, but this is just a simplified action)

then:


BUTTON_CLICKED(){

<-- what should i put here from the math You've written?

}

Regards.

Share this post


Link to post
Share on other sites
OK - I'll try and put some code down, see how you get on.

I'm guessing you're using C# (those look like indexers in your code), so I'll do it for that language. Should be easy enough to port to another language.


using System;

namespace Sigmoid
{
// Set up a class just containing static functions to effectively give you global curve functions
class MyCurves
{
public static float Sigmoid(float x, float min, float max, float hill, float e50)
{
float numerator = min + max * (float)Math.Pow(x, hill);
float denominator = (float)Math.Pow(x, hill) + (float)Math.Pow(e50, hill);
return numerator / denominator;
}

public static float LogSigmoid(float x, float min, float max, float hill, float e50)
{
return MyCurves.Sigmoid((float)Math.Log(x), min, max, hill, (float)Math.Log(e50));
}

public static float DecreasingSigmoid(float x, float min, float max, float hill, float e50)
{
return max - MyCurves.Sigmoid(x, min, max, hill, e50);
}

}

class Class1
{
static void Main(string[] args)
{
// Change skill_level to get different probabilities.
float skill_level = 10;

// Calculate some probabilities under various models
float Chance_of_success = MyCurves.Sigmoid(skill_level, 0, 100, 2, 50) / 100;
float Alternative_chance_of_success = MyCurves.LogSigmoid(skill_level, 0, 100, 2, 50) / 100;
float Chance_of_new_skill_point = MyCurves.DecreasingSigmoid(skill_level, 0, 50, 2, 10) / 100;

// Show the resultant probabilities
Console.WriteLine("Chance of success is " + Chance_of_success);
Console.WriteLine("Alternative chance of success is " + Alternative_chance_of_success);
Console.WriteLine("Chance of new skill point is " + Chance_of_new_skill_point);

Console.Read();
}
}
}





So - basically, when you button_click (or whatever), you get the chance of success from the Sigmoid class, using whichever model and parameters you've decided on, and then just rand it as per usual.

HTH,
Jim.

Share this post


Link to post
Share on other sites
Oh okay it works:

root@bjoxarine:~# ./1 6
Chance of success: 0.88644
Chancee of new skill point 0.88643

But i can't get it - maybe that's because i'm math looser.

So what should i do with those chances?
What to rand?

Please:)?

Share this post


Link to post
Share on other sites
You could use the method we use in the pen&paper RPG Runequest. I'm not sure if it's the "real" rules or if it's been modified by the GM, but here it is:

It's a D100 system, so when the player tries to use a skill a D100 is rolled.
The lowest 5% of the skill is a critical, the lowest 20% of the skill is a special and the highest 5% of the rest is a critical failure.
1 is always a critical and 100 is a "something weird".

Say the player has 20 points in bow&arrow.
1 = critical
2-4 = special
5-20 = success
21-96 = failure
97-99 = critical failure
100 = something weird

Something weird means that it's both good and bad for you. A sword attack might succeed, but the sword is stuck and wrenched out of your hands.


Anyway: to the skill gaining

When the player gets a success he checks a box on the sheet. When he gets another success he rolls a D100. If he scores more than his skill he gains points. How many points he gains is determined by a d6.

Because a player might very quickly gain a skill that's easy to train (lock-picking for example) the GM uses a "stress-level". If the player isn't in combat or otherwise has to act very quick, he needs a special or a critical to increase his skills.

Since you'll be using this in a computergame, you could add some additional modifiers. To increase a skill the player may need 30 skill-increase points for example, and give the player more skill-increase points if he's in great stress and few if he's not. That way a critical when he's in distress would also make his skill increase more likely.

You could also give him skill increase points for critical failures and 100's - it's up to you.


pseudo code:

player.skill.increasepoints = 4; // earlier in the game

//------
threatlevel = 3 //player is in dire striats. 2 means trouble, 1 means no threat
roll = rnd(99)+1;
if ( roll <= player.skill.value ) // success
{
player.skill.increasepoints += 1 * threatlevel;
if ( roll <= roof(player.skill.value / 20) ) // special
{
player.skill.increasepoints += 3 * threatlevel;
if ( roll <= roof(player.skill.value / 5) ) // critical
{
player.skill.increasepoints += 6 * threatlevel;
// code for the critical action
} else // code for the special action
} else // code for the successful action
} else if (roll = 100) // something weird
{
// do code for something weird
} else // failure
{
if ( roll > floor( (100 - player.skill.vlaue ) / 5) ) // critical failure
{
player.skill.increasepoints += 1 * threatlevel // give player some consolidation points. You could punish him instead by subtracting points.
// code for critical failure
} else { // normal failure
// code for failure
}
}

// max skill.increasepoints that can be gained in a single roll is 3 + 9 + 18 = 30


if ( player.skill.increasepoints >= 30) // player is ready to gain more skill points. Yay!
{
player.skill.increasepoints = 0;
skillroll = rnd(99)+1;
if ( (skillroll > player.skill.value ) | skillroll == 100 ) // yay! player gains skill points
{
player.skill += rnd(5)+1 // give player 1-6 points. Of course the increase could be whatever you wish.
} else
{
// do nothing - skill points are forfeited because the player already has many skill points
}
}



It's a complicated game mechanic but it gives you great control.
it adds realism by making it harder to gain the initial skill points - if he has 0 points he has only a 1% chance to get skill-increase points at all (1 is always a critical).
As he gains skills it becomes easier until he starts to have many, then it becomes harder until when he has 100 or more points it's back to 1% chance. Of course it would be possible to make it less than 1% chance if the player has more than 100 points as well, but I'll leave that up to you.

It also adds realism by making it harder to gain skill points if the player isn't in threat. This encourages the player to seek challenges, or at least discurages activity such as standing in a spot and jumping up and down to increase the jump skill. Unfortunately it also forces you, the programmer/designer to create a way for the game to know if the player is in trouble. The threat-level could also be used to play mood music and other things, so it's not a wasted effort in any case. Examples of what could change the threat-level is the players HP, the enemy's skills/strength, if the player is close to a cliff, how high that cliff is, jumping over a deep crevice is more dangerous than jumping over a puddle, or on flat ground.

It also removes any form of cap. The player will continue to gain points even after 100, but it will be s l o w.

It's harder to implement than a simple log curve, but in my opinion it would be worth it. I know I'll use something like this in my game (as soon as I start to actually code that is [smile]), and that I'd rather play a game with a skill sytem like this rather than one with Morrowind's skill-system, or any level-based game ever produced.

Share this post


Link to post
Share on other sites
Quote:

So what should i do with those chances?
What to rand?


OK - this is how I would use the code I posted. In addition, at the end of this post I'm going to try and put some more information about the sigmoid curve, to help you understand what's going on.

First things first - a player attempts to use a skill - we'll assume they try and 'jump' (to continue to previous posters example).

This player has 'jump' skill 17. Then, first we need to know what chance they have of being succesful. So we would call:

float chance_of_succes = Sigmoid(17, min, max, hill, level_50)

Where we have pre-specified numbers for the parameters min, max, hill and level_50. We could of course change the model of skill_level to probability of success (by using LogSigmoid, for example), and we can change parameters - I'll comment on this in a minute.

So - once we've scaled chance_of_success, we know the probability they make the jump. Now we need to evaluate whether they actually made it. A simple method of getting a random number in C++ (not sure if it holds for C, but the underlying principle does) is to use the function rand, which generates a 'psuedo-random integer in the range 0 to RAND_MAX'. Therefore, if we use:

float prob = (float)rand()/RAND_MAX

we would have a number between 0 and 1, with probability chance_of_success of being less than chance_of_success. Hence, if prob is less than chance_of_success, then they made the jump. If not, they get to try out their 'fly' skill.

The same basic methodology holds for whether they increase in skill points. When they trigger something that might increase their skill, you evaluate their chance of a skillpoint increase, and then see whether they're succesful, as above. Triggers are up to you to determine.

Note that all this assumes that this is the model of success and progression that you want to use (which is an assumption I made based upon your previous post).

OK - I also mentioned changing parameters for probability modeling. Let's say that you normally use this model for the chance of a jump being successful:

float chance_of_success = LogSigmoid(skill_level, 0.1, 0.9, 2, 10)

So - even at skill level 0 they have a 10% chance of success (min = 0.1), at very high levels of skill they have nearly 100% chance of success (max = 0.9 - means that upper asymptote is 0.1 + 0.9 - sorry, missed that bit in the original post), the function has a gradient equal to 2 (which you've determined through trial-and-error until you've got a curve you're happy with), and the at skill_level 10 you have a 55% chance of success (e50 = 10; range is 0.9; 0.9 / 2 + 0.1 = 0.45).

However, they're trying to make a huge jump - which you've decided should be more difficult than a standard jump. How do you adjust the probability of success?

The simple solution is to make the level_50 parameter dependent upon the distance jumped. For example, we might have:

level_50 = 1 + distance_in_meters

This right-shifts the curve with increased distance, meaning that someone with the same skill level has less chance of success at further distances. You are therefore adding a complexity element to your probability of success - and integrating this into a class / function should be pretty straightforward.

Quote:

But i can't get it - maybe that's because i'm math looser


Nobody's a math loser. First things first - positive attitude. Now that's done, let's try and explan the math of what's going on, using our ever-so-helpful ASCII art skills.

The sigmoid curve looks a bit like an S-shape, like this:


Probability |
of | --------
success | --------
| --------
| -------
| ---
+-----------------------------------

Skill level



OK - so that looks linear, but trust me, it's an S-shape. It has 4 parameters, as mentioned above.

The first parameter tells you what the probability of response is when skill_level = 0 - it's like a baseline probability. In the example above, I used a min of 0.1 - meaning that even someone with no skill level at all has a 10% chance of success.

The second parameter represents the upper asymptote - this just means the number that the curve get's closer and closer to as skill_level gets bigger and bigger. In actuality, using the equation and models I've given, the upper asymptote is min+max (not max as I said above - d'oh!). In our example, we have a max of 0.9; as we have a min of 0.1, this curve will get closer and closer to 0.1 + 0.9 = 1.0 - therefore, as skill level gets higher and higher, the chance of success gets closer and closer to 1 (although it never actually get's there).

I'll do the fourth parameter next (as the third is a doozy). As the response curve runs from min to max, it has to cross every point in between. The level_50 parameter tells us what skill_level is required to get exactly 50% of the difference between min and max. So - in our case, we have a max of 0.9. This means the difference between the baseline probability (min) and the upper asymptote is 0.9. 50% of this is 0.45 - so level_50 tells us what skill_level gives exactly 0.45 + 0.1 = 0.55 probability of success. Altering this moves the curve left and right, altering the relationship between skill_level and probability of success.

The third parameter is a sort-of gradient parameter - in that it tells you how steep the curve is. In particular, changing hill from lower to greater than 1 alters the shape of the curve fairly dramatically, changing it from an s-shape to something more like a constrained-log function (ie the top half of the s only).

The best way to see how this curve works, as I said above, is to open something like excel, make a column from 0 to 100 (by 1's) and then a column corresponding to the results of the sigmoid function, and plot the 2 columns. Then you can see the s-shape, and if you change the parameters of the curve you can see how it adjusts - and therefore tailor make it to your own specifications.

Anyway - this may be over-the-top for where you want to be at the moment - and I may have misinterpreted how you want to have your success / progression model - but hope some of this is of interest.

Quote:

You could use the method we use in the pen&paper RPG Runequest.


Yeah, having a good background in a variety of P&P RPG's does help give you some idea of what works and what doesn't (look at Neverwinter Nights for example).

Jim.





Share this post


Link to post
Share on other sites
Jim, it works - Yes, You rule man, this is what i really wanted..
I really appreciate Your help, stay kewl !

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!