瀏覽代碼

Fixed sql char deletion code using a broken pet deletion query (ran very slow, and had a typo in a binary shift operation) (bugreport:3304).
Fixed change r13774 to the code responsible for deciding whether to move 1 extra cell when stopping walking; it had its logic inverted by mistake (bugreport:3312).
Cleaned up the itemlist, cartlist and storagelist gm command code:
- fixed buffer overflows in all three functions (bugreport:456).
- merged all three atcommand functions into a single one; the appropriate behavior is detected from the command's name.
- using the StringBuf class instead of static-size buffers and string operations for more efficient and safe processing.
- using 'jname' (the one without underscores) as the primary item name in the list, and not using the aegis name for cards at all (since it's almost identical).
- fixed forged item details never being displayed due to a missing strcat().
- extended item info (crafted/named items, pet eggs) will now be displayed for storage and cart list as well.

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

ultramage 16 年之前
父節點
當前提交
e54bf092d2
共有 3 個文件被更改,包括 150 次插入218 次删除
  1. 3 5
      src/char_sql/char.c
  2. 143 209
      src/map/atcommand.c
  3. 4 4
      src/map/unit.c

+ 3 - 5
src/char_sql/char.c

@@ -1373,11 +1373,9 @@ int delete_char_sql(int char_id)
 		Sql_ShowDebug(sql_handle);
 
 	//Delete all pets that are stored in eggs (inventory + cart)
-	if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE pet_id IN "
-		"(SELECT card1|card2<<2 FROM `%s` WHERE char_id = '%d' AND card0 = -256"
-		" UNION"
-		" SELECT card1|card2<<2 FROM `%s` WHERE char_id = '%d' AND card0 = -256)",
-		pet_db, inventory_db, char_id, cart_db, char_id) )
+	if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` USING `%s` JOIN `%s` ON `pet_id` = `card1`|`card2`<<16 WHERE `%s`.char_id = '%d' AND card0 = -256", pet_db, pet_db, inventory_db, inventory_db, char_id) )
+		Sql_ShowDebug(sql_handle);
+	if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` USING `%s` JOIN `%s` ON `pet_id` = `card1`|`card2`<<16 WHERE `%s`.char_id = '%d' AND card0 = -256", pet_db, pet_db, cart_db, cart_db, char_id) )
 		Sql_ShowDebug(sql_handle);
 
 	/* remove homunculus */ 

+ 143 - 209
src/map/atcommand.c

@@ -8221,238 +8221,173 @@ int atcommand_resetskill(const int fd, struct map_session_data* sd, const char*
 }
 
 /*==========================================
- * #storagelist <character>: Displays the items list of a player's storage.
+ * #storagelist: Displays the items list of a player's storage.
+ * #cartlist: Displays contents of target's cart.
+ * #itemlist: Displays contents of target's inventory.
  *------------------------------------------*/
