roh/conf.old/area/
roh/config/code/python/
roh/config/game/area/
roh/config/game/signs/
roh/help/dmhelp/
roh/help/help/
roh/log/
roh/log/staff/
roh/monsters/ocean/
roh/objects/misc/
roh/objects/ocean/
roh/player/
roh/rooms/area/1/
roh/rooms/misc/
roh/rooms/ocean/
roh/src-2.47e/
/*
 * skills.cpp
 *	 Skill manipulation functions.
 *   ____            _
 *  |  _ \ ___  __ _| |_ __ ___  ___
 *  | |_) / _ \/ _` | | '_ ` _ \/ __|
 *  |  _ <  __/ (_| | | | | | | \__ \
 *  |_| \_\___|\__,_|_|_| |_| |_|___/
 *
 * Permission to use, modify and distribute is granted via the
 *  Creative Commons - Attribution - Non Commercial - Share Alike 3.0 License
 *    http://creativecommons.org/licenses/by-nc-sa/3.0/
 *
 * 	Copyright (C) 2007-2012 Jason Mitchell, Randi Mitchell
 * 	   Contributions by Tim Callahan, Jonathan Hseu
 *  Based on Mordor (C) Brooke Paul, Brett J. Vickers, John P. Freeman
 *
 */
#include "mud.h"
#include "skills.h"
#include "commands.h"
#include "clans.h"
#include <sstream>

#define NOT_A_SKILL -10

int SkillInfo::getGainType() const {
    return (gainType);
}
int Skill::getGainBonus() const {
    return (gainBonus);
}
bool SkillInfo::isKnownOnly() const {
    return (knownOnly);
}
bool SkillInfo::hasBaseSkill() const {
    return (!baseSkill.empty());
}

bool Config::isKnownOnly(const bstring& skillName) const {
    std::map<bstring, SkillInfo*>::const_iterator it = skills.find(skillName);
    if (it != skills.end())
        return (((*it).second)->isKnownOnly());
    return (false);
}
//*****************************************************************
// Skill - Keeps track of skill information for a Creature
//*****************************************************************

Skill::Skill() {
    reset();
}
Skill::Skill(const bstring& pName, int pGained) {
    reset();
    setName(pName);
    gained = pGained;
}

void Skill::reset() {
    name = "";
    gained = 0;
    gainBonus = 0;
    skillInfo = 0;
}

// End constructors
//--------------------------------------------------------------------

//--------------------------------------------------------------------
// Get/Set Functions
void SkillInfo::setName(bstring pName) {
    name = pName;
}

void SkillCommand::setName(bstring pName) {
    SkillInfo::name = pName;
    Command::name = pName;
}
bstring Skill::getName() const {
    return (name);
}
SkillInfo* Skill::getSkillInfo() {
    return (skillInfo);
}
int Skill::getGained() const {
    return (gained);
}

int Skill::getGainType() const {
    return (skillInfo ? skillInfo->getGainType() : NOT_A_SKILL);
}

bool Skill::hasBaseSkill() const {
    return (skillInfo && skillInfo->hasBaseSkill());
}
bstring Skill::getBaseSkill() {
    return (skillInfo ? skillInfo->getBaseSkill() : "");
}

bstring Skill::getDisplayName() const {
    return (skillInfo ? skillInfo->getDisplayName() : "");
}
bstring Skill::getGroup() const {
    return (skillInfo ? skillInfo->getGroup() : "");
}

void Skill::setGained(int pGained) {
    gained = pGained;
}

void Skill::setName(bstring pName) {
    name = pName;
    updateParent();
}

void Skill::updateParent() {
    skillInfo = gConfig->getSkill(name);
}
// End Get/Set Functions
//--------------------------------------------------------------------

//--------------------------------------------------------------------
// Misc Functions
void Skill::upBonus(int amt) {
    gainBonus += amt;
}
void Skill::clearBonus() {
    gainBonus = 0;
}
void Skill::improve(int amt) {
    gained += amt;
}
// End Misc Functions
//--------------------------------------------------------------------

