summaryrefslogtreecommitdiff
path: root/doc/ea_job_system.txt
blob: 5a6db5e3c4ad7487b7b68e7164ffa4c7cc901cb2 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
//===== Athena Doc=== =====================================
//= rAthena Job System
//===== By ================================================
//= Skotlex
//===== Version ===========================================
//= 0.2
//=========================================================
//= 0.1 - First release, explained as well as I could.
//= 0.2 - Added info on third jobs. [Euphy]
//===== Description =======================================
//= A reference description of eA's inner job system (for
//= use on scripts through the eaclass and roclass script
//= commands)
//=========================================================

Preface:
-------------------------------------------------------------------------------

	Most scripters are aware of the class values used in RO and their constants specified on db/const.txt. Each class has a number associated to it for referencing, so when someone's class is 9 that means they are a wizard. However, this list of job numbers has no real order behind it, and no logic behind it's assignation.

	You can add 3999 to a job to get their rebirth ID, but if you try to do the same to get the Baby class ID, that fails on the super Baby class. Also, there's no way to calculate, from a given first class, which classes would be their "evolution". That is, given the Archer's ID, you cannot just add a value that will return you "Hunter", and will still work if applied to the other classes. It didn't help much when they added Taekwon Boy, a first class, with an ID of 4046, and much later they added Ninja/Gunslinger with the IDs 25/24. How do you identify a first class on all this mess without recurring to very ugly range checks?

The eA Job System:
-------------------------------------------------------------------------------

	Since the code also required to do this kind of checks for various skills (The Soul Linker Spirit buffs specially come to mind), an alternate job ID system was developed, which attempts to make more sense and make it easier to check where a particular job stands in relation to the rest.

	The scheme consists in that every job can be broken down by 3 criteria:

- Base Job: This determines to which class-tree a job belongs. All jobs can be traced back to their root. The base job of all classes has to be one of the following:

	EAJ_NOVICE	0x0
	EAJ_SWORDMAN	0x1
	EAJ_MAGE	0x2
	EAJ_ARCHER	0x3
	EAJ_ACOLYTE	0x4
	EAJ_MERCHANT	0x5
	EAJ_THIEF	0x6
	EAJ_TAEKWON	0x7
	EAJ_GUNSLINGER	0x9
	EAJ_NINJA	0x0A
	EAJ_GANGSI	0x0D

- Branch: All classes can be classified as "1st Class", "2-1 Class" or "2-2 Class":
	
	EAJL_2_1	0x100
	EAJL_2_2	0x200
	EAJL_2	0x300

- The third category is type. Classes can either be normal, rebirth/advanced, adopted, or third class.

	EAJL_UPPER	0x1000
	EAJL_BABY	0x2000
	EAJL_THIRD	0x4000

So using these three categories, any job class can be constructed from the others. Let's take a swordman, for example.

The first step is basic swordman, with nothing else:

	EAJ_SWORDMAN

The next step is to either become a 2-1 or a 2-2 job:

	EAJ_SWORDMAN|EAJL_2_1 -> EAJ_KNIGHT
	EAJ_SWORDMAN|EAJL_2_2 -> EAJ_CRUSADER

if a swordman is adopted...

	EAJ_SWORDMAN|EAJL_BABY -> EAJ_BABY_SWORDMAN

Or getting out the rebirth versions of a swordman:

	EAJ_SWORDMAN|EAJL_UPPER	-> EAJ_SWORDMAN_HIGH
	EAJ_SWORDMAN|EAJL_2_1|EAJL_UPPER	-> EAJ_LORD_KNIGHT
	EAJ_SWORDMAN|EAJL_2_2|EAJL_UPPER	-> EAJ_PALADIN
	EAJ_SWORDMAN|EAJL_2_2|EAJL_THIRD	-> EAJ_ROYAL_GUARD

Why are we using the bitwise OR operand ('|') rather than just adding? Because the OR is wreck-proof:

	EAJ_SWORDMAN_HIGH|EAJL_UPPER -> EAJ_SWORDMAN_HIGH

If we had used addition, we would have gotten a completely different result.

The EAJL (eA Job Level) constants
-------------------------------------------------------------------------------

	There are a few constants which can be used to filter out and make job comparisons easier.

EAJL_2_1:
	Checks if the class is a 2-1 class:
	if (@job&EAJL_2_1)
		mes "Using the classic 2-1 job, huh?";

EAJL_2_2:
	Checks if the class is 2-2.

EAJL_2:
	Checks if the class is a 2nd Class. If the check fails, you can be sure the character is a first class.
	if (!(@job&EAJL_2))
		mes "Will you wait until Job 50 to change?";

EAJL_UPPER:
	Check if a class is Rebirth/Advanced:
	if(@job&EAJL_UPPER)
		mes "It must have taken you a LONG time...";

