Browse Source

Improved itemlink logic (#7532)

Fixed tags and separators for various packet versions.

If itemlink is disabled it will output the item name with the refine as prefix and the slots as suffix (if equipment)
It will also append [0] if the item is an equipment and has 0 slots (to make it easier to tell from non-equipment items)

Disabled feature on packet versions older than 2015-11-04 until proven otherwise

Fixes #7441

Co-authored-by: Lemongrass3110 <lemongrass@kstp.at>
Lemon 2 years ago
parent
commit
7e62670882

+ 2 - 2
conf/battle/feature.conf

@@ -141,10 +141,10 @@ feature.dynamicnpc_rangey: 2
 feature.dynamicnpc_direction: no
 feature.dynamicnpc_direction: no
 
 
 // Itemlink System on informational related commands (Note 1)
 // Itemlink System on informational related commands (Note 1)
-// Generates <ITEML> string for an item and can be used for npctalk, message,
+// Generates an itemlink string for an item and can be used for npctalk, message,
 // dispbottom, and broadcast commands. The result is clickable-item name just
 // dispbottom, and broadcast commands. The result is clickable-item name just
 // like from SHIFT+Click from player's inventory/cart/equipment window.
 // like from SHIFT+Click from player's inventory/cart/equipment window.
-// Requires: 2010-00-00RagexeRE or later
+// Requires: 2015-11-04Ragexe or later
 feature.itemlink: on
 feature.itemlink: on
 
 
 // Stylist UI (Note 1)
 // Stylist UI (Note 1)

+ 2 - 2
conf/msg_conf/map_msg.conf

@@ -1447,7 +1447,7 @@
 
 
 // @iteminfo
 // @iteminfo
 1276: Please enter an item name/ID (usage: @ii/@iteminfo <item name/ID>).
 1276: Please enter an item name/ID (usage: @ii/@iteminfo <item name/ID>).
-1277: Item: '%s'/'%s'[%d] (%u) Type: %s | Extra Effect: %s
+1277: Item: '%s'/'%s' (%u) Type: %s | Extra Effect: %s
 1278: None
 1278: None
 1279: With script
 1279: With script
 1280: NPC Buy:%dz, Sell:%dz | Weight: %.1f
 1280: NPC Buy:%dz, Sell:%dz | Weight: %.1f
@@ -1457,7 +1457,7 @@
 
 
 // @whodrops
 // @whodrops
 1284: Please enter item name/ID (usage: @whodrops <item name/ID>).
 1284: Please enter item name/ID (usage: @whodrops <item name/ID>).
-1285: Item: '%s'[%d] (ID: %u)
+1285: Item: '%s' (ID: %u)
 1286:  - Item is not dropped by mobs.
 1286:  - Item is not dropped by mobs.
 1287:  - Common mobs with highest drop chance (only max %d are listed):
 1287:  - Common mobs with highest drop chance (only max %d are listed):
 
 

+ 2 - 2
conf/msg_conf/map_msg_chn.conf

@@ -1192,7 +1192,7 @@
 
 
 // @iteminfo
 // @iteminfo
 1276: 請輸入 物品名稱/ID (用法: @ii/@iteminfo <物品名稱/ID>).
 1276: 請輸入 物品名稱/ID (用法: @ii/@iteminfo <物品名稱/ID>).
-1277: 物品: '%s'/'%s'[%d] (%u) 類型: %s | 額外效果: %s
+1277: 物品: '%s'/'%s' (%u) 類型: %s | 額外效果: %s
 1278: None
 1278: None
 1279: With script
 1279: With script
 1280: NPC 買價:%dz, 賣價:%dz | 重量: %.1f 
 1280: NPC 買價:%dz, 賣價:%dz | 重量: %.1f 
@@ -1202,7 +1202,7 @@
 
 
 // @whodrops
 // @whodrops
 1284: Please enter 物品名稱/ID (用法: @whodrops <物品名稱/ID>).
 1284: Please enter 物品名稱/ID (用法: @whodrops <物品名稱/ID>).
-1285: Item: '%s'[%d] (ID:%d)
+1285: Item: '%s' (ID:%d)
 1286:  - Item is not dropped by mobs.
 1286:  - Item is not dropped by mobs.
 1287:  - Common mobs with highest drop chance (only max %d are listed):
 1287:  - Common mobs with highest drop chance (only max %d are listed):
 
 

+ 2 - 2
conf/msg_conf/map_msg_frn.conf

@@ -1205,7 +1205,7 @@
 
 
 // @iteminfo
 // @iteminfo
 1276: Entrez un nom/ID d'objet (usage: @ii/@iteminfo <nom/ID>).
 1276: Entrez un nom/ID d'objet (usage: @ii/@iteminfo <nom/ID>).
-1277: Item: '%s'/'%s'[%d] (%u) Type: %s | Extra Effect: %s
+1277: Item: '%s'/'%s' (%u) Type: %s | Extra Effect: %s
 1278: Aucun
 1278: Aucun
 1279: Avec script
 1279: Avec script
 1280: NPC Acheté:%dz, Vendu:%dz | Poids: %.1f 
 1280: NPC Acheté:%dz, Vendu:%dz | Poids: %.1f 
@@ -1215,7 +1215,7 @@
 
 
 // @whodrops
 // @whodrops
 1284: Entrez un nom/ID d'Objet (usage: @whodrops <nom/ID_objet>).
 1284: Entrez un nom/ID d'Objet (usage: @whodrops <nom/ID_objet>).
-1285: Objet: '%s'[%d] (ID:%d)
+1285: Objet: '%s' (ID:%d)
 1286:  - Cet Objet n'est lâché par aucun monstre.
 1286:  - Cet Objet n'est lâché par aucun monstre.
 1287:  - Monstres communs avec la plus grande chance de drop (seuls %d max sont listés):
 1287:  - Monstres communs avec la plus grande chance de drop (seuls %d max sont listés):
 
 

+ 2 - 2
conf/msg_conf/map_msg_idn.conf

@@ -1293,7 +1293,7 @@
 
 
 // @iteminfo
 // @iteminfo
 1276: Harap masukkan nama/ID item. (Penggunaan: @ii/@iteminfo <nama/ID item>).
 1276: Harap masukkan nama/ID item. (Penggunaan: @ii/@iteminfo <nama/ID item>).
-1277: Item: '%s'/'%s'[%d] (%u) Jenis: %s | Efek tambahan: %s
+1277: Item: '%s'/'%s' (%u) Jenis: %s | Efek tambahan: %s
 1278: Tidak ada
 1278: Tidak ada
 1279: Dengan script.
 1279: Dengan script.
 1280: NPC Harga Beli:%dz, Harga jual:%dz | Berat: %.1f 
 1280: NPC Harga Beli:%dz, Harga jual:%dz | Berat: %.1f 
@@ -1303,7 +1303,7 @@
 
 
 // @whodrops
 // @whodrops
 1284: Harap masukkan nama/ID item. (Penggunaan: @whodrops <nama/ID item>).
 1284: Harap masukkan nama/ID item. (Penggunaan: @whodrops <nama/ID item>).
-1285: Item: '%s'[%d] (ID:%d)
+1285: Item: '%s' (ID:%d)
 1286:  - Item ini tidak dijatuhkan dari monster.
 1286:  - Item ini tidak dijatuhkan dari monster.
 1287:  - Monster biasa dengan kemungkinan menjatuhkan barang tertinggi. (Maks. hanya %d yang ditampilkan):
 1287:  - Monster biasa dengan kemungkinan menjatuhkan barang tertinggi. (Maks. hanya %d yang ditampilkan):
 
 

+ 2 - 2
conf/msg_conf/map_msg_por.conf

@@ -1375,7 +1375,7 @@
 
 
 // @iteminfo
 // @iteminfo
 1276: Digite o nome/ID de um item (uso: @ii/@iteminfo <nome do item/ID>).
 1276: Digite o nome/ID de um item (uso: @ii/@iteminfo <nome do item/ID>).
-1277: Item: '%s'/'%s'[%d] (%u) Tipo: %s | Efeito Extra: %s
+1277: Item: '%s'/'%s' (%u) Tipo: %s | Efeito Extra: %s
 1278: Nenhum
 1278: Nenhum
 1279: Com script
 1279: Com script
 1280: NPC Compra:%dz, Venda:%dz | Peso: %.1f 
 1280: NPC Compra:%dz, Venda:%dz | Peso: %.1f 
@@ -1385,7 +1385,7 @@
 
 
 // @whodrops
 // @whodrops
 1284: Digite o nome/ID de um item (uso: @whodrops <nome do item/ID>).
 1284: Digite o nome/ID de um item (uso: @whodrops <nome do item/ID>).
-1285: Item: '%s'[%d] (ID:%d)
+1285: Item: '%s' (ID:%d)
 1286:  - Item não derrubado por monstros.
 1286:  - Item não derrubado por monstros.
 1287:  - Monstros comuns com maiores chances de drop (somente máx %d são listados):
 1287:  - Monstros comuns com maiores chances de drop (somente máx %d são listados):
 
 

+ 2 - 2
conf/msg_conf/map_msg_rus.conf

@@ -1205,7 +1205,7 @@
 
 
 // @iteminfo
 // @iteminfo
 1276: Введите ID/название предмета (Использование: @ii/@iteminfo <ID/название предмета>).
 1276: Введите ID/название предмета (Использование: @ii/@iteminfo <ID/название предмета>).
-1277: Предмет: '%s'/'%s'[%d] (%u) Тип: %s | Доп. эффект: %s
+1277: Предмет: '%s'/'%s' (%u) Тип: %s | Доп. эффект: %s
 1278: Пусто
 1278: Пусто
 1279: Скрипт
 1279: Скрипт
 1280: НИП покупка:%d зени, продажа:%d зени | Вес: %.1f 
 1280: НИП покупка:%d зени, продажа:%d зени | Вес: %.1f 
@@ -1215,7 +1215,7 @@
 
 
 // @whodrops
 // @whodrops
 1284: Введите ID/название предмета (Использование: @whodrops <ID/название предмета>).
 1284: Введите ID/название предмета (Использование: @whodrops <ID/название предмета>).
-1285: Предмет: '%s'[%d] (ID:%d)
+1285: Предмет: '%s' (ID:%d)
 1286:  - Предмет не падает с монстров.
 1286:  - Предмет не падает с монстров.
 1287:  - Обычные монстры с высоким шансом выпадения (перечислено только %d):
 1287:  - Обычные монстры с высоким шансом выпадения (перечислено только %d):
 
 

+ 2 - 2
conf/msg_conf/map_msg_spn.conf

@@ -1344,7 +1344,7 @@
 
 
 // @iteminfo
 // @iteminfo
 1276: Introduce el nombre/ID de un objeto (instrucciones: @ii/@iteminfo <nombre/ID del objeto>).
 1276: Introduce el nombre/ID de un objeto (instrucciones: @ii/@iteminfo <nombre/ID del objeto>).
-1277: Objeto: '%s'/'%s'[%d] (%u) Tipo: %s | Efecto: %s
+1277: Objeto: '%s'/'%s' (%u) Tipo: %s | Efecto: %s
 1278: Ninguno
 1278: Ninguno
 1279: Contiene código
 1279: Contiene código
 1280: Compra en NPC:%dz, Venta:%dz | Peso: %.1f
 1280: Compra en NPC:%dz, Venta:%dz | Peso: %.1f
@@ -1354,7 +1354,7 @@
 
 
 // @whodrops
 // @whodrops
 1284: Introduce el nombre/ID de un objeto (instrucciones: @whodrops <nombre/ID del objeto>). 
 1284: Introduce el nombre/ID de un objeto (instrucciones: @whodrops <nombre/ID del objeto>). 
-1285: Objeto: '%s'[%d] (ID:%d)
+1285: Objeto: '%s' (ID:%d)
 1286: - Ningún monstruo tiene ese objeto.
 1286: - Ningún monstruo tiene ese objeto.
 1287: - Estos monstruos tienen ese objeto (sólo se muestran un máximo de %d):
 1287: - Estos monstruos tienen ese objeto (sólo se muestran un máximo de %d):
 
 

+ 2 - 2
conf/msg_conf/map_msg_tha.conf

@@ -1198,7 +1198,7 @@
 
 
 // @iteminfo
 // @iteminfo
 1276: â»Ã´Ãкت×èÍ/ID item (ÇÔ¸Õãªé: @ii/@iteminfo <ª×èÍ/ID item>).
 1276: â»Ã´Ãкت×èÍ/ID item (ÇÔ¸Õãªé: @ii/@iteminfo <ª×èÍ/ID item>).
-1277: Item: '%s'/'%s'[%d] (%u) Type: %s | Extra Effect: %s
+1277: Item: '%s'/'%s' (%u) Type: %s | Extra Effect: %s
 1278: None
 1278: None
 1279: With script
 1279: With script
 1280: NPC Buy:%dz, Sell:%dz | Weight: %.1f
 1280: NPC Buy:%dz, Sell:%dz | Weight: %.1f
@@ -1208,7 +1208,7 @@
 
 
 // @whodrops
 // @whodrops
 1284: â»Ã´Ãкت×èÍ/ID item (ÇÔ¸Õãªé: @whodrops <ª×èÍ/ID item>).
 1284: â»Ã´Ãкت×èÍ/ID item (ÇÔ¸Õãªé: @whodrops <ª×èÍ/ID item>).
-1285: Item: '%s'[%d] (ID:%d)
+1285: Item: '%s' (ID:%d)
 1286:  - Item ¹ÕéäÁèÁÕµ¡¨Ò¡ monster.
 1286:  - Item ¹ÕéäÁèÁÕµ¡¨Ò¡ monster.
 1287:  - Monster ·ÑèÇä»·ÕèÁÕâÍ¡Òʵ¡ÊÙ§ÊØ´ (áÊ´§à¾Õ§ %d ÃÒ¡ÒÃ):
 1287:  - Monster ·ÑèÇä»·ÕèÁÕâÍ¡Òʵ¡ÊÙ§ÊØ´ (áÊ´§à¾Õ§ %d ÃÒ¡ÒÃ):
 
 

+ 14 - 26
src/map/atcommand.cpp

@@ -4008,7 +4008,7 @@ ACMD_FUNC(idsearch)
 	for(const auto &result : item_array) {
 	for(const auto &result : item_array) {
 		std::shared_ptr<item_data> id = result.second;
 		std::shared_ptr<item_data> id = result.second;
 
 
-		sprintf(atcmd_output, msg_txt(sd,78), item_db.create_item_link( id->nameid ).c_str(), id->nameid); // %s: %u
+		sprintf(atcmd_output, msg_txt(sd,78), item_db.create_item_link( id ).c_str(), id->nameid); // %s: %u
 		clif_displaymessage(fd, atcmd_output);
 		clif_displaymessage(fd, atcmd_output);
 	}
 	}
 	sprintf(atcmd_output, msg_txt(sd,79), match); // It is %d affair above.
 	sprintf(atcmd_output, msg_txt(sd,79), match); // It is %d affair above.
@@ -6656,7 +6656,7 @@ ACMD_FUNC(autolootitem)
 			return -1;
 			return -1;
 		}
 		}
 		sd->state.autolootid[i] = item_data->nameid; // Autoloot Activated
 		sd->state.autolootid[i] = item_data->nameid; // Autoloot Activated
