1 | //===== eAthena Script ======================================= |
---|
2 | //= Kafra Express - Job Changing Module |
---|
3 | //===== By: ================================================== |
---|
4 | //= Skotlex |
---|
5 | //===== Current Version: ===================================== |
---|
6 | //= 4.0 |
---|
7 | //===== Compatible With: ===================================== |
---|
8 | //= eAthena SVN R8840+ |
---|
9 | //===== Description: ========================================= |
---|
10 | //= Part of the Kafra Express Script Package. |
---|
11 | //= Enables job changing through the class trees. |
---|
12 | //= Novice -> 1st Class, 1st Class -> 2nd Class, rebirths, etc |
---|
13 | //===== Additional Comments: ================================= |
---|
14 | //= See config.txt for configuration. |
---|
15 | //= When using Upper Job policy, previous jobs are stored in |
---|
16 | //= the permanent variables kej_class1 and kej_class2 |
---|
17 | //============================================================ |
---|
18 | |
---|
19 | - script keInit_jobchange -1,{ |
---|
20 | OnInit: //Load Config |
---|
21 | donpcevent "keConfig::OnLoadJobChange"; |
---|
22 | end; |
---|
23 | } |
---|
24 | |
---|
25 | function script F_keJobChange { |
---|
26 | |
---|
27 | function SF_to1stJob; |
---|
28 | function SF_to2ndJob; |
---|
29 | function SF_getJobIndex; |
---|
30 | function SF_getJobNames; |
---|
31 | function SF_testChangeJob; |
---|
32 | function SF_changeJob; |
---|
33 | |
---|
34 | set @job, eaClass(class); |
---|
35 | set @type, @job&~EAJ_UPPERMASK; //Because it is changed when rebirthing |
---|
36 | set @reset, 0; //Base Level is reset only on rebirths |
---|
37 | if ((@job&EAJ_BASEMASK) == EAJ_NOVICE) |
---|
38 | { //Novices |
---|
39 | if (@job&EAJL_2) //S. Novices |
---|
40 | goto L_FAIL; |
---|
41 | if ($@kejc_skipNovice) |
---|
42 | set @jobLv, 0; //jobLv is used again when checking for S.Novice's base level restriction. |
---|
43 | else |
---|
44 | set @jobLv, 10; |
---|
45 | if (SF_testChangeJob(0,0,@jobLv)) |
---|
46 | SF_to1stJob(0); |
---|
47 | } else |
---|
48 | if(@job&EAJL_2){ |
---|
49 | //Second classes |
---|
50 | if (@job&~EAJ_UPPERMASK) //rebirth/baby |
---|
51 | goto L_FAIL; |
---|
52 | if (SF_testChangeJob($@kejc_costRebirth,$@kejc_baseRebirth,$@kejc_jobRebirth)) { |
---|
53 | set @type, EAJL_UPPER; |
---|
54 | if ($@kejc_skipNovice) |
---|
55 | SF_to1stJob(1); |
---|
56 | else |
---|
57 | SF_changeJob @job,EAJ_NOVICE_HIGH,0,0,$@kejc_costRebirth,1,$@kejc_rebirthReset; |
---|
58 | } |
---|
59 | } else { |
---|
60 | //First classes |
---|
61 | if (SF_testChangeJob($@kejc_cost2ND,$@kejc_base2ND,$@kejc_job2ND)) |
---|
62 | SF_to2ndJob(); |
---|
63 | } |
---|
64 | return; |
---|
65 | L_FAIL: |
---|
66 | //Dead End |
---|
67 | callfunc "F_keIntro", e_swt2, "I cannot change you from your current job."; |
---|
68 | return; |
---|
69 | |
---|
70 | //Handles changing to 1st job. |
---|
71 | function SF_to1stJob { |
---|
72 | setarray @classes[0], |
---|
73 | EAJ_Acolyte|@type, |
---|
74 | EAJ_Archer|@type, |
---|
75 | EAJ_Mage|@type, |
---|
76 | EAJ_Merchant|@type, |
---|
77 | EAJ_Swordman|@type, |
---|
78 | EAJ_Thief|@type, |
---|
79 | EAJ_Taekwon|@type, |
---|
80 | EAJ_Super_Novice|@type, |
---|
81 | EAJ_GunSlinger|@type, |
---|
82 | EAJ_Ninja|@type; |
---|
83 | |
---|
84 | do { |
---|
85 | set @newjob, -1; |
---|
86 | if (@type == EAJL_UPPER && $@kejc_upperPolicy && kej_class1) { |
---|
87 | set @newjob, eaclass(kej_class1); |
---|
88 | set @newjob, (@newjob&EAJ_UPPERMASK)|@type; |
---|
89 | if (roclass(@newjob) == -1) |
---|
90 | set @newjob, -1; |
---|
91 | set @submenu, 1; |
---|
92 | } |
---|
93 | if (@newjob == -1) { |
---|
94 | SF_getJobNames getarraysize(@classes); |
---|
95 | if (@type&EAJL_UPPER || $@kejc_disable&1) |
---|
96 | set @names$[7], ""; //No S.Novice |
---|
97 | |
---|
98 | if (@type&~EAJ_UPPERMASK) |
---|
99 | { //No TK/NJ/GS for Baby/Advanced |
---|
100 | set @names$[6], ""; |
---|
101 | set @names$[8], ""; |
---|
102 | set @names$[9], ""; |
---|
103 | } else { |
---|
104 | if ($@kejc_disable&2) //No TK |
---|
105 | set @names$[6], ""; |
---|
106 | if ($@kejc_disable&4) //No GS |
---|
107 | set @names$[8], ""; |
---|
108 | if ($@kejc_disable&8) //No NJ |
---|
109 | set @names$[9], ""; |
---|
110 | } |
---|
111 | |
---|
112 | set @submenu, select( |
---|
113 | "- Cancel job change", |
---|
114 | @names$[0], @names$[1], @names$[2], |
---|
115 | @names$[3], @names$[4], @names$[5], |
---|
116 | @names$[6], @names$[7], @names$[8], |
---|
117 | @names$[9] |
---|
118 | ); |
---|
119 | |
---|
120 | if (@submenu > 1) { |
---|
121 | if (@submenu == 9 && //S. Novice's own change check. |
---|
122 | SF_testChangeJob(0,$@kejc_baseSN,@jobLv) == 0) |
---|
123 | return; |
---|
124 | set @newjob, @classes[@submenu-2]; |
---|
125 | } |
---|
126 | } |
---|
127 | |
---|
128 | if (@newjob > -1) { |
---|
129 | set @i, SF_getJobIndex(@newjob); |
---|
130 | if (@i > -1) |
---|
131 | set @weapon, $@kejc_weapon1[@i]; |
---|
132 | else |
---|
133 | set @weapon, 0; |
---|
134 | if (getarg(0)) { //Skipping High Novice, charge rebirth costs. |
---|
135 | if (SF_changeJob(@job,@newJob,@weapon,0,$@kejc_costRebirth,2,$@kejc_rebirthReset)) |
---|
136 | return; |
---|
137 | } else { |
---|
138 | if (SF_changeJob(@job,@newJob,@weapon,0,0,2,0)) |
---|
139 | return; |
---|
140 | } |
---|
141 | } |
---|
142 | } while (@submenu > 1); |
---|
143 | } |
---|
144 | |
---|
145 | function SF_to2ndJob { |
---|
146 | do { |
---|
147 | set @newjob, -1; |
---|
148 | if (@type == EAJL_UPPER && $@kejc_upperPolicy && kej_class2) { |
---|
149 | set @newjob, eaclass(kej_class2); |
---|
150 | set @newjob, (@newjob&EAJ_UPPERMASK)|@type; |
---|
151 | if (roclass(@newjob) == -1) |
---|
152 | set @newjob, -1; //Invalid class. |
---|
153 | else |
---|
154 | if ((@newjob&EAJ_BASEMASK) != (@job&EAJ_BASEMASK)) |
---|
155 | set @newjob, -1; //Saved next job does not corresponds to current 1st! |
---|
156 | } |
---|
157 | if (@newjob == -1) { //Fetch from menu. |
---|
158 | setarray @classes[0], |
---|
159 | (@job&EAJ_UPPERMASK)|@type|EAJL_2_1, |
---|
160 | (@job&EAJ_UPPERMASK)|@type|EAJL_2_2; |
---|
161 | |
---|
162 | if (roclass(@classes[0]) == -1) |
---|
163 | { //Can't upgrade? |
---|
164 | callfunc "F_keIntro", e_swt2, "I cant' change you from your current job."; |
---|
165 | return; |
---|
166 | } |
---|
167 | |
---|
168 | SF_getJobNames 2; |
---|
169 | set @submenu, select( |
---|
170 | "- Cancel job change", |
---|
171 | @names$[0],@names$[1] |
---|
172 | ); |
---|
173 | if (@submenu > 1) |
---|
174 | set @newjob, @classes[@submenu-2]; |
---|
175 | } |
---|
176 | if (@newjob > -1) { |
---|
177 | set @i, SF_getJobIndex(@newjob); |
---|
178 | if (@i > -1) { |
---|
179 | if (@newjob&EAJL_2_2) { //2-2 classes |
---|
180 | set @weapon, $@kejc_weapon_22[@i]; |
---|
181 | set @weapon2,$@kejc_weapon2_22[@i]; |
---|
182 | } else { //2-1 classes |
---|
183 | set @weapon, $@kejc_weapon_21[@i]; |
---|
184 | set @weapon2,$@kejc_weapon2_21[@i]; |
---|
185 | } |
---|
186 | } else { |
---|
187 | set @weapon, 0; |
---|
188 | set @weapon2, 0; |
---|
189 | } |
---|
190 | if (SF_changeJob(@job,@newJob,@weapon,@weapon2,$@kejc_cost2ND,0,0)) |
---|
191 | return; |
---|
192 | } |
---|
193 | } while (@submenu > 1); |
---|
194 | } |
---|
195 | |
---|
196 | //SubFunction: SF_testChangeJob(Zeny, BaseLv, JobLv) |
---|
197 | //Function that checks if the player qualifies for job changing. |
---|
198 | function SF_testChangeJob { |
---|
199 | set @fail, 0; |
---|
200 | if (Zeny < getarg(0)) |
---|
201 | set @fail, 1; |
---|
202 | if (BaseLevel < getarg(1)) |
---|
203 | set @fail, @fail|2; |
---|
204 | if (JobLevel < getarg(2)) |
---|
205 | set @fail, @fail|4; |
---|
206 | if (@fail > 0) { |
---|
207 | if (@fail&1) |
---|
208 | mes "You need "+getarg(0)+"z for the conversion process."; |
---|
209 | if (@fail&2) |
---|
210 | mes "You need to be at least Lv "+getarg(1)+"."; |
---|
211 | if (@fail&4) |
---|
212 | mes "You need at least job Lv "+getarg(2)+"."; |
---|
213 | callfunc "F_keIntro", e_pif, "Sorry, you don't qualify for a job change yet."; |
---|
214 | return 0; |
---|
215 | } |
---|
216 | |
---|
217 | if (SkillPoint > 0 && $@kejc_skillsPolicy == 0) { |
---|
218 | callfunc "F_keIntro", e_dots, "Sorry, use your remaining Skill points before being able to change class."; |
---|
219 | return 0; |
---|
220 | } |
---|
221 | return 1; |
---|
222 | } |
---|
223 | |
---|
224 | //SubFunction: SF_changeJob (CurrentJob, NewJob, Weapon, Weapon2, |
---|
225 | // Zeny, WipeSkills, ResetLv) |
---|
226 | //Attempts to change to the Jobgiven. |
---|
227 | //CurrentJob is actual job in eA format. |
---|
228 | //NewJob is job to change to in eA format. |
---|
229 | //Weapon is the ID of the weapon to grant |
---|
230 | //Weapon2 is the alternative weapon granted when your job level is above $@kejc_wBonusLv |
---|
231 | //Zeny is the money required (if negative, it is money awarded) |
---|
232 | //WipeSkills if 1, indicates that skills should be wiped, |
---|
233 | //if 2, it means basic skills have to be given back |
---|
234 | //Reset Level indicates the base lv must be reset to 1. |
---|
235 | //Note: Zeny/Base/Job requirements should had been checked with SF_testChangeJob already! |
---|
236 | function SF_changeJob { |
---|
237 | set @job, getarg(0); |
---|
238 | set @newjob,getarg(1); |
---|
239 | set @weapon,getarg(2); |
---|
240 | set @weapon2,getarg(3); |
---|
241 | set @cost,getarg(4); |
---|
242 | set @wipeSkill,getarg(5); |
---|
243 | set @resetLv,getarg(6); |
---|
244 | |
---|
245 | if (roclass(@newjob) == -1) { //Invalid job? |
---|
246 | callfunc "F_keIntro", -1, "I can't change you to this job..."; |
---|
247 | return 0; |
---|
248 | } |
---|
249 | |
---|
250 | set @jobStr$, jobname(roclass(@newjob)); |
---|
251 | if (@wipeSkill == 0 && SkillPoint > 0 && $@kejc_skillsPolicy == 1) { |
---|
252 | set @selection, select( |
---|
253 | "- Do not change yet.", |
---|
254 | "- Change to "+@jobStr$+" (skill points lost)", |
---|
255 | "- View details" |
---|
256 | ); |
---|
257 | } else { |
---|
258 | set @selection, select( |
---|
259 | "- Cancel", |
---|
260 | "- Change to "+@jobStr$, |
---|
261 | "- View details" |
---|
262 | ); |
---|
263 | } |
---|
264 | switch (@selection) { |
---|
265 | case 3: //Details |
---|
266 | mes "Okay.. listen up:"; |
---|
267 | next; |
---|
268 | mes "["+@name$+"]"; |
---|
269 | mes "Changing to "+@jobStr$+" now means:"; |
---|
270 | if (@wipeSkill == 0 && SkillPoint > 0 && $@kejc_skillsPolicy == 1) |
---|
271 | mes "- You will lose your "+SkillPoint+" unused skill points."; |
---|
272 | else if (@wipeSkill == 1) |
---|
273 | mes "- You will lose all your skills."; |
---|
274 | if (@resetLv) |
---|
275 | mes "- Your base level will be reset to 1."; |
---|
276 | if (@cost > 0) |
---|
277 | mes "- You will be charged "+@cost+"z."; |
---|
278 | else if (@cost < 0) |
---|
279 | mes "- You will be awarded with "+(0-@cost)+"z."; |
---|
280 | if (@weapon > 0) { |
---|
281 | if (@weapon2 > 0 && $@kejc_wBonusLv) { |
---|
282 | if (JobLevel < $@kejc_wBonusLv) { |
---|
283 | mes "- You will receive a "+getitemname(@weapon)+"["+getitemslots(@weapon)+"]."; |
---|
284 | mes "- If you wait until Job Lv"+$@kejc_wBonusLv+", you can receive instead a "+getitemname(@weapon2)+"["+getitemslots(@weapon2)+"]."; |
---|
285 | } else { |
---|
286 | mes "- You will receive a "+getitemname(@weapon2)+"["+getitemslots(@weapon2)+"] for reaching Job Lv"+$@kejc_wBonusLv+"."; |
---|
287 | } |
---|
288 | } else |
---|
289 | mes "- You will receive a "+getitemname(@weapon)+"."; |
---|
290 | } |
---|
291 | mes "So... will you change?"; |
---|
292 | if (select( |
---|
293 | "- Cancel", |
---|
294 | "- Change to "+@jobStr$ |
---|
295 | ) != 2) { |
---|
296 | callfunc "F_keIntro", e_dots, "...alright."; |
---|
297 | return 0; |
---|
298 | } |
---|
299 | callfunc "F_keIntro", -1, "Enjoy your new Job."; |
---|
300 | case 2: //Change |
---|
301 | //Set/Unset job path variables as needed. |
---|
302 | if($@kejc_upperPolicy) { |
---|
303 | if((@job&EAJ_BASEMASK) == @job && @job != EAJ_NOVICE) |
---|
304 | set kej_class1,class; //Advancing to second class, so... |
---|
305 | if(@job&EAJL_2) |
---|
306 | set kej_class2,class; //Only way of being here is by doing a rebirth |
---|
307 | if(@job&~EAJ_UPPERMASK) { |
---|
308 | set kej_class1,0; //Clear when one is a high class |
---|
309 | if(@job&~EAJL_2 && @job&EAJ_BASEMASK != EAJ_NOVICE) |
---|
310 | set kej_class2,0; //Clear when leaving high 1st class |
---|
311 | } |
---|
312 | } |
---|
313 | if (@resetLv) { |
---|
314 | jobchange Job_Novice_High; //Done to give players those 100 points from High classes |
---|
315 | resetlvl(1); |
---|
316 | } |
---|
317 | if (@wipeSkill) { |
---|
318 | resetskill; |
---|
319 | setoption(0); |
---|
320 | set SkillPoint,0; |
---|
321 | } else if ($@kejc_skillsPolicy == 1) |
---|
322 | set SkillPoint,0; |
---|
323 | if (@wipeSkill>1) |
---|
324 | skill 1,9,0; |
---|
325 | if($@kejc_resetDye) |
---|
326 | setlook 7,0; |
---|
327 | if ($@kejc_weaponPolicy && @weapon > 0) { |
---|
328 | if ($@kejc_wBonusLv && @weapon2 > 0 && JobLevel >= $@kejc_wBonusLv) |
---|
329 | getitem @weapon2,1; |
---|
330 | else |
---|
331 | getitem @weapon,1; |
---|
332 | } |
---|
333 | jobchange roclass(@newjob); |
---|
334 | if ($@kejc_announce) |
---|
335 | announce strcharinfo(0)+" has been promoted to "+@jobStr$+"!",8; |
---|
336 | set Zeny,Zeny-@cost; |
---|
337 | emotion e_grat; |
---|
338 | return 1; |
---|
339 | default: //Cancel... |
---|
340 | return 0; |
---|
341 | } |
---|
342 | } |
---|
343 | |
---|
344 | //SubFunction: SF_getJobIndex(Job) |
---|
345 | //Given a job in eA format, retrieves the basic index which is used for the |
---|
346 | //config arrays. |
---|
347 | function SF_getJobIndex { |
---|
348 | set @i, getarg(0); |
---|
349 | set @i, @i&EAJ_BASEMASK; |
---|
350 | switch (@i) { |
---|
351 | case EAJ_ACOLYTE: |
---|
352 | return 0; |
---|
353 | case EAJ_ARCHER: |
---|
354 | return 1; |
---|
355 | case EAJ_MAGE: |
---|
356 | return 2; |
---|
357 | case EAJ_MERCHANT: |
---|
358 | return 3; |
---|
359 | case EAJ_SWORDMAN: |
---|
360 | return 4; |
---|
361 | case EAJ_THIEF: |
---|
362 | return 5; |
---|
363 | case EAJ_TAEKWON: |
---|
364 | return 6; |
---|
365 | case EAJ_NOVICE: //Super Novice, actually |
---|
366 | return 7; |
---|
367 | case EAJ_GUNSLINGER: |
---|
368 | return 8; |
---|
369 | case EAJ_NINJA: |
---|
370 | return 9; |
---|
371 | default: |
---|
372 | return -1; |
---|
373 | } |
---|
374 | } |
---|
375 | |
---|
376 | //SubFunction: SF_getJobNames(Qty) |
---|
377 | //Fills an array @names$ with the job names taken from the array "classes", |
---|
378 | // making each entry start with "- " followed by the job name. |
---|
379 | function SF_getJobNames { |
---|
380 | set @size, getarg(0); |
---|
381 | for (set @i, 0; @i < @size; set @i, @i+1) |
---|
382 | setd "@names$["+@i+"]", "- "+jobname(roclass(@classes[@i])); |
---|
383 | } |
---|
384 | |
---|
385 | } |
---|