//*****************************************************************
//						Skill
//*****************************************************************
// Class to store base information about skills

//********************************************************************
//						setGroup
//********************************************************************
// Sets group, aborts if not valid

bool SkillInfo::setGroup(bstring &pGroup) {
    ASSERTLOG(pGroup != "");
    bstring groupName = gConfig->getSkillGroupDisplayName(pGroup);
    if (groupName == "") {
        return (false);
    }
    group = pGroup;
    return true;
}

bool SkillInfo::setBase(bstring &pBase) {
    ASSERTLOG(pBase != "");
    SkillInfo* skInfo = gConfig->getSkill(pBase);
    if (skInfo == NULL || skInfo == this || pBase == name) {
        return (false);
    }
    baseSkill = pBase;
    return true;
}

//bstring SkillInfo::getName() const { return(name); }
bstring SkillInfo::getGroup() const {
    return (group);
}
bstring SkillInfo::getBaseSkill() const {
    return (baseSkill);
}
bstring SkillInfo::getDisplayName() const {
    return (displayName);
}
//bstring SkillInfo::getDescription() const { return(description); }

//********************************************************************
//						checkImprove
//********************************************************************
// Check for an increase to the given skill; if there's a base skill, check
// that instead
//  Parameters: skillName - What skill are we checking for improvement
//				success - Was the skill sucessfull
//				attribute - What attribute will be helpful in raising the skill? (default: INT)
//				bns - Any bonus to the improve calculation (default: 0)

void Creature::checkImprove(const bstring& skillName, bool success, int attribute, int bns) {
    if (isMonster())
        return;
    if (inJail())
        return;

    Skill* crSkill = getSkill(skillName);
    if (!crSkill)
        return;

    int gainType = crSkill->getGainType();
    // not a skill!
    if (gainType == NOT_A_SKILL) {
        broadcast(::isDm,
                "^y*** Skill \"%s\" was requested by the mud, but was not\n    found in the skill list. Check *skills to verify.",
                skillName.c_str());
        return;
    }
    long j = 0, t;

    t = time(0);
    j = LT(this, LT_SKILL_INCREASE);
    //
    if (t < j)
        return;

    int chance = 0;
    int gained = crSkill->getGained();

    chance = 100 - (gained / 3);
    // Chance is too high right now, reduce it by half
    chance /= 2;

    if (gained < 100) {
        // You learn more from your failures at lower skill levels
        if (!success)
            chance *= 2;
    } else {
        // You learn less from failures at higher skill levels
        if (!success)
            chance /= 2;
    }

    if (gainType == SKILL_EASY) {
        // make it harder
        chance /= 2;
    } else if (gainType != SKILL_NORMAL) {
        chance += crSkill->getGainBonus();
    }

    // Unless max for level, 3% chance minimum
    chance = MAX(chance, 3);

    // 10 skill points per level possible, can't go over that
    if (gained >= (level * 10))
        chance = 0;

    int roll = mrand(1, 100);
    if (roll <= chance) {
        bool af = gConfig->isAprilFools();
        if (success) {
            printColor("Your practice %spays off, you have become %s at ^W%s^x!\n",
                    af ? "fails to " : "", af ? "worse" : "better",
                    crSkill->getDisplayName().c_str());
        } else {
            printColor("You %slearn from your mistakes, you have become %s at ^W%s^x!\n",
                    af ? "fail to " : "", af ? "worse" : "better",
                    crSkill->getDisplayName().c_str());
        }
        if (isPlayer()) {
            lasttime[LT_SKILL_INCREASE].ltime = t;
            // Length of wait is based on skill level, not player level
            long wait = 10L + (gained / 10);
            wait = MIN(wait, 150L);
            lasttime[LT_SKILL_INCREASE].interval = wait;
        }
        // Chance for a double improve for a hard skill
        if (gainType == SKILL_HARD && mrand(1,100) < 33)
            crSkill->improve(2);
        else
            crSkill->improve();

        crSkill->clearBonus();

    } else {
        // See if we have a hard skill on our hands, if so add a bonus to increase
        if (gainType == SKILL_MEDIUM) {
            crSkill->upBonus();
        } else if (gainType == SKILL_HARD) {
            crSkill->upBonus(2);
        }
    }
}