-		sprintf(atcmd_output, msg_txt(sd,1192), item_data->name.c_str(), item_db.create_item_link( item_data->nameid ).c_str(), item_data->nameid); // Autolooting item: '%s'/'%s' {%u}
+		sprintf(atcmd_output, msg_txt(sd,1192), item_data->name.c_str(), item_db.create_item_link( item_data ).c_str(), item_data->nameid); // Autolooting item: '%s'/'%s' {%u}
 		clif_displaymessage(fd, atcmd_output);
 		clif_displaymessage(fd, atcmd_output);
 		sd->state.autolooting = 1;
 		sd->state.autolooting = 1;
 		break;
 		break;
@@ -6667,7 +6667,7 @@ ACMD_FUNC(autolootitem)
 			return -1;
 			return -1;
 		}
 		}
 		sd->state.autolootid[i] = 0;
 		sd->state.autolootid[i] = 0;
-		sprintf(atcmd_output, msg_txt(sd,1194), item_data->name.c_str(), item_db.create_item_link( item_data->nameid ).c_str(), item_data->nameid); // Removed item: '%s'/'%s' {%u} from your autolootitem list.
+		sprintf(atcmd_output, msg_txt(sd,1194), item_data->name.c_str(), item_db.create_item_link( item_data ).c_str(), item_data->nameid); // Removed item: '%s'/'%s' {%u} from your autolootitem list.
 		clif_displaymessage(fd, atcmd_output);
 		clif_displaymessage(fd, atcmd_output);
 		ARR_FIND(0, AUTOLOOTITEM_SIZE, i, sd->state.autolootid[i] != 0);
 		ARR_FIND(0, AUTOLOOTITEM_SIZE, i, sd->state.autolootid[i] != 0);
 		if (i == AUTOLOOTITEM_SIZE) {
 		if (i == AUTOLOOTITEM_SIZE) {
@@ -6695,7 +6695,7 @@ ACMD_FUNC(autolootitem)
 					continue;
 					continue;
 				}
 				}
 
 
