ソースを参照

- Changed the exp tables format.

git-svn-id: https://svn.code.sf.net/p/rathena/svn/trunk@5135 54d463be-8e91-2dee-dedb-b68131a5f0ec
skotlex 19 年 前
コミット
4f5babb97d
10 ファイル変更154 行追加271 行削除
  1. 5 0
      Changelog-Trunk.txt
  2. 22 99
      db/exp.txt
  3. 8 17
      src/map/atcommand.c
  4. 0 8
      src/map/battle.c
  5. 0 4
      src/map/battle.h
  6. 7 15
      src/map/charcommand.c
  7. 1 1
      src/map/clif.c
  8. 107 126
      src/map/pc.c
  9. 3 0
      src/map/pc.h
  10. 1 1
      src/map/status.c

+ 5 - 0
Changelog-Trunk.txt

@@ -4,6 +4,11 @@ AS OF SVN REV. 5091, WE ARE NOW USING TRUNK.  ALL UNTESTED BUGFIXES/FEATURES GO
 IF YOU HAVE A WORKING AND TESTED BUGFIX PUT IT INTO STABLE AS WELL AS TRUNK.  EVERYTHING ELSE
 GOES INTO TRUNK AND WILL BE MERGED INTO STABLE BY VALARIS AND WIZPUTER. -- VALARIS
 
+2006/01/31
+	* Changed the exp table format. The new format allows specifying exp tables
+	  for any particular class. Thanks to Playstester for converting the official
+	  exp table to the new format. [Skotlex]
+	- UNTESTED: Report any problems asap.
 2006/01/30
 	* Autoloot now uses the item's base drop chance rather than final drop rate
 	  to determine if it should autoloot the item or not. [Skotlex]

+ 22 - 99
db/exp.txt

