浏览代码

- added defines JOB_MAX_BASIC and JOB_MAX to mmo.h so the code can know which are the max valid classes.
- @/#jobchange no longer strip your equipment since pc_jobchange removes any unequippables already.
- removed the wasteful define MAX_PC_CLASS and replaced it by the CLASS_COUNT define (which is automatically updated using the previous JOB_MAX* defines) + pc_class2idx function (which converts high class IDs into values that fit in CLASS_COUNT)
- Made status_charge a function rather than a define to get rid of those warnings that have been there since forever.
- Merged the CELL_NOVENDING code (see topic #129209)
- Small check that disables the pet catching process if you try to use another item.
- Added a check to fix a warning and prevent a crash in the npc duplicate check (even though I have no idea what this check is supposed to do, therefore I can't fix it properly other than to avoid the crash)


git-svn-id: https://svn.code.sf.net/p/rathena/svn/trunk@11572 54d463be-8e91-2dee-dedb-b68131a5f0ec

skotlex 17 年之前
父节点
当前提交
480a4f0ac8
共有 13 个文件被更改,包括 127 次插入82 次删除
  1. 6 0
      Changelog-Trunk.txt
  2. 2 0
      src/common/mmo.h
  3. 1 7
      src/map/atcommand.c
  4. 2 6
      src/map/charcommand.c
  5. 4 0
      src/map/map.c
  6. 4 4
      src/map/map.h
  7. 5 0
      src/map/npc.c
  8. 52 34
      src/map/pc.c
  9. 6 3
      src/map/pc.h
  10. 1 1
      src/map/script.c
  11. 37 26
      src/map/status.c
  12. 1 1
      src/map/status.h
  13. 6 0
      src/map/vending.c

+ 6 - 0
Changelog-Trunk.txt

@@ -4,6 +4,12 @@ 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.
 
 2007/10/24
+	* @/#jobchange no longer strips your equipment since pc_jobchange removes
+	  any unequippables already.
+	* Removed the wasteful define MAX_PC_CLASS and replaced it by the
+	  CLASS_COUNT define + pc_class2idx function. This should save a bunch of
+	  memory from the map server.
+	* Merged the CELL_NOVENDING code (see topic #129209) [Skotlex]
 	* Increased the max. send buffer size to 5M since 1M is not enough
 	* Updated vs7 and vs6 project files
 	* Added upgrade_svn11548.sql to convert the mail table to new format

+ 2 - 0
src/common/mmo.h

@@ -475,6 +475,7 @@ enum {
 	JOB_NINJA,
 	JOB_XMAS,
 	JOB_SUMMER,
+	JOB_MAX_BASIC,
 
 	JOB_NOVICE_HIGH = 4001,
 	JOB_SWORDMAN_HIGH,
@@ -527,6 +528,7 @@ enum {
 	JOB_STAR_GLADIATOR,
 	JOB_STAR_GLADIATOR2,
 	JOB_SOUL_LINKER,
+	JOB_MAX,
 };
 
 // sanity checks...

+ 1 - 7
src/map/atcommand.c

@@ -2175,14 +2175,8 @@ int atcommand_jobchange(const int fd, struct map_session_data* sd, const char* c
 	if (job == 37 ||job == 45)
 		return 0;
 
-	if ((job >= 0 && job < MAX_PC_CLASS))
+	if (pcdb_checkid(job))
 	{
-		int j;
-
-		for (j=0; j < MAX_INVENTORY; j++) {
-			if(sd->status.inventory[j].nameid>0 && sd->status.inventory[j].equip!=0)
-				pc_unequipitem(sd, j, 3);
-		}
 		if (pc_jobchange(sd, job, upper) == 0)
 			clif_displaymessage(fd, msg_txt(12)); // Your job has been changed.
 		else {

+ 2 - 6
src/map/charcommand.c

@@ -421,7 +421,7 @@ int charcommand_jobchange(const int fd, struct map_session_data* sd, const char*
 {
 	char character[100];
 	struct map_session_data* pl_sd;
-	int job = 0, upper = -1, j = 0;
+	int job = 0, upper = -1;
 
 	memset(character, '\0', sizeof(character));
 
@@ -462,15 +462,11 @@ int charcommand_jobchange(const int fd, struct map_session_data* sd, const char*
 		return -1;
 	}
 
-	if (job < 0 || job > MAX_PC_CLASS) {
+	if (!pcdb_checkid(job)) {
 		clif_displaymessage(fd, msg_txt(49)); // Invalid job ID.
 		return -1;
 	}
 
-	for (j=0; j < MAX_INVENTORY; j++) {
-		if(pl_sd->status.inventory[j].nameid>0 && pl_sd->status.inventory[j].equip!=0)
-			pc_unequipitem(pl_sd, j, 3);
-	}
 	if (pc_jobchange(pl_sd, job, upper) != 0) {
 		clif_displaymessage(fd, msg_txt(192)); // Impossible to change the character's job.
 		return -1;

+ 4 - 0
src/map/map.c

@@ -2307,6 +2307,8 @@ int map_getcellp(struct map_data* m,int x,int y,cell_t cellchk)
 			return (type2&CELL_REGEN);
 		case CELL_CHKICEWALL:
 			return (type2&CELL_ICEWALL);
+		case CELL_CHKNOVENDING:
+			return (type2&CELL_NOVENDING);
 		default:
 			return 0;
 	}
@@ -2336,6 +2338,8 @@ void map_setcell(int m,int x,int y,int cell)
 		case CELL_SETLANDPROTECTOR: map[m].cell[j] |= CELL_LANDPROTECTOR;  break;
 		case CELL_CLRLANDPROTECTOR: map[m].cell[j] &= ~CELL_LANDPROTECTOR; break;
 		case CELL_SETREGEN:         map[m].cell[j] |= CELL_REGEN;          break;
+		case CELL_SETNOVENDING:     map[m].cell[j] |= CELL_NOVENDING;      break;
+		case CELL_CLRNOVENDING:     map[m].cell[j] &= ~CELL_NOVENDING;     break;
 		default:
 			map[m].gat[j] = cell;
 			break;

+ 4 - 4
src/map/map.h

@@ -28,10 +28,6 @@
 //  but is not the official behaviour.
 //#define CIRCULAR_AREA
 
-#define MAX_PC_CLASS 4050
-#define PC_CLASS_BASE 0
-#define PC_CLASS_BASE2 (PC_CLASS_BASE + 4001)
-#define PC_CLASS_BASE3 (PC_CLASS_BASE2 + 22)
 #define MAX_NPC_PER_MAP 512
 #define BLOCK_SIZE 8
 #define AREA_SIZE battle_config.area_size
@@ -1219,6 +1215,7 @@ enum _look {
 #define CELL_SAFETYWALL	0x8
 #define CELL_LANDPROTECTOR	0x10
 #define CELL_BASILICA	0x20
+#define CELL_NOVENDING	0x40
 #define CELL_ICEWALL	0x80
 /*
  * map_getcell()で使用されるフラグ
@@ -1241,6 +1238,7 @@ typedef enum {
 	CELL_CHKLANDPROTECTOR,
 	CELL_CHKICEWALL,
 	CELL_CHKSTACK,
+	CELL_CHKNOVENDING,
 } cell_t;
 // map_setcell()で使用されるフラグ
 enum {
@@ -1257,6 +1255,8 @@ enum {
 	CELL_CLRSAFETYWALL,
 	CELL_SETICEWALL,
 	CELL_CLRICEWALL,
+	CELL_SETNOVENDING,
+	CELL_CLRNOVENDING,
 };
 
 extern struct map_data map[];

+ 5 - 0
src/map/npc.c

@@ -1463,6 +1463,11 @@ static void npc_parsename(struct npc_data* nd, const char* name, const char* sta
 		char this_mapname[32];
 		char other_mapname[32];
 		int i = 0;
+
+		//TODO: the debug message is broken, if nd->exname == NULL
+		//dnd is left uninitialized, and then is printed as that!
+		if (*nd->exname == '\0')
+			dnd = nd;  //Dumb anti-crash measure since I am not sure what this piece of code is supposed to do.
 		do
 		{
 			++i;

+ 52 - 34
src/map/pc.c

@@ -42,12 +42,12 @@
 
 
 #define PVP_CALCRANK_INTERVAL 1000	// PVP�‡ˆÊŒvŽZ‚ÌŠÔŠu
-static unsigned int exp_table[MAX_PC_CLASS][2][MAX_LEVEL];
-static unsigned int max_level[MAX_PC_CLASS][2];
+static unsigned int exp_table[CLASS_COUNT][2][MAX_LEVEL];
+static unsigned int max_level[CLASS_COUNT][2];
 static short statp[MAX_LEVEL+1];
 
 // h-files are for declarations, not for implementations... [Shinomori]
-struct skill_tree_entry skill_tree[MAX_PC_CLASS][MAX_SKILL_TREE];
+struct skill_tree_entry skill_tree[CLASS_COUNT][MAX_SKILL_TREE];
 // timer for night.day implementation
 int day_timer_tid;
 int night_timer_tid;
@@ -67,6 +67,15 @@ char motd_text[MOTD_LINE_SIZE][256]; // Message of the day buffer [Valaris]
 static const char feel_var[3][NAME_LENGTH] = {"PC_FEEL_SUN","PC_FEEL_MOON","PC_FEEL_STAR"};
 static const char hate_var[3][NAME_LENGTH] = {"PC_HATE_MOB_SUN","PC_HATE_MOB_MOON","PC_HATE_MOB_STAR"};
 
+//Converts a class to its array index for CLASS_COUNT defined arrays.
+//Note that it does not do a validity check for speed purposes, where parsing
+//player input make sure to use a pcdb_checkid first!
+int pc_class2idx(int class_) {
+	if (class_ >= JOB_NOVICE_HIGH)
+		return class_- JOB_NOVICE_HIGH+JOB_MAX_BASIC;
+	return class_;
+}
+
 int pc_isGM(struct map_session_data* sd)
 {
 	int i;
@@ -934,7 +943,7 @@ int pc_calc_skilltree(struct map_session_data *sd)
 			ShowError("pc_calc_skilltree: Unable to normalize job %d for character %s (%d:%d)\n", i, sd->status.name, sd->status.account_id, sd->status.char_id);
 		return 1;
 	}
-	
+	c = pc_class2idx(c);	
 	for(i=0;i<MAX_SKILL;i++){ 
 		if (sd->status.skill[i].flag != 13) //Don't touch plagiarized skills
 			sd->status.skill[i].id=0; //First clear skills.
@@ -1054,7 +1063,7 @@ static void pc_check_skilltree(struct map_session_data *sd, int skill)
 			ShowError("pc_check_skilltree: Unable to normalize job %d for character %s (%d:%d)\n", i, sd->status.name, sd->status.account_id, sd->status.char_id);
 		return;
 	}
-	
+	c = pc_class2idx(c);	
 	do {
 		flag=0;
 		for(i=0;i < MAX_SKILL_TREE && (id=skill_tree[c][i].id)>0;i++){
@@ -3008,7 +3017,7 @@ int pc_isUseitem(struct map_session_data *sd,int n)
 	if(item == NULL)
 		return 0;
 	//Not consumable item
-	if(item->type != 0 && item->type != 2)
+	if(item->type != IT_HEALING && item->type != IT_USABLE)
 		return 0;
 	if(!item->script) //if it has no script, you can't really consume it!
 		return 0;
@@ -3106,6 +3115,9 @@ int pc_useitem(struct map_session_data *sd,int n)
 
 	sd->itemid = sd->status.inventory[n].nameid;
 	sd->itemindex = n;
+	if(sd->catch_target_class != -1) //Abort pet catching.
+		sd->catch_target_class = -1;
+
 	amount = sd->status.inventory[n].amount;
 	script = sd->inventory_data[n]->script;
 	//Check if the item is to be consumed immediately [Skotlex]
@@ -4313,12 +4325,12 @@ int pc_gainexp(struct map_session_data *sd, struct block_list *src, unsigned int
  *------------------------------------------*/
 unsigned int pc_maxbaselv(struct map_session_data *sd)
 {
-  	return max_level[sd->status.class_][0];
+  	return max_level[pc_class2idx(sd->status.class_)][0];
 };
 
 unsigned int pc_maxjoblv(struct map_session_data *sd)
 {
-  	return max_level[sd->status.class_][1];
+  	return max_level[pc_class2idx(sd->status.class_)][1];
 };
 
 /*==========================================
@@ -4331,7 +4343,7 @@ unsigned int pc_nextbaseexp(struct map_session_data *sd)
 	if(sd->status.base_level>=pc_maxbaselv(sd) || sd->status.base_level<=0)
 		return 0;
 
-	return exp_table[sd->status.class_][0][sd->status.base_level-1];
+	return exp_table[pc_class2idx(sd->status.class_)][0][sd->status.base_level-1];
 }
 
 /*==========================================
@@ -4343,7 +4355,7 @@ unsigned int pc_nextjobexp(struct map_session_data *sd)
 
 	if(sd->status.job_level>=pc_maxjoblv(sd) || sd->status.job_level<=0)
 		return 0;
-	return exp_table[sd->status.class_][1][sd->status.job_level-1];
+	return exp_table[pc_class2idx(sd->status.class_)][1][sd->status.job_level-1];
 }
 
 /*==========================================
@@ -4584,7 +4596,7 @@ int pc_allskillup(struct map_session_data *sd)
 	else
 	{
 		int inf2;
-		for(i=0;i < MAX_SKILL_TREE && (id=skill_tree[sd->status.class_][i].id)>0;i++){
+		for(i=0;i < MAX_SKILL_TREE && (id=skill_tree[pc_class2idx(sd->status.class_)][i].id)>0;i++){
 			inf2 = skill_get_inf2(id);
 			if (
 				(inf2&INF2_QUEST_SKILL && !battle_config.quest_skill_learn) ||
@@ -7330,7 +7342,7 @@ int pc_readdb(void)
 	}
 	while(fgets(line, sizeof(line), fp))
 	{
-		int jobs[MAX_PC_CLASS], job_count, job;
+		int jobs[CLASS_COUNT], job_count, job, job_id;
 		int type;
 		unsigned int ui,maxlv;
 		char *split[4];
@@ -7339,12 +7351,12 @@ int pc_readdb(void)
 		if (pc_split_str(line,split,4) < 4)
 			continue;
 		
-		job_count = pc_split_atoi(split[1],jobs,':',MAX_PC_CLASS);
+		job_count = pc_split_atoi(split[1],jobs,':',CLASS_COUNT);
 		if (job_count < 1)
 			continue;
-		job = jobs[0];
-		if (!pcdb_checkid(job)) {
-			ShowError("pc_readdb: Invalid job ID %d.\n", job);
+		job_id = jobs[0];
+		if (!pcdb_checkid(job_id)) {
+			ShowError("pc_readdb: Invalid job ID %d.\n", job_id);
 			continue;
 		}
 		type = atoi(split[2]);
@@ -7354,9 +7366,11 @@ int pc_readdb(void)
 		}
 		maxlv = atoi(split[0]);
 		if (maxlv > MAX_LEVEL) {
-			ShowWarning("pc_readdb: Specified max level %u for job %d is beyond server's limit (%u).\n ", maxlv, job, MAX_LEVEL);
+			ShowWarning("pc_readdb: Specified max level %u for job %d is beyond server's limit (%u).\n ", maxlv, job_id, MAX_LEVEL);
 			maxlv = MAX_LEVEL;
 		}
+		
+		job = jobs[0] = pc_class2idx(job_id);
 		//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_atoui(split[3], exp_table[job][type],',',maxlv-1)+1;
 		//Reverse check in case the array has a bunch of trailing zeros... [Skotlex]
@@ -7366,7 +7380,7 @@ int pc_readdb(void)
 		while ((ui = max_level[job][type]) >= 2 && exp_table[job][type][ui-2] <= 0)
 			max_level[job][type]--;
 		if (max_level[job][type] < maxlv) {
-			ShowWarning("pc_readdb: Specified max %u for job %d, but that job's exp table only goes up to level %u.\n", maxlv, job, max_level[job][type]);
+			ShowWarning("pc_readdb: Specified max %u for job %d, but that job's exp table only goes up to level %u.\n", maxlv, job_id, max_level[job][type]);
 			ShowInfo("Filling the missing values with the last exp entry.\n");
 			//Fill the requested values with the last entry.
 			ui = (max_level[job][type] <= 2? 0: max_level[job][type]-2);
@@ -7374,26 +7388,28 @@ int pc_readdb(void)
 				exp_table[job][type][ui] = exp_table[job][type][ui-1];
 			max_level[job][type] = maxlv;
 		}
-//		ShowDebug("%s - Class %d: %d\n", type?"Job":"Base", job, max_level[job][type]);
+//		ShowDebug("%s - Class %d: %d\n", type?"Job":"Base", job_id, 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);
+			job_id = jobs[i];
+			if (!pcdb_checkid(job_id)) {
+				ShowError("pc_readdb: Invalid job ID %d.\n", job_id);
 				continue;
 			}
+			job = pc_class2idx(job_id);
 			memcpy(exp_table[job][type], exp_table[jobs[0]][type], sizeof(exp_table[0][0]));
 			max_level[job][type] = maxlv;
-//			ShowDebug("%s - Class %d: %u\n", type?"Job":"Base", job, max_level[job][type]);
+//			ShowDebug("%s - Class %d: %u\n", type?"Job":"Base", job_id, max_level[job][type]);
 		}
 	}
 	fclose(fp);
-	for (i = 0; i < MAX_PC_CLASS; i++) {
+	for (i = 0; i < JOB_MAX; i++) {
 		if (!pcdb_checkid(i)) continue;
 		if (i == JOB_WEDDING || i == JOB_XMAS || i == JOB_SUMMER)
 			continue; //Classes that do not need exp tables.
-		if (!max_level[i][0])
+		j = pc_class2idx(i);
+		if (!max_level[j][0])
 			ShowWarning("Class %s (%d) does not has a base exp table.\n", job_name(i), i);
-		if (!max_level[i][1])
+		if (!max_level[j][1])
 			ShowWarning("Class %s (%d) does not has a job exp table.\n", job_name(i), i);
 	}
 	ShowStatus("Done reading '"CL_WHITE"%s"CL_RESET"'.\n","exp.txt");
@@ -7410,7 +7426,7 @@ int pc_readdb(void)
 	while(fgets(line, sizeof(line), fp))
 	{
 		char *split[50];
-		int f=0, m=3;
+		int f=0, m=3, idx;
 		if(line[0]=='/' && line[1]=='/')
 			continue;
 		for(j=0,p=line;j<14 && p;j++){
@@ -7425,22 +7441,24 @@ int pc_readdb(void)
 			m++;
 		}
 		// check for bounds [celest]
-		if (atoi(split[0]) >= MAX_PC_CLASS)
+		idx = atoi(split[0]);
+		if(!pcdb_checkid(idx))
 			continue;
+		idx = pc_class2idx(idx);
 		k = atoi(split[1]); //This is to avoid adding two lines for the same skill. [Skotlex]
-		for(j = 0; j < MAX_SKILL_TREE && skill_tree[atoi(split[0])][j].id && skill_tree[atoi(split[0])][j].id != k; j++);
+		for(j = 0; j < MAX_SKILL_TREE && skill_tree[idx][j].id && skill_tree[idx][j].id != k; j++);
 		if (j == MAX_SKILL_TREE)
 		{
 			ShowWarning("Unable to load skill %d into job %d's tree. Maximum number of skills per class has been reached.\n", k, atoi(split[0]));
 			continue;
 		}
-		skill_tree[atoi(split[0])][j].id=k;
-		skill_tree[atoi(split[0])][j].max=atoi(split[2]);
-		if (f) skill_tree[atoi(split[0])][j].joblv=atoi(split[3]);
+		skill_tree[idx][j].id=k;
+		skill_tree[idx][j].max=atoi(split[2]);
+		if (f) skill_tree[idx][j].joblv=atoi(split[3]);
 
 		for(k=0;k<5;k++){
-			skill_tree[atoi(split[0])][j].need[k].id=atoi(split[k*2+m]);
-			skill_tree[atoi(split[0])][j].need[k].lv=atoi(split[k*2+m+1]);
+			skill_tree[idx][j].need[k].id=atoi(split[k*2+m]);
+			skill_tree[idx][j].need[k].lv=atoi(split[k*2+m+1]);
 		}
 	}
 	fclose(fp);

+ 6 - 3
src/map/pc.h

@@ -7,12 +7,14 @@
 #include "../common/mmo.h" // JOB_*, MAX_FAME_LIST, struct fame_list, struct mmo_charstatus
 #include "../common/timer.h" // INVALID_TIMER
 #include "battle.h" // battle_config
-#include "map.h" // MAX_PC_CLASS, struct map_session_data
+#include "map.h" // struct map_session_data
 #include "status.h" // OPTION_*
 #include "unit.h" // unit_stop_attack(), unit_stop_walking()
 
 //Update this max as necessary. 54 is the value needed for Super Baby currently
 #define MAX_SKILL_TREE 54
+//Total number of classes (for data storage)
+#define CLASS_COUNT (JOB_MAX - JOB_NOVICE_HIGH + JOB_MAX_BASIC)
 
 enum {
 	W_FIST,	//Bare hands
@@ -115,8 +117,9 @@ enum {
 #define pc_check_weapontype(sd, type) ((type)&((sd)->status.weapon < MAX_WEAPON_TYPE? \
 	1<<(sd)->status.weapon:(1<<(sd)->weapontype1)|(1<<(sd)->weapontype2)))
 //Checks if the given class value corresponds to a player class. [Skotlex]
-#define pcdb_checkid(class_) (class_ <= JOB_SUMMER || (class_ >= JOB_NOVICE_HIGH && class_ <= JOB_SOUL_LINKER))
+#define pcdb_checkid(class_) (class_ < JOB_MAX_BASIC || (class_ >= JOB_NOVICE_HIGH && class_ < JOB_MAX))
 
+int pc_class2idx(int class_);
 int pc_isGM(struct map_session_data *sd);
 int pc_getrefinebonus(int lv,int type);
 int pc_can_give_items(int level); //[Lupus]
@@ -289,7 +292,7 @@ struct skill_tree_entry {
 		unsigned char lv;
 	} need[5];
 }; // Celest
-extern struct skill_tree_entry skill_tree[MAX_PC_CLASS][MAX_SKILL_TREE];
+extern struct skill_tree_entry skill_tree[CLASS_COUNT][MAX_SKILL_TREE];
 
 int pc_read_gm_account(int fd);
 void pc_setinvincibletimer(struct map_session_data* sd, int val);

+ 1 - 1
src/map/script.c

@@ -5331,7 +5331,7 @@ BUILDIN_FUNC(jobchange)
 	if( script_hasdata(st,3) )
 		upper=script_getnum(st,3);
 
-	if ((job >= 0 && job < MAX_PC_CLASS))
+	if (pcdb_checkid(job))
 	{
 		pc_jobchange(script_rid2sd(st),job, upper);
 		if(use_irc && irc_announce_jobchange_flag)

+ 37 - 26
src/map/status.c

@@ -45,16 +45,16 @@ int StatusIconChangeTable[SC_MAX]; //Stores the icon that should be associated t
 int StatusSkillChangeTable[SC_MAX]; //Stores the skill that should be considered associated to this status change. 
 unsigned long StatusChangeFlagTable[SC_MAX]; //Stores the flag specifying what this SC changes.
 
-static int max_weight_base[MAX_PC_CLASS];
-static int hp_coefficient[MAX_PC_CLASS];
-static int hp_coefficient2[MAX_PC_CLASS];
-static int hp_sigma_val[MAX_PC_CLASS][MAX_LEVEL+1];
-static int sp_coefficient[MAX_PC_CLASS];
-static int aspd_base[MAX_PC_CLASS][MAX_WEAPON_TYPE];	//[blackhole89]
+static int max_weight_base[CLASS_COUNT];
+static int hp_coefficient[CLASS_COUNT];
+static int hp_coefficient2[CLASS_COUNT];
+static int hp_sigma_val[CLASS_COUNT][MAX_LEVEL+1];
+static int sp_coefficient[CLASS_COUNT];
+static int aspd_base[CLASS_COUNT][MAX_WEAPON_TYPE];	//[blackhole89]
 static int refinebonus[MAX_REFINE_BONUS][3];	// 精錬ボーナステーブル(refine_db.txt)
 int percentrefinery[5][MAX_REFINE+1];	// 精錬成功率(refine_db.txt)
 static int atkmods[3][MAX_WEAPON_TYPE];	// 武器ATKサイズ修正(size_fix.txt)
-static char job_bonus[MAX_PC_CLASS][MAX_LEVEL];
+static char job_bonus[CLASS_COUNT][MAX_LEVEL];
 
 static struct status_data dummy_status;
 int current_equip_item_index; //Contains inventory index of an equipped item. To pass it into the EQUP_SCRIPT [Lupus]
@@ -584,6 +584,13 @@ int status_set_sp(struct block_list *bl, unsigned int sp, int flag)
 	return status_zap(bl, 0, status->sp - sp);
 }
 
+int status_charge(struct block_list* bl, int hp, int sp)
+{
+	if(!((bl)->type&BL_CONSUME))
+		return hp+sp; //Assume all was charged so there are no 'not enough' fails.
+	return status_damage(NULL, bl, hp, sp, 0, 3);
+}
+
 //Inflicts damage on the target with the according walkdelay.
 //If flag&1, damage is passive and does not triggers cancelling status changes.
 //If flag&2, fail if target does not has enough to substract.
@@ -1189,8 +1196,8 @@ int status_base_amotion_pc(struct map_session_data* sd, struct status_data* stat
 	
 	// base weapon delay
 	amotion = (sd->status.weapon < MAX_WEAPON_TYPE)
-	 ? (aspd_base[sd->status.class_][sd->status.weapon]) // single weapon
-	 : (aspd_base[sd->status.class_][sd->weapontype1] + aspd_base[sd->status.class_][sd->weapontype2])*7/10; // dual-wield
+	 ? (aspd_base[pc_class2idx(sd->status.class_)][sd->status.weapon]) // single weapon
+	 : (aspd_base[pc_class2idx(sd->status.class_)][sd->weapontype1] + aspd_base[pc_class2idx(sd->status.class_)][sd->weapontype2])*7/10; // dual-wield
 	
 	// percentual delay reduction from stats
 	amotion-= amotion * (4*status->agi + status->dex)/1000;
@@ -1517,7 +1524,7 @@ static void status_calc_sigma(void)
 {
 	int i,j;
 
-	for(i = 0; i < MAX_PC_CLASS; i++)
+	for(i = 0; i < CLASS_COUNT; i++)
 	{
 		unsigned int k = 0;
 		hp_sigma_val[i][0] = hp_sigma_val[i][1] = 0;
@@ -1540,8 +1547,8 @@ static void status_calc_sigma(void)
 ///    f(x) = 35 + x*(A + B*C/D) + sum(i=2..x){ i*C/D }
 static unsigned int status_base_pc_maxhp(struct map_session_data* sd, struct status_data* status)
 {
-	unsigned int val;
-	val = 35 + sd->status.base_level*hp_coefficient2[sd->status.class_]/100 + hp_sigma_val[sd->status.class_][sd->status.base_level];
+	unsigned int val = pc_class2idx(sd->status.class_);
+	val = 35 + sd->status.base_level*hp_coefficient2[val]/100 + hp_sigma_val[val][sd->status.base_level];
 
 	if((sd->class_&MAPID_UPPERMASK) == MAPID_NINJA || (sd->class_&MAPID_UPPERMASK) == MAPID_GUNSLINGER)
 		val += 100; //Since their HP can't be approximated well enough without this.
@@ -1563,7 +1570,7 @@ static unsigned int status_base_pc_maxsp(struct map_session_data* sd, struct sta
 {
 	unsigned int val;
 
-	val = 10 + sd->status.base_level*sp_coefficient[sd->status.class_]/100;
+	val = 10 + sd->status.base_level*sp_coefficient[pc_class2idx(sd->status.class_)]/100;
 	val += val * status->int_/100;
 
 	if (sd->class_&JOBL_UPPER)
@@ -1606,7 +1613,7 @@ int status_calc_pc(struct map_session_data* sd,int first)
 
 	pc_calc_skilltree(sd);	// スキルツリ?の計算
 
-	sd->max_weight = max_weight_base[sd->status.class_]+sd->status.str*300;
+	sd->max_weight = max_weight_base[pc_class2idx(sd->status.class_)]+sd->status.str*300;
 
 	if(first&1) {
 		//Load Hp/SP from char-received data.
@@ -1959,10 +1966,11 @@ int status_calc_pc(struct map_session_data* sd,int first)
 // ----- STATS CALCULATION -----
 
 	// Job bonuses
+	index = pc_class2idx(sd->status.class_);
 	for(i=0;i<(int)sd->status.job_level && i<MAX_LEVEL;i++){
-		if(!job_bonus[sd->status.class_][i])
+		if(!job_bonus[index][i])
 			continue;
-		switch(job_bonus[sd->status.class_][i]) {
+		switch(job_bonus[index][i]) {
 			case 1: status->str++; break;
 			case 2: status->agi++; break;
 			case 3: status->vit++; break;
@@ -7296,7 +7304,7 @@ static int status_natural_heal_timer(int tid,unsigned int tick,int id,int data)
 
 int status_readdb(void)
 {
-	int i,j;
+	int i,j,class_;
 	FILE *fp;
 	char line[1024], path[1024],*p;
 
@@ -7323,15 +7331,16 @@ int status_readdb(void)
 			ShowDebug("%s: Not enough columns at line %d\n", path, i);
 			continue;
 		}
-		if(atoi(split[0])>=MAX_PC_CLASS)
+		class_ = atoi(split[0]);
+		if(!pcdb_checkid(class_))
 			continue;
-		
-		max_weight_base[atoi(split[0])]=atoi(split[1]);
-		hp_coefficient[atoi(split[0])]=atoi(split[2]);
-		hp_coefficient2[atoi(split[0])]=atoi(split[3]);
-		sp_coefficient[atoi(split[0])]=atoi(split[4]);
+		class_ = pc_class2idx(class_);
+		max_weight_base[class_]=atoi(split[1]);
+		hp_coefficient[class_]=atoi(split[2]);
+		hp_coefficient2[class_]=atoi(split[3]);
+		sp_coefficient[class_]=atoi(split[4]);
 		for(j=0;j<MAX_WEAPON_TYPE;j++)
-			aspd_base[atoi(split[0])][j]=atoi(split[j+5]);
+			aspd_base[class_][j]=atoi(split[j+5]);
 	}
 	fclose(fp);
 	ShowStatus("Done reading '"CL_WHITE"%s"CL_RESET"'.\n",path);
@@ -7353,10 +7362,12 @@ int status_readdb(void)
 			p=strchr(p,',');
 			if(p) *p++=0;
 		}
-		if(atoi(split[0])>=MAX_PC_CLASS)
+		class_ = atoi(split[0]);
+		if(!pcdb_checkid(class_))
 		    continue;
+		class_ = pc_class2idx(class_);
 		for(i=1;i<j && split[i];i++)
-			job_bonus[atoi(split[0])][i-1]=atoi(split[i]);
+			job_bonus[class_][i-1]=atoi(split[i]);
 	}
 	fclose(fp);
 	ShowStatus("Done reading '"CL_WHITE"%s"CL_RESET"'.\n",path);

+ 1 - 1
src/map/status.h

@@ -579,7 +579,7 @@ int status_damage(struct block_list *src,struct block_list *target,int hp,int sp
 //Define for standard HP/SP damage triggers.
 #define status_zap(bl, hp, sp) status_damage(NULL, bl, hp, sp, 0, 1)
 //Define for standard HP/SP skill-related cost triggers (mobs require no HP/SP to use skills)
-#define status_charge(bl, hp, sp) (!((bl)->type&BL_CONSUME) || status_damage(NULL, bl, hp, sp, 0, 3))
+int status_charge(struct block_list* bl, int hp, int sp);
 int status_percent_change(struct block_list *src,struct block_list *target,signed char hp_rate, signed char sp_rate, int flag);
 //Easier handling of status_percent_change
 #define status_percent_heal(bl, hp_rate, sp_rate) status_percent_change(NULL, bl, -(hp_rate), -(sp_rate), 1)

+ 6 - 0
src/map/vending.c

@@ -236,6 +236,12 @@ void vending_openvending(struct map_session_data* sd, const char* message, bool
 		clif_skill_fail(sd, MC_VENDING, 0, 0);
 		return;
 	}
+	
+	if ( map_getcell(sd->bl.m,sd->bl.x,sd->bl.y,CELL_CHKNOVENDING) )
+	{
+		clif_displaymessage (sd->fd, msg_txt(276));
+		return; //Can't vend in novending mapflag maps.
+	}
 
 	// check number of items in shop
 	if( count < 1 || count > MAX_VENDING || count > 2 + vending_skill_lvl )