PDA

View Full Version : Skill Caps and Start Skills


mollymillions
04-09-2005, 09:05 PM
I am not a C++ coder and had to do a fair amount of homework before I could start coding this.

For the db records where level = 0, the CAP value will be the start skill value for the skill and the FORMULA value will be used as the offset for the skill cap calculations (skillcap = offset + level * formula).

I need to finalise the start skills and formula offsets in these tables. I will get them inline with what was used previously and re-post in the near future.

MaxSkills.h is no longer needed, although I put the call to the new MaxSkill calc here as it required changing less lines of code. The existing Class_Skill table is no longer used.

All the new code will handle skill values > 255 but there is a check in GetMaxSkill to ensure none are returned greater then 252 as values > 252 may cause the skill succsess calcs to fail? I am pretty sure that all of the skill value = 254 or 255 checks have been removed, to allow for implementation of skill values greater than 255 in the future.

I added the following references to databse.h:

#include "../common/classes.h"
#include "../common/races.h"
#include "../common/skills.h"

to allow the use of the following global(?) constants:

PLAYER_CLASS_COUNT
HIGHEST_SKILL
LEVEL_CAP
Count_Array_Race


ToDo:
-The lists should be moved into SharedMem.
-The misc language skills are not getting handled correctly ATM.
-Free the array memeory in the Zone and World destructors?

http://members.dodo.net.au/~mollymillions/ClassSkills.sql
http://members.dodo.net.au/~mollymillions/RaceSkills.sql

mollymillions
04-09-2005, 09:06 PM
---------------------------------
insert \zone\net.cpp -line 200 ish
---------------------------------
LogFile->write(EQEMuLog::Status, "Loading skill caps");
database.LoadClassSkill(false);
database.LoadClassSkill(true);
--------------------------------
replace \zone\mob.h -line 275 ish
--------------------------------
int8 MaxSkill(int16 skillid, int16 class_, int16 race, int16 level);
inline int8 MaxSkill(int16 skillid) { return MaxSkill(skillid, GetClass(), GetRace(), GetLevel()); }

--------------------------------------
replace \zone\maxskill.h -line 2050 ish
--------------------------------------
int8 Mob::MaxSkill(int16 skillid, int16 class_, int16 Race, int16 level) {
return database.GetMaxSkill(skillid, class_, race, level);
}

-------------------------
insert \common\Database.h
-------------------------
#include "../common/classes.h"
#include "../common/races.h"
#include "../common/skills.h"
-----------------------------------------------
insert/replace \common\Database.h -line 500 ish
-----------------------------------------------
int16 CalcSkill(int16 classraceid, int8 skillid, int8 startlevel, int8 endlevel, int16 skillcap, int16 increment, int16 skillvalue, bool RaceMode);
void LoadClassSkill(bool RaceMode);
void DumpSkills();
int16 GetClassSkill(int8 skillid, int8 classid, int16 level);
int16 GetRaceSkill(int8 skillid, int16 raceid, int16 level);
int16 GetMaxSkill(int8 skillid, int8 class_, int16 race, int16 level);
uint16 class_skill[PLAYER_CLASS_COUNT * (HIGHEST_SKILL+1) * (LEVEL_CAP+1)];
uint16 race_skill[Count_Array_Race * (HIGHEST_SKILL+1) * (LEVEL_CAP+1)];
int16 GetTrainlevel(int16 eqrace, int16 eqclass, int8 skill_id);

