//===== 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 {
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;
}
}