//===== eAthena Script ======================================= //= Kafra Express - Job Swapping Module //===== By: ================================================== //= Skotlex //===== Current Version: ===================================== //= 3.4 //===== Compatible With: ===================================== //= eAthena SVN R7896+ //===== 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 @thisLevel, callfunc("GF_getJobLevel", Class); set @prevId, kej_prev_job; set @prevLv, kej_prev_joblv; set @prevLevel, 0; set @prevType, 0; if ($@kejs_revertPolicy && @prevId && @prevLv) { set @prevLevel, callfunc("GF_getJobLevel", @prevId); set @prevType, callfunc("GF_getJobType", @prevId); } 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() == 0) 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 || @prevId == 0 || (Upper == 2 && @prevType != 2)) return 0; if((@thisLevel == @prevLevel && Upper == @prevType) || $@kejs_revertPolicy == 2) return 1; if ($@kejs_SNpolicy && @prevType == Upper && ((@prevLevel == 3 && @thisLevel == 1) || (@prevLevel == 1 && @thisLevel == 3))) return 1; return 0; } //SubFunction SF_canSwitch, specifies if character can change to another job. function SF_canSwitch { if (@thisLevel == 3) return $@kejs_SNpolicy; if (@thisLevel == 1 || @thisLevel == 2) return 1; return 0; } //Sub Function SF_switch. Presents the switch job menu. Returns 1 only if the //menu was left by picking "Cancel". function SF_switch { switch (@thisLevel) { case 1: case 3: //First Classes set @cost, SF_calcSwapCost($@kejs_job1ST, $@kejs_cost1ST, $@kejs_discount1ST); set @preserve, $@kejs_preserve1ST; if (SF_testSwap($@kejs_job1ST, @cost)) { do { if ($@kejs_SNpolicy && Upper != 1) { //S. Novice Menu SF_getJobNames 7,Job_Acolyte,Job_Archer,Job_Mage,Job_Merchant,Job_Swordman,Job_Thief,Job_SuperNovice; set @kmenu, select( "- Cancel job swap", "- "+@name1$,"- "+@name2$,"- "+@name3$,"- "+@name4$,"- "+@name5$,"- "+@name6$,"- "+@name7$ ); } else { SF_getJobNames 6,Job_Acolyte,Job_Archer,Job_Mage,Job_Merchant,Job_Swordman,Job_Thief; set @kmenu, select( "- Cancel job swap", "- "+@name1$,"- "+@name2$,"- "+@name3$,"- "+@name4$,"- "+@name5$,"- "+@name6$ ); } switch (@kmenu) { case 2: //Acolyte if (SF_swapJob(callfunc("GF_getJobId", Job_Acolyte, Upper),@cost,@preserve)) return 0; break; case 3: //Archer if (SF_swapJob(callfunc("GF_getJobId", Job_Archer, Upper),@cost,@preserve)) return 0; break; case 4: //Mage if (SF_swapJob(callfunc("GF_getJobId", Job_Mage, Upper),@cost,@preserve)) return 0; break; case 5: //Merchant if (SF_swapJob(callfunc("GF_getJobId", Job_Merchant, Upper),@cost,@preserve)) return 0; break; case 6: //Swordman if (SF_swapJob(callfunc("GF_getJobId", Job_Swordman, Upper),@cost,@preserve)) return 0; break; case 7: //Thief if (SF_swapJob(callfunc("GF_getJobId", Job_Thief, Upper),@cost,@preserve)) return 0; break; case 8: //S. Novice if (SF_swapJob(callfunc("GF_getJobId", Job_SuperNovice, Upper),@cost,@preserve)) return 0; break; } } while (@kmenu > 1); return 1; } break; case 2: //Second Classes set @cost, SF_calcSwapCost($@kejs_job2ND, $@kejs_cost2ND, $@kejs_discount2ND); set @preserve, $@kejs_preserve2ND; if (SF_testSwap($@kejs_job2ND, @cost)) { do { if (sex == 1) { SF_getJobNames 12,Job_Alchem,Job_Assassin,Job_Bard,Job_Blacksmith,Job_Crusader,Job_Hunter,Job_Knight,Job_Monk,Job_Priest,Job_Rogue,Job_Sage,Job_Wizard; set @kmenu, select( "- Cancel job change", "- "+@name1$,"- "+@name2$,"- "+@name3$,"- "+@name4$,"- "+@name5$,"- "+@name6$, "- "+@name7$,"- "+@name8$,"- "+@name9$,"- "+@name10$,"- "+@name11$,"- "+@name12$ ); if (@kmenu >= 7) //Dancer should be at pos 7. set @kmenu, @kmenu+1; } else { SF_getJobNames 12,Job_Alchem,Job_Assassin,Job_Blacksmith,Job_Crusader,Job_Dancer,Job_Hunter,Job_Knight,Job_Monk,Job_Priest,Job_Rogue,Job_Sage,Job_Wizard; set @kmenu, select( "- Cancel job change", "- "+@name1$,"- "+@name2$,"- "+@name3$,"- "+@name4$,"- "+@name5$,"- "+@name6$, "- "+@name7$,"- "+@name8$,"- "+@name9$,"- "+@name10$,"- "+@name11$,"- "+@name12$ ); if (@kmenu >= 4) //Bard should be at pos 4. set @kmenu, @kmenu+1; } switch (@kmenu) { case 2: //ALCHEMIST if (SF_swapJob(callfunc("GF_getJobId", Job_Alchem, Upper),@cost,@preserve)) return 0; break; case 3: //ASSASSIN if (SF_swapJob(callfunc("GF_getJobId", Job_Assassin, Upper),@cost,@preserve)) return 0; break; case 4: //BARD if (SF_swapJob(callfunc("GF_getJobId", Job_Bard, Upper),@cost,@preserve)) return 0; break; case 5: //BLACKSMITH if (SF_swapJob(callfunc("GF_getJobId", Job_Blacksmith, Upper),@cost,@preserve)) return 0; break; case 6: //CRUSADER if (SF_swapJob(callfunc("GF_getJobId", Job_Crusader, Upper),@cost,@preserve)) return 0; break; case 7: //DANCER if (SF_swapJob(callfunc("GF_getJobId", Job_Dancer, Upper),@cost,@preserve)) return 0; break; case 8: //HUNTER if (SF_swapJob(callfunc("GF_getJobId", Job_Hunter, Upper),@cost,@preserve)) return 0; break; case 9: //KNIGHT if (SF_swapJob(callfunc("GF_getJobId", Job_Knight, Upper),@cost,@preserve)) return 0; break; case 10: //MONK if (SF_swapJob(callfunc("GF_getJobId", Job_Monk, Upper),@cost,@preserve)) return 0; break; case 11: //PRIEST if (SF_swapJob(callfunc("GF_getJobId", Job_Priest, Upper),@cost,@preserve)) return 0; break; case 12: //ROGUE if (SF_swapJob(callfunc("GF_getJobId", Job_Rogue, Upper),@cost,@preserve)) return 0; break; case 13: //SAGE if (SF_swapJob(callfunc("GF_getJobId", Job_Sage, Upper),@cost,@preserve)) return 0; break; case 14: //WIZARD if (SF_swapJob(callfunc("GF_getJobId", Job_Wizard, Upper),@cost,@preserve)) return 0; break; } } while (@kmenu > 1); return 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$, callfunc("GF_getJobName",@newjobId); set @oldJob$, callfunc("GF_getJobName",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(1); set @preserve, skillpointcount() -JobLevel -@basic +@newjoblv; //Preserve holds the final amount of SkillPoints you should have. if (@preserve < 0) { callfunc "F_keIntro", e_gasp, "You need "+(-@preserve)+" 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_announce) announce strcharinfo(0)+" has changed from "+@oldJob$+" to "+@newJob$+"...",16; if ($@kejs_resetDye) setlook 7,0; jobchange @newjobId, 0; skill 1,@basic,0; set JobLevel, @newjoblv; set SkillPoint, @preserve; setoption(0); sc_end -1; callfunc "F_keCharge",getarg(2),$@kejs_swapDiscount,1; emotion e_ok; return 1; } //SubFunction: SF_revertJob (cost) //Reverts to the previous job. function SF_revertJob { if (Class == kej_prev_job) { 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$, callfunc ("GF_getJobName",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(1); 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 "+callfunc ("GF_getJobName",@thisJobId)+" to "+@newjob$+"...",16; return 1; } //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 12: set @name12$, callfunc("GF_getJobName2",getarg(12),Upper); case 11: set @name11$, callfunc("GF_getJobName2",getarg(11),Upper); case 10: set @name10$, callfunc("GF_getJobName2",getarg(10),Upper); case 9: set @name9$, callfunc("GF_getJobName2",getarg(9),Upper); case 8: set @name8$, callfunc("GF_getJobName2",getarg(8),Upper); case 7: set @name7$, callfunc("GF_getJobName2",getarg(7),Upper); case 6: set @name6$, callfunc("GF_getJobName2",getarg(6),Upper); case 5: set @name5$, callfunc("GF_getJobName2",getarg(5),Upper); case 4: 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); case 1: set @name1$, callfunc("GF_getJobName2",getarg(1),Upper); default: return; } } }