浏览代码

* Resolved issues with item delay system.
- Fixed random crashes caused by map_session_data corruption due to out-of-bounds access to item_delay array (bugreport:4568, since r14455).
- Fixed item delay database not being compatible with @reloaditemdb. Item delays are now reset upon reloading, much like a restart would do (bugreport:4589).
- Fixed trailing commented lines in db/item_delay.txt could cause 'too many entries' error to be displayed.
- Fixed last entity of a cash food item not being recognized as cash food, thus not receiving use delay, due to access to deleted inventory slot (since r14426).
- These changes also fix a warning regarding variable 'i' in pc_useitem being potentionally uninitialized (bugreport:4559).

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

ai4rei 14 年之前
父节点
当前提交
c634198301
共有 4 个文件被更改,包括 36 次插入24 次删除
  1. 7 0
      Changelog-Trunk.txt
  2. 0 1
      db/item_delay.txt
  3. 6 5
      src/map/itemdb.c
  4. 23 18
      src/map/pc.c

+ 7 - 0
Changelog-Trunk.txt

@@ -1,5 +1,12 @@
 Date	Added
 
+2010/11/29
+	* Resolved issues with item delay system. [Ai4rei]
+	- Fixed random crashes caused by map_session_data corruption due to out-of-bounds access to item_delay array (bugreport:4568, since r14455).
+	- Fixed item delay database not being compatible with @reloaditemdb. Item delays are now reset upon reloading, much like a restart would do (bugreport:4589).
+	- Fixed trailing commented lines in db/item_delay.txt could cause 'too many entries' error to be displayed.
+	- Fixed last entity of a cash food item not being recognized as cash food, thus not receiving use delay, due to access to deleted inventory slot (since r14426).
+	- These changes also fix a warning regarding variable 'i' in pc_useitem being potentionally uninitialized (bugreport:4559).
 2010/11/28
 	* Added an option to re-roll the /dice emotion server-side, to prevent cheats during events (bugreport:4194). [Ai4rei]
 	* Added emotion_type enumeration for clif_emotion constants. [Ai4rei]

+ 0 - 1
db/item_delay.txt

@@ -1,6 +1,5 @@
 // Item Delay Database
 // Max number of entries is defined in itemdb.h as MAX_ITEMDELAYS
-// WARNING: Adding/removing/modifying entries here and then using @reloaditemdb will cause problems/inconsistencies!
 //
 // Structure:
 // Item ID,Delay in Milliseconds

+ 6 - 5
src/map/itemdb.c

@@ -27,8 +27,6 @@ static struct item_group itemgroup_db[MAX_ITEMGROUP];
 
 struct item_data dummy_item; //This is the default dummy item used for non-existant items. [Skotlex]
 
-int item_delays = 0;
-
 /*==========================================
  * –¼‘O‚ÅŒŸ�õ—p
  *------------------------------------------*/