EAJL_BABY:
	Check if a class is an adopted class.
	if (@job&EAJL_BABY)
		mes "Don't you hate being weak?";

EAJL_THIRD:
	Checks if a class is a third job.
	if(@job&EAJL_THIRD)
		mes "Wow, you've really grown!";

EAJ_UPPERMASK:
	The upper mask can be used to "strip" the upper/baby characteristics of a class, used when you want to know if someone is a certain class regardless of rebirth/adopted status. For example, the following code would go through for Monks, Champions and Baby Monks:
	if ((@job&EAJ_UPPERMASK) == EAJ_MONK)
		mes "Aren't knuckles such a cool weapon?";
	
	Note that if instead of EAJ_MONK you used EAJ_CHAMPION or EAJ_BABY_MONK, the check would had never passed, since the upper/baby state has been removed from the original job when checking.
	
EAJ_BASEMASK:
	This mask strips also the 2nd class attributes. It can be used to check against the basic job of a character. For example, the following code would go through for Merchants (+Baby Merchant and High Merchant), Blacksmiths (+Baby blacksmiths and Whitesmith) and Alchemist (+Baby Alchemist and +Creator):
	if ((@job&EAJ_BASEMASK) == EAJ_MERCHANT)
		mes "Why I can't have discount like you guys do?";

	Note that, like before, if you try to check versus any of the other classes (High merchant, blacksmith, etc) instead of basic merchant, the check will always fail for the same reasons previously explained.

EAJ_THIRDMASK:
	This mask strips 3rd class attributes.  It will give the "normal" class of a third job, regardless of rebirth/adopted status.  When used on non-third class characters, it will return the second job, or, if that also doesn't exist, the first.
	if ((@job&EAJ_THIRDMASK) == EAJ_WARLOCK_T)
		mes "You've gone through rebirth, I see.";

The script commands eaclass, roclass:
-------------------------------------------------------------------------------

	These script commands are what you can use in scripts to convert between the RO classic job id, and eA's job system. The following script code demonstrates how to use these script commands to guess what your next job will be:

	set @eac, eaclass();
	if (@eac&EAJL_2)
	{	//2nd class
		//If upper or baby, you can't rebirth
		if (@eac&(EAJL_UPPER|EAJL_BABY)) {
			mes "You can't go anywhere, can you?";
			close;
		}
		//Note that if we remove the EAJL_BABY check up there, the following check
		//will also fail, because there's no such thing as Rebirth-Baby classes.
		set @newclass, roclass(@eac|EAJL_UPPER);
		if (@newclass == -1) {
			//Don't you hate this of SG and SL?
			mes "Haha, your class doesn't has a rebirth version yet!";
			close;
		}
		mes "Still dreaming of the day you become a "+jobname(@newclass)+"?";
		close;
	}
	set @class1, roclass(@eac|EAJL_2_1);
	set @class2, roclass(@eac|EAJL_2_2);
	if (@class1 == -1) {
		//NJ/GS are the only classes who get stuck on their 1st class forever.
		mes "Looks like you are stuck forever on that class.";
		close;
	}
	if (@class2 == -1) {
		//Not quite true, currently the only 1st class that doesn't has two choices is Novice -> Supernovice (see s.novice section below)
		mes "Looks like you have no choice but to be a "+jobname(@class1)+".";
		close;
	}
	mes "Have you decided yet if you want to be a "+jobname(@class1)+" or a "+jobname(@class2)+"?";
	close;


Oddities of the System:
-------------------------------------------------------------------------------
About Bards and Dancers:
	These two classes are considered the same in eA's job system, since they both are the 2-2 job of archers. The only way to tell them apart is by using the gender of the character we are referring to. The script command roclass() will automatically use the gender of the attached player (or 'male' if there's no such player), but you can also explicitly pass the gender to the script command when there's no player attached.

About Novices and Super Novices:
	These are treated a bit differently from you'd expect. Because.. for instance, a novice is not supposed to be a 1st class, but it is considered as one on this tree system:

	EAJ_NOVICE -> Novice
	EAJ_NOVICE|EAJL_2_1 -> EAJ_SUPER_NOVICE
	EAJ_NOVICE|EAJL_UPPER -> EAJ_NOVICE_HIGH
	EAJ_NOVICE|EAJL_BABY	-> EAJ_BABY
	EAJ_NOVICE|EAJL_BABY|EAJL_2_1 -> EAJ_SUPER_BABY

	So as you can see, on this job system, the Super Novice is treated as the 2-1 job of a Novice, and the Novice job it's at the same level of the other 1st jobs. Even though that may seem like a hindrance, it makes it very easy to add a check to discard Novice types from a quest:

	if ((@job&EAJ_BASEMASK) == EAJ_NOVICE)
		//Novice class detected.