//********************************************************************
//						knowsSkill
//********************************************************************

bool Creature::knowsSkill(const bstring& skillName) const {
    if (isMonster())
        return (true);
    if (isCt())
        return (true);
    if (skillName == "")
        return (false);

    std::map<bstring, Skill*>::const_iterator csIt;
    if ((csIt = skills.find(skillName)) == skills.end())
        return (false);
    else
        return (true);
}

//********************************************************************
//						getSkill
//********************************************************************
// Returns the requested skill if it can be found on the creature

Skill* Creature::getSkill(const bstring& skillName, bool useBase) const {
    if (skillName == "")
        return (null);

    SkillMap::const_iterator csIt = skills.find(skillName);
    if (csIt == skills.end())
        return (NULL);
    else {
        Skill* toReturn = (*csIt).second;
        if (useBase) {
            SkillInfo* skillInfo = toReturn->getSkillInfo();
            if (skillInfo && skillInfo->hasBaseSkill()) {
                Skill* baseSkill = getSkill(skillInfo->getBaseSkill());
                if (baseSkill)
                    return (baseSkill);
            }
        }
        return (toReturn);
    }
}

//*********************************************************************
//                      setSkill
//*********************************************************************

bool Creature::setSkill(const bstring skillStr, int gained) {
    if(!gConfig->skillExists(skillStr))
        return(false);

    // TODO: Handle adding of parent skill here
    Skill* skill = getSkill(skillStr, false);
    if(skill) {
        if(skill->hasBaseSkill()) {
            Skill* baseSkill = getSkill(skill->getBaseSkill(), false);
            if(!baseSkill)
                addSkill(skill->getBaseSkill(), gained);
            else
                setSkill(skill->getBaseSkill(), gained);
        }
        skill->setGained(gained);

    }
    else  {
        addSkill(skillStr, gained);
    }

    return(true);
}

//********************************************************************
//						addSkill
//********************************************************************
// Add a new skill of 'skillName' at 'gained' level

void Creature::addSkill(const bstring& skillName, int gained) {
    if (skillName == "" || getSkill(skillName, false) != NULL)
        return;

    Skill* skill = new Skill(skillName, gained);
    skills[skillName] = skill;

    // Add any base skill we need as well
    SkillInfo* skillInfo = skill->getSkillInfo();
    if (skillInfo && skillInfo->hasBaseSkill()) {
        if (!knowsSkill(skillInfo->getBaseSkill())) {
            addSkill(skillInfo->getBaseSkill(), gained);
        }
    }
}

//********************************************************************
//						remSkill
//********************************************************************

void Creature::remSkill(const bstring& skillName) {
    if (skillName == "")
        return;
    SkillMap::iterator it = skills.find(skillName);
    if (it == skills.end())
        return;
    Skill* skill = (*it).second;

    if (!skill)
        return;
    delete skill;
    skills.erase(skillName);
}

#define SKILL_CHART_SIZE		21
char skillLevelStr[][SKILL_CHART_SIZE] = { "^rHorrible^x",			// 0-24
        "^rPoor^x",				// 25-49
        "^rFair^x",				// 50-74
        "^mMediocre^x",			// 75-99
        "^mDecent^x",			// 100-124
        "^mBelow Average^x",	// 125-149
        "^wCompetent^x",		// 150-174
        "^wAverage^x",			// 175-199
        "^wAbove Average^x",	// 200-224
        "^cProficient^x",		// 225-249
        "^cSkilled^x",			// 250-274
        "^cTalented^x",			// 275-299
        "^bVery Good^x",		// 300-324
        "^bAdept^x",			// 325-349
        "^bSuperb^x",			// 350-374
        "^gExceptional^x",		// 375-399
        "^gExpert^x",			// 400-424
        "^gMaster^x",			// 425-449
        "^ySuperior Master^x",	// 450-474
        "^yGrand Master^x",		// 474-499
        "^yGodlike^x"			// 500
        };