@@ -667,7 +665,7 @@ static int itemdb_read_itemtrade(void)
 static int itemdb_read_itemdelay(void)
 {
 	FILE *fp;
-	int nameid, j;
+	int nameid, j, item_delays = 0;
 	char line[1024], *str[10], *p;
 	struct item_data *id;
 
@@ -679,12 +677,12 @@ static int itemdb_read_itemdelay(void)
 
 	while(fgets(line, sizeof(line), fp))
 	{
+		if (line[0] == '/' && line[1] == '/')
+			continue;
 		if (item_delays == MAX_ITEMDELAYS) {
 			ShowError("itemdb_read_itemdelay: Too many entries specified in %s/item_delay.txt! Increase MAX_ITEMDELAYS in itemdb.h!\n", db_path);
 			break;
 		}
-		if (line[0] == '/' && line[1] == '/')
-			continue;
 		memset(str, 0, sizeof(str));
 		for (j = 0, p = line; j < 2 && p; j++) {
 			str[j] = p;
@@ -1075,7 +1073,10 @@ void itemdb_reload(void)
 	// readjust itemdb pointer cache for each player
 	iter = mapit_geteachpc();
 	for( sd = (struct map_session_data*)mapit_first(iter); mapit_exists(iter); sd = (struct map_session_data*)mapit_next(iter) )
+	{
+		memset(sd->item_delay, 0, sizeof(sd->item_delay));  // reset item delays
 		pc_setinventorydata(sd);
+	}
 	mapit_free(iter);
 }
 

+ 23 - 18
src/map/pc.c

@@ -66,8 +66,6 @@ char motd_text[MOTD_LINE_SIZE][256]; // Message of the day buffer [Valaris]
 struct duel duel_list[MAX_DUEL];
 int duel_count = 0;
 
-extern int item_delays; // [Paradox924X]
-
 //Links related info to the sd->hate_mob[]/sd->feel_map[] entries
 const struct sg_data sg_info[3] = {
 		{ SG_SUN_ANGER, SG_SUN_BLESS, SG_SUN_COMFORT, "PC_FEEL_SUN", "PC_HATE_MOB_SUN", is_day_of_sun },
@@ -532,11 +530,6 @@ int pc_setinventorydata(struct map_session_data *sd)
 	for(i=0;i<MAX_INVENTORY;i++) {
 		id = sd->status.inventory[i].nameid;
 		sd->inventory_data[i] = id?itemdb_search(id):NULL;
-		if(sd->inventory_data[i] && sd->inventory_data[i]->delay > 0) { // Load delays
-			sd->item_delay[item_delays].nameid = sd->inventory_data[i]->nameid;
-			sd->item_delay[item_delays].tick = 0;
-			++item_delays;
-		}
 	}
 	return 0;
 }
@@ -3662,7 +3655,7 @@ int pc_isUseitem(struct map_session_data *sd,int n)
  *------------------------------------------*/
 int pc_useitem(struct map_session_data *sd,int n)
 {
-	unsigned int delay, tick = gettick();
+	unsigned int tick = gettick();
 	int amount, i, nameid;
 	struct script_code *script;
 
@@ -3691,13 +3684,6 @@ int pc_useitem(struct map_session_data *sd,int n)
 
 	// Store information for later use before it is lost (via pc_delitem) [Paradox924X]
 	nameid = sd->inventory_data[n]->nameid;
-	delay = sd->inventory_data[n]->delay;
-
-	if( sd->inventory_data[n]->delay > 0 ) { // Check if there is a delay on this item [Paradox924X]
-		ARR_FIND(0, item_delays, i, sd->item_delay[i].nameid == nameid);
-		if( i < item_delays && DIFF_TICK(sd->item_delay[i].tick, tick) > 0 )
-			return 0; // Delay has not expired yet
-	}
 
 	//Since most delay-consume items involve using a "skill-type" target cursor,
 	//perform a skill-use check before going through. [Skotlex]
@@ -3706,6 +3692,27 @@ int pc_useitem(struct map_session_data *sd,int n)
 	if( sd->inventory_data[n]->flag.delay_consume && ( sd->ud.skilltimer != -1 /*|| !status_check_skilluse(&sd->bl, &sd->bl, ALL_RESURRECTION, 0)*/ ) )
 		return 0;
 
+	if( sd->inventory_data[n]->delay > 0 ) { // Check if there is a delay on this item [Paradox924X]
+		ARR_FIND(0, MAX_ITEMDELAYS, i, sd->item_delay[i].nameid == nameid || !sd->item_delay[i].nameid);
+		if( i < MAX_ITEMDELAYS )
+		{
+			if( sd->item_delay[i].nameid )
+			{// found
+				if( DIFF_TICK(sd->item_delay[i].tick, tick) > 0 )
+					return 0; // Delay has not expired yet
+			}
+			else
+			{// not yet used item (all slots are initially empty)
+				sd->item_delay[i].nameid = nameid;
+			}
+			sd->item_delay[i].tick = tick + sd->inventory_data[n]->delay;
+		}
+		else
+		{// should not happen
+			ShowError("pc_useitem: Exceeded item delay array capacity! (nameid=%d, char_id=%d)\n", nameid, sd->status.char_id);
+		}
+	}
+
 	sd->itemid = sd->status.inventory[n].nameid;
 	sd->itemindex = n;
 	if(sd->catch_target_class != -1) //Abort pet catching.
@@ -3741,10 +3748,8 @@ int pc_useitem(struct map_session_data *sd,int n)
 
 	//Update item use time.
 	sd->canuseitem_tick = tick + battle_config.item_use_interval;
-	if( itemdb_iscashfood(sd->status.inventory[n].nameid) )
+	if( itemdb_iscashfood(nameid) )
 		sd->canusecashfood_tick = tick + battle_config.cashfood_use_interval;
-	if( delay > 0 && i < item_delays )
-		sd->item_delay[i].tick = tick + delay;
 
 	run_script(script,0,sd->bl.id,fake_nd->bl.id);
 	potion_flag = 0;