-				sprintf(atcmd_output, "'%s'/'%s' {%u}", item_data->name.c_str(), item_db.create_item_link( item_data->nameid ).c_str(), item_data->nameid);
+				sprintf(atcmd_output, "'%s'/'%s' {%u}", item_data->name.c_str(), item_db.create_item_link( item_data ).c_str(), item_data->nameid);
 				clif_displaymessage(fd, atcmd_output);
 				clif_displaymessage(fd, atcmd_output);
 			}
 			}
 		}
 		}
@@ -7761,10 +7761,7 @@ ACMD_FUNC(mobinfo)
 
 
 			int droprate = mob_getdroprate( &sd->bl, mob, mob->dropitem[i].rate, drop_modifier );
 			int droprate = mob_getdroprate( &sd->bl, mob, mob->dropitem[i].rate, drop_modifier );
 
 
-			if (id->slots)
-				sprintf(atcmd_output2, " - %s[%d]  %02.02f%%", item_db.create_item_link( id->nameid ).c_str(), id->slots, (float)droprate / 100);
-			else
-				sprintf(atcmd_output2, " - %s  %02.02f%%", item_db.create_item_link( id->nameid ).c_str(), (float)droprate / 100);
+			sprintf(atcmd_output2, " - %s  %02.02f%%", item_db.create_item_link( id ).c_str(), (float)droprate / 100);
 			strcat(atcmd_output, atcmd_output2);
 			strcat(atcmd_output, atcmd_output2);
 			if (++j % 3 == 0) {
 			if (++j % 3 == 0) {
 				clif_displaymessage(fd, atcmd_output);
 				clif_displaymessage(fd, atcmd_output);
@@ -7801,15 +7798,9 @@ ACMD_FUNC(mobinfo)
 				if (mvppercent > 0) {
 				if (mvppercent > 0) {
 					j++;
 					j++;
 					if (j == 1) {
 					if (j == 1) {
-						if (id->slots)
-							sprintf(atcmd_output2, " %s[%d]  %02.02f%%", item_db.create_item_link( id->nameid ).c_str(), id->slots, mvppercent);
-						else
-							sprintf(atcmd_output2, " %s  %02.02f%%", item_db.create_item_link( id->nameid ).c_str(), mvppercent);
+						sprintf(atcmd_output2, " %s  %02.02f%%", item_db.create_item_link( id ).c_str(), mvppercent);
 					} else {
 					} else {
-						if (id->slots)
-							sprintf(atcmd_output2, " - %s[%d]  %02.02f%%", item_db.create_item_link( id->nameid ).c_str(), id->slots, mvppercent);
-						else
-							sprintf(atcmd_output2, " - %s  %02.02f%%", item_db.create_item_link( id->nameid ).c_str(), mvppercent);
+						sprintf(atcmd_output2, " - %s  %02.02f%%", item_db.create_item_link( id ).c_str(), mvppercent);
 					}
 					}
 					strcat(atcmd_output, atcmd_output2);
 					strcat(atcmd_output, atcmd_output2);
 				}
 				}
@@ -8243,8 +8234,8 @@ ACMD_FUNC(iteminfo)
 	for (const auto &result : item_array) {
 	for (const auto &result : item_array) {
 		std::shared_ptr<item_data> item_data = result.second;
 		std::shared_ptr<item_data> item_data = result.second;
 
 
-		sprintf(atcmd_output, msg_txt(sd,1277), // Item: '%s'/'%s'[%d] (%u) Type: %s | Extra Effect: %s
-			item_data->name.c_str(), item_db.create_item_link( item_data->nameid ).c_str(),item_data->slots,item_data->nameid,
+		sprintf(atcmd_output, msg_txt(sd,1277), // Item: '%s'/'%s' (%u) Type: %s | Extra Effect: %s
+			item_data->name.c_str(), item_db.create_item_link( item_data ).c_str(),item_data->nameid,
 			(item_data->type != IT_AMMO) ? itemdb_typename((enum item_types)item_data->type) : itemdb_typename_ammo((e_ammo_type)item_data->subtype),
 			(item_data->type != IT_AMMO) ? itemdb_typename((enum item_types)item_data->type) : itemdb_typename_ammo((e_ammo_type)item_data->subtype),
 			(item_data->script==NULL)? msg_txt(sd,1278) : msg_txt(sd,1279) // None / With script
 			(item_data->script==NULL)? msg_txt(sd,1278) : msg_txt(sd,1279) // None / With script
 		);
 		);
@@ -8301,7 +8292,7 @@ ACMD_FUNC(whodrops)
 	for (const auto &result : item_array) {
 	for (const auto &result : item_array) {
 		std::shared_ptr<item_data> id = result.second;
 		std::shared_ptr<item_data> id = result.second;
 
 
-		sprintf(atcmd_output, msg_txt(sd,1285), item_db.create_item_link( id->nameid ).c_str(), id->slots, id->nameid); // Item: '%s'[%d] (ID:%u)
+		sprintf(atcmd_output, msg_txt(sd,1285), item_db.create_item_link( id ).c_str(), id->nameid); // Item: '%s' (ID:%u)
 		clif_displaymessage(fd, atcmd_output);
 		clif_displaymessage(fd, atcmd_output);
 
 
 		if (id->mob[0].chance == 0) {
 		if (id->mob[0].chance == 0) {
@@ -9249,7 +9240,7 @@ ACMD_FUNC(itemlist)
 {
 {
 	int i, j, count, counter;
 	int i, j, count, counter;
 	const char* location;
 	const char* location;
-	const struct item* items;
+	struct item* items;
 	int size;
 	int size;
 	StringBuf buf;
 	StringBuf buf;
 
 
@@ -9277,7 +9268,7 @@ ACMD_FUNC(itemlist)
 	count = 0; // total slots occupied
 	count = 0; // total slots occupied
 	counter = 0; // total items found
 	counter = 0; // total items found
 	for( i = 0; i < size; ++i ) {
 	for( i = 0; i < size; ++i ) {
-		const struct item* it = &items[i];
+		struct item* it = &items[i];
 
 
 		if( it->nameid == 0  )
 		if( it->nameid == 0  )
 			continue;
 			continue;
@@ -9296,10 +9287,7 @@ ACMD_FUNC(itemlist)
 			StringBuf_Clear(&buf);
 			StringBuf_Clear(&buf);
 		}
 		}
 
 
-		if( it->refine )
-			StringBuf_Printf(&buf, "%d %s %+d (%s, id: %u)", it->amount, item_db.create_item_link( it->nameid ).c_str(), it->refine, itd->name.c_str(), it->nameid);
-		else
-			StringBuf_Printf(&buf, "%d %s (%s, id: %u)", it->amount, item_db.create_item_link( it->nameid ).c_str(), itd->name.c_str(), it->nameid);
+		StringBuf_Printf(&buf, "%d %s (%s, id: %u)", it->amount, item_db.create_item_link( *it ).c_str(), itd->name.c_str(), it->nameid);
 
 
 		if( it->equip ) {
 		if( it->equip ) {
 			char equipstr[CHAT_SIZE_MAX];
 			char equipstr[CHAT_SIZE_MAX];
@@ -9402,7 +9390,7 @@ ACMD_FUNC(itemlist)
 				if( counter2 != 1 )
 				if( counter2 != 1 )
 					StringBuf_AppendStr(&buf, ", ");
 					StringBuf_AppendStr(&buf, ", ");
 
 
-				StringBuf_Printf(&buf, "#%d %s (id: %u)", counter2, item_db.create_item_link( card->nameid ).c_str(), card->nameid);
+				StringBuf_Printf(&buf, "#%d %s (id: %u)", counter2, item_db.create_item_link( card ).c_str(), card->nameid);
 			}
 			}
 
 
 			if( counter2 > 0 )
 			if( counter2 > 0 )

+ 80 - 59
src/map/itemdb.cpp

@@ -1250,90 +1250,111 @@ std::shared_ptr<item_data> ItemDatabase::searchname( const char *name ){
 * @return <ITEML> string for the item
 * @return <ITEML> string for the item
 * @author [Cydh]
 * @author [Cydh]
 **/
 **/
-std::string ItemDatabase::create_item_link( struct item& item ){
-	std::shared_ptr<item_data> data = this->find( item.nameid );
-
+std::string ItemDatabase::create_item_link(struct item& item, std::shared_ptr<item_data>& data){
 	if( data == nullptr ){
 	if( data == nullptr ){
 		ShowError( "Tried to create itemlink for unknown item %u.\n", item.nameid );
 		ShowError( "Tried to create itemlink for unknown item %u.\n", item.nameid );
 		return "Unknown item";
 		return "Unknown item";
 	}
 	}
 
 
-// All these dates are unconfirmed
-#if PACKETVER >= 20100000
-	if( !battle_config.feature_itemlink ){
-		// Feature is disabled
-		return data->ename;
-	}
-
+	std::string itemstr;
 	struct item_data* id = data.get();
 	struct item_data* id = data.get();
 
 
-#if PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200724
-	const std::string start_tag = "<ITEML>";
-	const std::string closing_tag = "</ITEML>";
-#else // PACKETVER >= 20100000
-	const std::string start_tag = "<ITEMLINK>";
-	const std::string closing_tag = "</ITEMLINK>";
+// All these dates are unconfirmed
+#if PACKETVER >= 20151104
+	if( battle_config.feature_itemlink ) {
+
+#if PACKETVER >= 20160113
+		const std::string start_tag = "<ITEML>";
+		const std::string closing_tag = "</ITEML>";
+#else // PACKETVER >= 20151104
+		const std::string start_tag = "<ITEM>";
+		const std::string closing_tag = "</ITEM>";
 #endif
 #endif
 
 
-	std::string itemstr = start_tag;
+		itemstr += start_tag;
 
 
-	itemstr += util::string_left_pad(util::base62_encode(id->equip), '0', 5);
-	itemstr += itemdb_isequip2(id) ? "1" : "0";
-	itemstr += util::base62_encode(item.nameid);
-	if (item.refine > 0) {
-		itemstr += "%" + util::string_left_pad(util::base62_encode(item.refine), '0', 2);
-	}
-	if (itemdb_isequip2(id)) {
-		itemstr += "&" + util::string_left_pad(util::base62_encode(id->look), '0', 2);
-	}
-#if PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200724
-	itemstr += "'" + util::string_left_pad(util::base62_encode(item.enchantgrade), '0', 2);
+		itemstr += util::string_left_pad(util::base62_encode(id->equip), '0', 5);
+		itemstr += itemdb_isequip2(id) ? "1" : "0";
+		itemstr += util::base62_encode(item.nameid);
+		if (item.refine > 0) {
+			itemstr += "%" + util::string_left_pad(util::base62_encode(item.refine), '0', 2);
+		}
+
+#if PACKETVER >= 20161116
+		if (itemdb_isequip2(id)) {
+			itemstr += "&" + util::string_left_pad(util::base62_encode(id->look), '0', 2);
+		}
 #endif
 #endif
 
 
-#if PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200724
-	const std::string card_sep = ")";
-	const std::string optid_sep = "+";
-	const std::string optpar_sep = ",";
-	const std::string optval_sep = "-";
-#else
-	const std::string card_sep = "(";
-	const std::string optid_sep = "*";
-	const std::string optpar_sep = "+";
-	const std::string optval_sep = ",";
+#if PACKETVER >= 20200724
+		itemstr += "'" + util::string_left_pad(util::base62_encode(item.enchantgrade), '0', 2);
 #endif
 #endif
 
 
-	for (uint8 i = 0; i < MAX_SLOTS; ++i) {
-		itemstr += card_sep + util::string_left_pad(util::base62_encode(item.card[i]), '0', 2);
-	}
+#if PACKETVER >= 20200724
+		const std::string card_sep = ")";
+		const std::string optid_sep = "+";
+		const std::string optpar_sep = ",";
+		const std::string optval_sep = "-";
+#elif PACKETVER >= 20161116
+		const std::string card_sep = "(";
+		const std::string optid_sep = "*";
+		const std::string optpar_sep = "+";
+		const std::string optval_sep = ",";
+#else // PACKETVER >= 20151104
+		const std::string card_sep = "'";
+		const std::string optid_sep = ")";
+		const std::string optpar_sep = "*";
+		const std::string optval_sep = "+";
+#endif
 
 
-#if PACKETVER >= 20150225
-	for (uint8 i = 0; i < MAX_ITEM_RDM_OPT; ++i) {
-		if (item.option[i].id == 0) {
-			break; // ignore options including ones beyond this one since the client won't even display them
+		for (uint8 i = 0; i < MAX_SLOTS; ++i) {
+			itemstr += card_sep + util::string_left_pad(util::base62_encode(item.card[i]), '0', 2);
 		}
 		}
-		// Option ID
-		itemstr += optid_sep + util::string_left_pad(util::base62_encode(item.option[i].id), '0', 2);
-		// Param
-		itemstr += optpar_sep + util::string_left_pad(util::base62_encode(item.option[i].param), '0', 2);
-		// Value
-		itemstr += optval_sep + util::string_left_pad(util::base62_encode(item.option[i].value), '0', 2);
+
+		for (uint8 i = 0; i < MAX_ITEM_RDM_OPT; ++i) {
+			if (item.option[i].id == 0) {
+				break; // ignore options including ones beyond this one since the client won't even display them
+			}
+			// Option ID
+			itemstr += optid_sep + util::string_left_pad(util::base62_encode(item.option[i].id), '0', 2);
+			// Param
+			itemstr += optpar_sep + util::string_left_pad(util::base62_encode(item.option[i].param), '0', 2);
+			// Value
+			itemstr += optval_sep + util::string_left_pad(util::base62_encode(item.option[i].value), '0', 2);
+		}
+
+		itemstr += closing_tag;
+		if ((itemdb_isequip2(id)) && (data->slots == 0))
+			itemstr += " [" + std::to_string(data->slots) + "]";
+
+		return itemstr;
 	}
 	}
 #endif
 #endif
 
 
-	itemstr += closing_tag;
+	// This can be reached either because itemlinks are disabled via configuration or because the packet version does not support the feature
+	// If that's the case then we format the item prepending the refine and appending the slots
+	if (item.refine > 0)
+		itemstr += "+" + std::to_string(item.refine) + " ";
+
+	itemstr += data->ename;
+
+	if (itemdb_isequip2(id))
+		itemstr += "[" + std::to_string(data->slots) + "]";
+
 	return itemstr;
 	return itemstr;
-#else
-	// Did not exist before that
-	return data->ename;
-#endif
 }
 }
 
 
-std::string ItemDatabase::create_item_link( t_itemid id ){
+std::string ItemDatabase::create_item_link( std::shared_ptr<item_data>& data ){
 	struct item it = {};
 	struct item it = {};
+	it.nameid = data->nameid;
+
+	return this->create_item_link( it, data );
+}
 
 
-	it.nameid = id;
+std::string ItemDatabase::create_item_link(struct item& item) {
+	std::shared_ptr<item_data> data = this->find(item.nameid);
 
 
-	return this->create_item_link( it );
+	return this->create_item_link(item, data);
 }
 }
 
 
 ItemDatabase item_db;
 ItemDatabase item_db;

+ 5 - 2
src/map/itemdb.hpp

@@ -2149,8 +2149,11 @@ public:
 	// Additional
 	// Additional
 	std::shared_ptr<item_data> searchname( const char* name );
 	std::shared_ptr<item_data> searchname( const char* name );
 	std::shared_ptr<item_data> search_aegisname( const char *name );
 	std::shared_ptr<item_data> search_aegisname( const char *name );
-	std::string create_item_link( struct item& data );
-	std::string create_item_link( t_itemid id );
+	std::string create_item_link(struct item& item);
+	std::string create_item_link( std::shared_ptr<item_data>& data );
+
+private:
+	std::string create_item_link(struct item& item, std::shared_ptr<item_data>& data);
 };
 };
 
 
 extern ItemDatabase item_db;
 extern ItemDatabase item_db;