char craftSkillLevelStr[][25] = { "Novice", "Apprentice", "Journeyman", "Expert", "Artisian",
        "Master", "Grand Master" };

//********************************************************************
//						showSkills
//********************************************************************
// Show the skills and skill levels of 'player'  to 'sock'

int showSkills(Player* toShow, Creature* player, bool showMagic = false, bool showWeapons = false) {
    std::map<bstring, bstring>::iterator sgIt;
    std::map<bstring, Skill*>::iterator sIt;
    Skill* crtSkill = 0;
    int known = 0;
    double skill = 0;
    const Clan *clan = 0;

    bool showProgress = player->flagIsSet(P_SHOW_SKILL_PROGRESS);
    bool showDigits = !showProgress;

    int barLength = 20;

    if (player->getClan())
        clan = gConfig->getClan(player->getClan());

    // Tell the player what skills they are looking at
    if (toShow->getAsPlayer() == player)
        toShow->printColor("^YYour Skills:");
    else
        toShow->printColor("^Y%s's Skills:", player->getCName());

    if (showMagic)
        toShow->printColor(" ^Ytype \"skills\" to show non-magical skills.");
    else if (player->getClass() != BERSERKER)
        toShow->printColor(" ^Ytype \"skills magic\" to show magical skills.");

    toShow->print("\n");

    for (sgIt = gConfig->skillGroups.begin(); sgIt != gConfig->skillGroups.end(); sgIt++) {
        if ((*sgIt).first == "arcane" || (*sgIt).first == "divine" || (*sgIt).first == "magic") {
            if (!showMagic)
                continue;
        } else {
            if (showMagic)
                continue;
        }


        std::ostringstream oStr;
        known = 0;
        oStr << "^W" << (*sgIt).second << "^x\n";
        for (sIt = player->skills.begin(); sIt != player->skills.end(); sIt++) {
            crtSkill = (*sIt).second;
            if (crtSkill->getGroup() == (*sgIt).first) {
                //1+player->saves[st].chance)/10
                known++;

                //bool isCraft = crtSkill->getGroup() == "craft";

                int curSkill = 0;
                float maxSkill = 0;
                //if(isCraft) {
                //	maxSkill = MIN(player->getLevel()*10, 100);
                //	curSkill = MIN(crtSkill->getGained(), (int)maxSkill);
                //} else {
                maxSkill = MIN(player->getLevel()*10.0, MAXALVL*10.0);
                curSkill = MIN(crtSkill->getGained(), maxSkill);
                //}

                skill = curSkill;
                if (clan)
                    skill += clan->getSkillBonus(crtSkill->getName());
                skill /= 25;

                int displayNum = (int) skill;

                displayNum = MAX(0, MIN(SKILL_CHART_SIZE-1, displayNum));

                //bstring progressBar(int barLength, float percentFull, bstring text, char progressChar, bool enclosed)
                oStr << " ";
                if (showProgress) {
                    oStr << " ";

                    bstring progress = "" + bstring(curSkill) + "/" + bstring(maxSkill);
                    if (gConfig->isKnownOnly(crtSkill->getName()))
                        oStr << progressBar(barLength, 1);
                    else
                        oStr
                                << progressBar(barLength, (1.0 * curSkill) / maxSkill,
                                        progress.c_str());
                }

                oStr << " " << crtSkill->getDisplayName() << " - ";
                if (gConfig->isKnownOnly(crtSkill->getName())) {
                    oStr << "^WKnown^x\n";
                    continue;
                }
                //if(!isCraft) {
                //	// Not a crafting skill
                oStr << skillLevelStr[displayNum];
                //} else {
                //	// Crafting Skill
                //	int disp = (curSkill/maxSkill)*6;
                //	oStr << craftSkillLevelStr[disp];
                //}
                if (showDigits)
                    oStr << " (" << curSkill << ")";

                skill = 0;
                if (clan)
                    skill = clan->getSkillBonus(crtSkill->getName());
                if ((int) skill)
                    oStr << " (Clan: " << skill << ")";
                if ((*sIt).first == "defense" && player->isEffected("protection"))
                    oStr << " (Protection: 10)";

                if (toShow->isCt()) {  // && !isCraft)
//					oStr << " (" << crtSkill->getGained() << ")";
                    oStr << " [" << player->getSkillLevel(crtSkill->getName()) << "]";
                }
                oStr << "\n";
            }
        }
        if (known)
            toShow->printColor("%s", oStr.str().c_str());
    }
    return (0);
}