-int atcommand_storagelist(const int fd, struct map_session_data* sd, const char* command, const char* message)
+int atcommand_itemlist(const int fd, struct map_session_data* sd, const char* command, const char* message)
 {
-	struct item_data *item_data, *item_temp;
-	int i, j, count = 0, counter = 0, counter2 = 0;
-	char character[NAME_LENGTH], output[200], outputtmp[200];
+	int i, j, count, counter;
+	const char* location;
+	const struct item* items;
+	int size;
+	StringBuf buf;
+
 	nullpo_retr(-1, sd);
 
-	memset(character, '\0', sizeof(character));
-	memset(output, '\0', sizeof(output));
-	memset(outputtmp, '\0', sizeof(outputtmp));
+	if( strcmp(command+1, "storagelist") == 0 )
+	{
+		location = "storage";
+		items = sd->status.storage.items;
+		size = MAX_STORAGE;
+	}
+	else
+	if( strcmp(command+1, "cartlist") == 0 )
+	{
+		location = "cart";
+		items = sd->status.cart;
+		size = MAX_CART;
+	}
+	else
+	if( strcmp(command+1, "itemlist") == 0 )
+	{
+		location = "inventory";
+		items = sd->status.inventory;
+		size = MAX_INVENTORY;
+	}
+	else
+		return 1;
+
+	StringBuf_Init(&buf);
 
-	for (i = 0; i < MAX_STORAGE; i++)
+	count = 0; // total slots occupied
+	counter = 0; // total items found
+	for( i = 0; i < size; ++i )
 	{
-		struct item* it = &sd->status.storage.items[i];
-		if( it->nameid > 0 && (item_data = itemdb_search(it->nameid)) != NULL )
-		{
-			counter = counter + it->amount;
-			count++;
-			if (count == 1) {
-				sprintf(output, "------ Storage items list of '%s' ------", sd->status.name);
-				clif_displaymessage(fd, output);
-			}
-			if (it->refine)
-				sprintf(output, "%d %s %+d (%s %+d, id: %d)", it->amount, item_data->name, it->refine, item_data->jname, it->refine, it->nameid);
-			else
-				sprintf(output, "%d %s (%s, id: %d)", it->amount, item_data->name, item_data->jname, it->nameid);
-			clif_displaymessage(fd, output);
+		const struct item* it = &items[i];
+		struct item_data* itd;
 
-			memset(output, '\0', sizeof(output));
-			counter2 = 0;
-			for (j = 0; j < item_data->slot; j++) {
-				if (it->card[j]) {
-					if ((item_temp = itemdb_search(it->card[j])) != NULL) {
-						if (output[0] == '\0')
-							sprintf(outputtmp, " -> (card(s): #%d %s (%s), ", ++counter2, item_temp->name, item_temp->jname);
-						else
-							sprintf(outputtmp, "#%d %s (%s), ", ++counter2, item_temp->name, item_temp->jname);
-						strcat(output, outputtmp);
-					}
-				}
-			}
-			if (output[0] != '\0') {
-				output[strlen(output) - 2] = ')';
-				output[strlen(output) - 1] = '\0';
-				clif_displaymessage(fd, output);
-			}
-		}
-	}
+		if( it->nameid == 0 || (itd = itemdb_search(it->nameid)) == NULL )
+			continue;
 
-	if (count == 0)
-		clif_displaymessage(fd, "No item found in the storage of this player.");
-	else {
-		sprintf(output, "%d item(s) found in %d kind(s) of items.", counter, count);
-		clif_displaymessage(fd, output);
-	}
+		counter += it->amount;
+		count++;
 
-	return 0;
-}
+		if( count == 1 )
+		{
+			StringBuf_Printf(&buf, "------ %s items list of '%s' ------", location, sd->status.name);
+			clif_displaymessage(fd, StringBuf_Value(&buf));
+			StringBuf_Clear(&buf);
+		}
 