@@ -1,99 +1,22 @@
-9,9,9,9,10,10,10,10,30,144,30,11,60,288
-16,16,16,16,18,18,18,18,43,184,43,20,86,368
-25,25,25,25,28,28,28,28,58,284,58,31,116,568
-36,36,36,36,40,40,40,40,76,348,76,44,152,696
-77,77,77,77,85,85,85,91,116,603,116,100,232,1206
-112,112,112,112,123,123,123,151,180,887,180,166,360,1774
-153,153,153,153,168,168,168,205,220,1096,220,226,440,2192
-200,200,200,200,220,220,220,268,272,1598,272,295,544,3196
-253,253,253,253,278,278,278,340,336,2540,336,374,672,5080
-320,320,320,320,400,400,400,0,520,3676,520,0,1040,7352
-385,385,385,385,481,481,481,0,604,4290,604,0,1208,8580
-490,490,490,490,613,613,613,0,699,4946,699,0,1398,9892
-585,585,585,585,731,731,731,0,802,6679,802,0,1604,13358
-700,700,700,700,875,875,875,0,948,9492,948,0,1896,18984
-830,830,830,830,1038,1038,1038,0,1125,12770,1125,0,2250,31925
-970,970,970,970,1213,1213,1213,0,1668,14344,1668,0,3336,35860
-1120,1120,1120,1120,1400,1400,1400,0,1937,16005,1937,0,3874,40013
-1260,1260,1260,1260,1575,1575,1575,0,2226,20642,2226,0,4452,51605
-1420,1420,1420,1420,1775,1775,1775,0,3040,27434,3040,0,6080,68585
-1620,1620,1620,1620,2268,2268,2268,0,3988,35108,3988,0,7976,87770
-1860,1860,1860,1860,2604,2604,2604,0,5564,38577,5564,0,11128,96443
-1990,1990,1990,1990,2786,2786,2786,0,6272,42206,6272,0,12544,105515
-2240,2240,2240,2240,3136,3136,3136,0,7021,52708,7021,0,14042,131770
-2504,2504,2504,2504,3506,3506,3506,0,9114,66971,9114,0,18228,167428
-2950,2950,2950,2950,4130,4130,4130,0,11473,82688,11473,0,28683,206720
-3426,3426,3426,3426,4796,4796,4796,0,15290,89544,15290,0,38225,223860
-3934,3934,3934,3934,5508,5508,5508,0,16891,96669,16891,0,42228,241673
-4474,4474,4474,4474,6264,6264,6264,0,18570,117821,18570,0,46425,294553
-6889,6889,6889,6889,9645,9645,9645,0,23229,144921,23229,0,58073,362303
-7995,7995,7995,7995,12392,12392,12392,0,28359,174201,28359,0,70898,479053
-9174,9174,9174,9174,14220,14220,14220,0,36478,186677,36478,0,91195,513362
-10425,10425,10425,10425,16159,16159,16159,0,39716,199584,39716,0,99290,548856
-11748,11748,11748,11748,18209,18209,18209,0,43088,238617,43088,0,107720,656197
-13967,13967,13967,13967,21649,21649,21649,0,52417,286366,52417,0,131043,787507
-15775,15775,15775,15775,24451,24451,24451,0,62495,337147,62495,0,156238,927154
-17678,17678,17678,17678,27401,27401,27401,0,78160,358435,78160,0,195408,985696
-19677,19677,19677,19677,30499,30499,30499,0,84175,380376,84175,0,210430,1046034
-21773,21773,21773,21773,33748,33748,33748,0,90404,447685,90404,0,226010,1231134
-30543,30543,30543,30543,47342,47342,47342,0,107611,526989,107611,0,269028,1449220
-34212,34212,34212,34212,58160,58160,58160,0,125915,610246,125915,0,314788,1678177
-38065,38065,38065,38065,64711,64711,64711,0,153941,644736,153941,0,384853,1773024
-42102,42102,42102,42102,71573,71573,71573,0,191781,793535,191781,0,479453,2182221
-46323,46323,46323,46323,78749,78749,78749,0,204351,921810,204351,0,510878,2534978
-53026,53026,53026,53026,90144,90144,90144,0,248352,1106758,248352,0,620880,3043585
-58419,58419,58419,58419,99312,99312,99312,0,286212,1260955,286212,0,715530,3782865
-64041,64041,64041,64041,108870,108870,108870,0,386371,1487304,386371,0,965928,4461912
-69892,69892,69892,69892,118816,118816,118816,0,409795,1557657,409795,0,1024488,4672971
-75973,75973,75973,75973,129154,129154,129154,0,482092,1990632,482092,0,1205230,5971896
-102468,102468,102468,102468,174196,174196,174196,0,509596,2083386,509596,0,1273990,6250158
-115254,115254,115254,115254,213220,213220,213220,0,0,0,982092,0,0,6875174
-128692,128692,128692,128692,238080,238080,238080,0,0,0,992092,0,0,7562691
-142784,142784,142784,142784,264150,264150,264150,0,0,0,1002092,0,0,8318960
-157528,157528,157528,157528,291427,291427,291427,0,0,0,1012092,0,0,9150856
-178184,178184,178184,178184,329640,329640,329640,0,0,0,1022092,0,0,10065942
-196300,196300,196300,196300,363155,363155,363155,0,0,0,1032092,0,0,11877812
-215198,215198,215198,215198,398116,398116,398116,0,0,0,1042092,0,0,14015818
-234879,234879,234879,234879,434526,434526,434526,0,0,0,1052092,0,0,16538655
-255341,255341,255341,255341,472381,472381,472381,0,0,0,1062092,0,0,19515624
-330188,330188,330188,330188,610848,610848,610848,0,0,0,1072092,0,0,23028437
-365914,365914,365914,365914,731828,731828,731828,0,0,0,1082092,0,0,28094693
-403224,403224,403224,403224,806448,806448,806448,0,0,0,1092092,0,0,34275525
-442116,442116,442116,442116,884232,884232,884232,0,0,0,1102092,0,0,41816141
-482590,482590,482590,482590,965180,965180,965180,0,0,0,1112092,0,0,51015692
-536948,536948,536948,536948,1073896,1073896,1073896,0,0,0,1122092,0,0,62239144
-585191,585191,585191,585191,1170382,1170382,1170382,0,0,0,1132092,0,0,79666104
-635278,635278,635278,635278,1270556,1270556,1270556,0,0,0,1142092,0,0,101972614
-687211,687211,687211,687211,1374422,1374422,1374422,0,0,0,1152092,0,0,130524946
-740988,740988,740988,740988,1481976,1481976,1481976,0,0,0,1162092,0,0,167071930
-925400,925400,925400,925400,1850800,1850800,1850800,0,0,0,1172092,0,0,213852071
-1473746,1473746,1473746,1473746,3389616,3389616,3389616,0,0,0,1182092,0,0,0
-1594058,1594058,1594058,1594058,3666333,3666333,3666333,0,0,0,1192092,0,0,0
-1718928,1718928,1718928,1718928,3953534,3953534,3953534,0,0,0,1202092,0,0,0
-1848355,1848355,1848355,1848355,4251217,4251217,4251217,0,0,0,1212092,0,0,0
-1982340,1982340,1982340,1982340,4559382,4559382,4559382,0,0,0,1222092,0,0,0
-2230113,2230113,2230113,2230113,5129260,5129260,5129260,0,0,0,1232092,0,0,0
-2386162,2386162,2386162,2386162,5488173,5488173,5488173,0,0,0,1242092,0,0,0
-2547417,2547417,2547417,2547417,5859059,5859059,5859059,0,0,0,1252092,0,0,0
-2713878,2713878,2713878,2713878,6241919,6241919,6241919,0,0,0,1262092,0,0,0
-3206160,3206160,3206160,3206160,7374168,7374168,7374168,0,0,0,1272092,0,0,0
-3681024,3681024,3681024,3681024,9570662,9570662,9570662,0,0,0,1282092,0,0,0
-4022472,4022472,4022472,4022472,10458427,10458427,10458427,0,0,0,1292092,0,0,0
-4377024,4377024,4377024,4377024,11380262,11380262,11380262,0,0,0,1302092,0,0,0
-4744680,4744680,4744680,4744680,12336168,12336168,12336168,0,0,0,1312092,0,0,0
-5125440,5125440,5125440,5125440,13326144,13326144,13326144,0,0,0,1322092,0,0,0
-5767272,5767272,5767272,5767272,14994907,14994907,14994907,0,0,0,1332092,0,0,0
-6204000,6204000,6204000,6204000,16130400,16130400,16130400,0,0,0,1342092,0,0,0
-6655464,6655464,6655464,6655464,17304200,17304200,17304200,0,0,0,1352092,0,0,0
-7121664,7121664,7121664,7121664,18516326,18516326,18516326,0,0,0,1362092,0,0,0
-7602600,7602600,7602600,7602600,19766760,19766760,19766760,0,0,0,1372092,0,0,0
-9738720,9738720,9738720,9738720,29216160,29216160,29216160,0,0,0,1382092,0,0,0
-11649960,11649960,11649960,11649960,34949880,34949880,34949880,0,0,0,1392092,0,0,0
-13643520,13643520,13643520,13643520,40930560,40930560,40930560,0,0,0,1402092,0,0,0
-18339300,18339300,18339300,18339300,55017900,55017900,55017900,0,0,0,1412092,0,0,0
-23836800,23836800,23836800,23836800,71510400,71510400,71510400,0,0,0,1422092,0,0,0
-35658000,35658000,35658000,35658000,106974000,106974000,106974000,0,0,0,1432092,0,0,0
-48687000,48687000,48687000,48687000,146061000,146061000,146061000,0,0,0,1442092,0,0,0
-58135000,58135000,58135000,58135000,174405000,174405000,174405000,0,0,0,1452092,0,0,0
-99999999,99999999,99999999,99999999,343210000,343210000,343210000,0,0,0,1462092,0,0,0
-0,0,0,0,0,0,0,0,0,0,0,0,0,0
+//Experience tables format:
+//Max Level,Class list,Type (0 - Base Exp, 1 - Job Exp),Exp for Lv 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
+//Base - Normal and Baby Jobs
+99,0:1:2:3:4:5:6:7:8:9:10:11:12:13:14:15:16:17:18:19:20:21:23:24:25:26:4023:4024:4025:4026:4027:4028:4029:4030:4031:4032:4033:4034:4035:4036:4037:4038:4039:4040:4041:4042:4043:4044:4045:4046:4047:4048:4049,0,9,16,25,36,77,112,153,200,253,320,385,490,585,700,830,970,1120,1260,1420,1620,1860,1990,2240,2504,2950,3426,3934,4474,6889,7995,9174,10425,11748,13967,15775,17678,19677,21773,30543,34212,38065,42102,46323,53026,58419,64041,69892,75973,102468,115254,128692,142784,157528,178184,196300,215198,234879,255341,330188,365914,403224,442116,482590,536948,585191,635278,687211,740988,925400,1473746,1594058,1718928,1848355,1982340,2230113,2386162,2547417,2713878,3206160,3681024,4022472,4377024,4744680,5125440,5767272,6204000,6655464,7121664,7602600,9738720,11649960,13643520,18339300,23836800,35658000,48687000,58135000,99999999
+//Base - Adv Jobs
+99,4001:4002:4003:4004:4005:4006:4007:4008:4009:4010:4011:4012:4013:4014:4015:4016:4017:4018:4019:4020:4021:4022,0,10,18,28,40,85,123,168,220,278,400,481,613,731,875,1038,1213,1400,1575,1775,2268,2604,2786,3136,3506,4130,4796,5508,6264,9645,12392,14220,16159,18209,21649,24451,27401,30499,33748,47342,58160,64711,71573,78749,90144,99312,108870,118816,129154,174196,213220,238080,264150,291427,329640,363155,398116,434526,472381,610848,731828,806448,884232,965180,1073896,1170382,1270556,1374422,1481976,1850800,3389616,3666333,3953534,4251217,4559382,5129260,5488173,5859059,6241919,7374168,9570662,10458427,11380262,12336168,13326144,14994907,16130400,17304200,18516326,19766760,29216160,34949880,40930560,55017900,71510400,106974000,146061000,174405000,343210000
+//Job - Novice
+10,0:4023,1,10,18,28,40,91,151,205,268,340
+//Job - 1st Classes
+50,1:2:3:4:5:6:24:25:26:4024:4025:4026:4027:4028:4029:4046,1,30,43,58,76,116,180,220,272,336,520,604,699,802,948,1125,1668,1937,2226,3040,3988,5564,6272,7021,9114,11473,15290,16891,18570,23229,28359,36478,39716,43088,52417,62495,78160,84175,90404,107611,125915,153941,191781,204351,248352,286212,386371,409795,482092,509596
+//Job - 2nd Classes
+50,7:8:9:10:11:12:13:14:15:16:17:18:19:20:21:4030:4031:4032:4033:4034:4035:4036:4037:4038:4039:4040:4041:4042:4032:4044:4049,1,144,184,284,348,603,887,1096,1598,2540,3676,4290,4946,6679,9492,12770,14344,16005,20642,27434,35108,38577,42206,52708,66971,82688,89544,96669,117821,144921,174201,186677,199584,238617,286366,337147,358435,380376,447685,526989,610246,644736,793535,921810,1106758,1260955,1487304,1557657,1990632,2083386
+//Job - Super Novice
+99,23:4045,1,30,43,58,76,116,180,220,272,336,520,604,699,802,948,1125,1668,1937,2226,3040,3988,5564,6272,7021,9114,11473,15290,16891,18570,23229,28359,36478,39716,43088,52417,62495,78160,84175,90404,107611,125915,153941,191781,204351,248352,286212,386371,409795,482092,509596,982092,992092,1002092,1012092,1022092,1032092,1042092,1052092,1062092,1072092,1082092,1092092,1102092,1112092,1122092,1132092,1142092,1152092,1162092,1172092,1182092,1192092,1202092,1212092,1222092,1232092,1242092,1252092,1262092,1272092,1282092,1292092,1302092,1312092,1322092,1332092,1342092,1352092,1362092,1372092,1382092,1392092,1402092,1412092,1422092,1432092,1442092,1452092,1462092
+//Job - Novice High
+10,4001,1,11,20,31,44,100,166,226,295,374
+//Job - Adv First Classes
+50,4002:4003:4004:4005:4006:4007,1,60,86,116,152,232,360,440,544,672,1040,1208,1398,1604,1896,2250,3336,3874,4452,6080,7976,11128,12544,14042,18228,28683,38225,42228,46425,58073,70898,91195,99290,107720,131043,156238,195408,210430,226010,269028,314788,384853,479453,510878,620880,715530,965928,1024488,1205230,1273990
+//Job - Adv Second Classes
+70,4008:4009:4010:4011:4012:4013:4014:4015:4016:4017:4018:4019:4020:4021:4022,1,288,368,568,696,1206,1774,2192,3196,5080,7352,8580,9892,13358,18984,31925,35860,40013,51605,68585,87770,96443,105515,131770,167428,206720,223860,241673,294553,362303,479053,513362,548856,656197,787507,927154,985696,1046034,1231134,1449220,1678177,1773024,2182221,2534978,3043585,3782865,4461912,4672971,5971896,6250158,6875174,7562691,8318960,9150856,10065942,11877812,14015818,16538655,19515624,23028437,28094693,34275525,41816141,51015692,62239144,79666104,101972614,130524946,167071930,213852071
+//Job - Star Gladiator
+50,4047:4048,1,27434,27434,27434,27434,27434,27434,27434,27434,27434,27434,27434,27434,27434,27434,27434,27434,27434,27434,54868,70216,77154,84412,105416,133942,165376,179088,193338,235642,289842,348402,373354,399168,477234,572732,674294,716870,760752,895370,1053978,1220492,1289472,1587070,1843620,2213516,2521910,2974608,3115314,3981264,4166772

