EQEmulator Forums

EQEmulator Forums (https://www.eqemulator.org/forums/index.php)
-   Development::Development (https://www.eqemulator.org/forums/forumdisplay.php?f=590)
-   -   Skill Caps and Start Skills (https://www.eqemulator.org/forums/showthread.php?t=18324)

mollymillions 04-09-2005 09:05 PM

Skill Caps and Start Skills
 
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/~mollymil...lassSkills.sql
http://members.dodo.net.au/~mollymil...RaceSkills.sql



mollymillions 04-09-2005 09:06 PM

Code:

---------------------------------
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

Code:

-----------------------------
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;         
        }
}



All times are GMT -4. The time now is 10:11 AM.

Powered by vBulletin®, Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.