-/*==========================================
- * Displays contents of target's cart [HiddenDragon]
- *------------------------------------------*/
-int atcommand_cart_list(const int fd, struct map_session_data* sd, const char* command, const char* message)
-{
-	char outputtmp[200];
-	char output[200];
-	char character[NAME_LENGTH];
-	struct item_data *item_data, *item_temp;
-	int i, j, count = 0, counter = 0, counter2;
-	nullpo_retr(-1, sd);
+		if( it->refine )
+			StringBuf_Printf(&buf, "%d %s %+d (%s, id: %d)", it->amount, itd->jname, it->refine, itd->name, it->nameid);
+		else
+			StringBuf_Printf(&buf, "%d %s (%s, id: %d)", it->amount, itd->jname, itd->name, it->nameid);
 
-	memset(character, '\0', sizeof(character));
-	memset(output, '\0', sizeof(output));
-	memset(outputtmp, '\0', sizeof(outputtmp));
+		if( it->equip )
+		{
+			char equipstr[200];
+			strcpy(equipstr, " | equipped: ");
+			if( it->equip & EQP_GARMENT )
+				strcat(equipstr, "garment, ");
+			if( it->equip & EQP_ACC_L )
+				strcat(equipstr, "left accessory, ");
+			if( it->equip & EQP_ARMOR )
+				strcat(equipstr, "body/armor, ");
+			if( (it->equip & EQP_ARMS) == EQP_HAND_R )
+				strcat(equipstr, "right hand, ");
+			if( (it->equip & EQP_ARMS) == EQP_HAND_L )
+				strcat(equipstr, "left hand, ");
+			if( (it->equip & EQP_ARMS) == EQP_ARMS )
+				strcat(equipstr, "both hands, ");
+			if( it->equip & EQP_SHOES )
+				strcat(equipstr, "feet, ");
+			if( it->equip & EQP_ACC_R )
+				strcat(equipstr, "right accessory, ");
+			if( (it->equip & EQP_HELM) == EQP_HEAD_LOW )
+				strcat(equipstr, "lower head, ");
+			if( (it->equip & EQP_HELM) == EQP_HEAD_TOP )
+				strcat(equipstr, "top head, ");
+			if( (it->equip & EQP_HELM) == (EQP_HEAD_LOW|EQP_HEAD_TOP) )
+				strcat(equipstr, "lower/top head, ");
+			if( (it->equip & EQP_HELM) == EQP_HEAD_MID )
+				strcat(equipstr, "mid head, ");
+			if( (it->equip & EQP_HELM) == (EQP_HEAD_LOW|EQP_HEAD_MID) )
+				strcat(equipstr, "lower/mid head, ");
+			if( (it->equip & EQP_HELM) == EQP_HELM )
+				strcat(equipstr, "lower/mid/top head, ");
+			// remove final ', '
+			equipstr[strlen(equipstr) - 2] = '\0';
+			StringBuf_AppendStr(&buf, equipstr);
+		}
 
-	for (i = 0; i < MAX_CART; i++) {
-		if (sd->status.cart[i].nameid > 0 && (item_data = itemdb_search(sd->status.cart[i].nameid)) != NULL) {
-			counter = counter + sd->status.cart[i].amount;
-			count++;
-			if (count == 1) {
-				sprintf(output, "------ Cart items list of '%s' ------", sd->status.name);
-				clif_displaymessage(fd, output);
-			}
-			if (sd->status.cart[i].refine)
-				sprintf(output, "%d %s %+d (%s %+d, id: %d)", sd->status.cart[i].amount, item_data->name, sd->status.cart[i].refine, item_data->jname, sd->status.cart[i].refine, sd->status.cart[i].nameid);
+		clif_displaymessage(fd, StringBuf_Value(&buf));
+		StringBuf_Clear(&buf);
+
+		if( it->card[0] == CARD0_PET )
+		{// pet egg
+			if (it->card[3])
+				StringBuf_Printf(&buf, " -> (pet egg, pet id: %u, named)", (unsigned int)MakeDWord(it->card[1], it->card[2]));
 			else
-				sprintf(output, "%d %s (%s, id: %d)", sd->status.cart[i].amount, item_data->name, item_data->jname, sd->status.cart[i].nameid);
-			clif_displaymessage(fd, output);
-			memset(output, '\0', sizeof(output));
-			counter2 = 0;
-			for (j = 0; j < item_data->slot; j++) {
-				if (sd->status.cart[i].card[j]) {
-					if ( (item_temp = itemdb_search(sd->status.cart[i].card[j])) != NULL) {
-						if (output[0] == '\0')
-							sprintf(outputtmp, " -> (card(s): #%d %s (%s), ", ++counter2, item_temp->name, item_temp->jname);
-						else
-							sprintf(outputtmp, "#%d %s (%s), ", ++counter2, item_temp->name, item_temp->jname);
-						strcat(output, outputtmp);
-					}
-				}
-			}
-			if (output[0] != '\0') {
-				output[strlen(output) - 2] = ')';
-				output[strlen(output) - 1] = '\0';
-				clif_displaymessage(fd, output);
-			}
+				StringBuf_Printf(&buf, " -> (pet egg, pet id: %u, unnamed)", (unsigned int)MakeDWord(it->card[1], it->card[2]));
 		}
-	}
-	if (count == 0)
-		clif_displaymessage(fd, "No item found in the cart of this player.");
-	else {
-		sprintf(output, "%d item(s) found in %d kind(s) of items.", counter, count);
-		clif_displaymessage(fd, output);
-	}
+		else
+		if(it->card[0] == CARD0_FORGE)
+		{// forged item
+			StringBuf_Printf(&buf, " -> (crafted item, creator id: %u, star crumbs %d, element %d)", (unsigned int)MakeDWord(it->card[2], it->card[3]), it->card[1]>>8, it->card[1]&0x0f);
+		}
+		else
+		if(it->card[0] == CARD0_CREATE)
+		{// created item
+			StringBuf_Printf(&buf, " -> (produced item, creator id: %u)", (unsigned int)MakeDWord(it->card[2], it->card[3]));
+		}
+		else
+		{// normal item
+			int counter2 = 0;
 
-	return 0;
-}
+			for( j = 0; j < itd->slot; ++j )
+			{
+				struct item_data* card;
 
-int atcommand_itemlist(const int fd, struct map_session_data* sd, const char* command, const char* message)
-{
-	struct item_data *item_data, *item_temp;
-	int i, j, equip, count, counter, counter2;
-	char character[NAME_LENGTH], output[200], equipstr[100], outputtmp[200];
-	struct item *i_item; //Current inventory item.
-	nullpo_retr(-1, sd);
+				if( it->card[j] == 0 || (card = itemdb_search(it->card[j])) == NULL )
+					continue;
 
-	memset(character, '\0', sizeof(character));
-	memset(output, '\0', sizeof(output));
-	memset(equipstr, '\0', sizeof(equipstr));
-	memset(outputtmp, '\0', sizeof(outputtmp));
+				counter2++;
 
-	counter = 0;
-	count = 0;
-	for (i = 0; i < MAX_INVENTORY; i++) {
-		i_item = &sd->status.inventory[i];
-		if (sd->status.inventory[i].nameid > 0 && (item_data = itemdb_exists(i_item->nameid)) != NULL) {
-			counter = counter + i_item->amount;
-			count++;
-			if (count == 1) {
-				sprintf(output, "------ Items list of '%s' ------", sd->status.name);
-				clif_displaymessage(fd, output);
-			}
-			if ((equip = i_item->equip)) {
-				strcpy(equipstr, "| equiped: ");
-				if (equip & EQP_GARMENT)
-					strcat(equipstr, "robe/gargment, ");
-				if (equip & EQP_ACC_L)
-					strcat(equipstr, "left accessory, ");
-				if (equip & EQP_ARMOR)
-					strcat(equipstr, "body/armor, ");
-				if ((equip & EQP_ARMS) == EQP_HAND_R)
-					strcat(equipstr, "right hand, ");
-				if ((equip & EQP_ARMS) == EQP_HAND_L)
-					strcat(equipstr, "left hand, ");
-				if ((equip & EQP_ARMS) == EQP_ARMS)
-					strcat(equipstr, "both hands, ");
-				if (equip & EQP_SHOES)
-					strcat(equipstr, "feet, ");
-				if (equip & EQP_ACC_R)
-					strcat(equipstr, "right accessory, ");
-				if ((equip & EQP_HELM) == EQP_HEAD_LOW)
-					strcat(equipstr, "lower head, ");
-				if ((equip & EQP_HELM) == EQP_HEAD_TOP)
-					strcat(equipstr, "top head, ");
-				if ((equip & EQP_HELM) == (EQP_HEAD_LOW|EQP_HEAD_TOP))
-					strcat(equipstr, "lower/top head, ");
-				if ((equip & EQP_HELM) == EQP_HEAD_MID)
-					strcat(equipstr, "mid head, ");
-				if ((equip & EQP_HELM) == (EQP_HEAD_LOW|EQP_HEAD_MID))
-					strcat(equipstr, "lower/mid head, ");
-				if ((equip & EQP_HELM) == EQP_HELM)
-					strcat(equipstr, "lower/mid/top head, ");
-				// remove final ', '
-				equipstr[strlen(equipstr) - 2] = '\0';
-			} else
-				memset(equipstr, '\0', sizeof(equipstr));
-			if (i_item->refine)
-				sprintf(output, "%d %s %+d (%s %+d, id: %d) %s", i_item->amount, item_data->name, i_item->refine, item_data->jname, i_item->refine, i_item->nameid, equipstr);
-			else
-				sprintf(output, "%d %s (%s, id: %d) %s", i_item->amount, item_data->name, item_data->jname, i_item->nameid, equipstr);
-			clif_displaymessage(fd, output);
-			memset(output, '\0', sizeof(output));
-			counter2 = 0;
-
-			if(i_item->card[0]==CARD0_PET) { //pet eggs
-				if (i_item->card[3])
-					sprintf(outputtmp, " -> (pet egg, pet id: %u, named)", (unsigned int)MakeDWord(i_item->card[1], i_item->card[2]));
-				else
-					sprintf(outputtmp, " -> (pet egg, pet id: %u, unnamed)", (unsigned int)MakeDWord(i_item->card[1], i_item->card[2]));
-				strcat(output, outputtmp);
-			} else
-			if(i_item->card[0]==CARD0_FORGE) { //forged items.
-				sprintf(outputtmp, " -> (crafted item, creator id: %u, star crumbs %d, element %d)", (unsigned int)MakeDWord(i_item->card[2], i_item->card[3]), i_item->card[1]>>8, i_item->card[1]&0x0f);
-			} else
-			if(i_item->card[0]==CARD0_CREATE) { //created items.
-				sprintf(outputtmp, " -> (produced item, creator id: %u)", (unsigned int)MakeDWord(i_item->card[2], i_item->card[3]));
-				strcat(output, outputtmp);
-			} else //Normal slots
-			for (j = 0; j < item_data->slot; j++) {
-				if (sd->status.inventory[i].card[j]) {
-					if ((item_temp = itemdb_exists(i_item->card[j])) != NULL) {
-						if (output[0] == '\0')
-							sprintf(outputtmp, " -> (card(s): #%d %s (%s), ", ++counter2, item_temp->name, item_temp->jname);
-						else
-							sprintf(outputtmp, "#%d %s (%s), ", ++counter2, item_temp->name, item_temp->jname);
-						strcat(output, outputtmp);
-					}
-				}
-			}
-			if (output[0] != '\0') {
-				output[strlen(output) - 2] = ')';
-				output[strlen(output) - 1] = '\0';
-				clif_displaymessage(fd, output);
+				if( counter2 == 1 )
+					StringBuf_AppendStr(&buf, " -> (card(s): ");
+
+				if( counter2 != 1 )
+					StringBuf_AppendStr(&buf, ", ");
+
+				StringBuf_Printf(&buf, "#%d %s (id: %d)", counter2, card->jname, card->nameid);
 			}
+
+			if( counter2 > 0 )
+				StringBuf_AppendStr(&buf, ")");
 		}
-	}
-	if (count == 0)
-	{
-		clif_displaymessage(fd, "No item found on this player.");
-		return -1;
+
+		if( StringBuf_Length(&buf) > 0 )
+			clif_displaymessage(fd, StringBuf_Value(&buf));
+
+		StringBuf_Clear(&buf);
 	}
 
-	sprintf(output, "%d item(s) found in %d kind(s) of items.", counter, count);
-	clif_displaymessage(fd, output);
+	if( count == 0 )
+		StringBuf_Printf(&buf, "No item found in this player's %s.", location);
+	else
+		StringBuf_Printf(&buf, "%d item(s) found in %d %s slots.", counter, count, location);
+
+	clif_displaymessage(fd, StringBuf_Value(&buf));
+
+	StringBuf_Destroy(&buf);
+
 	return 0;
 }
 
 int atcommand_stats(const int fd, struct map_session_data* sd, const char* command, const char* message)
 {
-	char character[NAME_LENGTH];
 	char job_jobname[100];
 	char output[200];
 	int i;
@@ -8478,7 +8413,6 @@ int atcommand_stats(const int fd, struct map_session_data* sd, const char* comma
 		{ NULL, 0 }
 	};
 
-	memset(character, '\0', sizeof(character));
 	memset(job_jobname, '\0', sizeof(job_jobname));
 	memset(output, '\0', sizeof(output));
 
@@ -8907,8 +8841,8 @@ AtCommandInfo atcommand_info[] = {
 	{ "agitend2",          60,60,     atcommand_agitend2 },
 	{ "skreset",           60,60,     atcommand_resetskill },
 	{ "streset",           60,60,     atcommand_resetstat },
-	{ "storagelist",       40,40,     atcommand_storagelist },
-	{ "cartlist",          40,40,     atcommand_cart_list },
+	{ "storagelist",       40,40,     atcommand_itemlist },
+	{ "cartlist",          40,40,     atcommand_itemlist },
 	{ "itemlist",          40,40,     atcommand_itemlist },
 	{ "stats",             40,40,     atcommand_stats },
 	{ "delitem",           60,60,     atcommand_delitem },
@@ -9061,7 +8995,7 @@ bool is_atcommand(const int fd, struct map_session_data* sd, const char* message
 	//Attempt to use the command
 	if ( (info->func(fd, (*atcmd_msg == atcommand_symbol) ? sd : ssd, command, params) != 0) )
 	{
-		sprintf(output,msg_txt(154), command);
+		sprintf(output,msg_txt(154), command); // %s failed.
 		clif_displaymessage(fd, output);
 	}
 	

+ 4 - 4
src/map/unit.c

@@ -636,7 +636,7 @@ int unit_warp(struct block_list *bl,short m,short x,short y,int type)
  * &0x1: Issue a fixpos packet afterwards
  * &0x2: Force the unit to move one cell if it hasn't yet
  * &0x4: Enable moving to the next cell when unit was already half-way there
- *       (could trigger additional on-touch/place code)
+ *       (may cause on-touch/place side-effects, such as a scripted map change)
  *------------------------------------------*/
 int unit_stop_walking(struct block_list *bl,int type)
 {
@@ -656,9 +656,9 @@ int unit_stop_walking(struct block_list *bl,int type)
 	ud->walktimer = INVALID_TIMER;
 	ud->state.change_walk_target = 0;
 	tick = gettick();
-	if ((type&0x02 && !ud->walkpath.path_pos) //Force moving at least one cell.
-		|| (!(type&0x04) && td && DIFF_TICK(td->tick, tick) <= td->data/2)) //Enough time has passed to cover half-cell
-	{	
+	if( (type&0x02 && !ud->walkpath.path_pos) //Force moving at least one cell.
+	||  (type&0x04 && td && DIFF_TICK(td->tick, tick) <= td->data/2) //Enough time has passed to cover half-cell
+	) {	
 		ud->walkpath.path_len = ud->walkpath.path_pos+1;
 		unit_walktoxy_timer(-1, tick, bl->id, ud->walkpath.path_pos);
 	}