Jump to content

eleriaqueen

Members
  • Posts

    56
  • Joined

  • Last visited

  • Days Won

    4

Posts posted by eleriaqueen

  1. I'll look into these functions, thanks for the info. Look I'm happy to at least try and come up with a solution for this "puzzle", since I'll likely use it too! 🙂
    I tried to handle Super Novice, but at first glance it doesn't look doable, becuase the job has access to other classes' skills mixed with his skills.

    I'll try to work some more on Super Novice and Summoner. If I can't do it I'll look into using the functions you mentioned, it will likely require a huge rewrite so I rather try to fix it with the "current code".

    Edit: I managed to make Super Novice and Summoner work. I also swapped ShowError() with clif_displaymessage() so that the messages appear ingame.

    enum Job_Tier {
    	Basic = 0,
    	First,
    	First_High,
    	Second,
    	Second_High,
    	Third,
    	Third_High,
    	Fourth,
    	Super_Novice,
    	Super_Novice_E,
    	Hyper_Novice,
    	Summoner,
    	Spirit_Handler,
    };
    
    // Helper Function: Returns the job tier
    Job_Tier pc_get_job_tier(uint64 class_) {
    	
    	if (class_ ==  MAPID_SPIRIT_HANDLER) return Job_Tier::Spirit_Handler;
    	if (class_ ==  MAPID_SUMMONER) return Job_Tier::Summoner;
    	
    	if (class_ ==  MAPID_HYPER_NOVICE) return Job_Tier::Hyper_Novice;
    	if (class_ ==  MAPID_SUPER_NOVICE_E) return Job_Tier::Super_Novice_E;
    	if (class_ ==  MAPID_SUPER_NOVICE) return Job_Tier::Super_Novice;
    	
    	if (class_ & JOBL_FOURTH) return Job_Tier::Fourth;
    	
    	if (class_ ==  MAPID_RUNE_KNIGHT_T) return Job_Tier::Third_High;
    	if (class_ ==  MAPID_WARLOCK_T) return Job_Tier::Third_High;
    	if (class_ ==  MAPID_RANGER_T) return Job_Tier::Third_High;
    	if (class_ ==  MAPID_ARCH_BISHOP_T) return Job_Tier::Third_High;
    	if (class_ ==  MAPID_MECHANIC_T) return Job_Tier::Third_High;
    	if (class_ ==  MAPID_GUILLOTINE_CROSS_T) return Job_Tier::Third_High;
    	if (class_ ==  MAPID_ROYAL_GUARD_T) return Job_Tier::Third_High;
    	if (class_ ==  MAPID_SORCERER_T) return Job_Tier::Third_High;
    	if (class_ ==  MAPID_MINSTRELWANDERER_T) return Job_Tier::Third_High;
    	if (class_ ==  MAPID_SURA_T) return Job_Tier::Third_High;
    	if (class_ ==  MAPID_GENETIC_T) return Job_Tier::Third_High;
    	if (class_ ==  MAPID_SHADOW_CHASER_T) return Job_Tier::Third_High;
    	
    	if (class_ & JOBL_THIRD) return Job_Tier::Third;
    	
    	if (class_ == MAPID_LORD_KNIGHT) return Job_Tier::Second_High;
    	if (class_ == MAPID_HIGH_WIZARD) return Job_Tier::Second_High;
    	if (class_ == MAPID_SNIPER) return Job_Tier::Second_High;
    	if (class_ == MAPID_HIGH_PRIEST) return Job_Tier::Second_High;
    	if (class_ == MAPID_WHITESMITH) return Job_Tier::Second_High;
    	if (class_ == MAPID_ASSASSIN_CROSS) return Job_Tier::Second_High;
    	if (class_ == MAPID_PALADIN) return Job_Tier::Second_High;
    	if (class_ == MAPID_PROFESSOR) return Job_Tier::Second_High;
    	if (class_ == MAPID_CLOWNGYPSY) return Job_Tier::Second_High;
    	if (class_ == MAPID_CHAMPION) return Job_Tier::Second_High;
    	if (class_ == MAPID_CREATOR) return Job_Tier::Second_High;
    	if (class_ == MAPID_STALKER) return Job_Tier::Second_High;
    	
    	if (class_ & JOBL_2) return Job_Tier::Second;
    	
    	if (class_ == MAPID_SWORDMAN_HIGH) return Job_Tier::First_High;
    	if (class_ == MAPID_MAGE_HIGH) return Job_Tier::First_High;
    	if (class_ == MAPID_ARCHER_HIGH) return Job_Tier::First_High;
    	if (class_ == MAPID_ACOLYTE_HIGH) return Job_Tier::First_High;
    	if (class_ == MAPID_MERCHANT_HIGH) return Job_Tier::First_High;
    	if (class_ == MAPID_THIEF_HIGH) return Job_Tier::First_High;
    	
    	if ((class_ & MAPID_BASEMASK) != MAPID_NOVICE) return Job_Tier::First;
    	
    	return Job_Tier::Basic; // Novice/Summoner
    }
    
    // Helper Function : Returns the skill's job tier
    Job_Tier skill_get_job_tier(uint16 skill_id) {
    	// Novice
    	if (skill_id > 0 && skill_id < SM_SWORD) return Job_Tier::Basic;
    	
    	// Swordman
    	else if (skill_id >= SM_SWORD && skill_id <= SM_ENDURE) return Job_Tier::First;
    	
    	// Magician
    	else if (skill_id >= MG_SRECOVERY && skill_id <= MG_THUNDERSTORM) return Job_Tier::First;
    	
    	// Acolyte
    	else if (skill_id >= AL_DP && skill_id <= AL_CURE) return Job_Tier::First;
    	
    	// Merchant
    	else if (skill_id >= MC_INCCARRY && skill_id <= MC_MAMMONITE) return Job_Tier::First;
    	
    	// Archer
    	else if (skill_id >= AC_OWL && skill_id <= AC_SHOWER) return Job_Tier::First;
    	
    	// Thief
    	else if (skill_id >= TF_DOUBLE && skill_id <= TF_DETOXIFY) return Job_Tier::First;
    	
    	// Taekwon Kid
    	else if (skill_id >= TK_RUN && skill_id <= TK_HIGHJUMP) return Job_Tier::First;
    	else if (skill_id == TK_MISSION) return Job_Tier::First;
    	
    	// Knight
    	else if (skill_id >= KN_SPEARMASTERY && skill_id <= KN_CAVALIERMASTERY) return Job_Tier::Second;
    	
    	// Priest
    	else if (skill_id >= PR_MACEMASTERY && skill_id <= PR_MAGNUS) return Job_Tier::Second;
    	
    	// Wizard
    	else if (skill_id >= WZ_FIREPILLAR && skill_id <= WZ_ESTIMATION) return Job_Tier::Second;
    	
    	// Blacksmith
    	else if (skill_id >= BS_IRON && skill_id <= BS_MAXIMIZE) return Job_Tier::Second;
    	
    	// Hunter
    	else if (skill_id >= HT_SKIDTRAP && skill_id <= HT_SPRINGTRAP) return Job_Tier::Second;
    	
    	// Assassin
    	else if (skill_id >= AS_RIGHT && skill_id <= AS_SPLASHER) return Job_Tier::Second;
    	
    	// Rogue
    	else if (skill_id >= RG_SNATCHER && skill_id <= RG_PLAGIARISM) return Job_Tier::Second;
    	
    	// Alchemist
    	else if (skill_id >= AM_AXEMASTERY && skill_id <= AM_RESURRECTHOMUN) return Job_Tier::Second;
    	
    	// Crusader
    	else if (skill_id >= CR_TRUST && skill_id <= CR_SPEARQUICKEN) return Job_Tier::Second;
    	
    	// Monk
    	else if (skill_id >= MO_IRONHAND && skill_id <= MO_COMBOFINISH) return Job_Tier::Second;
    	
    	// Sage
    	else if (skill_id >= SA_ADVANCEDBOOK && skill_id <= SA_COMA) return Job_Tier::Second;
    	
    	// Bard & Dancer
    	else if (skill_id >= BD_ADAPTATION && skill_id <= BD_RAGNAROK) return Job_Tier::Second;
    	
    	// Bard
    	else if (skill_id >= BA_MUSICALLESSON && skill_id <= BA_APPLEIDUN) return Job_Tier::Second;
    	
    	// Dancer
    	else if (skill_id >= DC_DANCINGLESSON && skill_id <= DC_SERVICEFORYOU) return Job_Tier::Second;
    	
    	// Lord Knight
    	else if (skill_id >= LK_AURABLADE && skill_id <= LK_FURY) return Job_Tier::Second_High;
    	else if (skill_id >= LK_SPIRALPIERCE && skill_id <= LK_JOINTBEAT) return Job_Tier::Second_High;
    	
    	// High Priest
    	else if (skill_id >= HP_ASSUMPTIO && skill_id <= HP_MEDITATIO) return Job_Tier::Second_High;
    	else if (skill_id == HP_MANARECHARGE) return Job_Tier::Second_High;
    	
    	// High Wizard
    	else if (skill_id >= HW_SOULDRAIN && skill_id <= HW_MAGICPOWER) return Job_Tier::Second_High;
    	else if (skill_id == HW_NAPALMVULCAN) return Job_Tier::Second_High;
    	else if (skill_id >= HW_GANBANTEIN && skill_id <= HW_GRAVITATION) return Job_Tier::Second_High;
    	
    	// Paladin
    	else if (skill_id >= PA_PRESSURE && skill_id <= PA_GOSPEL) return Job_Tier::Second_High;
    	else if (skill_id == PA_SHIELDCHAIN) return Job_Tier::Second_High;
    	
    	// Champion
    	else if (skill_id >= CH_PALMSTRIKE && skill_id <= CH_CHAINCRUSH) return Job_Tier::Second_High;
    	else if (skill_id == CH_SOULCOLLECT) return Job_Tier::Second_High;
    	
    	// Professor
    	else if (skill_id >= PF_HPCONVERSION && skill_id <= PF_SOULBURN) return Job_Tier::Second_High;
    	else if (skill_id >= PF_MINDBREAKER && skill_id <= PF_SPIDERWEB) return Job_Tier::Second_High;
    	else if (skill_id == PF_DOUBLECASTING) return Job_Tier::Second_High;
    	
    	// Assassin Cross
    	else if (skill_id >= ASC_KATAR && skill_id <= ASC_BREAKER) return Job_Tier::Second_High;
    	else if (skill_id >= ASC_METEORASSAULT && skill_id <= ASC_CDP) return Job_Tier::Second_High;
    	
    	// Sniper
    	else if (skill_id >= SN_SIGHT && skill_id <= SN_WINDWALK) return Job_Tier::Second_High;
    	
    	// Whitesmith
    	else if (skill_id >= WS_MELTDOWN && skill_id <= WS_SYSTEMCREATE) return Job_Tier::Second_High;
    	else if (skill_id == WS_WEAPONREFINE) return Job_Tier::Second_High;
    	else if (skill_id >= WS_CARTTERMINATION && skill_id <= WS_OVERTHRUSTMAX) return Job_Tier::Second_High;
    	
    	// Stalker
    	else if (skill_id >= ST_CHASEWALK && skill_id <= ST_STEALBACKPACK) return Job_Tier::Second_High;
    	else if (skill_id >= ST_PRESERVE && skill_id <= ST_FULLSTRIP) return Job_Tier::Second_High;
    	
    	// Creator
    	else if (skill_id >= CR_ALCHEMY && skill_id <= CR_SYNTHESISPOTION) return Job_Tier::Second_High;
    	else if (skill_id >= CR_SLIMPITCHER && skill_id <= CR_FULLPROTECTION) return Job_Tier::Second_High;
    	else if (skill_id == CR_ACIDDEMONSTRATION) return Job_Tier::Second_High;
    	
    	// Clown / Gypsy
    	else if (skill_id >= CG_ARROWVULCAN && skill_id <= CG_MARIONETTE) return Job_Tier::Second_High;
    	else if (skill_id >= CG_LONGINGFREEDOM && skill_id <= CG_TAROTCARD) return Job_Tier::Second_High;
    	else if (skill_id == CG_SPECIALSINGER) return Job_Tier::Second_High;
    	
    	// Star Gladiator
    	else if (skill_id >= SG_FEEL && skill_id <= SG_FUSION) return Job_Tier::Second;
    	
    	// Soul Linker
    	else if (skill_id == SL_ALCHEMIST) return Job_Tier::Second;
    	else if (skill_id >= SL_MONK && skill_id <= SL_SKA) return Job_Tier::Second;
    	else if (skill_id == SL_HIGH) return Job_Tier::Second;
    	// else if (skill_id >= SL_DEATHKNIGHT && skill_id <= SL_GUNNER) return 2;
    	
    	// Gunslinger
    	else if (skill_id >= GS_GLITTERING && skill_id <= GS_GROUNDDRIFT) return Job_Tier::Second_High;
    	
    	// Ninja
    	else if (skill_id >= NJ_TOBIDOUGU && skill_id <= NJ_ISSEN) return Job_Tier::Second_High;
    	
    	// Rune Knight
    	else if (skill_id >= RK_ENCHANTBLADE && skill_id <= RK_PHANTOMTHRUST) return Job_Tier::Third;
    	else if (skill_id >= RK_DRAGONBREATH_WATER && skill_id <= RK_LUXANIMA) return Job_Tier::Third;
    	
    	// Guillotine Cross
    	else if (skill_id >= GC_VENOMIMPRESS && skill_id <= GC_CROSSRIPPERSLASHER) return Job_Tier::Third;
    	else if (skill_id == GC_DARKCROW) return Job_Tier::Third;
    	
    	// Arch-Bishop
    	else if (skill_id >= AB_JUDEX && skill_id <= AB_SILENTIUM) return Job_Tier::Third;
    	else if (skill_id == AB_SECRAMENT) return Job_Tier::Third;
    	else if (skill_id == AB_OFFERTORIUM) return Job_Tier::Third;
    	else if (skill_id >= AB_VITUPERATUM && skill_id <= AB_CONVENIO) return Job_Tier::Third;
    	
    	// Warlock
    	else if (skill_id >= WL_WHITEIMPRISON && skill_id <= WL_FREEZE_SP) return Job_Tier::Third;
    	else if (skill_id == WL_TELEKINESIS_INTENSE) return Job_Tier::Third;
    	
    	// Ranger
    	else if (skill_id >= RA_ARROWSTORM && skill_id <= RA_ICEBOUNDTRAP) return Job_Tier::Third;
    	else if (skill_id == RA_UNLIMIT) return Job_Tier::Third;
    	
    	// Mechanic
    	else if (skill_id >= NC_MADOLICENCE && skill_id <= NC_DISJOINT) return Job_Tier::Third;
    	else if (skill_id == NC_MAGMA_ERUPTION) return Job_Tier::Third;
    	
    	// Shadow Chaser
    	else if (skill_id >= SC_FATALMENACE && skill_id <= SC_FEINTBOMB) return Job_Tier::Third;
    	else if (skill_id == SC_ESCAPE) return Job_Tier::Third;
    	
    	// Royal Guard
    	else if (skill_id >= LG_CANNONSPEAR && skill_id <= LG_INSPIRATION) return Job_Tier::Third;
    	else if (skill_id == LG_KINGS_GRACE) return Job_Tier::Third;
    	
    	// Sura
    	else if (skill_id >= SR_DRAGONCOMBO && skill_id <= SR_GENTLETOUCH_REVITALIZE) return Job_Tier::Third;
    	else if (skill_id >= SR_HOWLINGOFLION && skill_id <= SR_RIDEINLIGHTNING) return Job_Tier::Third;
    	else if (skill_id == SR_FLASHCOMBO) return Job_Tier::Third;
    	
    	// Wanderer
    	else if (skill_id >= WA_SWING_DANCE && skill_id <= WA_MOONLIT_SERENADE) return Job_Tier::Third;
    	
    	// Ministrel
    	else if (skill_id >= MI_RUSH_WINDMILL && skill_id <= MI_HARMONIZE) return Job_Tier::Third;
    	
    	// Wanderer && Ministrel
    	else if (skill_id >= WM_LESSON && skill_id <= WM_UNLIMITED_HUMMING_VOICE) return Job_Tier::Third;
    	else if (skill_id == WM_FRIGG_SONG)  return Job_Tier::Third;
    	
    	// Sorcerer
    	else if (skill_id >= SO_FIREWALK && skill_id <= SO_EARTH_INSIGNIA) return Job_Tier::Third;
    	else if (skill_id == SO_ELEMENTAL_SHIELD) return Job_Tier::Third;
    
    	// Genetic
    	else if (skill_id >= GN_TRAINING_SWORD && skill_id <= GN_SLINGITEM_RANGEMELEEATK) return Job_Tier::Third;
    	else if (skill_id == GN_ILLUSIONDOPING) return Job_Tier::Third;
    	
    	// Rebellion
    	else if (skill_id >= RL_GLITTERING_GREED && skill_id <= RL_B_FLICKER_ATK) return Job_Tier::Third;
    	
    	// Star Emperor
    	else if (skill_id >= SJ_LIGHTOFMOON && skill_id <= SJ_PROMINENCEKICK) return Job_Tier::Third;
    	
    	// Soul Reaper
    	else if (skill_id >= SP_SOULGOLEM && skill_id <= SP_KAUTE) return Job_Tier::Third;
    	
    	// Kagerou && Oboro
    	else if (skill_id >= KO_YAMIKUMO && skill_id <= KO_IZAYOI) return Job_Tier::Third;
    	
    	// Kagerou
    	else if (skill_id >= KG_KAGEHUMI && skill_id <= KG_KAGEMUSYA) return Job_Tier::Third;
    	
    	// Oboro
    	else if (skill_id >= OB_ZANGETSU && skill_id <= OB_AKAITSUKI) return Job_Tier::Third;
    	
    	// Super Novice 2 
    	else if (skill_id >= NV_BREAKTHROUGH && skill_id <= NV_TRANSCENDENCE) return Job_Tier::Third;
    	
    	// Summoner
    	else if (skill_id >= SU_BASIC_SKILL && skill_id <= SU_SPIRITOFSEA) return Job_Tier::Third;
    	
    	// ALL 3rd jobs
    	else if (skill_id == ALL_FULL_THROTTLE) return Job_Tier::Third;
    	
    	// Dragon Knight 
    	else if (skill_id >= DK_SERVANTWEAPON && skill_id <= DK_STORMSLASH) return Job_Tier::Fourth;
    	else if (skill_id == DK_DRAGONIC_BREATH) return Job_Tier::Fourth;
    	else if (skill_id == DK_DRAGONIC_PIERCE) return Job_Tier::Fourth;
    	
    	// Arc Mage 
    	else if (skill_id >= AG_DEADLY_PROJECTION && skill_id <= AG_FROZEN_SLASH) return Job_Tier::Fourth;
    	else if (skill_id == AG_DESTRUCTIVE_HURRICANE_CLIMAX) return Job_Tier::Fourth;
    	else if (skill_id == AG_ENERGY_CONVERSION) return Job_Tier::Fourth;
    	
    	// Inquisitor 
    	else if (skill_id >= IQ_POWERFUL_FAITH && skill_id <= IQ_THIRD_EXOR_FLAME) return Job_Tier::Fourth;
    	else if (skill_id == IQ_BLAZING_FLAME_BLAST) return Job_Tier::Fourth;
    	
    	// Imperial Guard 
    	else if (skill_id >= IG_GUARD_STANCE && skill_id <= IG_CROSS_RAIN) return Job_Tier::Fourth;
    	else if (skill_id >= IG_RADIANT_SPEAR && skill_id <= IG_IMPERIAL_PRESSURE) return Job_Tier::Fourth;
    	
    	// Cardinal 
    	else if (skill_id >= CD_REPARATIO && skill_id <= CD_FRAMEN) return Job_Tier::Fourth;
    	else if (skill_id == CD_DIVINUS_FLOS) return Job_Tier::Fourth;
    	
    	// Shadow Cross 
    	else if (skill_id >= SHC_SHADOW_EXCEED && skill_id <= SHC_FATAL_SHADOW_CROW) return Job_Tier::Fourth;
    	else if (skill_id == SHC_CROSS_SLASH) return Job_Tier::Fourth;
    	
    	// Meister 
    	else if (skill_id >= MT_AXE_STOMP && skill_id <= MT_SUMMON_ABR_INFINITY) return Job_Tier::Fourth;
    	else if (skill_id >= MT_SPARK_BLASTER && skill_id <= MT_MIGHTY_SMASH) return Job_Tier::Fourth;
    	else if (skill_id >= MT_RUSH_STRIKE && skill_id <= MT_ENERGY_CANNONADE) return Job_Tier::Fourth;
    	
    	// Biolo 
    	else if (skill_id >= BO_ACIDIFIED_ZONE_WATER_ATK && skill_id <= BO_ACIDIFIED_ZONE_FIRE_ATK) return Job_Tier::Fourth;
    	else if (skill_id >= BO_BIONIC_PHARMACY && skill_id <= BO_HELLTREE) return Job_Tier::Fourth;
    	else if (skill_id >= BO_EXPLOSIVE_POWDER && skill_id <= BO_MAYHEMIC_THORNS) return Job_Tier::Fourth;
    	else if (skill_id >= BO_MYSTERY_POWDER && skill_id <= BO_DUST_EXPLOSION) return Job_Tier::Fourth;
    	
    	// Abyss Chaser 
    	else if (skill_id >= ABC_DAGGER_AND_BOW_M && skill_id <= ABC_FRENZY_SHOT) return Job_Tier::Fourth;
    	else if (skill_id >= ABC_HIT_AND_SLIDING && skill_id <= ABC_ABYSS_FLAME) return Job_Tier::Fourth;
    	
    	// Wind Hawk
    	else if (skill_id >= WH_ADVANCED_TRAP && skill_id <= WH_FLAMETRAP) return Job_Tier::Fourth;
    	else if (skill_id == WH_WILD_WALK) return Job_Tier::Fourth;
    	
    	// Troubadour && Trouvere
    	else if (skill_id >= TR_STAGE_MANNER && skill_id <= TR_PRON_MARCH) return Job_Tier::Fourth;
    	else if (skill_id == TR_RHYTHMICAL_WAVE) return Job_Tier::Fourth;
    	
    	// Elemental Master
    	else if (skill_id >= EM_MAGIC_BOOK_M && skill_id <= EM_ELEMENTAL_VEIL) return Job_Tier::Fourth;
    	else if (skill_id == EM_PSYCHIC_STREAM) return Job_Tier::Fourth;
    	
    	// Night Watch
    	else if (skill_id >= NW_P_F_I && skill_id <= NW_MISSION_BOMBARD) return Job_Tier::Fourth;
    	else if (skill_id >= NW_WILD_SHOT && skill_id <= NW_MIDNIGHT_FALLEN) return Job_Tier::Fourth;
    	
    	// Soul Ascetic
    	else if (skill_id >= SOA_TALISMAN_MASTERY && skill_id <= SOA_SOUL_OF_HEAVEN_AND_EARTH) return Job_Tier::Fourth;
    	
    	// Spirit Handler
    	else if (skill_id >= SH_MYSTICAL_CREATURE_MASTERY && skill_id <= SH_BLESSING_OF_MYSTICAL_CREATURES) return Job_Tier::Fourth;
    	else if (skill_id >= SH_CHUL_HO_BATTERING && skill_id <= SH_HYUN_ROK_SPIRIT_POWER) return Job_Tier::Fourth;
    	
    	// Hyper Novice
    	else if (skill_id >= HN_SELFSTUDY_TATICS && skill_id <= HN_RULEBREAK) return Job_Tier::Fourth;
    	else if (skill_id == HN_OVERCOMING_CRISIS) return Job_Tier::Fourth;
    	
    	// Sky Emperor
    	else if (skill_id >= SKE_SKY_MASTERY && skill_id <= SKE_ENCHANTING_SKY) return Job_Tier::Fourth;
    	else if (skill_id >= SKE_SKY_SUN && skill_id <= SKE_STAR_LIGHT_KICK) return Job_Tier::Fourth;
    	
    	// Shinkiro && Shiranui
    	else if (skill_id >= SS_TOKEDASU && skill_id <= SS_ANKOKURYUUAKUMU) return Job_Tier::Fourth;
    	else if (skill_id == SS_FOUR_CHARM) return Job_Tier::Fourth;
    	
    	// Sky Emperor
    	else if (skill_id >= SKE_SKY_MASTERY && skill_id <= SKE_ENCHANTING_SKY) return Job_Tier::Fourth;
    	
    	return Job_Tier::Basic; // Default to Novice if unknown
    }
    
    /*==========================================
     * Update skill_lv for player sd
     * Skill point allocation
     *------------------------------------------*/
    void pc_skillup(map_session_data *sd,uint16 skill_id)
    {
    	uint16 idx = skill_get_index(skill_id);
    
    	nullpo_retv(sd);
    	
    	if (!idx) {
    		if (skill_id)
    			ShowError("pc_skillup: Player attempts to level up invalid skill '%d'\n", skill_id);
    		return;
    	}	
    
    	int32 skill_point = pc_calc_skillpoint( sd );
    	
    	int32 novice_max_skillpoint = job_db.find( JOB_NOVICE )->max_job_level - 1;
    	int32 summoner_max_skillpoint = job_db.find( JOB_SUMMONER )->max_job_level - 1;
    	 
    	int32 max_skillpoint_1st = job_db.find( JOB_SWORDMAN )->max_job_level - 1;
    	int32 max_skillpoint_2nd = job_db.find( JOB_KNIGHT )->max_job_level - 1;
    	int32 max_skillpoint_2nd_high = job_db.find( JOB_LORD_KNIGHT )->max_job_level - 1;
    	int32 max_skillpoint_3rd = job_db.find( JOB_RUNE_KNIGHT )->max_job_level - 1;
    	
    	int32 max_skillpoint_sn = job_db.find( JOB_SUPER_NOVICE )->max_job_level - 1;
    	int32 max_skillpoint_sn_e = job_db.find( JOB_SUPER_NOVICE_E )->max_job_level - 1;
    	
    	int32 max_skillpoint_summ = job_db.find( JOB_SUMMONER )->max_job_level - 1;
    	
    	int32 skillpoint_1st = sd->change_level_2nd - 1;
    	int32 skillpoint_2nd = sd->change_level_3rd - 1;
    	
    	int32 must_spend_novice = novice_max_skillpoint - skill_point;
    	int32 must_spend_1st = min(max_skillpoint_1st, novice_max_skillpoint + skillpoint_1st - skill_point);
    	int32 must_spend_2nd = min(max_skillpoint_2nd, novice_max_skillpoint + skillpoint_1st + skillpoint_2nd - skill_point);
    	int32 must_spend_2nd_high = min(max_skillpoint_2nd_high, novice_max_skillpoint + skillpoint_1st + skillpoint_2nd - skill_point);
    	int32 must_spend_3rd = min(max_skillpoint_3rd, novice_max_skillpoint + skillpoint_1st + skillpoint_2nd + max_skillpoint_3rd - skill_point);
    	
    	int32 must_spend_sn = min(max_skillpoint_sn, novice_max_skillpoint + max_skillpoint_sn - skill_point);
    	int32 must_spend_sn_e = min(max_skillpoint_sn_e, novice_max_skillpoint + max_skillpoint_sn + max_skillpoint_sn_e - skill_point);
    	
    	int32 must_spend_summ = max_skillpoint_summ - skill_point;
    	
    	StringBuf *helper_msg_novice = StringBuf_Malloc();
    	StringBuf *helper_msg_novice_high = StringBuf_Malloc();
    	StringBuf *helper_msg_1st = StringBuf_Malloc();
    	StringBuf *helper_msg_1st_high = StringBuf_Malloc();
    	StringBuf *helper_msg_2nd = StringBuf_Malloc();
    	StringBuf *helper_msg_2nd_high = StringBuf_Malloc();
    	StringBuf *helper_msg_3rd = StringBuf_Malloc();
    	
    	StringBuf *helper_msg_sn = StringBuf_Malloc();
    	StringBuf *helper_msg_sn_e = StringBuf_Malloc();
    	StringBuf *helper_msg_hn = StringBuf_Malloc();
    	
    	StringBuf *helper_msg_summoner = StringBuf_Malloc();
    	
    	StringBuf_Printf(helper_msg_novice, "%d %s", must_spend_novice, "more skillpoints are required in Basic Skill\n");
    	StringBuf_Printf(helper_msg_novice_high, "%d %s", must_spend_novice, "more skillpoints are required in Basic Skill\n");
    	StringBuf_Printf(helper_msg_1st, "%d %s", must_spend_1st, "more skillpoints are required in 1st Job Skill Tree\n");
    	StringBuf_Printf(helper_msg_1st_high, "%d %s", must_spend_1st, "more skillpoints are required in 1st High Job Skill Tree\n");
    	StringBuf_Printf(helper_msg_2nd, "%d %s", must_spend_2nd, "more skillpoints are required in 2nd Job Skill Tree\n");
    	StringBuf_Printf(helper_msg_2nd_high, "%d %s", must_spend_2nd_high, "more skillpoints are required in 2nd High Job Skill Tree\n");
    	StringBuf_Printf(helper_msg_3rd, "%d %s", must_spend_3rd, "more skillpoints are required in 3rd Job Skill Tree\n");
    	
    	StringBuf_Printf(helper_msg_sn, "%d %s", must_spend_sn, "more skillpoints are required in Super Novice (considered Novice Job) Skill Tree\n");
    	StringBuf_Printf(helper_msg_sn_e, "%d %s", must_spend_sn_e, "more skillpoints are required in Expanded Super Novice (considered 2nd Job) Skill Tree\n");
    	
    	StringBuf_Printf(helper_msg_summoner, "%d %s", must_spend_summ, "more skillpoints are required in Summoner Skill Tree\n");
    	
    	// Special Case for Super Novice
    	if (pc_get_job_tier(sd->class_) == Job_Tier::Super_Novice) {
    		if (skill_get_job_tier(skill_id) == Job_Tier::First && (skill_point < novice_max_skillpoint)) {
    			// ShowError(helper_msg_novice, must_spend_novice);
    			clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_novice));
    		}
    	}
    	// Special Case for Expanded Super Novice
    	else if (pc_get_job_tier(sd->class_) == Job_Tier::Super_Novice_E) {
    		if (skill_get_job_tier(skill_id) == Job_Tier::First && (skill_point < novice_max_skillpoint)) {
    			if (skill_point < novice_max_skillpoint) {
    				// ShowError(helper_msg_novice, must_spend_novice);
    				clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_novice));
    			}
    		}
    		if (skill_get_job_tier(skill_id) == Job_Tier::Second || skill_get_job_tier(skill_id) == Job_Tier::Third && (skill_point < novice_max_skillpoint + max_skillpoint_sn)) {
    			if (skill_point < novice_max_skillpoint) {
    				// ShowError(helper_msg_novice, must_spend_novice);
    				clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_novice));
    			}
    			if (skill_point < novice_max_skillpoint + skillpoint_1st) {
    				// ShowError(helper_msg_sn, must_spend_sn);
    				clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_sn));
    			}
    		}
    	}
    	// Special Case for Hyper Novice
    	else if (pc_get_job_tier(sd->class_) == Job_Tier::Hyper_Novice) {
    		if (skill_get_job_tier(skill_id) == Job_Tier::First && (skill_point < novice_max_skillpoint)) {
    			if (skill_point < novice_max_skillpoint) {
    				// ShowError(helper_msg_novice, must_spend_novice);
    				clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_novice));
    			}
    		}
    		if (skill_get_job_tier(skill_id) == Job_Tier::Second || skill_get_job_tier(skill_id) == Job_Tier::Third && (skill_point < novice_max_skillpoint + max_skillpoint_sn)) {
    			if (skill_point < novice_max_skillpoint) {
    				// ShowError(helper_msg_novice, must_spend_novice);
    				clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_novice));
    			}
    			if (skill_point < novice_max_skillpoint + max_skillpoint_sn) {
    				// ShowError(helper_msg_sn, must_spend_sn);
    				clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_sn));
    			}
    		}
    		if (skill_get_job_tier(skill_id) == Job_Tier::Fourth && (skill_point < novice_max_skillpoint + max_skillpoint_sn + max_skillpoint_sn_e)) {
    			if (skill_point < novice_max_skillpoint) {
    				// ShowError(helper_msg_novice, must_spend_novice);
    				clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_novice));
    			}
    			if (skill_point < novice_max_skillpoint + max_skillpoint_sn) {
    				// ShowError(helper_msg_sn, must_spend_sn);
    				clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_sn));
    			}
    			if (skill_point < novice_max_skillpoint + max_skillpoint_sn + max_skillpoint_sn_e) {
    				// ShowError(helper_msg_sn_e, must_spend_sn_e);
    				clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_sn_e));
    			}
    		}
    	}
    	
    	// Special Case for Spirit Handler
    	else if (pc_get_job_tier(sd->class_) == Job_Tier::Spirit_Handler) {
    		if (skill_get_job_tier(skill_id) == Job_Tier::Fourth && (skill_point < max_skillpoint_summ)) {
    			// ShowError(helper_msg_summoner, must_spend_summ);
    			clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_summoner));
    		}
    	}	
    	
    	else if (pc_get_job_tier(sd->class_) == Job_Tier::First) {
    		if (skill_get_job_tier(skill_id) == Job_Tier::First && (skill_point < novice_max_skillpoint)) {
    			// ShowError(helper_msg_novice, must_spend_novice);
    			clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_novice));
    		}
    	}
    	else if (pc_get_job_tier(sd->class_) == Job_Tier::First_High) {
    		if (skill_get_job_tier(skill_id) == Job_Tier::First && (skill_point < novice_max_skillpoint)) {
    			if (skill_point < novice_max_skillpoint) {
    				// ShowError(helper_msg_novice, must_spend_novice);
    				clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_novice));
    			}
    		}
    	}
    	else if (pc_get_job_tier(sd->class_) == Job_Tier::Second) {
    		if (skill_get_job_tier(skill_id) == Job_Tier::First && (skill_point < novice_max_skillpoint)) {
    			if (skill_point < novice_max_skillpoint) {
    				// ShowError(helper_msg_novice, must_spend_novice);
    				clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_novice));
    			}
    		}
    		if (skill_get_job_tier(skill_id) == Job_Tier::Second && (skill_point < novice_max_skillpoint + skillpoint_1st)) {
    			if (skill_point < novice_max_skillpoint) {
    				// ShowError(helper_msg_novice, must_spend_novice);
    				clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_novice));
    			}
    			if (skill_point < novice_max_skillpoint + skillpoint_1st) {
    				// ShowError(helper_msg_1st, must_spend_1st);
    				clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_1st));
    			}
    		}
    	}
    	else if (pc_get_job_tier(sd->class_) == Job_Tier::Second_High) {
    		if (skill_get_job_tier(skill_id) == Job_Tier::First && (skill_point < novice_max_skillpoint)) {
    			if (skill_point < novice_max_skillpoint) {
    				// ShowError(helper_msg_novice_high, must_spend_novice);
    				clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_novice_high));
    			}
    		}
    		if (skill_get_job_tier(skill_id) == Job_Tier::Second && (skill_point < novice_max_skillpoint + skillpoint_1st)) {
    			if (skill_point < novice_max_skillpoint) {
    				// ShowError(helper_msg_novice_high, must_spend_novice);
    				clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_novice_high));
    			}
    			if (skill_point < novice_max_skillpoint + skillpoint_1st) {
    				// ShowError(helper_msg_1st_high, must_spend_1st);
    				clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_1st_high));
    			}
    		}
    	}
    	else if (pc_get_job_tier(sd->class_) == Job_Tier::Third) {
    		if (skill_get_job_tier(skill_id) == Job_Tier::First && (skill_point < novice_max_skillpoint)) {
    			if (skill_point < novice_max_skillpoint) {
    				// ShowError(helper_msg_novice, must_spend_novice);
    				clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_novice));
    			}
    		}
    		if (skill_get_job_tier(skill_id) == Job_Tier::Second && (skill_point < novice_max_skillpoint + skillpoint_1st)) {
    			if (skill_point < novice_max_skillpoint) {
    				// ShowError(helper_msg_novice, must_spend_novice);
    				clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_novice));
    			}
    			if (skill_point < novice_max_skillpoint + skillpoint_1st) {
    				// ShowError(helper_msg_1st, must_spend_1st);
    				clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_1st));
    			}
    		}
    		if (skill_get_job_tier(skill_id) == Job_Tier::Third && (skill_point < novice_max_skillpoint + skillpoint_1st + max_skillpoint_2nd)) {
    			if (skill_point < novice_max_skillpoint) {
    				// ShowError(helper_msg_novice, must_spend_novice);
    				clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_novice));
    			}
    			if (skill_point < novice_max_skillpoint + skillpoint_1st) {
    				// ShowError(helper_msg_1st, must_spend_1st);
    				clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_1st));
    			}
    			if (skill_point < novice_max_skillpoint + skillpoint_1st + skillpoint_2nd) {
    				// ShowError(helper_msg_2nd, must_spend_2nd);
    				clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_2nd));
    			}
    		}
    	}
    	else if (pc_get_job_tier(sd->class_) == Job_Tier::Third_High) {
    		if (skill_get_job_tier(skill_id) == Job_Tier::First && (skill_point < novice_max_skillpoint)) {
    			if (skill_point < novice_max_skillpoint) {
    				// ShowError(helper_msg_novice_high, must_spend_novice);
    				clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_novice_high));
    			}
    		}
    		if (skill_get_job_tier(skill_id) == Job_Tier::Second && (skill_point < novice_max_skillpoint + skillpoint_1st)) {
    			if (skill_point < novice_max_skillpoint) {
    				// ShowError(helper_msg_novice_high, must_spend_novice);
    				clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_novice_high));
    			}
    			if (skill_point < novice_max_skillpoint + skillpoint_1st) {
    				// ShowError(helper_msg_1st_high, must_spend_1st);
    				clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_1st_high));
    			}
    		}
    		if ((skill_get_job_tier(skill_id) == Job_Tier::Third || Job_Tier::Third_High) && (skill_point < novice_max_skillpoint + skillpoint_1st + max_skillpoint_2nd)) {
    			if (skill_point < novice_max_skillpoint) {
    				// ShowError(helper_msg_novice_high, must_spend_novice);
    				clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_novice_high));
    			}
    			if (skill_point < novice_max_skillpoint + skillpoint_1st) {
    				// ShowError(helper_msg_1st_high, must_spend_1st);
    				clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_1st_high));
    			}
    			if (skill_point < novice_max_skillpoint + skillpoint_1st + skillpoint_2nd) {
    				// ShowError(helper_msg_2nd_high, must_spend_2nd_high);
    				clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_2nd_high));
    			}
    		}
    	}
    	else if (pc_get_job_tier(sd->class_) == Job_Tier::Fourth) {
    		if (skill_get_job_tier(skill_id) == Job_Tier::First && (skill_point < novice_max_skillpoint)) {
    			if (skill_point < novice_max_skillpoint) {
    				// ShowError(helper_msg_novice, must_spend_novice);
    				clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_novice));
    			}
    		}
    		if (skill_get_job_tier(skill_id) == Job_Tier::Second && (skill_point < novice_max_skillpoint + skillpoint_1st)) {
    			if (skill_point < novice_max_skillpoint) {
    				// ShowError(helper_msg_novice, must_spend_novice);
    				clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_novice));
    			}
    			if (skill_point < novice_max_skillpoint + skillpoint_1st) {
    				// ShowError(helper_msg_1st, must_spend_1st);
    				clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_1st));
    			}
    		}
    		if (skill_get_job_tier(skill_id) == Job_Tier::Third && (skill_point < novice_max_skillpoint + skillpoint_1st + max_skillpoint_2nd)) {
    			if (skill_point < novice_max_skillpoint) {
    				// ShowError(helper_msg_novice, must_spend_novice);
    				clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_novice));
    			}
    			if (skill_point < novice_max_skillpoint + skillpoint_1st) {
    				// ShowError(helper_msg_1st, must_spend_1st);
    				clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_1st));
    			}
    			// If character went rebirth 2nd and 3rd
    			if ((skill_point < novice_max_skillpoint + skillpoint_1st + skillpoint_2nd) && (skillpoint_2nd == max_skillpoint_2nd_high)) {
    				// ShowError(helper_msg_2nd_high, must_spend_2nd_high);
    				clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_2nd_high));
    			}
    			// If character went non-rebirth 2nd and 3rd
    			else if ((skill_point < novice_max_skillpoint + skillpoint_1st + skillpoint_2nd) && (skillpoint_2nd == max_skillpoint_2nd)) {
    				// ShowError(helper_msg_2nd, must_spend_2nd);
    				clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_2nd));
    			}
    		}
    		if (skill_get_job_tier(skill_id) == Job_Tier::Fourth && (skill_point < novice_max_skillpoint + skillpoint_1st + max_skillpoint_2nd + max_skillpoint_3rd)) {
    			if (skill_point < novice_max_skillpoint) {
    				// ShowError(helper_msg_novice, must_spend_novice);
    				clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_novice));
    			}
    			if (skill_point < novice_max_skillpoint + skillpoint_1st) {
    				// ShowError(helper_msg_1st, must_spend_1st);
    				clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_1st));
    			}
    			// if (skill_point < novice_max_skillpoint + skillpoint_1st + skillpoint_2nd) {
    			// 	// ShowError(helper_msg_2nd, must_spend_2nd);
    			// 	clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_2nd));
    			// }
    			// If character went rebirth 2nd and 3rd then 4th
    			if ((skill_point < novice_max_skillpoint + skillpoint_1st + skillpoint_2nd) && (skillpoint_2nd == max_skillpoint_2nd_high)) {
    				// ShowError(helper_msg_2nd_high, must_spend_2nd_high);
    				clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_2nd_high));
    			}
    			// If character went non-rebirth 2nd and 3rd then 4th
    			else if ((skill_point < novice_max_skillpoint + skillpoint_1st + skillpoint_2nd) && (skillpoint_2nd == max_skillpoint_2nd)) {
    				// ShowError(helper_msg_2nd, must_spend_2nd);
    				clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_2nd));
    			}
    			if (skill_point < novice_max_skillpoint + skillpoint_1st + skillpoint_2nd + max_skillpoint_3rd) {
    				// ShowError(helper_msg_3rd, must_spend_3rd);
    				clif_displaymessage(sd->fd, StringBuf_Value(helper_msg_3rd));
    			}
    		}
    	}
    	StringBuf_Free(helper_msg_novice);
    	StringBuf_Free(helper_msg_novice_high);
    	StringBuf_Free(helper_msg_1st);
    	StringBuf_Free(helper_msg_1st_high);
    	StringBuf_Free(helper_msg_2nd);
    	StringBuf_Free(helper_msg_2nd_high);
    	StringBuf_Free(helper_msg_3rd);
    	
    	StringBuf_Free(helper_msg_sn);
    	StringBuf_Free(helper_msg_sn_e);
    	StringBuf_Free(helper_msg_hn);
    	
    	StringBuf_Free(helper_msg_summoner);
    
    	... Rest of the function code ...
    }

     

  2. Class skills aren't well organized into neatly defined id ranges if I recall correctly. Some SM_ skills may have high ID's. We also need a way to check skillpoints invested in a specific job, so that if user tries to skill up a 2nd Job skill we could check if they spent all their first job skills. Oh dang, we also need to have specific code to handle Second High jobs / Third High jobs as high 2nd can go to joblvl 70.

    Edit: I may have found a way, but my code is very long. This time I'm using ShowError() function for testing purposes.

    enum Job_Tier {
    	Basic = 0,
    	First,
    	First_High,
    	Second,
    	Second_High,
    	Third,
    	Third_High,
    	Fourth
    };
    
    // Helper Function: Returns the player character's job tier
    Job_Tier pc_get_job_tier(uint64 class_) {
    	if (class_ & JOBL_FOURTH) return Job_Tier::Fourth;
    	
    	if (class_ ==  MAPID_RUNE_KNIGHT_T) return Job_Tier::Third_High;
    	if (class_ ==  MAPID_WARLOCK_T) return Job_Tier::Third_High;
    	if (class_ ==  MAPID_RANGER_T) return Job_Tier::Third_High;
    	if (class_ ==  MAPID_ARCH_BISHOP_T) return Job_Tier::Third_High;
    	if (class_ ==  MAPID_MECHANIC_T) return Job_Tier::Third_High;
    	if (class_ ==  MAPID_GUILLOTINE_CROSS_T) return Job_Tier::Third_High;
    	if (class_ ==  MAPID_ROYAL_GUARD_T) return Job_Tier::Third_High;
    	if (class_ ==  MAPID_SORCERER_T) return Job_Tier::Third_High;
    	if (class_ ==  MAPID_MINSTRELWANDERER_T) return Job_Tier::Third_High;
    	if (class_ ==  MAPID_SURA_T) return Job_Tier::Third_High;
    	if (class_ ==  MAPID_GENETIC_T) return Job_Tier::Third_High;
    	if (class_ ==  MAPID_SHADOW_CHASER_T) return Job_Tier::Third_High;
    	
    	if (class_ & JOBL_THIRD) return Job_Tier::Third;
    	
    	if (class_ == MAPID_LORD_KNIGHT) return Job_Tier::Second_High;
    	if (class_ == MAPID_HIGH_WIZARD) return Job_Tier::Second_High;
    	if (class_ == MAPID_SNIPER) return Job_Tier::Second_High;
    	if (class_ == MAPID_HIGH_PRIEST) return Job_Tier::Second_High;
    	if (class_ == MAPID_WHITESMITH) return Job_Tier::Second_High;
    	if (class_ == MAPID_ASSASSIN_CROSS) return Job_Tier::Second_High;
    	if (class_ == MAPID_PALADIN) return Job_Tier::Second_High;
    	if (class_ == MAPID_PROFESSOR) return Job_Tier::Second_High;
    	if (class_ == MAPID_CLOWNGYPSY) return Job_Tier::Second_High;
    	if (class_ == MAPID_CHAMPION) return Job_Tier::Second_High;
    	if (class_ == MAPID_CREATOR) return Job_Tier::Second_High;
    	if (class_ == MAPID_STALKER) return Job_Tier::Second_High;
    	
    	if (class_ & JOBL_2) return Job_Tier::Second;
    	
    	if (class_ == MAPID_SWORDMAN_HIGH) return Job_Tier::First_High;
    	if (class_ == MAPID_MAGE_HIGH) return Job_Tier::First_High;
    	if (class_ == MAPID_ARCHER_HIGH) return Job_Tier::First_High;
    	if (class_ == MAPID_ACOLYTE_HIGH) return Job_Tier::First_High;
    	if (class_ == MAPID_MERCHANT_HIGH) return Job_Tier::First_High;
    	if (class_ == MAPID_THIEF_HIGH) return Job_Tier::First_High;
    	
    	if ((class_ & MAPID_BASEMASK) != MAPID_NOVICE) return Job_Tier::First;
    	
    	return Job_Tier::Basic; // Novice/Summoner
    }
    
    // Helper Function : Returns the skill's job tier
    Job_Tier skill_get_job_tier(uint16 skill_id) {
    	// Novice
    	if (skill_id > 0 && skill_id < SM_SWORD) return Job_Tier::Basic;
    	
    	// Swordman
    	else if (skill_id >= SM_SWORD && skill_id <= SM_ENDURE) return Job_Tier::First;
    	
    	// Magician
    	else if (skill_id >= MG_SRECOVERY && skill_id <= MG_THUNDERSTORM) return Job_Tier::First;
    	
    	// Acolyte
    	else if (skill_id >= AL_DP && skill_id <= AL_CURE) return Job_Tier::First;
    	
    	// Merchant
    	else if (skill_id >= MC_INCCARRY && skill_id <= MC_MAMMONITE) return Job_Tier::First;
    	
    	// Archer
    	else if (skill_id >= AC_OWL && skill_id <= AC_SHOWER) return Job_Tier::First;
    	
    	// Thief
    	else if (skill_id >= TF_DOUBLE && skill_id <= TF_DETOXIFY) return Job_Tier::First;
    	
    	// Taekwon Kid
    	else if (skill_id >= TK_RUN && skill_id <= TK_HIGHJUMP) return Job_Tier::First;
    	else if (skill_id == TK_MISSION) return Job_Tier::First;
    	
    	// Knight
    	else if (skill_id >= KN_SPEARMASTERY && skill_id <= KN_CAVALIERMASTERY) return Job_Tier::Second;
    	
    	// Priest
    	else if (skill_id >= PR_MACEMASTERY && skill_id <= PR_MAGNUS) return Job_Tier::Second;
    	
    	// Wizard
    	else if (skill_id >= WZ_FIREPILLAR && skill_id <= WZ_ESTIMATION) return Job_Tier::Second;
    	
    	// Blacksmith
    	else if (skill_id >= BS_IRON && skill_id <= BS_MAXIMIZE) return Job_Tier::Second;
    	
    	// Hunter
    	else if (skill_id >= HT_SKIDTRAP && skill_id <= HT_SPRINGTRAP) return Job_Tier::Second;
    	
    	// Assassin
    	else if (skill_id >= AS_RIGHT && skill_id <= AS_SPLASHER) return Job_Tier::Second;
    	
    	// Rogue
    	else if (skill_id >= RG_SNATCHER && skill_id <= RG_PLAGIARISM) return Job_Tier::Second;
    	
    	// Alchemist
    	else if (skill_id >= AM_AXEMASTERY && skill_id <= AM_RESURRECTHOMUN) return Job_Tier::Second;
    	
    	// Crusader
    	else if (skill_id >= CR_TRUST && skill_id <= CR_SPEARQUICKEN) return Job_Tier::Second;
    	
    	// Monk
    	else if (skill_id >= MO_IRONHAND && skill_id <= MO_COMBOFINISH) return Job_Tier::Second;
    	
    	// Sage
    	else if (skill_id >= SA_ADVANCEDBOOK && skill_id <= SA_COMA) return Job_Tier::Second;
    	
    	// Bard & Dancer
    	else if (skill_id >= BD_ADAPTATION && skill_id <= BD_RAGNAROK) return Job_Tier::Second;
    	
    	// Bard
    	else if (skill_id >= BA_MUSICALLESSON && skill_id <= BA_APPLEIDUN) return Job_Tier::Second;
    	
    	// Dancer
    	else if (skill_id >= DC_DANCINGLESSON && skill_id <= DC_SERVICEFORYOU) return Job_Tier::Second;
    	
    	// Lord Knight
    	else if (skill_id >= LK_AURABLADE && skill_id <= LK_FURY) return Job_Tier::Second_High;
    	else if (skill_id >= LK_SPIRALPIERCE && skill_id <= LK_JOINTBEAT) return Job_Tier::Second_High;
    	
    	// High Priest
    	else if (skill_id >= HP_ASSUMPTIO && skill_id <= HP_MEDITATIO) return Job_Tier::Second_High;
    	else if (skill_id == HP_MANARECHARGE) return Job_Tier::Second_High;
    	
    	// High Wizard
    	else if (skill_id >= HW_SOULDRAIN && skill_id <= HW_MAGICPOWER) return Job_Tier::Second_High;
    	else if (skill_id == HW_NAPALMVULCAN) return Job_Tier::Second_High;
    	else if (skill_id >= HW_GANBANTEIN && skill_id <= HW_GRAVITATION) return Job_Tier::Second_High;
    	
    	// Paladin
    	else if (skill_id >= PA_PRESSURE && skill_id <= PA_GOSPEL) return Job_Tier::Second_High;
    	else if (skill_id == PA_SHIELDCHAIN) return Job_Tier::Second_High;
    	
    	// Champion
    	else if (skill_id >= CH_PALMSTRIKE && skill_id <= CH_CHAINCRUSH) return Job_Tier::Second_High;
    	else if (skill_id == CH_SOULCOLLECT) return Job_Tier::Second_High;
    	
    	// Professor
    	else if (skill_id >= PF_HPCONVERSION && skill_id <= PF_SOULBURN) return Job_Tier::Second_High;
    	else if (skill_id >= PF_MINDBREAKER && skill_id <= PF_SPIDERWEB) return Job_Tier::Second_High;
    	else if (skill_id == PF_DOUBLECASTING) return Job_Tier::Second_High;
    	
    	// Assassin Cross
    	else if (skill_id >= ASC_KATAR && skill_id <= ASC_BREAKER) return Job_Tier::Second_High;
    	else if (skill_id >= ASC_METEORASSAULT && skill_id <= ASC_CDP) return Job_Tier::Second_High;
    	
    	// Sniper
    	else if (skill_id >= SN_SIGHT && skill_id <= SN_WINDWALK) return Job_Tier::Second_High;
    	
    	// Whitesmith
    	else if (skill_id >= WS_MELTDOWN && skill_id <= WS_SYSTEMCREATE) return Job_Tier::Second_High;
    	else if (skill_id == WS_WEAPONREFINE) return Job_Tier::Second_High;
    	else if (skill_id >= WS_CARTTERMINATION && skill_id <= WS_OVERTHRUSTMAX) return Job_Tier::Second_High;
    	
    	// Stalker
    	else if (skill_id >= ST_CHASEWALK && skill_id <= ST_STEALBACKPACK) return Job_Tier::Second_High;
    	else if (skill_id >= ST_PRESERVE && skill_id <= ST_FULLSTRIP) return Job_Tier::Second_High;
    	
    	// Creator
    	else if (skill_id >= CR_ALCHEMY && skill_id <= CR_SYNTHESISPOTION) return Job_Tier::Second_High;
    	else if (skill_id >= CR_SLIMPITCHER && skill_id <= CR_FULLPROTECTION) return Job_Tier::Second_High;
    	else if (skill_id == CR_ACIDDEMONSTRATION) return Job_Tier::Second_High;
    	
    	// Clown / Gypsy
    	else if (skill_id >= CG_ARROWVULCAN && skill_id <= CG_MARIONETTE) return Job_Tier::Second_High;
    	else if (skill_id >= CG_LONGINGFREEDOM && skill_id <= CG_TAROTCARD) return Job_Tier::Second_High;
    	else if (skill_id == CG_SPECIALSINGER) return Job_Tier::Second_High;
    	
    	// Star Gladiator
    	else if (skill_id >= SG_FEEL && skill_id <= SG_FUSION) return Job_Tier::Second;
    	
    	// Soul Linker
    	else if (skill_id == SL_ALCHEMIST) return Job_Tier::Second;
    	else if (skill_id >= SL_MONK && skill_id <= SL_SKA) return Job_Tier::Second;
    	else if (skill_id == SL_HIGH) return Job_Tier::Second;
    	// else if (skill_id >= SL_DEATHKNIGHT && skill_id <= SL_GUNNER) return 2;
    	
    	// Gunslinger
    	else if (skill_id >= GS_GLITTERING && skill_id <= GS_GROUNDDRIFT) return Job_Tier::Second_High;
    	
    	// Ninja
    	else if (skill_id >= NJ_TOBIDOUGU && skill_id <= NJ_ISSEN) return Job_Tier::Second_High;
    	
    	// Rune Knight
    	else if (skill_id >= RK_ENCHANTBLADE && skill_id <= RK_PHANTOMTHRUST) return Job_Tier::Third;
    	else if (skill_id >= RK_DRAGONBREATH_WATER && skill_id <= RK_LUXANIMA) return Job_Tier::Third;
    	
    	// Guillotine Cross
    	else if (skill_id >= GC_VENOMIMPRESS && skill_id <= GC_CROSSRIPPERSLASHER) return Job_Tier::Third;
    	else if (skill_id == GC_DARKCROW) return Job_Tier::Third;
    	
    	// Arch-Bishop
    	else if (skill_id >= AB_JUDEX && skill_id <= AB_SILENTIUM) return Job_Tier::Third;
    	else if (skill_id == AB_SECRAMENT) return Job_Tier::Third;
    	else if (skill_id == AB_OFFERTORIUM) return Job_Tier::Third;
    	else if (skill_id >= AB_VITUPERATUM && skill_id <= AB_CONVENIO) return Job_Tier::Third;
    	
    	// Warlock
    	else if (skill_id >= WL_WHITEIMPRISON && skill_id <= WL_FREEZE_SP) return Job_Tier::Third;
    	else if (skill_id == WL_TELEKINESIS_INTENSE) return Job_Tier::Third;
    	
    	// Ranger
    	else if (skill_id >= RA_ARROWSTORM && skill_id <= RA_ICEBOUNDTRAP) return Job_Tier::Third;
    	else if (skill_id == RA_UNLIMIT) return Job_Tier::Third;
    	
    	// Mechanic
    	else if (skill_id >= NC_MADOLICENCE && skill_id <= NC_DISJOINT) return Job_Tier::Third;
    	else if (skill_id == NC_MAGMA_ERUPTION) return Job_Tier::Third;
    	
    	// Shadow Chaser
    	else if (skill_id >= SC_FATALMENACE && skill_id <= SC_FEINTBOMB) return Job_Tier::Third;
    	else if (skill_id == SC_ESCAPE) return Job_Tier::Third;
    	
    	// Royal Guard
    	else if (skill_id >= LG_CANNONSPEAR && skill_id <= LG_INSPIRATION) return Job_Tier::Third;
    	else if (skill_id == LG_KINGS_GRACE) return Job_Tier::Third;
    	
    	// Sura
    	else if (skill_id >= SR_DRAGONCOMBO && skill_id <= SR_GENTLETOUCH_REVITALIZE) return Job_Tier::Third;
    	else if (skill_id >= SR_HOWLINGOFLION && skill_id <= SR_RIDEINLIGHTNING) return Job_Tier::Third;
    	else if (skill_id == SR_FLASHCOMBO) return Job_Tier::Third;
    	
    	// Wanderer
    	else if (skill_id >= WA_SWING_DANCE && skill_id <= WA_MOONLIT_SERENADE) return Job_Tier::Third;
    	
    	// Ministrel
    	else if (skill_id >= MI_RUSH_WINDMILL && skill_id <= MI_HARMONIZE) return Job_Tier::Third;
    	
    	// Wanderer && Ministrel
    	else if (skill_id >= WM_LESSON && skill_id <= WM_UNLIMITED_HUMMING_VOICE) return Job_Tier::Third;
    	else if (skill_id == WM_FRIGG_SONG)  return Job_Tier::Third;
    	
    	// Sorcerer
    	else if (skill_id >= SO_FIREWALK && skill_id <= SO_EARTH_INSIGNIA) return Job_Tier::Third;
    	else if (skill_id == SO_ELEMENTAL_SHIELD) return Job_Tier::Third;
    
    	// Genetic
    	else if (skill_id >= GN_TRAINING_SWORD && skill_id <= GN_SLINGITEM_RANGEMELEEATK) return Job_Tier::Third;
    	else if (skill_id == GN_ILLUSIONDOPING) return Job_Tier::Third;
    	
    	// Rebellion
    	else if (skill_id >= RL_GLITTERING_GREED && skill_id <= RL_B_FLICKER_ATK) return Job_Tier::Third;
    	
    	// Star Emperor
    	else if (skill_id >= SJ_LIGHTOFMOON && skill_id <= SJ_PROMINENCEKICK) return Job_Tier::Third;
    	
    	// Soul Reaper
    	else if (skill_id >= SP_SOULGOLEM && skill_id <= SP_KAUTE) return Job_Tier::Third;
    	
    	// Kagerou && Oboro
    	else if (skill_id >= KO_YAMIKUMO && skill_id <= KO_IZAYOI) return Job_Tier::Third;
    	
    	// Kagerou
    	else if (skill_id >= KG_KAGEHUMI && skill_id <= KG_KAGEMUSYA) return Job_Tier::Third;
    	
    	// Oboro
    	else if (skill_id >= OB_ZANGETSU && skill_id <= OB_AKAITSUKI) return Job_Tier::Third;
    	
    	// Super Novice 2 
    	else if (skill_id >= NV_BREAKTHROUGH && skill_id <= NV_TRANSCENDENCE) return Job_Tier::Third;
    	
    	// ALL 3rd jobs
    	else if (skill_id == ALL_FULL_THROTTLE) return Job_Tier::Third;
    	
    	// Dragon Knight 
    	else if (skill_id >= DK_SERVANTWEAPON && skill_id <= DK_STORMSLASH) return Job_Tier::Fourth;
    	else if (skill_id == DK_DRAGONIC_BREATH) return Job_Tier::Fourth;
    	else if (skill_id == DK_DRAGONIC_PIERCE) return Job_Tier::Fourth;
    	
    	// Arc Mage 
    	else if (skill_id >= AG_DEADLY_PROJECTION && skill_id <= AG_FROZEN_SLASH) return Job_Tier::Fourth;
    	else if (skill_id == AG_DESTRUCTIVE_HURRICANE_CLIMAX) return Job_Tier::Fourth;
    	else if (skill_id == AG_ENERGY_CONVERSION) return Job_Tier::Fourth;
    	
    	// Inquisitor 
    	else if (skill_id >= IQ_POWERFUL_FAITH && skill_id <= IQ_THIRD_EXOR_FLAME) return Job_Tier::Fourth;
    	else if (skill_id == IQ_BLAZING_FLAME_BLAST) return Job_Tier::Fourth;
    	
    	// Imperial Guard 
    	else if (skill_id >= IG_GUARD_STANCE && skill_id <= IG_CROSS_RAIN) return Job_Tier::Fourth;
    	else if (skill_id >= IG_RADIANT_SPEAR && skill_id <= IG_IMPERIAL_PRESSURE) return Job_Tier::Fourth;
    	
    	// Cardinal 
    	else if (skill_id >= CD_REPARATIO && skill_id <= CD_FRAMEN) return Job_Tier::Fourth;
    	else if (skill_id == CD_DIVINUS_FLOS) return Job_Tier::Fourth;
    	
    	// Shadow Cross 
    	else if (skill_id >= SHC_SHADOW_EXCEED && skill_id <= SHC_FATAL_SHADOW_CROW) return Job_Tier::Fourth;
    	else if (skill_id == SHC_CROSS_SLASH) return Job_Tier::Fourth;
    	
    	// Meister 
    	else if (skill_id >= MT_AXE_STOMP && skill_id <= MT_SUMMON_ABR_INFINITY) return Job_Tier::Fourth;
    	else if (skill_id >= MT_SPARK_BLASTER && skill_id <= MT_MIGHTY_SMASH) return Job_Tier::Fourth;
    	else if (skill_id >= MT_RUSH_STRIKE && skill_id <= MT_ENERGY_CANNONADE) return Job_Tier::Fourth;
    	
    	// Biolo 
    	else if (skill_id >= BO_ACIDIFIED_ZONE_WATER_ATK && skill_id <= BO_ACIDIFIED_ZONE_FIRE_ATK) return Job_Tier::Fourth;
    	else if (skill_id >= BO_BIONIC_PHARMACY && skill_id <= BO_HELLTREE) return Job_Tier::Fourth;
    	else if (skill_id >= BO_EXPLOSIVE_POWDER && skill_id <= BO_MAYHEMIC_THORNS) return Job_Tier::Fourth;
    	else if (skill_id >= BO_MYSTERY_POWDER && skill_id <= BO_DUST_EXPLOSION) return Job_Tier::Fourth;
    	
    	// Abyss Chaser 
    	else if (skill_id >= ABC_DAGGER_AND_BOW_M && skill_id <= ABC_FRENZY_SHOT) return Job_Tier::Fourth;
    	else if (skill_id >= ABC_HIT_AND_SLIDING && skill_id <= ABC_ABYSS_FLAME) return Job_Tier::Fourth;
    	
    	// Wind Hawk
    	else if (skill_id >= WH_ADVANCED_TRAP && skill_id <= WH_FLAMETRAP) return Job_Tier::Fourth;
    	else if (skill_id == WH_WILD_WALK) return Job_Tier::Fourth;
    	
    	// Troubadour && Trouvere
    	else if (skill_id >= TR_STAGE_MANNER && skill_id <= TR_PRON_MARCH) return Job_Tier::Fourth;
    	else if (skill_id == TR_RHYTHMICAL_WAVE) return Job_Tier::Fourth;
    	
    	// Elemental Master
    	else if (skill_id >= EM_MAGIC_BOOK_M && skill_id <= EM_ELEMENTAL_VEIL) return Job_Tier::Fourth;
    	else if (skill_id == EM_PSYCHIC_STREAM) return Job_Tier::Fourth;
    	
    	// Night Watch
    	else if (skill_id >= NW_P_F_I && skill_id <= NW_MISSION_BOMBARD) return Job_Tier::Fourth;
    	else if (skill_id >= NW_WILD_SHOT && skill_id <= NW_MIDNIGHT_FALLEN) return Job_Tier::Fourth;
    	
    	// Soul Ascetic
    	else if (skill_id >= SOA_TALISMAN_MASTERY && skill_id <= SOA_SOUL_OF_HEAVEN_AND_EARTH) return Job_Tier::Fourth;
    	
    	// Spirit Handler
    	else if (skill_id >= SH_MYSTICAL_CREATURE_MASTERY && skill_id <= SH_BLESSING_OF_MYSTICAL_CREATURES) return Job_Tier::Fourth;
    	else if (skill_id >= SH_CHUL_HO_BATTERING && skill_id <= SH_HYUN_ROK_SPIRIT_POWER) return Job_Tier::Fourth;
    	
    	// Hyper Novice
    	else if (skill_id >= HN_SELFSTUDY_TATICS && skill_id <= HN_RULEBREAK) return Job_Tier::Fourth;
    	else if (skill_id == HN_OVERCOMING_CRISIS) return Job_Tier::Fourth;
    	
    	// Sky Emperor
    	else if (skill_id >= SKE_SKY_MASTERY && skill_id <= SKE_ENCHANTING_SKY) return Job_Tier::Fourth;
    	else if (skill_id >= SKE_SKY_SUN && skill_id <= SKE_STAR_LIGHT_KICK) return Job_Tier::Fourth;
    	
    	// Shinkiro && Shiranui
    	else if (skill_id >= SS_TOKEDASU && skill_id <= SS_ANKOKURYUUAKUMU) return Job_Tier::Fourth;
    	else if (skill_id == SS_FOUR_CHARM) return Job_Tier::Fourth;
    	
    	// Sky Emperor
    	else if (skill_id >= SKE_SKY_MASTERY && skill_id <= SKE_ENCHANTING_SKY) return Job_Tier::Fourth;
    	
    	return Job_Tier::Basic; // Default to Novice if unknown
    }
    
    /*==========================================
     * Update skill_lv for player sd
     * Skill point allocation
     *------------------------------------------*/
    void pc_skillup(map_session_data *sd,uint16 skill_id)
    {
    	uint16 idx = skill_get_index(skill_id);
    
    	nullpo_retv(sd);
    	
    	if (!idx) {
    		if (skill_id)
    			ShowError("pc_skillup: Player attempts to level up invalid skill '%d'\n", skill_id);
    		return;
    	}
      
    	int32 skill_point = pc_calc_skillpoint( sd );
    	
    	int32 novice_max_skillpoint = job_db.find( JOB_NOVICE )->max_job_level - 1;
    	int32 summoner_max_skillpoint = job_db.find( JOB_SUMMONER )->max_job_level - 1;
    	
    	int32 max_skillpoint_1st = job_db.find( JOB_SWORDMAN )->max_job_level - 1;
    	int32 max_skillpoint_2nd = job_db.find( JOB_KNIGHT )->max_job_level - 1;
    	int32 max_skillpoint_2nd_high = job_db.find( JOB_LORD_KNIGHT )->max_job_level - 1;
    	int32 max_skillpoint_3rd = job_db.find( JOB_RUNE_KNIGHT )->max_job_level - 1;
    	int32 max_skillpoint_4th = job_db.find( JOB_DRAGON_KNIGHT )->max_job_level - 1;
    	
    	int32 skillpoint_1st = sd->change_level_2nd - 1;
    	int32 skillpoint_2nd = sd->change_level_3rd - 1;
    	
    	int32 must_spend_novice = novice_max_skillpoint - skill_point;
    	int32 must_spend_1st = min(max_skillpoint_1st, novice_max_skillpoint + skillpoint_1st - skill_point);
    	int32 must_spend_2nd = min(max_skillpoint_2nd, novice_max_skillpoint + skillpoint_1st + skillpoint_2nd - skill_point);
    	int32 must_spend_2nd_high = min(max_skillpoint_2nd_high, novice_max_skillpoint + skillpoint_1st + skillpoint_2nd - skill_point);
    	int32 must_spend_3rd = min(max_skillpoint_3rd, novice_max_skillpoint + skillpoint_1st + skillpoint_2nd + max_skillpoint_3rd - skill_point);
    	
    	char helper_msg_novice[128];
    	char helper_msg_novice_high[128];
    	char helper_msg_1st[128];
    	char helper_msg_1st_high[128];
    	char helper_msg_2nd[128];
    	char helper_msg_2nd_high[128];
    	char helper_msg_3rd[128];
    	
    	sprintf(helper_msg_novice, "%s", "You need to spend %d more skillpoints in Novice Skill Tree\n");
    	sprintf(helper_msg_novice_high, "%s", "You need to spend %d more skillpoints in Novice High Skill Tree\n");
    	sprintf(helper_msg_1st, "%s", "You need to spend %d more skillpoints in 1st Job Skill Tree\n");
    	sprintf(helper_msg_1st_high, "%s", "You need to spend %d more skillpoints in 1st High Job Skill Tree\n");
    	sprintf(helper_msg_2nd, "%s", "You need to spend %d more skillpoints in 2nd Job Skill Tree\n");
    	sprintf(helper_msg_2nd_high, "%s", "You need to spend %d more skillpoints in 2nd High Job Skill Tree\n");
    	sprintf(helper_msg_3rd, "%s", "You need to spend %d more skillpoints in 3rd Job Skill Tree\n");
    	
    	if (pc_get_job_tier(sd->class_) == Job_Tier::First) {
    		if (skill_get_job_tier(skill_id) == Job_Tier::First && (skill_point < novice_max_skillpoint)) {
    			ShowError(helper_msg_novice, must_spend_novice);
    		}
    	}
    	if (pc_get_job_tier(sd->class_) == Job_Tier::First_High) {
    		if (skill_get_job_tier(skill_id) == Job_Tier::First && (skill_point < novice_max_skillpoint)) {
    			if (skill_point < novice_max_skillpoint) {
    				ShowError(helper_msg_novice, must_spend_novice);
    			}
    		}
    	}
    	if (pc_get_job_tier(sd->class_) == Job_Tier::Second) {
    		if (skill_get_job_tier(skill_id) == Job_Tier::First && (skill_point < novice_max_skillpoint)) {
    			if (skill_point < novice_max_skillpoint) {
    				ShowError(helper_msg_novice, must_spend_novice);
    			}
    		}
    		if (skill_get_job_tier(skill_id) == Job_Tier::Second && (skill_point < novice_max_skillpoint + skillpoint_1st)) {
    			if (skill_point < novice_max_skillpoint) {
    				ShowError(helper_msg_novice, must_spend_novice);
    			}
    			if (skill_point < novice_max_skillpoint + skillpoint_1st) {
    				ShowError(helper_msg_1st, must_spend_1st);
    			}
    		}
    	}
    	if (pc_get_job_tier(sd->class_) == Job_Tier::Second_High) {
    		if (skill_get_job_tier(skill_id) == Job_Tier::First && (skill_point < novice_max_skillpoint)) {
    			if (skill_point < novice_max_skillpoint) {
    				ShowError(helper_msg_novice_high, must_spend_novice);
    			}
    		}
    		if (skill_get_job_tier(skill_id) == Job_Tier::Second && (skill_point < novice_max_skillpoint + skillpoint_1st)) {
    			if (skill_point < novice_max_skillpoint) {
    				ShowError(helper_msg_novice_high, must_spend_novice);
    			}
    			if (skill_point < novice_max_skillpoint + skillpoint_1st) {
    				ShowError(helper_msg_1st_high, must_spend_1st);
    			}
    		}
    	}
    	if (pc_get_job_tier(sd->class_) == Job_Tier::Third) {
    		if (skill_get_job_tier(skill_id) == Job_Tier::First && (skill_point < novice_max_skillpoint)) {
    			if (skill_point < novice_max_skillpoint) {
    				ShowError(helper_msg_novice, must_spend_novice);
    			}
    		}
    		if (skill_get_job_tier(skill_id) == Job_Tier::Second && (skill_point < novice_max_skillpoint + skillpoint_1st)) {
    			if (skill_point < novice_max_skillpoint) {
    				ShowError(helper_msg_novice, must_spend_novice);
    			}
    			if (skill_point < novice_max_skillpoint + skillpoint_1st) {
    				ShowError(helper_msg_1st, must_spend_1st);
    			}
    		}
    		if (skill_get_job_tier(skill_id) == Job_Tier::Third && (skill_point < novice_max_skillpoint + skillpoint_1st + max_skillpoint_2nd)) {
    			if (skill_point < novice_max_skillpoint) {
    				ShowError(helper_msg_novice, must_spend_novice);
    			}
    			if (skill_point < novice_max_skillpoint + skillpoint_1st) {
    				ShowError(helper_msg_1st, must_spend_1st);
    			}
    			if (skill_point < novice_max_skillpoint + skillpoint_1st + skillpoint_2nd) {
    				ShowError(helper_msg_2nd, must_spend_2nd);
    			}
    		}
    	}
    	if (pc_get_job_tier(sd->class_) == Job_Tier::Third_High) {
    		if (skill_get_job_tier(skill_id) == Job_Tier::First && (skill_point < novice_max_skillpoint)) {
    			if (skill_point < novice_max_skillpoint) {
    				ShowError(helper_msg_novice_high, must_spend_novice);
    			}
    		}
    		if (skill_get_job_tier(skill_id) == Job_Tier::Second && (skill_point < novice_max_skillpoint + skillpoint_1st)) {
    			if (skill_point < novice_max_skillpoint) {
    				ShowError(helper_msg_novice_high, must_spend_novice);
    			}
    			if (skill_point < novice_max_skillpoint + skillpoint_1st) {
    				ShowError(helper_msg_1st_high, must_spend_1st);
    			}
    		}
    		if ((skill_get_job_tier(skill_id) == Job_Tier::Third || Job_Tier::Third_High) && (skill_point < novice_max_skillpoint + skillpoint_1st + max_skillpoint_2nd)) {
    			if (skill_point < novice_max_skillpoint) {
    				ShowError(helper_msg_novice_high, must_spend_novice);
    			}
    			if (skill_point < novice_max_skillpoint + skillpoint_1st) {
    				ShowError(helper_msg_1st_high, must_spend_1st);
    			}
    			if (skill_point < novice_max_skillpoint + skillpoint_1st + skillpoint_2nd) {
    				ShowError(helper_msg_2nd_high, must_spend_2nd_high);
    			}
    		}
    	}
    	if (pc_get_job_tier(sd->class_) == Job_Tier::Fourth) {
    		if (skill_get_job_tier(skill_id) == Job_Tier::First && (skill_point < novice_max_skillpoint)) {
    			if (skill_point < novice_max_skillpoint) {
    				ShowError(helper_msg_novice, must_spend_novice);
    			}
    		}
    		if (skill_get_job_tier(skill_id) == Job_Tier::Second && (skill_point < novice_max_skillpoint + skillpoint_1st)) {
    			if (skill_point < novice_max_skillpoint) {
    				ShowError(helper_msg_novice, must_spend_novice);
    			}
    			if (skill_point < novice_max_skillpoint + skillpoint_1st) {
    				ShowError(helper_msg_1st, must_spend_1st);
    			}
    		}
    		if (skill_get_job_tier(skill_id) == Job_Tier::Third && (skill_point < novice_max_skillpoint + skillpoint_1st + max_skillpoint_2nd)) {
    			if (skill_point < novice_max_skillpoint) {
    				ShowError(helper_msg_novice, must_spend_novice);
    			}
    			if (skill_point < novice_max_skillpoint + skillpoint_1st) {
    				ShowError(helper_msg_1st, must_spend_1st);
    			}
    			if (skill_point < novice_max_skillpoint + skillpoint_1st + skillpoint_2nd) {
    				ShowError(helper_msg_2nd, must_spend_2nd);
    			}
    		}
    		if (skill_get_job_tier(skill_id) == Job_Tier::Fourth && (skill_point < novice_max_skillpoint + skillpoint_1st + max_skillpoint_2nd + max_skillpoint_3rd)) {
    			if (skill_point < novice_max_skillpoint) {
    				ShowError(helper_msg_novice, must_spend_novice);
    			}
    			if (skill_point < novice_max_skillpoint + skillpoint_1st) {
    				ShowError(helper_msg_1st, must_spend_1st);
    			}
    			if (skill_point < novice_max_skillpoint + skillpoint_1st + skillpoint_2nd) {
    				ShowError(helper_msg_2nd, must_spend_2nd);
    			}
    			if (skill_point < novice_max_skillpoint + skillpoint_1st + skillpoint_2nd + max_skillpoint_3rd) {
    				ShowError(helper_msg_3rd, must_spend_3rd);
    			}
    		}
    	}
      ... Rest of Function ...
    }

    Summoner and Super Novice are likely badly handled.

  3. Hi. I'm trying to achieve this too now that I read your request, It made me remember that a while ago I wanted to do something like what you explained.

    Here's what I managed to produce so far, sadly it only works with Novice as I'm checking NV_BASIC skill level.

    /*==========================================
     * Update skill_lv for player sd
     * Skill point allocation
     *------------------------------------------*/
    void pc_skillup(map_session_data *sd,uint16 skill_id)
    {
    	uint16 idx = skill_get_index(skill_id);
    
    	nullpo_retv(sd);
    	
    	if (!idx) {
    		if (skill_id)
    			ShowError("pc_skillup: Player attempts to level up invalid skill '%d'\n", skill_id);
    		return;
    	}
    	
    	// If user tries to put points in a skill other than NV_BASIC while NV_BASIC is not maxed
    	if(skill_id > NV_BASIC && sd->status.skill[NV_BASIC].lv < skill_tree_get_max(NV_BASIC, sd->status.class_)){
    		StringBuf *nov_msg = StringBuf_Malloc();
    		StringBuf_Printf(nov_msg, "You must spend %d skillpoints on Basic Skill in Novice skill tree first", skill_tree_get_max(NV_BASIC, sd->status.class_));
    		
    		clif_displaymessage(sd->fd, StringBuf_Value(nov_msg));
    		
    		StringBuf_Free(nov_msg);
    		
    		// Do not spend the point
    		// return;
    	}
      ... Rest of the function ...
    }

    Edit: I can't find a way to check how many skillpoints have been invested in a specific job by the player. With that info we could check invested points in 1st / 2nd / 3rd jobs and display a message when trying to up a skill when not all previous job skills have been invested.

  4. A free tool I've used several times to upscale various game textures and stuff (mainly out of curiosity) is Chainner. It works well with NVIDIA GPU slightly less so with AMD/ATI GPU.
    It's not particularly easy nor particularly hard to use either but it's different to say the least !
     

    I wouldn't recommend converting to JPEG before upscaling, you want to have the least amount of artifacts before doing AI uspcaling. (JPEG compression creates artifacts and image noise)

    PNG always preferred as it has losless compression.

  5. @Sapito Sucio I think patch "BodyPalMF" can cause issues. I had the game crash when switching to job High Thief and it would subsequently crash everytime I would get to character select screen.

    I then made my own patched 2022-04-06 exe to confirm and tried with "BodyPalMF" -> it crashed. Then I disabled that patch -> it didn't crash any more.

    • Upvote 1
  6. 4 hours ago, dalubhasa333 said:

    It works fine using DgVoodoo2 with directx 12, however i need to type /skip to turn it of then the game run very smooth.

    Im looking to turn off the "frame skip" permanently so i will not retype it everytime i log in to the game.

     

    Are you gonna ask for this on every topic on these forums ? Haven't you made your own topic asking for it already ?

  7. Hi, I didn't have to do anything to enable 4th jobs on my local server using (hexed) 20220406 ragexe on 2022 client data.

    Maybe you're missing the 4th jobs sprites while the server side works fine ?

    • Like 1
  8. 9 hours ago, Sapito Sucio said:

    I use DgVoodoo on my local folder, I don't know If I should ship it on the ro-folder too, tho, as it can cause problems with some graphic cards, mostly AMDs

    I would advise against shipping DgVoodoo with FroggoClient simply because it's not widely used so some people may struggle to configure it decently and people would ask you a lot of troubleshooting questions about DgVoodoo and not your client.

  9. @Sapito Sucio If I'm not mistaken Froggo RO seems to have been hexed for 150 inventory limit but as far as I understand this requires editing the server config ? Perhaps you should leave this at 90 or whatever's the standard KRO limit or add mention of this quirk on the first post ?

    Also, not sure you can do something about it even if I set DirectX7 in Setup it always reverts to DirectX9 for some reason 😄

×
×
  • Create New...