+ 8 - 17
src/map/atcommand.c

@@ -2676,12 +2676,12 @@ int atcommand_baselevelup(
 	}
 
 	if (level > 0) {
-		if (sd->status.base_level == battle_config.max_base_level) {	/* check for max level by Valaris */
+		if (sd->status.base_level == pc_maxbaselv(sd)) {	/* check for max level by Valaris */
 			clif_displaymessage(fd, msg_table[47]); /* Base level can't go any higher. */
 			return -1;
 		}	/* End Addition */
-		if ((unsigned int)level > battle_config.max_base_level || (unsigned int)level > (battle_config.max_base_level - sd->status.base_level)) // fix positiv overflow
-			level = battle_config.max_base_level - sd->status.base_level;
+		if (level > pc_maxbaselv(sd) || level > (pc_maxbaselv(sd) - sd->status.base_level)) // fix positiv overflow
+			level = pc_maxbaselv(sd) - sd->status.base_level;
 		for (i = 1; i <= level; i++)
 			sd->status.status_point += (sd->status.base_level + i + 14) / 5;
 		sd->status.base_level += level;
@@ -2697,7 +2697,7 @@ int atcommand_baselevelup(
 			clif_displaymessage(fd, msg_table[158]); /* Base level can't go any lower. */
 			return -1;
 		}
-		if (level < -(int)battle_config.max_base_level || level < (1 - (int)sd->status.base_level)) /* fix negativ overflow */
+		if (level < -(int)pc_maxbaselv(sd) || level < (1 - (int)sd->status.base_level)) /* fix negativ overflow */
 			level = 1 - sd->status.base_level;
 		if (sd->status.status_point > 0) {
 			for (i = 0; i > level; i--)
@@ -2725,7 +2725,6 @@ int atcommand_joblevelup(
 	const int fd, struct map_session_data* sd,
 	const char* command, const char* message)
 {
-	unsigned int up_level = battle_config.max_job_level;
 	int level=0;
 	nullpo_retr(-1, sd);
 	
@@ -2735,21 +2734,13 @@ int atcommand_joblevelup(
 		clif_displaymessage(fd, "Please, enter a level adjustement (usage: @joblvup/@jlevel/@joblvlup <number of levels>).");
 		return -1;
 	}
-
-	if ((sd->class_&MAPID_UPPERMASK) == MAPID_NOVICE) //Novice
-		up_level = 10;
-	else if ((sd->class_&MAPID_BASEMASK) == MAPID_NOVICE) //S. Novice
-		up_level = battle_config.max_sn_level;
-	else if (sd->class_&JOBL_UPPER && sd->class_&JOBL_2)
-		up_level = battle_config.max_adv_level; //2nd Adv Class
-
 	if (level > 0) {
-		if (sd->status.job_level == up_level) {
+		if (sd->status.job_level == pc_maxjoblv(sd)) {
 			clif_displaymessage(fd, msg_table[23]); // Job level can't go any higher.
 			return -1;
 		}
-		if ((unsigned int)level > up_level || (unsigned int)level > (up_level - sd->status.job_level)) // fix positiv overflow
-			level = up_level - sd->status.job_level;
+		if (level > pc_maxjoblv(sd) || level > (pc_maxjoblv(sd) - sd->status.job_level)) // fix positiv overflow
+			level = pc_maxjoblv(sd) - sd->status.job_level;
 		sd->status.job_level += level;
 		clif_updatestatus(sd, SP_JOBLEVEL);
 		clif_updatestatus(sd, SP_NEXTJOBEXP);
@@ -2763,7 +2754,7 @@ int atcommand_joblevelup(
 			clif_displaymessage(fd, msg_table[159]); // Job level can't go any lower.
 			return -1;
 		}
-		if (level < -(int)up_level || level < (1 - (int)sd->status.job_level)) // fix negativ overflow
+		if (level < -(int)pc_maxjoblv(sd) || level < (1 - (int)sd->status.job_level)) // fix negativ overflow
 			level = 1 - sd->status.job_level;
 		sd->status.job_level += level;
 		clif_updatestatus(sd, SP_JOBLEVEL);

+ 0 - 8
src/map/battle.c

@@ -3708,10 +3708,6 @@ static const struct battle_data_short {
 	{ "item_drop_treasure_max",            &battle_config.item_drop_treasure_max },
 	{ "prevent_logout",                    &battle_config.prevent_logout		},	// Added by RoVeRT
 	{ "alchemist_summon_reward",           &battle_config.alchemist_summon_reward	},	// [Valaris]
-	{ "max_base_level",                    &battle_config.max_base_level	},	// [Valaris]
-	{ "max_job_level",                     &battle_config.max_job_level	},
-	{ "max_advanced_job_level",            &battle_config.max_adv_level	},
-	{ "max_super_novice_level",            &battle_config.max_sn_level	},
 	{ "drops_by_luk",                      &battle_config.drops_by_luk	},	// [Valaris]
 	{ "drops_by_luk2",                     &battle_config.drops_by_luk2	},	// [Skotlex]
 	{ "equip_natural_break_rate",          &battle_config.equip_natural_break_rate	},
@@ -4097,10 +4093,6 @@ void battle_set_defaults() {
 	battle_config.item_drop_treasure_min=1;
 	battle_config.item_drop_treasure_max=10000;
 	battle_config.prevent_logout = 10000;	// Added by RoVeRT
-	battle_config.max_base_level = 255;	// Added by Valaris
-	battle_config.max_job_level = 50;
-	battle_config.max_adv_level = 70;
-	battle_config.max_sn_level = 99;
 	battle_config.drops_by_luk = 0;	// [Valaris]
 	battle_config.drops_by_luk2 = 0;
 	battle_config.equip_natural_break_rate = 1;

+ 0 - 4
src/map/battle.h

@@ -292,10 +292,6 @@ extern struct Battle_Config {
 	unsigned short prevent_logout;	// Added by RoVeRT
 
 	unsigned short alchemist_summon_reward;	// [Valaris]
-	unsigned short max_base_level;	//Max Base Level [Valaris]
-	unsigned short max_job_level;	//Max job level (normal classes) [Skotlex]
-	unsigned short max_sn_level;	//Max job level (super novice) [Skotlex]
-	unsigned short max_adv_level;	//Max job level (advanced classes) [Skotlex]
 	unsigned short drops_by_luk;
 	unsigned short drops_by_luk2;
 	unsigned short equip_natural_break_rate;	//Base Natural break rate for attacks.

+ 7 - 15
src/map/charcommand.c

@@ -1258,12 +1258,12 @@ int charcommand_baselevel(
 		if (pc_isGM(sd) >= pc_isGM(pl_sd)) { // you can change base level only lower or same gm level
 
 			if (level > 0) {
-				if (pl_sd->status.base_level == battle_config.max_base_level) {	// check for max level by Valaris
+				if (pl_sd->status.base_level == pc_maxbaselv(sd)) {	// check for max level by Valaris
 					clif_displaymessage(fd, msg_table[91]); // Character's base level can't go any higher.
 					return 0;
 				}	// End Addition
-				if ((unsigned int)level > battle_config.max_base_level || (unsigned int)level > (battle_config.max_base_level - pl_sd->status.base_level)) // fix positiv overflow
-					level = battle_config.max_base_level - pl_sd->status.base_level;
+				if (level > pc_maxbaselv(pl_sd) || level > (pc_maxbaselv(pl_sd)- pl_sd->status.base_level)) // fix positiv overflow
+					level = pc_maxbaselv(pl_sd) - pl_sd->status.base_level;
 				for (i = 1; i <= level; i++)
 					pl_sd->status.status_point += (pl_sd->status.base_level + i + 14) / 5;
 				pl_sd->status.base_level += level;
@@ -1279,7 +1279,7 @@ int charcommand_baselevel(
 					clif_displaymessage(fd, msg_table[193]); // Character's base level can't go any lower.
 					return -1;
 				}
-				if (level < -(int)battle_config.max_base_level || level < (1 - (int)pl_sd->status.base_level)) // fix negativ overflow
+				if (level < -(int)pc_maxbaselv(pl_sd) || level < (1 - (int)pl_sd->status.base_level)) // fix negativ overflow
 					level = 1 - pl_sd->status.base_level;
 				if (pl_sd->status.status_point > 0) {
 					for (i = 0; i > level; i--)
@@ -1316,7 +1316,6 @@ int charcommand_joblevel(
 	const char* command, const char* message)
 {
 	struct map_session_data *pl_sd;
-	unsigned int max_level = battle_config.max_job_level;
 	char player[NAME_LENGTH];
 	int level = 0;
 	//転生や養子の場合の元の職業を算出する
@@ -1329,20 +1328,13 @@ int charcommand_joblevel(
 
 	if ((pl_sd = map_nick2sd(player)) != NULL) {
 		if (pc_isGM(sd) >= pc_isGM(pl_sd)) { // you can change job level only lower or same gm level
-			if ((pl_sd->class_&MAPID_UPPERMASK) == MAPID_NOVICE)
-				max_level = 10; //Novice
-			else if ((pl_sd->class_&MAPID_BASEMASK) == MAPID_NOVICE)
-				max_level = battle_config.max_sn_level; //S. Novice
-			else if (pl_sd->class_&JOBL_UPPER && pl_sd->class_&JOBL_2)
-				max_level = battle_config.max_adv_level; //Adv. Class
-
 			if (level > 0) {
-				if (pl_sd->status.job_level == max_level) {
+				if (pl_sd->status.job_level == pc_maxjoblv(pl_sd)) {
 					clif_displaymessage(fd, msg_table[67]); // Character's job level can't go any higher.
 					return -1;
 				}
-				if (pl_sd->status.job_level + level > max_level)
-					level = max_level - pl_sd->status.job_level;
+				if (pl_sd->status.job_level + level > pc_maxjoblv(pl_sd))
+					level = pc_maxjoblv(pl_sd) - pl_sd->status.job_level;
 				pl_sd->status.job_level += level;
 				clif_updatestatus(pl_sd, SP_JOBLEVEL);
 				clif_updatestatus(pl_sd, SP_NEXTJOBEXP);

+ 1 - 1
src/map/clif.c

@@ -8814,7 +8814,7 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd)
 	    pc_checkskill(sd,SG_STAR_COMFORT))
 		status_calc_pc(sd,0);
 	
-	if (pc_checkskill(sd, SG_DEVIL) && sd->status.job_level >= battle_config.max_job_level)
+	if (pc_checkskill(sd, SG_DEVIL) && !pc_nextjobafter(sd))
 		clif_status_load(&sd->bl, SI_DEVIL, 1);  //blindness [Komurka]
 	
 	map_foreachinarea(clif_getareachar,sd->bl.m,sd->bl.x-AREA_SIZE,sd->bl.y-AREA_SIZE,sd->bl.x+AREA_SIZE,sd->bl.y+AREA_SIZE,BL_ALL,sd);

+ 107 - 126
src/map/pc.c

@@ -41,7 +41,8 @@
 #endif
 
 #define PVP_CALCRANK_INTERVAL 1000	// PVP順位計算の間隔
-static int exp_table[14][MAX_LEVEL];
+static int exp_table[MAX_PC_CLASS][2][MAX_LEVEL];
+static int max_level[MAX_PC_CLASS][2];
 static short statp[MAX_LEVEL];
 
 // h-files are for declarations, not for implementations... [Shinomori]
@@ -4642,7 +4643,7 @@ int pc_checkjoblevelup(struct map_session_data *sd)
 		status_calc_pc(sd,0);
 
 		clif_misceffect(&sd->bl,1);
-		if (pc_checkskill(sd, SG_DEVIL) && sd->status.job_level >= battle_config.max_job_level)
+		if (pc_checkskill(sd, SG_DEVIL) && !pc_nextjobafter(sd))
 			clif_status_change(&sd->bl,SI_DEVIL, 1); //Permanent blind effect from SG_DEVIL.
 
 		if (script_config.event_script_type == 0) {
@@ -4727,29 +4728,31 @@ int pc_gainexp(struct map_session_data *sd,int base_exp,int job_exp)
 	return 0;
 }
 
+/*==========================================
+ * Returns max level for this character.
+ *------------------------------------------
+ */
+
+int pc_maxbaselv(struct map_session_data *sd) {
+  	return max_level[sd->status.class_][0];
+};
+
+int pc_maxjoblv(struct map_session_data *sd) {
+  	return max_level[sd->status.class_][1];
+};
+
 /*==========================================
  * base level側必要??値計算
  *------------------------------------------
  */
 int pc_nextbaseexp(struct map_session_data *sd)
 {
-	int i =0;
-
 	nullpo_retr(0, sd);
 
-	if(sd->status.base_level>=MAX_LEVEL || sd->status.base_level<=0)
+	if(sd->status.base_level>=pc_maxbaselv(sd) || sd->status.base_level<=0)
 		return 0;
 
-	i = (sd->class_&JOBL_UPPER)?4:0; //4 is the base for upper, 0 for normal/baby ones.
-
-	if ((sd->class_&MAPID_UPPERMASK) == MAPID_NOVICE)
-		; //Add 0, it's novice.
-	else if ((sd->class_&MAPID_UPPERMASK) == MAPID_SUPER_NOVICE)
-		i = 3; //Super Novice/Super Baby
-	else 
-		i+= (sd->class_&JOBL_2)?2:1;	//Add 2 for second classes, add 1 for first classes.
-
-	return exp_table[i][sd->status.base_level-1];
+	return exp_table[sd->status.class_][0][sd->status.base_level-1];
 }
 
 /*==========================================
@@ -4758,27 +4761,11 @@ int pc_nextbaseexp(struct map_session_data *sd)
  */
 int pc_nextjobexp(struct map_session_data *sd)
 {
-	int i;
-
 	nullpo_retr(0, sd);
 
-	if(sd->status.job_level>=MAX_LEVEL || sd->status.job_level<=0)
+	if(sd->status.job_level>=pc_maxjoblv(sd) || sd->status.job_level<=0)
 		return 0;
-
-	i = (sd->class_&JOBL_UPPER)?11:7; //11 is the base for upper, 7 for normal/baby ones.
-
-	if ((sd->class_&MAPID_UPPERMASK) == MAPID_NOVICE)
-		; //Add 0, it's novice.
-	else if ((sd->class_&MAPID_UPPERMASK) == MAPID_SUPER_NOVICE)
-		i = 10; //Super Novice/Super Baby
-	else if ((sd->class_&MAPID_UPPERMASK) == MAPID_STAR_GLADIATOR) {
-		i = 13; //Star Gladiator - slow JExp (as for 2nd class)
-		if (sd->status.job_level >= battle_config.max_job_level)
-			return 0; //Since SG aren't really an advanced class... [Skotlex]
-	} else 
-		i+= (sd->class_&JOBL_2)?2:1;	//Add 2 for second classes, add 1 for first classes.
-
-	return exp_table[i][sd->status.job_level-1];
+	return exp_table[sd->status.class_][1][sd->status.job_level-1];
 }
 
 /*==========================================
@@ -4787,23 +4774,12 @@ int pc_nextjobexp(struct map_session_data *sd)
  */
 int pc_nextbaseafter(struct map_session_data *sd)
 {
-	int i;
-
 	nullpo_retr(0, sd);
 
-	if(sd->status.base_level>=MAX_LEVEL || sd->status.base_level<=0)
+	if(sd->status.base_level>=pc_maxbaselv(sd) || sd->status.base_level<=0)
 		return 0;
 
-	i = (sd->class_&JOBL_UPPER)?4:0; //4 is the base for upper, 0 for normal/baby ones.
-
-	if ((sd->class_&MAPID_UPPERMASK) == MAPID_NOVICE)
-		; //Add 0, it's novice.
-	else if ((sd->class_&MAPID_UPPERMASK) == MAPID_SUPER_NOVICE)
-		i = 3; //Super Novice/Super Baby
-	else 
-		i+= (sd->class_&JOBL_2)?2:1;	//Add 2 for second classes, add 1 for first classes.
-
-	return exp_table[i][sd->status.base_level];
+	return exp_table[sd->status.class_][0][sd->status.base_level];
 }
 
 /*==========================================
@@ -4812,27 +4788,12 @@ int pc_nextbaseafter(struct map_session_data *sd)
  */
 int pc_nextjobafter(struct map_session_data *sd)
 {
-	int i;
-
 	nullpo_retr(0, sd);
 
-	if(sd->status.job_level>=MAX_LEVEL || sd->status.job_level<=0)
+	if(sd->status.job_level>=pc_maxjoblv(sd) || sd->status.job_level<=0)
 		return 0;
 
-	i = (sd->class_&JOBL_UPPER)?11:7; //11 is the base for upper, 7 for normal/baby ones.
-
-	if ((sd->class_&MAPID_UPPERMASK) == MAPID_NOVICE)
-		; //Add 0, it's novice.
-	else if ((sd->class_&MAPID_UPPERMASK) == MAPID_SUPER_NOVICE)
-		i = 10; //Super Novice/Super Baby
-	else if ((sd->class_&MAPID_UPPERMASK) == MAPID_STAR_GLADIATOR) {
-		i = 13; //Star Gladiator - slow JExp (as for 2nd class)
-		if (sd->status.job_level >= battle_config.max_job_level)
-			return 0; //Since SG aren't really an advanced class... [Skotlex]
-	} else 
-		i+= (sd->class_&JOBL_2)?2:1;	//Add 2 for second classes, add 1 for first classes.
-
-	return exp_table[i][sd->status.job_level];
+	return exp_table[sd->status.class_][1][sd->status.job_level];
 }
 /*==========================================
 
@@ -5236,7 +5197,7 @@ int pc_resetskill(struct map_session_data* sd)
 	int i, skill, inf2;
 	nullpo_retr(0, sd);
 
-	if (pc_checkskill(sd, SG_DEVIL) && sd->status.job_level >= battle_config.max_job_level)
+	if (pc_checkskill(sd, SG_DEVIL) &&  !pc_nextjobafter(sd))
 		clif_status_load(&sd->bl, SI_DEVIL, 0); //Remove perma blindness due to skill-reset. [Skotlex]
 	
 	for (i = 1; i < MAX_SKILL; i++) {
@@ -5553,7 +5514,8 @@ int pc_damage(struct block_list *src,struct map_session_data *sd,int damage)
 			mob_changestate(md,MS_WALK,0);
 		}
 		if(battle_config.mobs_level_up && md && md->state.state!=MS_DEAD &&
-			md->level < battle_config.max_base_level && !md->guardian_data // Guardians should not level. [Skotlex]
+			md->level < pc_maxbaselv(sd) &&
+			!md->guardian_data // Guardians should not level. [Skotlex]
 		) { 	// monster level up [Valaris]
 			clif_misceffect(&md->bl,0);
 			md->level++;
@@ -5786,14 +5748,14 @@ int pc_readparam(struct map_session_data *sd,int type)
  */
 int pc_setparam(struct map_session_data *sd,int type,int val)
 {
-	int i = 0,up_level = battle_config.max_job_level;
+	int i = 0;
 
 	nullpo_retr(0, sd);
 
 	switch(type){
 	case SP_BASELEVEL:
-		if ((val+ sd->status.base_level) > battle_config.max_base_level) //Capping to max
-			val = battle_config.max_base_level - sd->status.base_level;
+		if ((val+ sd->status.base_level) > pc_maxbaselv(sd)) //Capping to max
+			val = pc_maxbaselv(sd) - sd->status.base_level;
 		if (val > (int)sd->status.base_level) {
 			for (i = 1; i <= (val - (int)sd->status.base_level); i++)
 				sd->status.status_point += (sd->status.base_level + i + 14) / 5 ;
@@ -5808,14 +5770,8 @@ int pc_setparam(struct map_session_data *sd,int type,int val)
 		pc_heal(sd, sd->status.max_hp, sd->status.max_sp);
 		break;
 	case SP_JOBLEVEL:
-		if ((sd->class_&MAPID_UPPERMASK) == MAPID_NOVICE)
-			up_level = 10;	//Novice & Baby Novice have 10 Job Levels only
-		else if ((sd->class_&MAPID_UPPERMASK) == MAPID_SUPER_NOVICE) //Super Novice & Super Baby can go up to 99
-			up_level = battle_config.max_sn_level;
-		else if (sd->class_&JOBL_UPPER && sd->class_&JOBL_2) //3rd Job has 70 Job Levels
-			up_level = battle_config.max_adv_level;
 		if (val >= (int)sd->status.job_level) {
-			if (val > up_level) val = up_level;
+			if (val > pc_maxjoblv(sd)) val = pc_maxjoblv(sd);
 			sd->status.skill_point += (val-sd->status.job_level);
 			sd->status.job_level = val;
 			sd->status.job_exp = 0;
@@ -8049,6 +8005,35 @@ void pc_setstand(struct map_session_data *sd){
 	sd->state.dead_sit = 0;
 }
 
+int pc_split_str(char *str,char **val,int num)
+{
+	int i;
+
+	for (i=0; i<num && str; i++){
+		val[i] = str;
+		str = strchr(str,',');
+		if (str && i<num-1) //Do not remove a trailing comma.
+			*str++=0;
+	}
+	return i;
+}
+
+int pc_split_atoi(char *str,int *val, char sep, int max)
+{
+	int i,j;
+	for (i=0; i<max; i++) {
+		if (!str) break;
+		val[i] = atoi(str);
+		str = strchr(str,sep);
+		if (str)
+			*str++=0;
+	}
+	//Zero up the remaining.
+	for(j=i; j < max; j++)
+		val[j] = 0;
+	return i;
+}
+
 //
 // 初期化物
 //
@@ -8067,70 +8052,66 @@ int pc_readdb(void)
 {
 	int i,j,k;
 	FILE *fp;
-	char line[1024],*p;
+	char line[16000],*p;
 
 	// 必要??値?み?み
 	memset(exp_table,0,sizeof(exp_table));
+	memset(max_level,0,sizeof(max_level));
 	sprintf(line, "%s/exp.txt", db_path);
 	fp=fopen(line, "r");
 	if(fp==NULL){
 		ShowError("can't read %s\n", line);
 		return 1;
 	}
-	i=0;
 	while(fgets(line, sizeof(line)-1, fp)){
-		int bn,b1,b2,b3,b4,b5,b6,jn,j1,j2,j3,j4,j5,j6;
+		int jobs[MAX_PC_CLASS], job_count, job;
+		int type, max;
+		char *split[3];
 		if(line[0]=='/' && line[1]=='/')
 			continue;
-		if(sscanf(line,"%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",&bn,&b1,&b2,&b3,&b4,&b5,&b6,&jn,&j1,&j2,&j3,&j4,&j5,&j6)!=14)
+		if (pc_split_str(line,split,4) < 4)
 			continue;
-		exp_table[0][i]=bn;
-		exp_table[1][i]=b1;
-		exp_table[2][i]=b2;
-		exp_table[3][i]=b3;
-		exp_table[4][i]=b4;
-		exp_table[5][i]=b5;
-		exp_table[6][i]=b6;
-		exp_table[7][i]=jn;
-		exp_table[8][i]=j1;
-		exp_table[9][i]=j2;
-		exp_table[10][i]=j3;
-		exp_table[11][i]=j4;
-		exp_table[12][i]=j5;
-		exp_table[13][i]=j6;
-		i++;
-	}
-	if (i > battle_config.max_base_level)
-	{	//Empty Base level columns
-		for (j = battle_config.max_base_level-1; j < i && exp_table[0][j]>0; j++)
-		{
-			exp_table[0][j]=0;
-			exp_table[1][j]=0;
-			exp_table[2][j]=0;
-			exp_table[3][j]=0;
-			exp_table[4][j]=0;
-			exp_table[5][j]=0;
-			exp_table[6][j]=0;
-		}
-	}
-	if (i > battle_config.max_sn_level)
-	{	//Empty SN job exp columns
-		for (j = battle_config.max_sn_level-1; j < i && exp_table[10][j]>0; j++)
-			exp_table[10][j]=0;
-	}
-	if (i > battle_config.max_adv_level)
-	{	//Empty Adv Jobs columns
-		for (j = battle_config.max_adv_level-1; j < i && exp_table[13][j]>0; j++)
-			exp_table[13][j]=0;
-	}
-	if (i > battle_config.max_job_level)
-	{	//Empty normal Job columns
-		for (j = battle_config.max_job_level-1; j < i &&
-			(exp_table[8][j]>0 || exp_table[9][j]>0 || exp_table[12][j]>0); j++)
-		{
-			exp_table[8][j]=0; //1st Job
-			exp_table[9][j]=0; //2nd Job
-			exp_table[12][j]=0; //Adv 1st Job
+		
+		job_count = pc_split_atoi(split[1],jobs,':',MAX_PC_CLASS);
+		if (job_count < 1)
+			continue;
+		job = jobs[0];
+		if (!pcdb_checkid(job)) {
+			ShowError("pc_readdb: Invalid job ID %d.\n", job);
+			continue;
+		}
+		type = atoi(split[2]);
+		if (type < 0 || type > 1) {
+			ShowError("pc_readdb: Invalid type %d (must be 0 for base levels, 1 for job levels).\n", type);
+			continue;
+		}
+		max = atoi(split[0]);
+		if (max > MAX_LEVEL) {
+			ShowWarning("pc_readdb: Specified max level %d for job %d is beyond server's limit (%d).\n ", max, job, MAX_LEVEL);
+			max = MAX_LEVEL;
+		}
+		//We send one less and then one more because the last entry in the exp array should hold 0.
+		max_level[job][type] = pc_split_atoi(split[3], exp_table[job][type],',',max-1)+1;
+		//Reverse check in case the array has a bunch of trailing zeros... [Skotlex]
+		//The reasoning behind the -2 is this... if the max level is 5, then the array
+		//should look like this:
+	   //0: x, 1: x, 2: x: 3: x 4: 0 <- last valid value is at 3.
+		while ((i = max_level[job][type]-2) >= 0 && exp_table[job][type][i] <= 0)
+			max_level[job][type]--;
+	
+		if (max_level[job][type] < max) {
+			ShowError("pc_readdb: Specified max %d for job %d, but that job's exp table only goes up to level %d.\n", max, job, max_level[job][type]);
+		}
+//		ShowDebug("%s - Class %d: %d\n", type?"Job":"Base", job, max_level[job][type]);
+		for (i = 1; i < job_count; i++) {
+			job = jobs[i];
+			if (!pcdb_checkid(job)) {
+				ShowError("pc_readdb: Invalid job ID %d.\n", job);
+				continue;
+			}
+			memcpy(exp_table[job][type], exp_table[jobs[0]][type], sizeof(exp_table[0][0]));
+			max_level[job][type] = max_level[jobs[0]][type];
+//			ShowDebug("%s - Class %d: %d\n", type?"Job":"Base", job, max_level[job][type]);
 		}
 	}
 	fclose(fp);

+ 3 - 0
src/map/pc.h

@@ -116,6 +116,9 @@ int pc_stopattack(struct map_session_data*);
 int pc_follow(struct map_session_data*, int); // [MouseJstr]
 int pc_stop_following(struct map_session_data*);
 
+
+int pc_maxbaselv(struct map_session_data *sd);
+int pc_maxjoblv(struct map_session_data *sd);
 int pc_checkbaselevelup(struct map_session_data *sd);
 int pc_checkjoblevelup(struct map_session_data *sd);
 int pc_gainexp(struct map_session_data*,int,int);

+ 1 - 1
src/map/status.c

@@ -1624,7 +1624,7 @@ int status_calc_pc(struct map_session_data* sd,int first)
 	// Relative modifiers from passive skills
 	if((skill=pc_checkskill(sd,SA_ADVANCEDBOOK))>0)
 		sd->aspd_rate -= (skill/2);
-	if((skill = pc_checkskill(sd,SG_DEVIL)) > 0 && sd->status.job_level >= battle_config.max_job_level)
+	if((skill = pc_checkskill(sd,SG_DEVIL)) > 0 && !pc_nextjobafter(sd))
 		sd->aspd_rate -= (skill*3);
 
 	if(pc_isriding(sd))