//********************************************************************
//						getSkillLevel
//********************************************************************
// Return the player level equilvalent of the given skill

double Creature::getSkillLevel(const bstring& skillName, bool useBase) const {
    if (isMonster())
        return (level);

    Skill* skill = getSkill(skillName, useBase);
    if (!skill) {
        if (isCt())
            return (MAXALVL);
        else
            return (0);
    }
    int gained = getSkillGained(skillName);

    if (clan) {
        const Clan* c = gConfig->getClan(clan);
        if (clan)
            gained += c->getSkillBonus(skillName);
    }

    double level = 0.0;
    if (gained <= 100) {
        // If less than 100, adding 5 to help out lower levels
        level = ((double) gained + 5.0) / 10.0;
    } else {
        // If over 100, divide by 9.5 to provide more returns for higher levels
        level = (double) gained / 9.5;
    }
    return (level);
}

//********************************************************************
//						getSkillGained
//********************************************************************

double Creature::getSkillGained(const bstring& skillName, bool useBase) const {
    Skill* skill = getSkill(skillName, useBase);

    if (skill == NULL) {
        if (isCt())
            return (MAXALVL * 10);
        else
            return (0);
    }
    double gained = (skill->getGained() * 1.0);
    // Prevents a level 30 from deleveling to 25 and still fighting like a level 30
    if (gained / 10 > level)
        gained = level * 10.0;

    return (gained);
}

double Creature::getTradeSkillGained(const bstring& skillName, bool useBase) const {
    Skill* skill = getSkill(skillName, useBase);
    if (skill == NULL) {
        if (isCt())
            return (MAXALVL * 10);
        else
            return (0);
    }
    double gained = (skill->getGained() * 1.0);

    if (level < 7) {
        gained = MIN(gained, 75.0);
    } else if (level < 13) {
        gained = MIN(gained, 150.0);
    } else {
        gained = MIN(gained, 300.0);
    }

    return (gained);
}

//********************************************************************
//						dmSkills
//********************************************************************
// List the skill table, or optionally a player's known skills

int dmSkills(Player* player, cmd* cmnd) {

    if (cmnd->num < 2) {
        std::map<bstring, bstring>::iterator sgIt;
        std::map<bstring, SkillInfo*>::iterator sIt;
        player->printColor(
                "^xSkill Groups\n%-20s - %40s\n---------------------------------------------------------------\n",
                "Name", "DisplayName");
        for (sgIt = gConfig->skillGroups.begin(); sgIt != gConfig->skillGroups.end(); sgIt++) {
            player->print("%-20s - %40s\n", (*sgIt).first.c_str(), (*sgIt).second.c_str());
        }

        player->printColor(
                "\n^xSkills\n%-20s - %20s - %-15s\n-------------------------------------------------------------\n",
                "Name", "DisplayName", "Group");
        SkillInfo* skill;
        bstring curGroup;
        for (sgIt = gConfig->skillGroups.begin(); sgIt != gConfig->skillGroups.end(); sgIt++) {
            curGroup = (*sgIt).first;
            for (sIt = gConfig->skills.begin(); sIt != gConfig->skills.end(); sIt++) {
                skill = (*sIt).second;
                if (skill->getGroup() == curGroup) {
                    char color[3] = "";
                    if (skill->getGainType() == SKILL_MEDIUM)
                        strcpy(color, "^y");
                    else if (skill->getGainType() == SKILL_HARD)
                        strcpy(color, "^r");
                    else if (skill->getGainType() == SKILL_EASY)
                        strcpy(color, "^g");
                    player->printColor("%s%-20s - %20s - %-15s\n", color, skill->getName().c_str(),
                            skill->getDisplayName().c_str(), skill->getGroup().c_str());
                }
            }
        }
    } else {
        Creature* target = 0;
        cmnd->str[1][0] = up(cmnd->str[1][0]);
        target = gServer->findPlayer(cmnd->str[1]);
        cmnd->str[1][0] = low(cmnd->str[1][0]);
        if (!target || (!player->isCt() && target->flagIsSet(P_DM_INVIS)))
            target = player->getParent()->findCreature(player, cmnd);

        if (!target) {
            player->print("Target not found.\n");
            return (0);
        }
        player->print("Skills for: %s\n", target->getCName());
        showSkills(player, target, true);
    }
    return (0);
}

