Log in

View Full Version : MaxSkill Calculations


mollymillions
02-26-2005, 04:00 PM
A lot of our max skill calculations are incomplete and getting them right means adding a lot of ugly code to the MaxSkill class. Would it be possible to use a class_skillcap list and a block of generic code to get the max skills?

I am guessing that checking the value from a list, several times, is too expensive.

Heres some pseudo code of how I thought it could work:

/*
class_skillcap table example:

ClassID, SkillID, Index, Level, SkillCap
(MonkID), (BindWoundID), 1, 1, 200
(MonkID), (BindWoundID), 2, 50, 210
(PaladinID),(BindWoundID), 1, 10, 200
(PaladinID),(BindWoundID), 2, 50, 210

*/

public int GetMaxSkill(class, skill, level)
{
int caplevel = -1;
int index = 1;


//Get the base level
baselevel = GetCapLevel(class, skill, index);
if (level < baselevel || baselevel = -1)
return 0; // cant use skill


caplevel = baselevel;


while (level >= caplevel ) {
index++;
caplevel = GetCapLevel(class, skill, index);

if (caplevel = -1)
break;
}

if (caplevel = -1)
return 0; // cant use skill
else {

// workout the max skill and compare it to the skill cap
int maxskill = (((level - baselevel) * 5)+5);
int skillcap = GetCap(class, skill, caplevel);

if (maxskill > skillcap)
return = skillcap;
else
return = maxskill;
}
}

private int GetCapLevel(class, skill, index)
{
//return the skill cap level for this class, race and index
//return -1 if the item doesn't exist
}

private int GetCap(class, skill, level)
{
//return the skill cap for this class, race and skill cap level
}



The class_skillcap table would have about 500 records. (There would also have to be a race_skillcap list for the race specific skills).

fathernitwit
02-27-2005, 11:36 AM
this is perfectly reasonable to do, if you wanna code it up. The biggest reason it hasnt been done is that nobody wants to populate the database table.

I see these fields in the table:
classID
skillID
formula (integer which you switch on for various calculation formulas)
min_level (the level at which this cap starts to apply)
cap (the cap at this level)

some formula types, which apply until the formula's result exceeds the cap:
0. untrainable
1. untrained (at this level it cannot be trained, but will be avaliable later)
2. just use cap
3. (level * 5) + 5
4. ((level - min_level) * 5) + 5
... I believe theres some others in there ...

I dont see the point of your index field really, just store them sorted by level, and run throught the list until the level of the next entry is higher than your current level, or the list ends.

Actually, you could pull these from the database and apply them as you load them to calculate the level cap at each level and then just store that in a big array in shared memory:
uint8 skill_caps[MAX_CLASS][MAX_SKILL][LEVEL_CAP]...
for level 70, thats 78kb of data... which is nothing in shared memory...
dont really use a 3d array though, use:
uint8 skill_caps[MAX_CLASS * MAX_SKILL * LEVEL_CAP]
and index it with:
getskillcap(class, skill, level) \
skill_caps[class * (MAX_SKILL + LEVEL_CAP) + skill * LEVEL_CAP + level)
This is a very shared-memory friendly system, and is what I recommend.

I dont know if it would be worth your time to put all the race-based caps into the database, its prolly easier to just make a quick switch statement for them, and intelligently combine the results with the results of the class stuff.

However you do it, these caps should all be loaded into memory at zone start time, if not shared memory.

There would need to be at least 1200 entries in this table for each class/skill combination, maybe reducable by making the default 'untrainable', but there will be a lot of extra entries for 50+ and 60+ levels, so it'll end up being a few thousand... not that it matters.

mollymillions
02-28-2005, 04:12 AM
OK, i will get all the data together for starters.

mollymillions
03-03-2005, 02:29 AM
http://members.dodo.net.au/~mollymillions/Skills.xls

*Edit* -Added code to create table. It's going to take quite a while to locate all the 65+ caps.

