//===== eAthena Script ======================================= //= Kafra Express - Job Changing Module //===== By: ================================================== //= Skotlex //===== Current Version: ===================================== //= 3.5 //===== Compatible With: ===================================== //= eAthena SVN R3579+ //===== Description: ========================================= //= Part of the Kafra Express Script Package. //= Enables job changing through the class trees. //= Novice -> 1st Class, 1st Class -> 2nd Class, rebirths, etc //===== Additional Comments: ================================= //= See config.txt for configuration. //= When using Upper Job policy, previous jobs are stored in //= the server wide variables kej_class1 and kej_class2 //============================================================ - script keInit_jobchange -1,{ OnInit: //Load Config donpcevent "keConfig::OnLoadJobChange"; end; } function script F_keJobChange { function SF_to1stJob; function SF_to2ndJob; function SF_getJobNames; function SF_testChangeJob; function SF_changeJob; set @job, callfunc("GF_getJobLevel", class); set @upper, Upper; //Because it is changed when rebirthing set @reset, 0; //Base Level is reset only on rebirths switch (@job) { case 0: //Novices if ($@kejc_skipNovice) set @jobLv, 0; //jobLv is used again when checking for S.Novice's base level restriction. else set @jobLv, 10; if (SF_testChangeJob(0,0,@jobLv)) SF_to1stJob(0); break; case 1: //First Classes if (SF_testChangeJob($@kejc_cost2ND,$@kejc_base2ND,$@kejc_job2ND)) SF_to2ndJob(); break; case 2: //Second Classes if (Upper == 0 && BaseClass != Job_Taekwon) { if (SF_testChangeJob($@kejc_costRebirth,$@kejc_baseRebirth,$@kejc_jobRebirth)) { set @upper, 1; if ($@kejc_skipNovice) SF_to1stJob(1); else SF_changeJob @job,Upper,Job_Novice,1,0,0,$@kejc_costRebirth,1,$@kejc_rebirthReset; } break; } default: //Dead End callfunc "F_keIntro", e_swt2, "I cannot change you from your current job."; break; } return; //Handles changing to 1st job. function SF_to1stJob { do { set @submenu, 1; if (@upper == 1 && $@kejc_upperPolicy && kej_class1) { switch (kej_class1) { case Job_Acolyte: set @submenu, 2; break; case Job_Archer: set @submenu, 3; break; case Job_Mage: set @submenu, 4; break; case Job_Merchant: set @submenu, 5; break; case Job_Swordman: set @submenu, 6; break; case Job_Thief: set @submenu, 7; break; case Job_Taekwon: set @submenu, 8; break; } } if (@submenu == 1) { SF_getJobNames 8,Job_Acolyte,Job_Archer,Job_Mage,Job_Merchant,Job_Swordman,Job_Thief,Job_Taekwon,Job_SuperNovice; switch (@upper) { case 0: //All set @submenu, select( "- Cancel job change", "- "+@name1$, "- "+@name2$, "- "+@name3$, "- "+@name4$, "- "+@name5$, "- "+@name6$, "- "+@name7$, "- "+@name8$ ); break; case 1: //No Taekwon/S.Novice set @submenu, select( "- Cancel job change", "- "+@name1$, "- "+@name2$, "- "+@name3$, "- "+@name4$, "- "+@name5$, "- "+@name6$ ); break; case 2: //No Taekwon set @submenu, select( "- Cancel job change", "- "+@name1$, "- "+@name2$, "- "+@name3$, "- "+@name4$, "- "+@name5$, "- "+@name6$, "- "+@name8$ ); if (@submenu == 8) set @submenu, 9; break; } } switch (@submenu) { case 2: //Acolyte set @newJob,Job_Acolyte; set @weapon, $@kejc_wAcolyte; break; case 3: //Archer set @newJob,Job_Archer; set @weapon, $@kejc_wArcher; break; case 4: //Mage set @newJob,Job_Mage; set @weapon, $@kejc_wMage; break; case 5: //Merchant set @newJob,Job_Merchant; set @weapon, $@kejc_wMerchant; break; case 6: //Swordman set @newJob,Job_Swordman; set @weapon, $@kejc_wSwordman; break; case 7: //Thief set @newJob,Job_Thief; set @weapon, $@kejc_wThief; break; case 8: //Taekwon set @newJob,Job_Taekwon; set @weapon, $@kejc_wTaekwon; break; case 9: //S. Novice set @newJob,Job_SuperNovice; set @weapon, $@kejc_wSuperNovice; if (SF_testChangeJob(0,$@kejc_baseSN,@jobLv) == 0) return; break; } if (@submenu > 1) { if (getarg(0)) { //Skipping High Novice, charge rebirth costs. if (SF_changeJob(@job,Upper,@newJob,1,@weapon,0,$@kejc_costRebirth,2,$@kejc_rebirthReset)) return; } else { if (SF_changeJob(@job,Upper,@newJob,@upper,@weapon,0,0,2,0)) return; } } } while (@submenu > 1); } function SF_to2ndJob { do { set @submenu, 1; if (@upper == 1 && $@kejc_upperPolicy && kej_class2) { switch (kej_class2) { case Job_Priest: case Job_Hunter: case Job_Wizard: case Job_Blacksmith: case Job_Knight: case Job_Knight2: case Job_Assassin: case Job_Star_Gladiator: case Job_Star_Gladiator2: set @submenu, 2; break; case Job_Monk: case Job_Bard: case Job_Dancer: case Job_Sage: case Job_Alchem: case Job_Crusader: case Job_Crusader2: case Job_Rogue: case Job_Soul_Linker: set @submenu, 3; break; } } if (@submenu == 1) { //Fetch from menu. switch (BaseClass) { case Job_Acolyte: SF_getJobNames 2,Job_Priest,Job_Monk; break; case Job_Archer: SF_getJobNames 3,Job_Hunter,Job_Bard,Job_Dancer; if (sex == 0) set @name2$, @name3$; break; case Job_Mage: SF_getJobNames 2,Job_Wizard,Job_Sage; break; case Job_Merchant: SF_getJobNames 2,Job_Blacksmith,Job_Alchem; break; case Job_Swordman: SF_getJobNames 2,Job_Knight,Job_Crusader; break; case Job_Thief: SF_getJobNames 2,Job_Assassin,Job_Rogue; break; case Job_Taekwon: SF_getJobNames 2,Job_Star_Gladiator,Job_Soul_Linker; break; default: callfunc "F_keIntro", e_swt2, "I don't know how to change you from your current job."; return; } set @submenu, select( "- Cancel job change", "- "+@name1$, "- "+@name2$ ); } switch (BaseClass) { case Job_Acolyte: switch (@submenu) { case 2: //Priest set @newJob,Job_Priest; set @weapon,$@kejc_wPriest; set @weapon2,$@kejc_w2Priest; break; case 3: //Monk set @newJob,Job_Monk; set @weapon,$@kejc_wMonk; set @weapon2,$@kejc_w2Monk; break; } break; case Job_Archer: switch (@submenu) { case 2: //Hunter set @newJob,Job_Hunter; set @weapon,$@kejc_wHunter; set @weapon2,$@kejc_w2Hunter; break; case 3: //Bard/Dancer if (sex == 1) { //Bard set @newJob,Job_Bard; set @weapon,$@kejc_wBard; set @weapon2,$@kejc_w2Bard; } else { //Dancer set @newJob,Job_Dancer; set @weapon,$@kejc_wDancer; set @weapon2,$@kejc_w2Dancer; } break; } break; case Job_Mage: switch (@submenu) { case 2: //Wizard set @newJob,Job_Wizard; set @weapon,$@kejc_wWizard; set @weapon2,$@kejc_w2Wizard; break; case 3: //Sage set @newJob,Job_Sage; set @weapon,$@kejc_wSage; set @weapon2,$@kejc_w2Sage; break; } break; case Job_Merchant: switch (@submenu) { case 2: //Blacksmith set @newJob,Job_Blacksmith; set @weapon,$@kejc_wBlacksmith; set @weapon2,$@kejc_w2Blacksmith; break; case 3: //Alchemist set @newJob,Job_Alchem; set @weapon,$@kejc_wAlchemist; set @weapon2,$@kejc_w2Alchemist; break; } break; case Job_Swordman: switch (@submenu) { case 2: //Knight set @newJob,Job_Knight; set @weapon,$@kejc_wKnight; set @weapon2,$@kejc_w2Knight; break; case 3: //Crusader set @newJob,Job_Crusader; set @weapon,$@kejc_wCrusader; set @weapon2,$@kejc_w2Crusader; break; default: mes "uh oh"; break; } break; case Job_Thief: switch (@submenu) { case 2: //Assassin set @newJob,Job_Assassin; set @weapon,$@kejc_wAssassin; set @weapon2,$@kejc_w2Assassin; break; case 3: //Rogue set @newJob,Job_Rogue; set @weapon,$@kejc_wRogue; set @weapon2,$@kejc_w2Rogue; break; } break; case Job_Taekwon: switch (@submenu) { case 2: //Star Gladiator set @newJob,Job_Star_Gladiator; set @weapon,$@kejc_wStarGladiator; set @weapon2,$@kejc_w2StarGladiator; break; case 3: //Soul Linker set @newJob,Job_Soul_Linker; set @weapon,$@kejc_wSoulLinker; set @weapon2,$@kejc_w2SoulLinker; break; } break; } if (@submenu > 1) { if (SF_changeJob(@job,Upper,@newJob,@upper,@weapon,@weapon2,$@kejc_cost2ND,0,0)) return; } } while (@submenu > 1); } //SubFunction: SF_testChangeJob(Zeny, BaseLv, JobLv) //Function that checks if the player qualifies for job changing. function SF_testChangeJob { set @fail, 0; if (Zeny < getarg(0)) set @fail, 1; if (BaseLevel < getarg(1)) set @fail, @fail+2; if (JobLevel < getarg(2)) set @fail, @fail+4; if (@fail > 0) { if (@fail&1) mes "You need "+getarg(0)+"z for the conversion process."; if (@fail&2) mes "You need to be at least Lv "+getarg(1)+"."; if (@fail&4) mes "You need at least job Lv "+getarg(2)+"."; callfunc "F_keIntro", e_pif, "Sorry, you don't qualify for a job change yet."; return 0; } if (SkillPoint > 0 && $@kejc_skillsPolicy == 0) { callfunc "F_keIntro", e_dots, "Sorry, use your remaining Skill points before being able to change class."; return 0; } return 1; } //SubFunction: SF_changeJob (CurrentJobLv, CurrentJobType, NewJobBase, NewJobType //Weapon, Weapon2, Zeny, WipeSkills, ResetLv) //Attempts to change to the Jobgiven. //CurrentJobLv is 0-3 (novice, 1st class, 2nd class, s.novice) //Type is 0-2 (Normal, Advanced Class, Baby) //Weapon is the ID of the weapon to grant //Weapon2 is the alternative weapon granted when your job level is above $@kejc_wBonusLv //Zeny is the money required (if negative, it is money awarded) //WipeSkills if 1, indicates that skills should be wiped, //if 2, it means basic skills have to be given back //Reset Level indicates the base lv must be reset to 1. //Note: Zeny/Base/Job requirements should had been checked with SF_testChangeJob already! function SF_changeJob { set @newjob,getarg(2); set @newtype,getarg(3); set @weapon,getarg(4); set @weapon2,getarg(5); set @cost,getarg(6); set @wipeSkill,getarg(7); set @resetLv,getarg(8); set @jobStr$, callfunc("GF_getJobName2",@newjob, @newtype); if (@wipeSkill == 0 && SkillPoint > 0 && $@kejc_skillsPolicy == 1) { set @selection, select( "- Do not change yet", "- Change to "+@jobStr$+" (skill points lost)", "- View details" ); } else { set @selection, select( "- Cancel", "- Change to "+@jobStr$, "- View details" ); } switch (@selection) { case 3: //Details mes "Okay.. listen up:"; next; mes "["+@name$+"]"; mes "Changing to "+@jobStr$+" now means:"; if (@wipeSkill == 0 && SkillPoint > 0 && $@kejc_skillsPolicy == 1) mes "- You will lose your "+SkillPoint+" unused skill points."; else if (@wipeSkill == 1) mes "- You will lose all your skills."; if (@resetLv) mes "- Your base level will be reset to 1."; if (@cost > 0) mes "- You will be charged "+@cost+"z."; else if (@cost < 0) mes "- You will be aided with "+(0-@cost)+"z."; if (@weapon > 0) { if (@weapon2 > 0 && $@kejc_wBonusLv) { if (JobLevel < $@kejc_wBonusLv) { mes "- You will receive a "+getitemname(@weapon)+"["+getitemslots(@weapon)+"]."; mes "- If you wait until Job Lv"+$@kejc_wBonusLv+", you can receive instead a "+getitemname(@weapon2)+"["+getitemslots(@weapon)+"]."; } else { mes "- You will receive a "+getitemname(@weapon2)+"["+getitemslots(@weapon)+"] for reaching Job Lv"+$@kejc_wBonusLv+"."; } } else mes "- You will receive a "+getitemname(@weapon)+"."; } mes "So... will you change?"; if (select( "- Cancel", "- Change to "+@jobStr$ ) != 2) { callfunc "F_keIntro", e_dots, "...alright."; return 0; } callfunc "F_keIntro", -1, "Enjoy your new Job."; case 2: //Change //Set/Unset job path variables as needed. if($@kejc_upperPolicy) { set @class,getarg(0); set @type, getarg(1); if(@class == 1 && @type == 0) set kej_class1,class; //Advancing to second class, so... if(@class == 2) set kej_class2,class; //Only way of being here is by doing a rebirth if(@type > 0) set kej_class1,0; //Clear when one is a high class if(@type > 0 && @class == 1) set kej_class2,0; //Clear when leaving high 1st class } if (@resetLv) { jobchange Job_Novice_High; //Done to give players those 100 points from High classes resetlvl(1); } if (@wipeSkill) { resetskill; setoption(0); set SkillPoint,0; } else if ($@kejc_skillsPolicy == 1) set SkillPoint,0; if (@wipeSkill>1) skill 1,9,0; if($@kejc_resetDye) setlook 7,0; jobchange @newjob, @newtype; if ($@kejc_announce) announce strcharinfo(0)+" has been promoted to "+@jobStr$+"!",8; set Zeny,Zeny-@cost; if ($@kejc_weaponPolicy && @weapon > 0) { if ($@kejc_wBonusLv && @weapon2 > 0) { if (JobLevel < $@kejc_wBonusLv) getitem @weapon,1; else getitem @weapon2,1; } else getitem @weapon,1; } emotion e_grat; return 1; default: //Cancel... callfunc "F_keIntro", e_dots, "...alright."; return 0; } } //SubFunction: SF_getJobNames(Qty, Jobid1, Jobid2,...) //Workaround until eA gets a fix for the bug where you can't use callfunc or //callsub within a menu function SF_getJobNames { switch (getarg(0)) { case 8: set @name8$, callfunc("GF_getJobName2",getarg(8),@upper); set @name7$, callfunc("GF_getJobName2",getarg(7),@upper); set @name6$, callfunc("GF_getJobName2",getarg(6),@upper); set @name5$, callfunc("GF_getJobName2",getarg(5),@upper); set @name4$, callfunc("GF_getJobName2",getarg(4),@upper); case 3: set @name3$, callfunc("GF_getJobName2",getarg(3),@upper); case 2: set @name2$, callfunc("GF_getJobName2",getarg(2),@upper); set @name1$, callfunc("GF_getJobName2",getarg(1),@upper); } return; } }