//===== eAthena Script =======================================
//= Kafra Express - Job Changing Module
//===== By: ==================================================
//= Skotlex
//===== Current Version: =====================================
//= 4.0
//===== Compatible With: =====================================
//= eAthena SVN R8840+
//===== 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 permanent 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_getJobIndex;
	function SF_getJobNames;
	function SF_testChangeJob;
	function SF_changeJob;

	set @job, eaClass(class);
	set @type, @job&~EAJ_UPPERMASK; //Because it is changed when rebirthing
	set @reset, 0;	//Base Level is reset only on rebirths
	if ((@job&EAJ_BASEMASK) == EAJ_NOVICE) 
	{	//Novices
		if (@job&EAJL_2) //S. Novices
			goto L_FAIL;
		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);
	} else
	if(@job&EAJL_2){
		//Second classes
		if (@job&~EAJ_UPPERMASK) //rebirth/baby
			goto L_FAIL;
		if (SF_testChangeJob($@kejc_costRebirth,$@kejc_baseRebirth,$@kejc_jobRebirth)) {
			set @type, EAJL_UPPER;
			if ($@kejc_skipNovice)
				SF_to1stJob(1);
			else
				SF_changeJob @job,EAJ_NOVICE_HIGH,0,0,$@kejc_costRebirth,1,$@kejc_rebirthReset;
		}
	} else {
		//First classes
		if (SF_testChangeJob($@kejc_cost2ND,$@kejc_base2ND,$@kejc_job2ND))
			SF_to2ndJob();
	}
	return;
L_FAIL:
	//Dead End
	callfunc "F_keIntro", e_swt2, "I cannot change you from your current job.";
	return;

//Handles changing to 1st job.
function SF_to1stJob {
	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;

	do {
		set @newjob, -1;
		if (@type == EAJL_UPPER && $@kejc_upperPolicy && kej_class1) {
			set @newjob, eaclass(kej_class1);
			set @newjob, (@newjob&EAJ_UPPERMASK)|@type;
			if (roclass(@newjob) == -1)
				set @newjob, -1;
			set @submenu, 1;
		}
		if (@newjob == -1) {
			SF_getJobNames getarraysize(@classes);
			if (@type&EAJL_UPPER || $@kejc_disable&1)
				set @names$[7], ""; //No S.Novice
	
			if (@type&~EAJ_UPPERMASK)
			{	//No TK/NJ/GS for Baby/Advanced
				set @names$[6], "";
				set @names$[8], "";
				set @names$[9], "";
			} else {
				if ($@kejc_disable&2) //No TK
					set @names$[6], "";
				if ($@kejc_disable&4) //No GS
					set @names$[8], "";
				if ($@kejc_disable&8) //No NJ
					set @names$[9], "";
			}

			set @submenu, select(
				"- Cancel job change",
				@names$[0], @names$[1], @names$[2],
				@names$[3], @names$[4], @names$[5],
				@names$[6], @names$[7], @names$[8],
				@names$[9]
				);

			if (@submenu > 1) {
				if (@submenu == 9 && //S. Novice's own change check.
					SF_testChangeJob(0,$@kejc_baseSN,@jobLv) == 0)
					return;
				set @newjob, @classes[@submenu-2];
			}
		}

		if (@newjob > -1) {
			set @i, SF_getJobIndex(@newjob);
			if (@i > -1)
				set @weapon, $@kejc_weapon1[@i];
			else
				set @weapon, 0;
			if (getarg(0)) { //Skipping High Novice, charge rebirth costs.
				if (SF_changeJob(@job,@newJob,@weapon,0,$@kejc_costRebirth,2,$@kejc_rebirthReset))
					return;
			} else {
				if (SF_changeJob(@job,@newJob,@weapon,0,0,2,0))
					return;
			}
		}
	} while (@submenu > 1);
}