fathernitwit
03-03-2005, 05:08 AM
gunna be a lot of work still to turn that into a db table like we need, but its a good start.

Wiz
03-03-2005, 06:24 AM
Here you go, mostly accurate up to PoP table, also table of racial skills.

http://www.wintersroar.com/files/caps.zip

Function for it here:


int8 Database::GetSkillCap(int8 skillid, int8 in_class, int16 in_level)
{
int8 skill_level = 0, skill_formula = 0;
int16 base_cap = 0, skill_cap = 0, skill_cap2 = 0, skill_cap3 = 0;
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
int32 affected_rows = 0;
MYSQL_RES *result;
MYSQL_ROW row;
//Fetch the data from DB.
if (RunQuery(query, MakeAnyLenString(&query, "SELECT level, formula, pre50cap, post50cap, post60cap from skillcaps where skill = %i && class = %i", skillid, in_class), errbuf, &result, &affected_rows))
{
if (affected_rows != 0)
{
row = mysql_fetch_row(result);
skill_level = atoi(row[0]);
skill_formula = atoi(row[1]);
skill_cap = atoi(row[2]);
if (atoi(row[3]) > skill_cap)
skill_cap2 = (atoi(row[3])-skill_cap)/10; //Split the post-50 skill cap into difference between pre-50 cap and post-50 cap / 10 to determine amount of points per level.
skill_cap3 = atoi(row[4]);
}
delete[] query;
mysql_free_result(result);
}

if (skill_cap == 0) //Can't train this skill at all.
return 255; //Untrainable

if (in_level < skill_level)
return 254; //Untrained

//Determine pre-51 level-based cap
if (skill_formula > 0)
base_cap = in_level*skill_formula+skill_formula;
if (base_cap > skill_cap || skill_formula == 0)
base_cap = skill_cap;
//If post 50, add post 50 cap to base cap.
if (in_level > 50 && skill_cap2 > 0)
base_cap += skill_cap2*(in_level-50);
//No cap should ever go above its post50cap
if (skill_cap3 > 0 && base_cap > skill_cap3)
base_cap = skill_cap3;
//Base cap is now the max value at the person's level, return it!
return base_cap;
}


Just assign pp.skills to 254/255 selected from this when a character is created, and 0 to anything that isn't 254 or 255 (asides from the 5 in a melee skill).

fathernitwit
03-03-2005, 01:09 PM
hey wiz,
I had the code for this, and I looked it over, but I didnt like the way it deals with the higher level skill caps. But since im not the one programming it right now, I guess I cant really voice what I dont like, eh?

Wiz
03-03-2005, 09:16 PM
hey wiz,
I had the code for this, and I looked it over, but I didnt like the way it deals with the higher level skill caps. But since im not the one programming it right now, I guess I cant really voice what I dont like, eh?

It pretty much deals with them as live does. What's the issue with it exactly?

fathernitwit
03-04-2005, 05:36 AM
theres no issue per-se, I know it works for live-like skill caps up around level 60. I would just rather have a system that is more flexible. Allowing people to put as many differernt caps at as many different levels as they want, with whatever formula they want to use in between each milestone. Gives us better flexibility into the future, and for custom servers.

Wiz
03-04-2005, 06:17 AM
theres no issue per-se, I know it works for live-like skill caps up around level 60. I would just rather have a system that is more flexible. Allowing people to put as many differernt caps at as many different levels as they want, with whatever formula they want to use in between each milestone. Gives us better flexibility into the future, and for custom servers.

Could always do something like:

table: (skillid, class, race, level, max)

And code that takes the entry >= your skilllevel and the entry closest to your level and < your level. Calculate the difference between the two caps / the difference between the two levels.

So you have a skill with a cap of 10 at level 10 and a cap of 50 at level 20. You can gain 1 in it per level up to 10, then 4 per level up to 20, so your cap at level 12 would be 18.

I'm not really inclined to split my table entries or do the writing-up for it though :P

mollymillions
03-04-2005, 02:29 PM
This is minor, but code needs to handle skill values > 254.