//===== eAthena Script ======================================= //= Kafra Express - Job Swapping Module //===== By: ================================================== //= Skotlex //===== Current Version: ===================================== //= 3.8 //===== Compatible With: ===================================== //= eAthena SVN8840+ //===== Description: ========================================= //= Part of the Kafra Express Script Package. //= Enables job changing among classes of the same 'type' //= (ie among 1st classes, or among 2nd classes) //===== Additional Comments: ================================= //= See config.txt for configuration. //= * The previous Job, when enabled, is stored in: //= kej_prev_job (job id) //= kej_prev_joblv (job level) //= kej_prev_skills (skill count) //= kej_prev_dye (cloth dye) //============================================================ - script keInit_jobSwap -1,{ OnInit: //Load Config donpcevent "keConfig::OnLoadJobSwap"; end; } function script F_keJobSwap { function SF_canRevert; function SF_canSwitch; function SF_revertJob; function SF_switch; function SF_calcSwapCost; function SF_testSwap; function SF_swapJob; function SF_getJobNames; set @thisJob, eaclass(Class); set @type, @thisJob&~EAJ_UPPERMASK; set @prevJob, eaclass(kej_prev_job); set @prevLv, kej_prev_joblv; if (SF_canRevert()) { //Qualifies for Reverting do { set @revertmenu, select( "- Return", "- Return to previous class", "- Change into another class" ); switch (@revertmenu) { case 2: //Revert if (SF_revertJob()) return; break; case 3: //Switch if (SF_switch()) return; break; } } while (@revertmenu > 1); return; } if (SF_canSwitch()) { SF_switch(); return; } callfunc "F_keIntro", e_swt2, "There are no available jobs of your level."; return; //SubFunction SF_canRevert, specifies if the character can revert to previous job. function SF_canRevert { if ($@kejs_revertPolicy == 0 || @prevLv == 0 || (@thisJob&EAJL_BABY != @prevJob&EAJL_BABY)) return 0; if ($@kejs_revertPolicy == 2) return 1; if ((@thisJob&EAJ_BASEMASK) == EAJ_NOVICE) { if ($@kejs_disable&1) return 0; if (@prevJob&(EAJL_UPPER|EAJL_2)) return 0; return 1; } if ((@prevJob&EAJ_BASEMASK) == EAJ_NOVICE) { if ($@kejs_disable&1) return 0; if (@thisJob&(EAJL_UPPER|EAJL_2)) return 0; return 1; } if (@thisJob&~EAJ_UPPERMASK != @prevJob&~EAJ_UPPERMASK) return 0; if (@thisJob&EAJL_2 && !(@prevJob&EAJL_2)) return 0; if (@prevJob&EAJL_2 && !(@thisJob&EAJL_2)) return 0; return 1; } //SubFunction SF_canSwitch, specifies if character can change to another job. function SF_canSwitch { switch(@thisJob&EAJ_BASEMASK) { case EAJ_NOVICE: if ($@kejs_disable&1 || !@thisJob&EAJL_2) return 0; break; case EAJ_TAEKWON: if ($@kejs_disable&2) return 0; break; case EAJ_GUNSLINGER: if ($@kejs_disable&4) return 0; break; case EAJ_NINJA: if ($@kejs_disable&8) return 0; break; } return 1; } //Sub Function SF_switch. Presents the switch job menu. Returns 1 only if the //menu was left by picking "Cancel". function SF_switch { if (@thisJob&EAJL_2 && (@thisJob&EAJ_BASEMASK) != EAJ_NOVICE) { //Second Classes set @cost, SF_calcSwapCost($@kejs_job2ND, $@kejs_cost2ND, $@kejs_discount2ND); set @preserve, $@kejs_preserve2ND; if (!SF_testSwap($@kejs_job2ND, @cost)) return 0; setarray @classes[0], EAJ_Assassin|@type, EAJ_Rogue|@type, EAJ_Blacksmith|@type, EAJ_Alchemist|@type, EAJ_Hunter|@type, EAJ_BardDancer|@type, EAJ_Knight|@type, EAJ_Crusader|@type, EAJ_Priest|@type, EAJ_Monk|@type, EAJ_Wizard|@type, EAJ_Sage|@type, EAJ_Star_Gladiator|@type, EAJ_Soul_Linker|@type; SF_getJobNames getarraysize(@classes); if (@type || $@kejs_disable&2) { //No SG/SL set @names$[12], ""; set @names$[13], ""; } do { set @kmenu, select( "- Cancel job change", @names$[0], @names$[1], @names$[2], @names$[3], @names$[4], @names$[5], @names$[6], @names$[7], @names$[8], @names$[9], @names$[10], @names$[11], @names$[12], @names$[13] ); if (@kmenu > 1) { set @job, roclass(@classes[@kmenu-2]); if (@job > -1 && SF_swapJob(@job,@cost,@preserve)) return 1; } } while (@kmenu > 1); return 0; } else { //First Classes set @cost, SF_calcSwapCost($@kejs_job1ST, $@kejs_cost1ST, $@kejs_discount1ST); set @preserve, $@kejs_preserve1ST; if (!SF_testSwap($@kejs_job1ST, @cost)) return 0; setarray @classes[0], EAJ_Acolyte|@type, EAJ_Archer|@type, EAJ_Mage|@type, EAJ_Merchant|@type, EAJ_Swordman|@type, EAJ_Thief|@type, EAJ_Taekwon|@type, EAJ_Super_Novice|@type, EAJ_GunSlinger|@type, EAJ_Ninja|@type; SF_getJobNames getarraysize(@classes); if ($@kejs_disable&1 || @type&EAJL_UPPER) set @names$[7], ""; //No S.Novice if (@type) { //No TK/NJ/GS for Baby/Advanced set @names$[6], ""; set @names$[8], ""; set @names$[9], ""; } else { if ($@kejs_disable&2) //No TK set @names$[6], ""; if ($@kejs_disable&4) //No GS set @names$[8], ""; if ($@kejs_disable&8) //No NJ set @names$[9], ""; } do { set @kmenu, select( "- Cancel job swap", @names$[0], @names$[1], @names$[2], @names$[3], @names$[4], @names$[5], @names$[6], @names$[7], @names$[8], @names$[9] ); if (@kmenu > 1) { set @job, roclass(@classes[@kmenu-2]); if (@job > -1 && SF_swapJob(@job,@cost,@preserve)) return 0; } } while (@kmenu > 1); return 0; } } //SubFunction: SF_calcSwapCost (MinJob, BaseCost, Discount) //Calculates cost to swap jobs function SF_calcSwapCost { set @cost, getarg(1); set @cost, @cost - @cost*getarg(2)*(JobLevel-getarg(0))/100; if (@cost < 0) set @cost,0; //Free Change return @cost; } //SubFunction: SF_testSwap(MinJobLv, Cost) //Checks if the player qualifies for job changing. function SF_testSwap { if (JobLevel < getarg(0)) { callfunc "F_keIntro", e_dots, "You need to be at least Job Lv "+getarg(0)+" before exchanging."; return 0; } set @cost, callfunc("F_keCost",getarg(1),$@kejs_swapDiscount); if (Zeny < @cost) { callfunc "F_keIntro", e_dots, "You need "+@cost+"z to be able to change."; return 0; } return 1; } //SubFunction: SF_swapJob (JobNumber, Zeny, PreserveRate) //Attempts to swap to the Jobgiven. //Zeny is the money cost //Preserve is how much of the previous job to preserve. function SF_swapJob { set @newjobId, getarg(0); set @cost, callfunc("F_keCost",getarg(1),$@kejs_swapDiscount); set @preserve, getarg(2); if (Class == @newjobId) { callfunc "F_keIntro", e_meh, "Um... you are already that class!"; return 0; } set @newJob$, jobname(@newjobId); set @oldJob$, jobname(Class); set @newjoblv, JobLevel*@preserve/100; if (@newjoblv > 1) { if (select("- Cancel", "- Change to a Lv"+@newjoblv+" "+@newJob$+" ("+@cost+"z)") != 2) return 0; } else { set @newjoblv,1; if (select("- Cancel", "- Change to "+@newJob$+" ("+@cost+"z)") != 2) return 0; } set @basic, getSkilllv("NV_BASIC"); set @skillpoint, skillpointcount() -JobLevel -@basic +@newjoblv; //Preserve holds the final amount of SkillPoints you should have. if (@skillpoint < 0) { callfunc "F_keIntro", e_gasp, "You need "+(-@skillpoint)+" more skill points to change class!"; return 0; } set @thisJoblevel, JobLevel; resetSkill; //Set previous job as needed. if ($@kejs_revertPolicy) { set kej_prev_job, Class; set kej_prev_joblv, @thisJoblevel; set kej_prev_skills, SkillPoint; if($@kejs_saveDye) set kej_prev_dye,getlook(7); } if ($@kejs_announce) announce strcharinfo(0)+" has changed from "+@oldJob$+" to "+@newJob$+"...",bc_blue; if ($@kejs_resetDye) setlook 7,0; jobchange @newjobId, 0; skill 1,@basic,0; set JobLevel, @newjoblv; set SkillPoint, @skillpoint; setoption(0); sc_end -1; callfunc "F_keCharge",getarg(1),$@kejs_swapDiscount,1; emotion e_ok; return 1; } //SubFunction: SF_revertJob (cost) //Reverts to the previous job. function SF_revertJob { if (@thisJob == @prevJob) { callfunc "F_keIntro", e_no, "Hmm... You can't go back, because your previous class is the same as your current one??"; return 0; } set @newjob$, jobname(kej_prev_job); set @cost,callfunc("F_keCost",$@kejs_revertCost,$@kejs_revertDiscount); if (select("- Cancel","- Return to a Lv"+kej_prev_joblv+" "+@newjob$+" ("+@cost+"z)") != 2) return 0; if (!(callfunc("F_keCharge",$@kejs_revertCost,$@kejs_revertDiscount,1))) { callfunc "F_keIntro", -1, "Sorry, you need "+@cost+"z before you can revert to a Lv"+kej_prev_joblv+" "+@newjob$+"."; return 0; } set @thisJobId, Class; set @thisJobLv, JobLevel; set @basic, getSkilllv("NV_BASIC"); resetSkill; set @skill, SkillPoint; if($@kejs_saveDye) { set @prevDye, getlook(7); setlook 7,0; } if ($@kejs_resetDye) setlook 7,0; jobchange kej_prev_job, 0; if($@kejs_saveDye) { setlook 7,kej_prev_dye; set kej_prev_dye,@prevDye; } set JobLevel, kej_prev_joblv; set SkillPoint, kej_prev_skills; skill 1, @basic, 0; set SkillPoint, SkillPoint-@basic; set kej_prev_job, @thisJobId; set kej_prev_joblv, @thisJobLv; set kej_prev_skills, @skill; setoption(0); sc_end -1; if ($@kejs_announce) announce strcharinfo(0)+" has changed from "+jobname(@thisJobId)+" to "+@newjob$+"...",bc_blue; return 1; } //SubFunction: SF_getJobNames(Qty) //Fills an array @names$ with the job names taken from the array "classes", // making each entry start with "- " followed by the job name. function SF_getJobNames { set @size, getarg(0); for (set @i, 0; @i < @size; set @i, @i+1) setd "@names$["+@i+"]", "- "+jobname(roclass(@classes[@i])); } }