//********************************************************************
//						dmSetSkills
//********************************************************************

int dmSetSkills(Player *admin, cmd* cmnd) {
    Player* target = 0;

    if (cmnd->num < 2) {
        admin->print("Set skills for who?\n");
        return (0);
    }

    cmnd->str[1][0] = up(cmnd->str[1][0]);
    target = gServer->findPlayer(cmnd->str[1]);

    if (!target) {
        admin->print("No player logged on with that name.\n");
        return (0);
    }

    PlayerClass *pClass = gConfig->classes[target->getClassString()];
    if (pClass) {
        target->checkSkillsGain(pClass->getSkillBegin(), pClass->getSkillEnd(), true);
        LevelGain *lGain;
        for (int level = 2; level <= target->getLevel(); level++) {
            lGain = pClass->getLevelGain(level);
            if (!lGain) {
                admin->print("Error: Can't find any information for level %d!\n", level);
            } else {
                if (lGain->hasSkills()) {
                    target->checkSkillsGain(lGain->getSkillBegin(), lGain->getSkillEnd(), true);
                }
            }
        }
        admin->print("%s's skills have been set for %s level.\n", target->getCName(), target->hisHer());
    } else {
        admin->print("Unable to find class %s.\n", target->getClassString().c_str());
    }

    return (0);
}

//********************************************************************
//						cmdSkills
//********************************************************************
// Display all skills a player knows and their level

int cmdSkills(Player* player, cmd* cmnd) {
    Creature* target = player;
    bool magicOnly = false;
    bool online = true;
    int pos = 1;

    magicOnly = cmnd->str[1][0] && !strncmp(cmnd->str[1], "magic", strlen(cmnd->str[1]));

    if (player->isCt()) {
        if (magicOnly)
            pos = 2;
        if (cmnd->str[pos][0]) {
            cmnd->str[pos][0] = up(cmnd->str[pos][0]);
            target = gServer->findPlayer(cmnd->str[pos]);

            if (!target) {
                Player* pTarget = 0;
                loadPlayer(cmnd->str[pos], &pTarget);
                target = pTarget;
                online = false;
            }

            if (!target) {
                player->print("No player logged on with that name.\n");
                return (0);
            }
            if (target->isDm() && !player->isDm()) {
                player->print("You cannot view that player's skills.\n");
                if (!online)
                    free_crt(target);
                return (0);
            }
        }
    }

    showSkills(player, target, magicOnly);
    if (!online)
        free_crt(target);
    return (0);
}
// End Skill functions related to Creatures
//--------------------------------------------------------------------

struct {
    const char *songstr;
    int songno;
    int (*songfn)();
} songlist[] =
        { { "healing", SONG_HEAL, (int (*)()) songHeal },
                { "magic", SONG_MP, (int (*)()) songMPHeal }, { "restoration", SONG_RESTORE,
                        (int (*)()) songRestore }, { "destruction", SONG_DESTRUCTION,
                        (int (*)()) songOffensive }, { "mass-destruction", SONG_MASS_DESTRUCTION,
                        (int (*)()) songMultiOffensive }, { "holiness", SONG_BLESS,
                        (int (*)()) songBless }, { "protection", SONG_PROTECTION,
                        (int (*)()) songProtection }, { "flight", SONG_FLIGHT,
                        (int (*)()) songFlight }, { "recall", SONG_RECALL, (int (*)()) songRecall },
                { "safety", SONG_SAFETY, (int (*)()) songSafety }, { "@", -1, 0 } };
