//===== 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	{
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(1);
	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$+"...",16;
		
	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(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 "+jobname(@thisJobId)+" to "+@newjob$+"...",16;
	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]));
}

}