--------------------------------------------
replace \common\Database.cpp -line 5670 ish
--------------------------------------------
int16 Database::GetTrainlevel(int16 eqrace, int16 eqclass, int8 skill_id) {

//is the skill trainable?
if(GetMaxSkill(skill_id, eqclass, eqrace, LEVEL_CAP)==0)
return LEVEL_CAP+1; // Untrainable

//skill is trainable so get the level?
for (int level = 1;level<LEVEL_CAP;level++) {
if (GetMaxSkill(skill_id, eqclass, eqrace, level)>0)
return level;
}

//catch
return LEVEL_CAP+1; // Untrainable
}
-----------------
Insert \common\Database.cpp -line 6020 ish
-----------------
void Database::LoadClassSkill(bool RaceMode) {
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
char* sql;

int8 KEY_COUNT;
int8 skill_level = 0, skill_formula = 0;
int8 skillid=255, newskillid=255;
int8 level=1, newlevel=0;
int16 increment = 0, newincrement = 0, offset = 5;
int16 skillvalue=0, skillcap = 0, newskillcap = 0;
int16 classraceid=255, newclassraceid=255;
if (RaceMode) {
KEY_COUNT = Count_Array_Race-1;
sql = "SELECT race, skill, level, formula, cap FROM raceskills ORDER BY race, skill, level";
} else {
KEY_COUNT = PLAYER_CLASS_COUNT;
sql = "SELECT class, skill, level, formula, cap FROM classskills ORDER BY class, skill, level";
}

//Default all caps to 0 (todo: use calloc() to initialize the array with zeros)
int16 ubound = (KEY_COUNT * (HIGHEST_SKILL+1) * (LEVEL_CAP+1));
for (int16 i=0; i<ubound;i++) {
if (RaceMode)
race_skill[i]=0;
else
class_skill[i]=0;
}

if (database.RunQuery(query, MakeAnyLenString(&query, sql), errbuf, &result)) {
safe_delete_array(query);

while((row = mysql_fetch_row(result))) {

newclassraceid = atoi(row[0]);
newskillid = atoi(row[1]);
newlevel = atoi(row[2]);
newincrement = atoi(row[3]);
newskillcap = atoi(row[4]);

if (RaceMode)
newclassraceid = (int16)GetArrayRace(newclassraceid);
if (newlevel > LEVEL_CAP+1)
newlevel = LEVEL_CAP+1;

if ((newclassraceid != classraceid) || (newskillid != skillid)){

//finalise the previous classskill
if ((classraceid <= KEY_COUNT) && (skillid <= HIGHEST_SKILL) && (level >0) && (skillcap > 0)){
skillvalue = CalcSkill(classraceid, skillid, level,(int8)(LEVEL_CAP+1), skillcap, increment, skillvalue, RaceMode);
}

offset = 5; //default formula offset
increment = 0;
skillcap = 0;
skillvalue = 0;
level = 1;
}
if ((newclassraceid < KEY_COUNT+1) && (newskillid < HIGHEST_SKILL+1)) {

if (newlevel == 0){

//write the start skill and get the formula offset
CalcSkill(newclassraceid, newskillid, newlevel,(int8)(1), newskillcap, 0, newskillcap, RaceMode);
offset = newincrement;
level = 0;
}
else if(level > 0){
if (skillvalue == 0)
skillvalue = offset;

skillvalue = CalcSkill(newclassraceid, newskillid, level, newlevel, skillcap, newincrement, skillvalue, RaceMode);
}
skillcap = newskillcap;
increment = newincrement;
level = newlevel;
classraceid = newclassraceid;
skillid = newskillid;
}
}
mysql_free_result(result);

//finalise the previous class/race skill
if ((classraceid <= KEY_COUNT) && (skillid <= HIGHEST_SKILL) && (level >0) && (skillcap > 0))
skillvalue = CalcSkill(classraceid, skillid, level,(int8)(LEVEL_CAP+1), skillcap, increment, skillvalue, RaceMode);
}
else
LogFile->write(EQEMuLog::Error, "Error in LoadClassSkillCaps query %s: %s", query, errbuf);

safe_delete_array(query);
}
int16 Database::CalcSkill(int16 classraceid, int8 skillid, int8 level, int8 endlevel, int16 skillcap, int16 increment, int16 skillvalue, bool RaceMode) {

//All paramaters must be validated before the call
while(level < endlevel) {
skillvalue = skillvalue + increment;
if (skillvalue > skillcap)
skillvalue=skillcap;

if (RaceMode)
race_skill[(classraceid-1) * ((HIGHEST_SKILL+1) * (LEVEL_CAP+1)) + skillid * (LEVEL_CAP+1) + level] = skillvalue;
else
class_skill[(classraceid-1) * ((HIGHEST_SKILL+1) * (LEVEL_CAP+1)) + skillid * (LEVEL_CAP+1) + level] = skillvalue;
level++;
}
return skillvalue;
}
int16 Database::GetClassSkill(int8 skillid, int8 classid, int16 level)
{
if (classid > 0 && classid <= PLAYER_CLASS_COUNT && skillid >= 0 && skillid <= HIGHEST_SKILL && level >= 0 && level <= LEVEL_CAP)
return class_skill[(classid-1) * ((HIGHEST_SKILL+1) * (LEVEL_CAP+1)) + skillid * (LEVEL_CAP+1) + level];
else
return 0;
}
int16 Database::GetRaceSkill(int8 skillid, int16 raceid, int16 level)
{
(int16)raceid = GetArrayRace(raceid);
if (raceid > 0 && raceid < Count_Array_Race && skillid >= 0 && skillid <= HIGHEST_SKILL && level >= 0 && level <= LEVEL_CAP)
return race_skill[(raceid-1) * ((HIGHEST_SKILL+1) * (LEVEL_CAP+1)) + skillid * (LEVEL_CAP+1) + level];
else
return 0;
}
int16 Database::GetMaxSkill(int8 skillid, int8 class_, int16 race, int16 level) {

//Handle GM classes
if (class_>19)
class_ = class_-19;

int16 ClassSkill = database.GetClassSkill(skillid,class_,level);
int16 RaceSkill = database.GetRaceSkill(skillid,race,level);

//Get the greater of the race or class cap
if (RaceSkill > ClassSkill) {
if (RaceSkill > 252)
RaceSkill = 252;
return RaceSkill;
} else {
if (ClassSkill > 252)
ClassSkill = 252;
return ClassSkill;
}
}
----------------------------
replace \zone\doors.cpp -line 180 ish
----------------------------
else
{ // door is locked, either no key works for it or player doesn't have the key - try to pick it
if(sender->MaxSkill(35, sender->GetClass(), sender->GetRace(), sender->GetLevel())>0 && GetLockpick()!=0)
{ // client has the lock pick skill and this lock can be picked

mollymillions
04-09-2005, 09:07 PM
-----------------------------
Replace \zone\client_process.cpp -line 1275 ish
-----------------------------
else if (gmskill->skillbank == 0x00)
{
// normal skills go here
if (gmskill->skill_id > HIGHEST_SKILL)
{
cout << "Wrong Training Skill (abilities)" << endl;
DumpPacket(app);
return;
}
int8 skilllevel = GetRawSkill(gmskill->skill_id);
//if ( skilllevel == 255)
//{
// // Client never gets this skill; check for gm status or fail
// return;
//}
//else if (skilllevel == 254)
//{
// // Client training new skill for the first time set the skill to level-1
// int16 t_level = database.GetTrainlevel(GetClass(), gmskill->skill_id);
// //cout<<"t_level:"<<t_level<<endl;
// if (t_level == 66 || t_level == 0)
// {
// return;
// }
// //m_pp.skills[gmskill->skill_id + 1] = t_level;
// SetSkill(gmskill->skill_id, t_level);
//}
if (skilllevel == 0) {
int16 t_level = database.GetTrainlevel(GetRace(), GetClass(), gmskill->skill_id);
if (t_level == 66 || t_level == 0)
{
return;
}
SetSkill(gmskill->skill_id, t_level);
}
else if (skilllevel <= 251)
{
// Client train a valid skill
// FIXME If the client doesn't do the "You are more skilled than I" check we should do it here
SetSkill(gmskill->skill_id, skilllevel + 1);
}
else
{
// Log a warning someones been hacking
LogFile->write(EQEMuLog::Error, "OP_GMTrainSkill: failed client: %s", GetName());
return;
}

-----------------
replace \zone\client_packet.cpp -line 5800 ish (redundant code)
-----------------
////validate skills
//for (int sk = 1; sk < MAX_PP_SKILL; sk++) {
// //int cap = GetSkillCap(sk-1);
// //int cap = MaxSkill(sk-1, GetClass(), GetLevel());
// int cap = MaxSkill( sk-1, GetClass(), GetRace(), GetLevel());
// if (cap >= 254)
// m_pp.skills[sk] = cap;
//}
----------------------------
insert \world\net.cpp -line 205 ish
----------------------------
LogFile->write(EQEMuLog::Status, "Loading start skills..");
database.LoadClassSkill(false);
database.LoadClassSkill(true);

--------------
insert \world\client.h -line 70 ish
--------------
void SetClassStartingSkills( PlayerProfile_Struct *pp ); //nolonger used
void SetRaceStartingSkills( PlayerProfile_Struct *pp ); //nolonger used
void SetStartingSkills( PlayerProfile_Struct *pp );

-------------------------------
insert \world\client.cpp -line 1300 ish
--------------------------------
void Client::SetStartingSkills( PlayerProfile_Struct *pp )
{
for (int8 skill=0;skill<=HIGHEST_SKILL;skill++) {
StartSkill = database.GetMaxSkill(skill,(int8)(pp->class_),(int16)(pp->race),0);
if (StartSkill > 0)
pp->skills[skill+1] = StartSkill;
}
}