int songlist_size = sizeof(songlist) / sizeof(*songlist);

//**********************************************************************
// get_song_name
//**********************************************************************
const char *get_song_name(int nIndex) {
    // do bounds checking
    ASSERTLOG(nIndex >= 0);
    ASSERTLOG(nIndex < songlist_size);

    nIndex = MAX(0, MIN(nIndex, songlist_size));

    return (songlist[nIndex].songstr);
}

//**********************************************************************
// get_song_num()
//**********************************************************************
int get_song_num(int nIndex) {
    // do bounds checking
    ASSERTLOG(nIndex >= 0);
    ASSERTLOG(nIndex < songlist_size);

    nIndex = MAX(0, MIN(nIndex, songlist_size));

    return (songlist[nIndex].songno);
}

//**********************************************************************
// get_song_function()
//**********************************************************************
SONGFN get_song_function(int nIndex) {
    // do bounds checking
    ASSERTLOG(nIndex >= 0);
    ASSERTLOG(nIndex < songlist_size);

    nIndex = MAX(0, MIN(nIndex, songlist_size));

    return (songlist[nIndex].songfn);
}

//**********************************************************************
//						getMaxSong
//**********************************************************************

int Config::getMaxSong() {
    return (songlist_size - 1);
}

// Clears skills
void Config::clearSkills() {
    // Clear skill groups
    skillGroups.clear();

    // Clear & delete skills
    SkillInfoMap::iterator sIt;
    SkillInfo* skill;
    for (sIt = skills.begin(); sIt != skills.end(); sIt++) {
        skill = (*sIt).second;
        delete skill;
        //skills.erase(sIt);
    }
    skills.clear();
    // Every skill command is in the skills list, so they've already been erased, just clear them
    skillCommands.clear();
}
// Updates skill pointers on players
void Config::updateSkillPointers() {
    for (PlayerMap::value_type pp : gServer->players) {
        for (SkillMap::value_type sp : pp.second->skills) {
            sp.second->updateParent();
        }
    }

}

//********************************************************************
//						skillExists
//********************************************************************
// True if the skill exists

bool Config::skillExists(const bstring& skillName) const {
    std::map<bstring, SkillInfo*>::const_iterator it = skills.find(skillName);
    return (it != skills.end());
}

//********************************************************************
//						getSkill
//********************************************************************
// Returns the given skill skill

SkillInfo* Config::getSkill(const bstring& skillName) const {
    std::map<bstring, SkillInfo*>::const_iterator it = skills.find(skillName);
    if (it != skills.end())
        return ((*it).second);
    return (0);
}

//********************************************************************
//						getSkillDisplayName
//********************************************************************
// Get the display name of the skill

bstring Config::getSkillDisplayName(const bstring& skillName) const {
    std::map<bstring, SkillInfo*>::const_iterator it = skills.find(skillName);
    if (it != skills.end())
        return (((*it).second)->getDisplayName());
    return ("");
}

//********************************************************************
//						getSkillGroupDisplayName
//********************************************************************
// Get the group display name of the skill

bstring Config::getSkillGroupDisplayName(const bstring& groupName) const {
    std::map<bstring, bstring>::const_iterator it = skillGroups.find(groupName);
    if (it != skillGroups.end())
        return ((*it).second);
    return ("");
}

//********************************************************************
//						getSkillGroup
//********************************************************************
// Get the skill group of the skill

bstring Config::getSkillGroup(const bstring& skillName) const {
    std::map<bstring, SkillInfo*>::const_iterator it = skills.find(skillName);
    if (it != skills.end())
        return (((*it).second)->getGroup());
    return ("");
}

// End Skill Related Functions
//--------------------------------------------------------------------

SkillInfo::SkillInfo() {
    gainType = SKILL_NORMAL;
    knownOnly = false;
}