function SF_to2ndJob {
	do {
		set @newjob, -1;	
		if (@type == EAJL_UPPER && $@kejc_upperPolicy && kej_class2) {
			set @newjob, eaclass(kej_class2);
			set @newjob, (@newjob&EAJ_UPPERMASK)|@type;
			if (roclass(@newjob) == -1)
				set @newjob, -1; //Invalid class.
			else
			if ((@newjob&EAJ_BASEMASK) != (@job&EAJ_BASEMASK))
				set @newjob, -1; //Saved next job does not corresponds to current 1st!
		}
		if (@newjob == -1) { //Fetch from menu.
			setarray @classes[0],
			(@job&EAJ_UPPERMASK)|@type|EAJL_2_1,
			(@job&EAJ_UPPERMASK)|@type|EAJL_2_2;

			if (roclass(@classes[0]) == -1)
			{	//Can't upgrade?
				callfunc "F_keIntro", e_swt2, "I cant' change you from your current job.";
				return;
			}

			SF_getJobNames 2;
			set @submenu, select(
				"- Cancel job change",
				@names$[0],@names$[1]
			);
			if (@submenu > 1)
				set @newjob, @classes[@submenu-2];
		}
		if (@newjob > -1) {
			set @i, SF_getJobIndex(@newjob);
			if (@i > -1) {
				if (@newjob&EAJL_2_2) { //2-2 classes
					set @weapon, $@kejc_weapon_22[@i];
					set @weapon2,$@kejc_weapon2_22[@i];
				} else { //2-1 classes
					set @weapon, $@kejc_weapon_21[@i];
					set @weapon2,$@kejc_weapon2_21[@i];
				}
			} else {
				set @weapon, 0;
				set @weapon2, 0;
			}
			if (SF_changeJob(@job,@newJob,@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 (CurrentJob, NewJob, Weapon, Weapon2,
// Zeny, WipeSkills, ResetLv)
//Attempts to change to the Jobgiven.
//CurrentJob is actual job in eA format.
//NewJob is job to change to in eA format.
//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 @job, getarg(0);
	set @newjob,getarg(1);
	set @weapon,getarg(2);
	set @weapon2,getarg(3);
	set @cost,getarg(4);
	set @wipeSkill,getarg(5);
	set @resetLv,getarg(6);

	if (roclass(@newjob) == -1) { //Invalid job?
		callfunc "F_keIntro", -1, "I can't change you to this job...";
		return 0;
	}

	set @jobStr$, jobname(roclass(@newjob));
	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 awarded 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(@weapon2)+"].";
					} else {
						mes "- You will receive a "+getitemname(@weapon2)+"["+getitemslots(@weapon2)+"] 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) {
				if((@job&EAJ_BASEMASK) == @job && @job != EAJ_NOVICE)
					set kej_class1,class; //Advancing to second class, so...
				if(@job&EAJL_2)
					set kej_class2,class; //Only way of being here is by doing a rebirth
				if(@job&~EAJ_UPPERMASK) {
					set kej_class1,0;	//Clear when one is a high class
					if(@job&~EAJL_2 && @job&EAJ_BASEMASK != EAJ_NOVICE)
						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;
			if ($@kejc_weaponPolicy && @weapon > 0) {
				if ($@kejc_wBonusLv && @weapon2 > 0 && JobLevel >= $@kejc_wBonusLv)
					getitem @weapon2,1;
				else
					getitem @weapon,1;
			}
			jobchange roclass(@newjob);
			if ($@kejc_announce)
				announce strcharinfo(0)+" has been promoted to "+@jobStr$+"!",8;
			set Zeny,Zeny-@cost;
			emotion e_grat;	
			return 1;
		default: //Cancel...
			return 0;	
	}
}

//SubFunction: SF_getJobIndex(Job)
//Given a job in eA format, retrieves the basic index which is used for the
//config arrays.
function SF_getJobIndex {
	set @i, getarg(0);
	set @i, @i&EAJ_BASEMASK;
	switch (@i) {
		case EAJ_ACOLYTE:
			return 0;
		case EAJ_ARCHER:
			return 1;
		case EAJ_MAGE:
			return 2;
		case EAJ_MERCHANT:
			return 3;
		case EAJ_SWORDMAN:
			return 4;
		case EAJ_THIEF:
			return 5;
		case EAJ_TAEKWON:
			return 6;
		case EAJ_NOVICE: //Super Novice, actually
			return 7;
		case EAJ_GUNSLINGER:
			return 8;
		case EAJ_NINJA:
			return 9;
		default:
			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]));
}

}
