Kaynağa Gözat

Added script command mesitemlink (#7565)

Adds a new script command for itemlink generation for usage inside NPC dialogs (mes "").
A few cleanups related to the normal itemlink feature.

Thanks to @Atemo and @aleos89 for their help!

Co-authored-by: Atemo <Atemo@users.noreply.github.com>
Co-authored-by: Aleos <aleos89@users.noreply.github.com>
Lemongrass3110 2 yıl önce
ebeveyn
işleme
f261307bbe

+ 13 - 0
conf/battle/feature.conf

@@ -147,6 +147,19 @@ feature.dynamicnpc_direction: no
 // Requires: 2015-11-04Ragexe or later
 feature.itemlink: on
 
+// Itemlink System on NPC messages (Note 1)
+// Generates an itemlink string for an item and can be used for NPC's mes command.
+// Requires: 2010-01-01 or later
+feature.mesitemlink: on
+
+// Force all mesitemlinks to be wrapped in brackets (Note 1)
+// Default: no
+feature.mesitemlink_brackets: no
+
+// Force all mesitemlinks to use the database name (Note 1)
+// Default: no
+feature.mesitemlink_dbname: no
+
 // Stylist UI (Note 1)
 // Requires: 2015-11-04 or later
 feature.stylist: on

+ 26 - 4
doc/script_commands.txt

@@ -1127,13 +1127,17 @@ In 2015 the tag name was changed to <ITEM> resulting in the following syntax:
 
 	<ITEM>Display Name<INFO>Item ID</INFO></ITEM>
 
+We therefore created script command "mesitemlink" that allows you to create the correct syntax
+depending on your configured packet version. We recommend that you use this script command
+instead of hardcoding the HTML-like tags. For more details see the documentation for "mesitemlink".
+
 The following sample will open a preview window for Red Potion:
 
 	mes "Did you ever consume a <ITEMLINK>Red Potion<INFO>501</INFO></ITEMLINK>?";
 	// Or in 2015:
 	mes "Did you ever consume a <ITEM>Red Potion<INFO>501</INFO></ITEM>?";
 
-NOTE: Be aware that item links are rendered incorrectly in 2015+ clients at the moment.
+NOTE: Be aware that item links are broken in some 2015 clients.
 
 URLs
 ----
@@ -10998,13 +11002,13 @@ If <char id> is specified, the specified player is used rather than the attached
 
 ---------------------------------------
 
-*itemlink(<item_id>,<refine>,<card0>,<card1>,<card2>,<card3>,<enchantgrade>{,<RandomIDArray>,<RandomValueArray>,<RandomParamArray>});
+*itemlink(<item_id>{,<refine>{,<card0>{,<card1>{,<card2>{,<card3>,{<enchantgrade>{,<RandomIDArray>,<RandomValueArray>,<RandomParamArray>}}}}}}});
 
 Generates an item link string for an item that can be used for npctalk, message,
 dispbottom, and broadcast commands. The result is a clickable-item name just
 like SHIFT+Click from a player's inventory/cart/equipment window. This command can be
-used with mes but the item name will not be clickable. You should use the normal client
-tags for displaying item links in mes dialogues, if the client supports them. 
+used with mes but the item name will not be clickable. You should use script command
+"mesitemlink" for displaying item links in mes dialogues, if the client supports them. 
 
 
 Examples:
@@ -11021,6 +11025,24 @@ Examples:
 RandomIDArray, RandomValueArray, and RandomParamArray only works if the
 client (and server) supports the Item Random Options feature (PACKETVER >= 20150225).
 
+---------------------------------------
+
+*mesitemlink(<item_id>{,<use_brackets>{,<display_name>});
+
+Generates an itemlink string for an item and can be used with NPC's mes command.
+The NPC message will show the item's name which will be clickable and opens the
+item description client side.
+By default <use_brackets> is true which surrounds the link with brackets. Send false to disable.
+By default the link will be created with the name of the item stored in the item database,
+but in some cases it might be necessary to overwrite the <display_name> with something else.
+
+Examples:
+
+	mes mesitemlink( 1201 ); // Will display "[Knife]" and will be clickable. If clicked it opens the description for Knife [3]
+	mes "Bring me a " + mesitemlink( 1201 ) + "."; // Will display "Bring me a [Knife]." and "[Knife]" will be clickable.
+	mes "Bring me a " + mesitemlink( 1201, false ) + "."; // Will display "Bring me a Knife." and "Knife" will be clickable.
+	mes "Bring me a " + mesitemlink( 1201, true, "Super cutting knife" ) + "."; // Will display "Bring me a [Super cutting knife]." and "[Super cutting knife]" will be clickable.
+
 ========================
 |14.- Channel commands.|
 ========================

+ 3 - 3
npc/custom/official/GeffenMagicTournament.txt

@@ -260,7 +260,7 @@ L_Shield:
 				case 3: goto L_Menu; break;
 			}
 			mes .@n$;
-			mes "<ITEM>"+getitemname(.@item)+"<INFO>"+.@item+"</INFO></ITEM>";
+			mes mesitemlink( .@item, false );
 			mes "Price is "+.@cost+" coins";
 			mes "Do you wish to exchange your coins?";
 			next;
@@ -303,7 +303,7 @@ L_Ring:
 						break;
 				}
 			mes .@n$;
-			mes "<ITEM>"+getitemname(.@item)+"<INFO>"+.@item+"</INFO></ITEM>";
+			mes mesitemlink( .@item, false );
 			mes "Price is "+.@cost+" coins";
 			mes "Do you wish to exchange your coins?";
 			next;
@@ -345,7 +345,7 @@ L_Armor:
 						break;
 				}
 			mes .@n$;
-			mes "<ITEM>"+getitemname(.@item)+"<INFO>"+.@item+"</INFO></ITEM>";
+			mes mesitemlink( .@item, false );
 			mes "Price is "+.@cost+" coins";
 			mes "Do you wish to exchange your coins?";
 			next;

+ 13 - 13
npc/re/custom/lasagna/lasagna_npcs.txt

@@ -2066,22 +2066,22 @@ lasagna,131,245,5	script	The diligent second son	4_CAT_3COLOR,{
 	mes "[Yota Chara]";
 	switch(.@s) {
 	case 1:
-		mes "<ITEM>Low-grade Horse Mackerel Amulet <INFO>28413</INFO></ITEM> is for my father who is far out to the sea.";
+		mes mesitemlink( 28413, false ) + " is for my father who is far out to the sea.";
 		break;
 	case 2:
-		mes "<ITEM>Low-grade Leaf Amulet <INFO>28416</INFO></ITEM> is for my mother who should be wandering about the deep side of the forest.";
+		mes mesitemlink( 28416, false ) + " is for my mother who should be wandering about the deep side of the forest.";
 		break;
 	case 3:
-		mes "<ITEM>Low-grade Rabbit Amulet <INFO>28419</INFO></ITEM> is for my brothers' health and wellness.";
+		mes mesitemlink( 28419, false ) + " is for my brothers' health and wellness.";
 		break;
 	case 4:
-		mes "<ITEM>Shining Twig Charm <INFO>28422</INFO></ITEM> is to wish for my mother to return home safely from anywhere in the world.";
+		mes mesitemlink( 28422, false ) + " is to wish for my mother to return home safely from anywhere in the world.";
 		break;
 	case 5:
-		mes "<ITEM>Fresh Tuna Amulet <INFO>28423</INFO></ITEM> is to wish for my father to return home quick with his ship full of tunas.";
+		mes mesitemlink( 28423, false ) + " is to wish for my father to return home quick with his ship full of tunas.";
 		break;
 	case 6:
-		mes "<ITEM>Plump Earthworm Amulet <INFO>28424</INFO></ITEM> is to wish for easy fishing so that my family won't be starved.";
+		mes mesitemlink( 28424, false ) + " is to wish for easy fishing so that my family won't be starved.";
 		break;
 	}
 	if (.@s < 4) {
@@ -2092,7 +2092,7 @@ lasagna,131,245,5	script	The diligent second son	4_CAT_3COLOR,{
 		.@cost = 30;
 		.@item_id = 28418 + .@s;
 	}
-	mes "Will you exchange it for " + .@cost + " <ITEM>Doram Token<INFO>25142</INFO></ITEM>?";
+	mes "Will you exchange it for " + .@cost + " " + mesitemlink( 25142, false ) + "?";
 	next;
 	if (select( "Exchange", "Cancel" ) == 2) {
 		mes "[Yota Chara]";
@@ -2164,7 +2164,7 @@ lasagna,131,250,5	script	The brave third#weapon	4_DR_M_02,{
 	emotion ET_SPARK;
 	mes "[Jogi Chara]";
 	mes "Whoa, a new weapon! New power!";
-	mes "What are you going to give me? Do you have a lot of weapons? Can I search into them? Will you exchange it for <ITEM>Doram Token <INFO>25142</INFO></ITEM>?";
+	mes "What are you going to give me? Do you have a lot of weapons? Can I search into them? Will you exchange it for " + mesitemlink( 25142, false ) + "?";
 	next;
 	if (select( "Search", "Cancel" ) == 1) {
 		setarray .@item_data[0],
@@ -2193,7 +2193,7 @@ lasagna,131,250,5	script	The brave third#weapon	4_DR_M_02,{
 			else {
 				mes "[Jogi Chara]";
 				mes "Whoa! This is ^3131FF" + getitemname(.@item_data[.@i]) + "^000000!";
-				mes "Exchange it for " + .@item_data[.@i+1] + " <ITEM>Doram Token<INFO>25142</INFO></ITEM>! Please? Will you do it, please?";
+				mes "Exchange it for " + .@item_data[.@i+1] + " " + mesitemlink( 25142, false ) + "! Please? Will you do it, please?";
 				next;
 				if (select( "Exchange", "Quit exchanging" ) == 2) {
 					mes "[Jogi Chara]";
@@ -2253,7 +2253,7 @@ lasagna,140,250,3	script	The skittish fourth#wea	4_DR_F_01,{
 	}
 	mes "[Dandi Chara]";
 	mes "Do you mind if I search you to see the items you have with you?";
-	mes "If I find an item suitable for Jogi, I'll pay <INFO>25142</INFO><ITEM>Doram Token </ITEM>....";
+	mes "If I find an item suitable for Jogi, I'll pay " + mesitemlink( 25142, false ) + "....";
 	next;
 	if (select( "Search", "Cancel" ) == 1) {
 		setarray .@item_data[0],	// keep the order
@@ -2298,7 +2298,7 @@ lasagna,140,250,3	script	The skittish fourth#wea	4_DR_F_01,{
 			else {
 				mes "[Dandi Chara]";
 				mes "Whoa, this must be ^3131FF" + getitemname(.@item_data[.@i]) + "^000000!!";
-				mes "Don't you want to exchange this with " + .@item_data[.@i+1] + " <ITEM>Doram Token<INFO>25142</INFO></ITEM>?";
+				mes "Don't you want to exchange this with " + .@item_data[.@i+1] + " " + mesitemlink( 25142, false ) + "?";
 				next;
 				if (select( "Exchange", "Quit exchanging" ) == 2) {
 					mes "[Dandi Chara]";
@@ -2388,8 +2388,8 @@ lasagna,140,245,3	script	The sensitive-minded ela	4_CAT_SAILOR3,{
 	mes "...I knew this was going to happen again. Worse, this one must require a lot more time to polish!";
 	next;
 	mes "[Goma Chara]";
-	mes "Hey, if you give me " + .@needCoin + "<ITEM>Doram Token<INFO>25142</INFO></ITEM>, I'll fix this for you.";
-	mes "<ITEM>This should produce the <INFO>" + .@next_charm_ID + "</INFO></ITEM> function, I guess. How do you like it?";
+	mes "Hey, if you give me " + .@needCoin + " " + mesitemlink( 25142, false ) + ", I'll fix this for you.";
+	mes "This should produce " + mesitemlink( .@next_charm_ID, false ) + ", I guess. How do you like it?";
 	next;
 	if (select( "Upgrade", "Cancel" ) == 2) {
 		mes "[Goma Chara]";

+ 1 - 1
npc/re/merchants/Emperium_Seller.txt

@@ -28,7 +28,7 @@ prt_in,212,169,3	script	Guild Clerk	4_M_04,{
 	next;
 	mes "[Guild Clerk]";
 	mes "As part of that,";
-	mes "we are selling a limited quantity of 100 <ITEM>Emperium<INFO>714</INFO></ITEM> every day";
+	mes "we are selling a limited quantity of 100 " + mesitemlink( 714, false ) + " every day";
 	mes "from ^0000ff18:00 to 23:59^000000 from ^0000ffMonday to Saturday^000000.";
 	next;
 	mes "[Guild Clerk]";

+ 1 - 1
npc/re/merchants/Slot_Move_Card_Sales.txt

@@ -15,7 +15,7 @@
 prt_in,211,173,3	script	Slot Move Card Sales#slo	4_F_01,{
 	mes "[Salesman]";
 	mes "Howdy.";
-	mes "I'm selling <ITEM>[Character Position Change Coupon]<INFO>12786</INFO></ITEM>.";
+	mes "I'm selling " + mesitemlink( 12786 ) + ".";
 	mes "You can ^4d4dffchange the slot position of a character using the card^000000.";
 	next;
 	mes "[Salesman]";

+ 1 - 1
npc/re/merchants/cashmall.txt

@@ -110,7 +110,7 @@ itemmall,41,53,3	script	Cat Hand Salesman Macaroon#cashmall	4_M_MERCAT1,{
 	mes "Welcome!";
 	mes "Today doesn't come every day!";
 	mes "Things to see today~ Voila!";
-	mes "You can only exchange with <ITEM>[[Kachua] Mileage Coupon]<INFO>1000274</INFO></ITEM>!";
+	mes "You can only exchange with " + mesitemlink( 1000274 ) + "!";
 	mes "Feel free to choose!";
 	next;
 	switch( select( "3-1st Job Group Skill Shadow", "3-2nd Job Group Skill Shadow", "Extended Job Group Skill Shadow", "General Shadow by Occupation", "Shadow Cube", "Smelting, Modification, Useful Items", "Drop Box", "Spellbook" ) ){

+ 1 - 1
npc/re/merchants/eden_market.txt

@@ -320,7 +320,7 @@ moc_para01,106,38,4	script	Market Group Hustler#ent	4_M_YOYOROGUE,{
 		next;
 		mes "[Hustler]";
 		mes "More special items are sold on weekends.";
-		mes "I have even seen an <ITEM>Izidor<INFO>709</INFO></ITEM> being sold~";
+		mes "I have even seen an " + mesitemlink( 709, false ) + " being sold~";
 		mes "It was amazing.";
 		mes "Of course it was super expensive and only a handful were up for sale.";
 		next;

+ 15 - 15
npc/re/merchants/enchan_illusion_16_2.txt

@@ -54,7 +54,7 @@ pay_d03_i,160,45,3	script	Gemcutter#ilp20	4_TOWER_17,3,3,{
 		mes "[ Gemcutter ]";
 		mes "The following is the list of equipment I can handle.";
 		for ( .@i = 0; .@i < .@size; ++.@i )
-			mes "<ITEM>" + .@reward_name$[.@i] + "<INFO>" + .@reward_id[.@i] + "</INFO></ITEM>";
+			mes mesitemlink( .@reward_id[.@i], false );
 		next;
 		mes "[ Gemcutter ]";
 		mes "Make sure ^0000FFyour equipment is refined to at least +" + .@refine_req + "^000000 before bringing it to me.";
@@ -133,7 +133,7 @@ pay_d03_i,160,45,3	script	Gemcutter#ilp20	4_TOWER_17,3,3,{
 		mes "[ Gemcutter ]";
 		mes "The following is the list of equipment I can handle.";
 		for ( .@i = 0; .@i < .@size; ++.@i )
-			mes "<ITEM>" + .@reward_name$[.@i] + "<INFO>" + .@reward_id[.@i] + "</INFO></ITEM>";
+			mes mesitemlink( .@reward_id[.@i], false );
 		next;
 		mes "[ Gemcutter ]";
 		mes "Make sure ^0000FFyour equipment is refined to at least +" + .@refine_req + "^000000 before bringing it to me.";
@@ -385,7 +385,7 @@ gef_dun01,139,228,3	script	Great Merchant#illgef	4_M_HUMERCHANT,{
 			case 1:
 				switch( select( "Illusion Infiltrator", "Illusion Sharpened Legbone of Ghoul", "Illusion Wizardry Staff", "Illusion Ballista", "Illusion Book of the Apocalypse" ) ) {
 				case 1:
-					mes "<ITEM>Illusion Infiltrator<INFO>28022</INFO></ITEM>";
+					mes mesitemlink( 28022, false );
 					mes "***********************************";
 					mes "Necessary Items";
 					mes "^0000cd+9 or higher^000000 Infiltrator ^C71585[1]^000000 x1";
@@ -395,7 +395,7 @@ gef_dun01,139,228,3	script	Great Merchant#illgef	4_M_HUMERCHANT,{
 					mes "20 Torn Papers";
 					break;
 				case 2:
-					mes "<ITEM>Illusion Sharpened Legbone of Ghoul<INFO>28023</INFO></ITEM>";
+					mes mesitemlink( 28023, false );
 					mes "********************************";
 					mes "Necessary Items";
 					mes "^0000cd+9 or higher^000000 Sharpened Legbone of Ghoul x1";
@@ -403,7 +403,7 @@ gef_dun01,139,228,3	script	Great Merchant#illgef	4_M_HUMERCHANT,{
 					mes "100 Clusters of Nightmares";
 					break;
 				case 3:
-					mes "<ITEM>Illusion Wizardry Staff<INFO>2039</INFO></ITEM>";
+					mes mesitemlink( 2039, false );
 					mes "********************************";
 					mes "Necessary Items";
 					mes "^0000cd+9 or higher^000000 Wizardry Staff x1";
@@ -411,7 +411,7 @@ gef_dun01,139,228,3	script	Great Merchant#illgef	4_M_HUMERCHANT,{
 					mes "100 Suspicious Pentacles";
 					break;
 				case 4:
-					mes "<ITEM>Illusion Ballista<INFO>18149</INFO></ITEM>";
+					mes mesitemlink( 18149, false );
 					mes "*************************";
 					mes "Necessary Items";
 					mes "^0000cd+9 or higher^000000 Ballista ^C71585[1]^000000 x1";
@@ -421,7 +421,7 @@ gef_dun01,139,228,3	script	Great Merchant#illgef	4_M_HUMERCHANT,{
 					mes "100 Shining Spores";
 					break;
 				case 5:
-					mes "<ITEM>Illusion Book of the Apocalypse<INFO>28612</INFO></ITEM>";
+					mes mesitemlink( 28612, false );
 					mes "***********************";
 					mes "Necessary Items";
 					mes "^0000cd+9 or higher^000000 Book of the Apocalypse x1";
@@ -432,7 +432,7 @@ gef_dun01,139,228,3	script	Great Merchant#illgef	4_M_HUMERCHANT,{
 				break;
 			case 2:
 				select("Illusion Ancient Cape");
-				mes "<ITEM>Illusion Ancient Cape<INFO>20840</INFO></ITEM>";
+				mes mesitemlink( 20840, false );
 				mes "*******************************";
 				mes "Necessary Items";
 				mes "^0000cd+9 or higher^000000 Ancient Cape ^C71585[1]^000000 x1";
@@ -444,7 +444,7 @@ gef_dun01,139,228,3	script	Great Merchant#illgef	4_M_HUMERCHANT,{
 			case 3:
 				switch( select( "Illusion Skull Ring", "Illusion Ring" ) ) {
 				case 1:
-					mes "<ITEM>Illusion Skull Ring<INFO>28508</INFO></ITEM>";
+					mes mesitemlink( 28508, false );
 					mes "*************************";
 					mes "Necessary Items";
 					mes "Skull Ring ^C71585[1]^000000 x1";
@@ -454,7 +454,7 @@ gef_dun01,139,228,3	script	Great Merchant#illgef	4_M_HUMERCHANT,{
 					mes "400 Dried Yggdrasil Leaves";
 					break;
 				case 2:
-					mes "<ITEM>Illusion Ring<INFO>28509</INFO></ITEM>";
+					mes mesitemlink( 28509, false );
 					mes "********************";
 					mes "Necessary Items";
 					mes "Ring ^C71585[1]^000000 x1";
@@ -647,8 +647,8 @@ ice_dun02,153,18,3	script	Illusion Stone Research	4_M_ALCHE_B,{
 			getitemname(.@reward_id[1]);
 		mes "[Illusion Stone Researcher]";
 		mes "The following is the list of equipment I can handle.";
-		mes "<ITEM>" + .@reward_name$[0] + "<INFO>" + .@reward_id[0] + "</INFO></ITEM>";
-		mes "<ITEM>" + .@reward_name$[1] + "<INFO>" + .@reward_id[1] + "</INFO></ITEM>";
+		mes mesitemlink( .@reward_id[0], false );
+		mes mesitemlink( .@reward_id[1], false );
 		next;
 		mes "[Illusion Stone Researcher]";
 		mes "Make sure ^4d4dffyour equipment is refined to at least +9^000000 before bringing it to me.";
@@ -695,9 +695,9 @@ ice_dun02,153,18,3	script	Illusion Stone Research	4_M_ALCHE_B,{
 			getitemname(.@reward_id[2]);
 		mes "[Illusion Stone Researcher]";
 		mes "The following is the list of equipment I can handle.";
-		mes "<ITEM>" + .@reward_name$[0] + "<INFO>" + .@reward_id[0] + "</INFO></ITEM>";
-		mes "<ITEM>" + .@reward_name$[1] + "<INFO>" + .@reward_id[1] + "</INFO></ITEM>";
-		mes "<ITEM>" + .@reward_name$[2] + "<INFO>" + .@reward_id[2] + "</INFO></ITEM>";
+		mes mesitemlink( .@reward_id[0], false );
+		mes mesitemlink( .@reward_id[1], false );
+		mes mesitemlink( .@reward_id[2], false );
 		next;
 		mes "[Illusion Stone Researcher]";
 		mes "Make sure ^4d4dffyour equipment is refined to at least +9^000000 before bringing it to me.";

+ 26 - 26
npc/re/merchants/enchan_illusion_17_1.txt

@@ -21,7 +21,7 @@ sp_cor,152,158,4	script	Butterfly Merchant#sp_cor	4_M_ORIENT01,{
 sp_cor,136,156,3	script	Grace Operator#ext162	4_M_REPAIR,{
 	mes "[Grace Operator]";
 	mes "Hello.";
-	mes "We have ^4d4dffGrace^000000 equipment that can be exchanged for <ITEM>[" + getitemname(25723) + "]<INFO>25723</INFO></ITEM>.";
+	mes "We have ^4d4dffGrace^000000 equipment that can be exchanged for " + mesitemlink( 25723 ) + ".";
 	mes "I will guide you to exchange items according to your job.";
 	close2;
 	switch( eaclass() & EAJ_THIRDMASK ) {
@@ -160,12 +160,12 @@ sp_cor,108,130,5	script	Rebellion#rm171_7	4_F_REBELLION3,{
 		npctalk "Elyumina: What? If you were just going to keep me standing here like a statue, why did you even call me? You jerks!", "Elyumina#rm171_4", bc_self;
 		if (checkweight(1201,3) == 0) {
 			mes "[Rebellion]";
-			mes "Do you want a Weapon Modification Device? It's 5 <ITEM>[Cor Cores]<INFO>25723</INFO></ITEM> or 1 million Zeny.";
+			mes "Do you want a Weapon Modification Device? It's 5 " + mesitemlink( 25723 ) + " or 1 million Zeny.";
 			mes "Your bag is full. Please make some room first.";
 			close;
 		}
 		mes "[Rebellion]";
-		mes "Do you want a Weapon Modification Device? It's 5 <ITEM>[Cor Cores]<INFO>25723</INFO></ITEM> or 1 million Zeny.";
+		mes "Do you want a Weapon Modification Device? It's 5 " + mesitemlink( 25723 ) + " or 1 million Zeny.";
 		mes "If you want a weapon, you can talk to Elyumina.";
 		next;
 		if (select("Request Weapon Modification Device (Physical).", "Request Weapon Modification Device (Magic).") == 1) {
@@ -178,9 +178,9 @@ sp_cor,108,130,5	script	Rebellion#rm171_7	4_F_REBELLION3,{
 			setarray .@ids[0],23779,23780,23781;
 		}
 		mes "[Rebellion]";
-		mes "I can randomly give you a <ITEM>[" + getitemname(.@ids[0]) + "]<INFO>" + .@ids[0] + "</INFO></ITEM>,";
-		mes "<ITEM>[" + getitemname(.@ids[1]) + "]<INFO>" + .@ids[1] + "</INFO></ITEM>,";
-		mes "or <ITEM>[" + getitemname(.@ids[2]) + "]<INFO>" + .@ids[2] + "</INFO></ITEM>.";
+		mes "I can randomly give you a " + mesitemlink( .@ids[0] ) + ",";
+		mes mesitemlink( .@ids[1] ) + ",";
+		mes "or " + mesitemlink( .@ids[2] ) + ".";
 		mes "Which one do you have, 5 Cor Cores or 1 million Zeny?";
 		next;
 		disable_items;
@@ -220,7 +220,7 @@ sp_cor,108,130,5	script	Rebellion#rm171_7	4_F_REBELLION3,{
 	case 3:
 		npctalk "Elyumina: What? If you were just going to keep me standing here like a statue, why did you even call me? You brutes!", "Elyumina#rm171_4", bc_self;
 		mes "[Rebellion]";
-		mes "Do you want an Armor Modification Module? It's 30 <ITEM>[Mysterious Components]<INFO>25669</INFO></ITEM> and 5 <ITEM>[Cor Cores]<INFO>25723</INFO></ITEM>.";
+		mes "Do you want an Armor Modification Module? It's 30 " + mesitemlink( 25669 ) + " and 5 " + mesitemlink( 25723 ) + ".";
 		if (checkweight(1201,3) == 0) {
 			mes "Your bag is full. Please make some room first.";
 			close;
@@ -287,7 +287,7 @@ sp_cor,111,130,3	script	Elyumina#rm171_4	4_EP17_ELYUMINA,{
 	case 1:
 		cutin "ep171_elyumina01",0;
 		mes "[Elyumina]";
-		mes "OS weapons? I'll handle that if you bring me 1 <ITEM>[Damaged Weapon]<INFO>25668</INFO></ITEM> and 50 <ITEM>[Mysterious Components]<INFO>25669</INFO></ITEM>.";
+		mes "OS weapons? I'll handle that if you bring me 1 " + mesitemlink( 25668 ) + " and 50 " + mesitemlink( 25669 ) + ".";
 		mes "I'll give you whatever kind I want to give you, among the ones I have. Why should I let you pick?";
 		next;
 		cutin "",255;
@@ -297,21 +297,21 @@ sp_cor,111,130,3	script	Elyumina#rm171_4	4_EP17_ELYUMINA,{
 			mes "Tsk, tsk. I said everything I make is good. Do you really have to choose? Alright, then listen up.";
 			next;
 			mes "[Elyumina]";
-			mes "Sword: <ITEM>[Cannon Rapier-OS]<INFO>13493</INFO></ITEM>";
-			mes "Two-handed Sword: <ITEM>[Beam Claymore-OS]<INFO>21047</INFO></ITEM>";
-			mes "Staff: <ITEM>[Rutilus Stick-OS]<INFO>26151</INFO></ITEM>";
-			mes "Book: <ITEM>[Circuit Board-OS]<INFO>28629</INFO></ITEM>";
-			mes "Axe: <ITEM>[Blasti-OS]<INFO>28136</INFO></ITEM>";
-			mes "Mace: <ITEM>[Saphir Hall-OS]<INFO>16088</INFO></ITEM>";
-			mes "Bow: <ITEM>[Virtual Bow-OS]<INFO>18178</INFO></ITEM>";
-			mes "Crossbow: <ITEM>[MH-P89-OS]<INFO>18179</INFO></ITEM>";
-			mes "Katar: <ITEM>[Meuchler-OS]<INFO>28038</INFO></ITEM>";
-			mes "Knuckle: <ITEM>[Burning Knuckle-OS]<INFO>1862</INFO></ITEM>";
-			mes "Sniper Rifle: <ITEM>[HR-S55-OS]<INFO>28253</INFO></ITEM>";
-			mes "Dagger: <ITEM>[Kuroiro-OS]<INFO>28755</INFO></ITEM>";
-			mes "Bow: <ITEM>[AC-B44-OS]<INFO>18180</INFO></ITEM>";
-			mes "Lance: <ITEM>[Boost Lance-OS]<INFO>32019</INFO></ITEM>";
-			mes "Mace: <ITEM>[Ultio-OS]<INFO>16089</INFO></ITEM>";
+			mes "Sword: " + mesitemlink( 13493 );
+			mes "Two-handed Sword: " + mesitemlink( 21047 );
+			mes "Staff: " + mesitemlink( 26151 );
+			mes "Book: " + mesitemlink( 28629 );
+			mes "Axe: " + mesitemlink( 28136 );
+			mes "Mace: " + mesitemlink( 16088 );
+			mes "Bow: " + mesitemlink( 18178 );
+			mes "Crossbow: " + mesitemlink( 18179 );
+			mes "Katar: " + mesitemlink( 28038 );
+			mes "Knuckle: " + mesitemlink( 1862 );
+			mes "Sniper Rifle: " + mesitemlink( 28253 );
+			mes "Dagger: " + mesitemlink( 28755 );
+			mes "Bow: " + mesitemlink( 18180 );
+			mes "Lance: " + mesitemlink( 32019 );
+			mes "Mace: " + mesitemlink( 16089 );
 			close3;
 		}
 		disable_items;
@@ -340,7 +340,7 @@ sp_cor,111,130,3	script	Elyumina#rm171_4	4_EP17_ELYUMINA,{
 	case 2:
 		cutin "ep171_elyumina04",0;
 		mes "[Elyumina]";
-		mes "If you want Illusion armor, bring me 50 <ITEM>[Cor Cores]<INFO>25723</INFO></ITEM>. I'll give you a piece.";
+		mes "If you want Illusion armor, bring me 50 " + mesitemlink( 25723 ) + ". I'll give you a piece.";
 		mes "Let's see... Ooh, when did I make so many varieties? Alright, I feel generous. What do you want?";
 		next;
 		cutin "",255;
@@ -363,8 +363,8 @@ sp_cor,111,130,3	script	Elyumina#rm171_4	4_EP17_ELYUMINA,{
 		}
 		cutin "ep171_elyumina01",0;
 		mes "[Elyumina]";
-		mes "<ITEM>[" + getitemname(.@item[0]) + "]<INFO>" + .@item[0] + "</INFO></ITEM>";
-		mes "<ITEM>[" + getitemname(.@item[1]) + "]<INFO>" + .@item[1] + "</INFO></ITEM>";
+		mes mesitemlink( .@item[0] );
+		mes mesitemlink( .@item[1] );
 		mes "Which one?";
 		next;
 		cutin "",255;

+ 2 - 2
npc/re/merchants/enchan_rockridge.txt

@@ -296,7 +296,7 @@ har_in01,24,69,3	script	Affable Lady#rockridge0	1_F_MERCHANT_02,{
 	}
 	mes "[Affable Lady]";
 	mes "Ah, you're interested in the";
-	mes "[<ITEM>" + .@item_name$[.@s] + "<INFO>" + .@item_id[.@s] + "</INFO></ITEM>].";
+	mes "[" + mesitemlink( .@item_id[.@s], false, .@item_name$[.@s] ) + "].";
 	mes "Click the name for the detailed description.";
 	mes "As I told you, it's ^0000CD3,000,000 Zeny^000000. Do you want to buy it?";
 	next;
@@ -371,7 +371,7 @@ har_in01,34,81,5	script	Howard#rr	4_M_TATIO,{
 	.@s = ( select(.@menu$) - 1 ) * 3;
 
 	mes "[Howard]";
-	mes "<ITEM>" + .@data$[.@s+2] + "<INFO>" + .@data$[.@s+1] + "</INFO></ITEM>, got it.";
+	mes mesitemlink( atoi( .@data$[.@s+1] ), false, .@data$[.@s+2] ) + ", got it.";
 	mes "That'll be " + .@data$[.@s] + " Rock Ridge Coins.";
 	mes "Are you certain you want this item?";
 	next;

+ 3 - 3
npc/re/merchants/ghost_palace_exchange.txt

@@ -13,7 +13,7 @@ dali02,51,130,4	script	Dimension Traveler	4_F_SHABBY,{
 	}
 	.@item_name_req$ = getitemname(6672);// Gray_Shard
 	mes "[Dimension Traveler]";
-	mes "Adventurer friend, <ITEM>[" + .@item_name_req$ + "]<INFO>6672</INFO></ITEM> is what I need. How about exchanging it with something I have?";
+	mes "Adventurer friend, " + mesitemlink( 6672 ) + " is what I need. How about exchanging it with something I have?";
 	next;
 	.@type = select( "Show me your weapon.", "Show me your armor.", "Anything special?", "I do not need." ) - 1;
 	mes "[Dimension Traveler]";
@@ -33,7 +33,7 @@ dali02,51,130,4	script	Dimension Traveler	4_F_SHABBY,{
 	}
 	next;
 	mes "[Dimension Traveler]";
-	mes "Ah! The number that is written beside <ITEM>[" + .@item_name_req$ + "]<INFO>6672</INFO></ITEM> will be needed.";
+	mes "Ah! The number that is written beside " + mesitemlink( 6672 ) + " will be needed.";
 	mes "Please keep that in mind.";
 
 	switch(.@type) {
@@ -80,7 +80,7 @@ dali02,51,130,4	script	Dimension Traveler	4_F_SHABBY,{
 		.@s = (select(.@menu$) - 1) * 2;
 		mes "[Dimension Traveler]";
 		if (.@type != 1)	// armor type doesn't display item info
-			mes "Do you mean <ITEM>[" + getitemname(.@items[.@s]) + "]<INFO>" + .@items[.@s] + "</INFO></ITEM>?";
+			mes "Do you mean " + mesitemlink( .@items[.@s] ) + "?";
 		mes "" + .@items[.@s+1] + " ^006400" + .@item_name_req$ + "^000000 are required in exchange.";
 		next;
 		switch( select( "Let's exchange.", "Let me see other stuff.", "I will come back later." ) ) {

+ 8 - 8
npc/re/merchants/new_insurance.txt

@@ -22,32 +22,32 @@ prontera,82,108,5	script	Heart Merchant#life01	4_M_NFDEADMAN2,5,5,{
 	next;
 	if(!countitem(.@old_item)){
 		mes "[Heart Merchant]";
-		mes "Do you have any <ITEM>["+.@old_item_name$+"]<INFO>" + .@old_item + "</INFO></ITEM> in your storage?";
+		mes "Do you have any " + mesitemlink( .@old_item ) + " in your storage?";
 		next;
 		mes "[Heart Merchant]";
-		mes "If you bring me a " + .@old_item_name$ + ", I'll exchange it to <ITEM>["+.@new_item_name$+"]<INFO>" + .@new_item + "</INFO></ITEM>. What do you think? Do you have any idea what this item is?";
+		mes "If you bring me a " + .@old_item_name$ + ", I'll exchange it to " + mesitemlink( .@new_item ) + ". What do you think? Do you have any idea what this item is?";
 	} else {
 		mes "[Heart Merchant]";
-		mes "Have you ever thought about replacing your <ITEM>["+.@old_item_name$+"]<INFO>" + .@old_item + "</INFO></ITEM> to something better? For example... <ITEM>["+.@new_item_name$+"]<INFO>" + .@new_item + "</INFO></ITEM>. What do you think?";
+		mes "Have you ever thought about replacing your " + mesitemlink( .@old_item ) + " to something better? For example... " + mesitemlink( .@new_item ) + ". What do you think?";
 	}
 	next;
 	switch(select("What is it?",(countitem(.@old_item)?"Exchange it please!":""),"I'm not interested")) {
 	case 1:
 		mes "[Heart Merchant]";
-		mes "<ITEM>["+.@old_item_name$+"]<INFO>" + .@old_item + "</INFO></ITEM> is an item that prevents you from losing experience on death once within the 30 minutes duration after use.";
+		mes mesitemlink( .@old_item ) + " is an item that prevents you from losing experience on death once within the 30 minutes duration after use.";
 		next;
 		mes "[Heart Merchant]";
-		mes "But a lot of people are sad about the time limit, right? So I looked into it and prepared the <ITEM>["+.@new_item_name$+"]<INFO>" + .@new_item + "</INFO></ITEM>.";
+		mes "But a lot of people are sad about the time limit, right? So I looked into it and prepared the " + mesitemlink( .@new_item ) + ".";
 		next;
 		mes "[Heart Merchant]";
-		mes "<ITEM>["+.@new_item_name$+"]<INFO>" + .@new_item + "</INFO></ITEM> is an item that will prevent the loss of experience on death once by just having it ^EE0000regardless of the duration^000000. Of course, after death, the "+.@new_item_name$+" is consumed.";
+		mes mesitemlink( .@new_item ) + " is an item that will prevent the loss of experience on death once by just having it ^EE0000regardless of the duration^000000. Of course, after death, the "+.@new_item_name$+" is consumed.";
 		next;
 		select("Why are you exchanging it?");
 		mes "[Heart Merchant]";
 		mes "Are you curious about that? I'm a merchant. Buying and selling things is my fate, whether it's related to one's life or death. Do you think I'm going to miss this opportunity to make money? I make money, and the living get a leeway from the pain of death. Isn't that a good deal?";
 		next;
 		mes "[Heart Merchant]";
-		mes "The exchange rate is 5 <ITEM>["+.@old_item_name$+"]<INFO>" + .@old_item + "</INFO></ITEM> for 1 <ITEM>["+.@new_item_name$+"]<INFO>" + .@new_item + "</INFO></ITEM>. Do you have any questions?";
+		mes "The exchange rate is 5 " + mesitemlink( .@old_item ) + " for 1 " + mesitemlink( .@new_item ) + ". Do you have any questions?";
 		next;
 		mes "[Heart Merchant]";
 		mes "Hm~ What do you think? Isn't it a fair trade? Do you want to always worry about time? It's a must-have for adventurers who enjoy breathtaking adventures.";
@@ -84,7 +84,7 @@ prontera,82,108,5	script	Heart Merchant#life01	4_M_NFDEADMAN2,5,5,{
 		}
 		if (countitem(.@old_item) < (.@amount*5)) {
 			mes "[Heart Merchant]";
-			mes "Um, excuse me but... you don't have enough " +.@old_item_name$+ ", no? It's 5 <ITEM>["+.@old_item_name$+"]<INFO>" + .@old_item + "</INFO></ITEM> for 1 <ITEM>["+.@new_item_name$+"]<INFO>" + .@new_item + "</INFO></ITEM>. Please check the quantity.";
+			mes "Um, excuse me but... you don't have enough " +.@old_item_name$+ ", no? It's 5 " + mesitemlink( .@old_item ) + " for 1 " + mesitemlink( .@new_item ) + ". Please check the quantity.";
 			close;
 		}
 		mes "[Heart Merchant]";

+ 1 - 1
npc/re/merchants/refine.txt

@@ -686,7 +686,7 @@ lhz_in02,281,24,5	duplicate(Dietrich#ns_prt)	Fruel#2	4_M_02
 // Shadowdecon/Zelunium exchange npcs
 prt_in,64,57,3	script	Pauline	4_M_02,{
 	mes "[" + strnpcinfo(1) + "]";
-	mes "Do you have <ITEM>[Shadowdecon Gemstone]<INFO>25728</INFO></ITEM> or <ITEM>[Zelunium Gemstone]<INFO>25730</INFO></ITEM>?";
+	mes "Do you have " + mesitemlink( 25728 ) + " or " + mesitemlink( 25730 ) + "?";
 	mes "We will exchange them for refined products for use as smelting goods.";
 	close2;
 	callshop "barter_refine_3";

+ 14 - 14
npc/re/quests/juno_monster_society.txt

@@ -736,7 +736,7 @@ ein_fild06,257,351,4	script	Map Examiner Bast#yma	4_F_CHNDRESS1,{
 			close;
 		case 2:
 			mes .@npc_name$;
-			mes "Can I move it to Einbroch? Give me one <ITEM>[" + .@item_name$ + "]<INFO>1000374</INFO></ITEM> and I can teleport you.";
+			mes "Can I move it to Einbroch? Give me one " + mesitemlink( 1000374 ) + " and I can teleport you.";
 			next;
 			select( "Give me 1 " + .@item_name$ + "." );
 			if (countitem(1000374) < 1) {
@@ -787,7 +787,7 @@ ein_fild06,257,351,4	script	Map Examiner Bast#yma	4_F_CHNDRESS1,{
 			close;
 		case 3:
 			mes .@npc_name$;
-			mes "Can I move it to Einbroch? Give me one <ITEM>[" + .@item_name$ + "]<INFO>1000374</INFO></ITEM> and I can teleport you.";
+			mes "Can I move it to Einbroch? Give me one " + mesitemlink( 1000374 ) + " and I can teleport you.";
 			next;
 			select( "Give me 1 " + .@item_name$ + "." );
 			if (countitem(1000374) < 1) {
@@ -872,7 +872,7 @@ gef_fild06,209,31,6	script	Map Examiner Gefil#yma	4_M_MIDDLE,{
 			close;
 		case 2:
 			mes .@npc_name$;
-			mes "Give me 1 <ITEM>[" + .@item_name$ + "]<INFO>1000374</INFO></ITEM> and I can teleport you to Geffen.";
+			mes "Give me 1 " + mesitemlink( 1000374 ) + " and I can teleport you to Geffen.";
 			next;
 			select( "Give me 1 " + .@item_name$ + "." );
 			if (countitem(1000374) < 1) {
@@ -916,7 +916,7 @@ gef_fild06,209,31,6	script	Map Examiner Gefil#yma	4_M_MIDDLE,{
 			close;
 		case 3:
 			mes .@npc_name$;
-			mes "Give me 1 <ITEM>[" + .@item_name$ + "]<INFO>1000374</INFO></ITEM> and I can teleport you to Geffen.";
+			mes "Give me 1 " + mesitemlink( 1000374 ) + " and I can teleport you to Geffen.";
 			next;
 			select( "Give me 1 " + .@item_name$ + "." );
 			if (countitem(1000374) < 1) {
@@ -1001,7 +1001,7 @@ lhz_fild01,240,107,4	script	Map Examiner Lipiri#yma	4_M_HUBOY,{
 			close;
 		case 2:
 			mes .@npc_name$;
-			mes "If it's a nearby city, it's Lighthalzen. Give me one <ITEM>[" + .@item_name$ + "]<INFO>1000374</INFO></ITEM> and I can teleport you.";
+			mes "If it's a nearby city, it's Lighthalzen. Give me one " + mesitemlink( 1000374 ) + " and I can teleport you.";
 			next;
 			select( "Give me 1 " + .@item_name$ + "." );
 			if (countitem(1000374) < 1) {
@@ -1052,7 +1052,7 @@ lhz_fild01,240,107,4	script	Map Examiner Lipiri#yma	4_M_HUBOY,{
 			close;
 		case 3:
 			mes .@npc_name$;
-			mes "If it's a nearby city, it's Lighthalzen. Give me one <ITEM>[" + .@item_name$ + "]<INFO>1000374</INFO></ITEM> and I can teleport you.";
+			mes "If it's a nearby city, it's Lighthalzen. Give me one " + mesitemlink( 1000374 ) + " and I can teleport you.";
 			next;
 			select( "Give me 1 " + .@item_name$ + "." );
 			if (countitem(1000374) < 1) {
@@ -1276,7 +1276,7 @@ hu_fild01,133,157,6	script	Map Examiner Huf#yma	4_MAL_CAPTAIN,{
 			close;
 		case 2:
 			mes .@npc_name$;
-			mes "Are you going home? Hugel is the nearest city. I need 1 piece of <ITEM>[" + .@item_name$ + "]<INFO>1000374</INFO></ITEM>.";
+			mes "Are you going home? Hugel is the nearest city. I need 1 piece of " + mesitemlink( 1000374 ) + ".";
 			next;
 			select( "Give me 1 " + .@item_name$ + "." );
 			if (countitem(1000374) < 1) {
@@ -1321,7 +1321,7 @@ hu_fild01,133,157,6	script	Map Examiner Huf#yma	4_MAL_CAPTAIN,{
 			close;
 		case 3:
 			mes .@npc_name$;
-			mes "Are you going home? Hugel is the nearest city. I need 1 piece of <ITEM>[" + .@item_name$ + "]<INFO>1000374</INFO></ITEM>.";
+			mes "Are you going home? Hugel is the nearest city. I need 1 piece of " + mesitemlink( 1000374 ) + ".";
 			next;
 			select( "Give me 1 " + .@item_name$ + "." );
 			if (countitem(1000374) < 1) {
@@ -1411,7 +1411,7 @@ tur_dun01,159,46,4	script	Map Examiner Tural#yma	4_M_BRZ_MAN1,{
 			close;
 		case 2:
 			mes .@npc_name$;
-			mes "Give me one <ITEM>[" + .@item_name$ + "]<INFO>1000374</INFO></ITEM> and I can teleport you to Alberta.";
+			mes "Give me one " + mesitemlink( 1000374 ) + " and I can teleport you to Alberta.";
 			next;
 			select( "Give me 1 " + .@item_name$ + "." );
 			if (countitem(1000374) < 1) {
@@ -1452,7 +1452,7 @@ tur_dun01,159,46,4	script	Map Examiner Tural#yma	4_M_BRZ_MAN1,{
 			close;
 		case 3:
 			mes .@npc_name$;
-			mes "Give me one <ITEM>[" + .@item_name$ + "]<INFO>1000374</INFO></ITEM> and I can teleport you to Alberta.";
+			mes "Give me one " + mesitemlink( 1000374 ) + " and I can teleport you to Alberta.";
 			next;
 			select( "Give me 1 " + .@item_name$ + "." );
 			if (countitem(1000374) < 1) {
@@ -1818,7 +1818,7 @@ tur_dun02,151,256,4	script	Map Examiner Tidun#yma	4_M_NINJA_BLUE,{
 			close;
 		case 2:
 			mes .@npc_name$;
-			mes "If you give me one <ITEM>[" + .@item_name$ + "]<INFO>1000374</INFO></ITEM>, I can teleport you to the nearby city, Alberta.";
+			mes "If you give me one " + mesitemlink( 1000374 ) + ", I can teleport you to the nearby city, Alberta.";
 			next;
 			select( "Give me 1 " + .@item_name$ + "." );
 			if (countitem(1000374) < 1) {
@@ -1863,7 +1863,7 @@ tur_dun02,151,256,4	script	Map Examiner Tidun#yma	4_M_NINJA_BLUE,{
 			close;
 		case 3:
 			mes .@npc_name$;
-			mes "If you give me one <ITEM>[" + .@item_name$ + "]<INFO>1000374</INFO></ITEM>, I can teleport you to the nearby city, Alberta.";
+			mes "If you give me one " + mesitemlink( 1000374 ) + ", I can teleport you to the nearby city, Alberta.";
 			next;
 			select( "Give me 1 " + .@item_name$ + "." );
 			if (countitem(1000374) < 1) {
@@ -1947,7 +1947,7 @@ tur_dun03,125,186,6	script	Map Examiner Tsensor#yma	4_M_SIT_NOVICE,{
 			close;
 		case 2:
 			mes .@npc_name$;
-			mes "Alberta Express 1 <ITEM>[" + .@item_name$ + "]<INFO>1000374</INFO></ITEM>, left immediately.";
+			mes "Alberta Express 1 " + mesitemlink( 1000374 ) + ", left immediately.";
 			next;
 			select( "Give me 1 " + .@item_name$ + "." );
 			if (countitem(1000374) < 1) {
@@ -1992,7 +1992,7 @@ tur_dun03,125,186,6	script	Map Examiner Tsensor#yma	4_M_SIT_NOVICE,{
 			close;
 		case 3:
 			mes .@npc_name$;
-			mes "Alberta Express 1 <ITEM>[" + .@item_name$ + "]<INFO>1000374</INFO></ITEM>, left immediately.";
+			mes "Alberta Express 1 " + mesitemlink( 1000374 ) + ", left immediately.";
 			next;
 			select( "Give me 1 " + .@item_name$ + "." );
 			if (countitem(1000374) < 1) {

+ 1 - 1
npc/re/quests/quests_16_1.txt

@@ -14258,7 +14258,7 @@ prt_cas,270,168,3	duplicate(Royal Guardian Knight#02)	Royal Guardian Knight#03	4
 prt_cas,165,260,6	script	Noblesse Operator#ext161	4_F_CRU,{
 	mes "[Noblesse Operator]";
 	mes "Hello.";
-	mes "We have ^4d4dffNoblesse^000000 equipment that can be exchanged for <ITEM>[Honor Token]<INFO>6919</INFO></ITEM>.";
+	mes "We have ^4d4dffNoblesse^000000 equipment that can be exchanged for " + mesitemlink( 6919 ) + ".";
 	mes "I will guide you to exchange items according to your job.";
 	close2;
 	switch( eaclass() & EAJ_THIRDMASK ) {

+ 3 - 3
npc/re/quests/quests_16_2.txt

@@ -11387,7 +11387,7 @@ rebel_in,100,40,4	script	Butterfly Merchant#rebel_in	4_M_ORIENT02,{
 rebel_in,99,51,3	script	Imperial Operator#ext162	4_M_REPAIR,{
 	mes "[Imperial Operator]";
 	mes "Hello.";
-	mes "We have ^4d4dffImperial^000000 equipment that can be exchanged for <ITEM>[" + getitemname(6919) + "]<INFO>6919</INFO></ITEM>.";
+	mes "We have ^4d4dffImperial^000000 equipment that can be exchanged for " + mesitemlink( 6919, false ) + ".";
 	mes "I will guide you to exchange items according to your job.";
 	close2;
 	switch( eaclass() & EAJ_THIRDMASK ) {
@@ -11519,7 +11519,7 @@ rebel_in,74,67,5	script	Strasse#rebel_in	4_M_TATIO,{
 
 	.@s = (select( "Agenda Robe", "Consultation Robe", "Costume Combat Vestige", "Hat of Republic", "Mercenary Ring A type", "Mercenary Ring B type" ) - 1) * 2;
 	mes "[Strasse]";
-	mes "<ITEM>" + getitemname(.@item[.@s]) + "<INFO>" + .@item[.@s] + "</INFO></ITEM>? I got it.";
+	mes mesitemlink( .@item[.@s], false ) + "? I got it.";
 	mes "You need " + .@item[.@s+1] + " Schwartz Honor Tokens.";
 	mes "Are you sure you want this?";
 	next;
@@ -11536,7 +11536,7 @@ rebel_in,74,67,5	script	Strasse#rebel_in	4_M_TATIO,{
 	}
 	// custom text
 	mes "[Strasse]";
-	mes "Here is your <ITEM>" + getitemname(.@item[.@s]) + "<INFO>" + .@item[.@s] + "</INFO></ITEM>.";
+	mes "Here is your " + mesitemlink( .@item[.@s], false ) + ".";
 	delitem 25155, .@item[.@s+1];
 	getitem .@item[.@s],1;
 	close;

+ 10 - 10
npc/re/quests/quests_rockridge.txt

@@ -781,15 +781,15 @@ har_in01,20,30,5	script	Wyatt Warp#har_in01	4_M_YATTWARP,{
 		next;
 		mes "[Wyatt Warp]";
 		mes "Both badges are worn by us Vigilantes, but they provide different effects.";
-		mes "I have <ITEM>Vigilante Badge (L)<INFO>28495</INFO></ITEM>";
-		mes "and <ITEM>Vigilante Badge (R)<INFO>28496</INFO></ITEM>.";
+		mes "I have " + mesitemlink( 28495, false, "Vigilante Badge (L)" );
+		mes "and " + mesitemlink( 28496, false, "Vigilante Badge (R)" ) + ".";
 		mes "Pick one you like.";
 		next;
 		setarray .@item_name$[0], "Vigilante Badge (L)", "Vigilante Badge (R)";
 		setarray .@item_id[0], 28495, 28496;
 		.@s = select( "Vigilante Badge (L)", "Vigilante Badge (R)" ) - 1;
 		mes "[Wyatt Warp]";
-		mes "Do you want <ITEM>" + .@item_name$[.@s] + "<INFO>" + .@item_id[.@s] + "</INFO></ITEM>?";
+		mes "Do you want " + mesitemlink( .@item_id[.@s], false, .@item_name$[.@s] ) + "?";
 		mes "Excellent choice!";
 		mes "Are you certain you want this?";
 		next;
@@ -3345,7 +3345,7 @@ harboro1,357,163,3	script	Food Distributer	4_COOK,{
 		mes "Sweet potato croquettes are on the menu today, and I can't make them because I didn't get the regular shipment from the mainland.";
 		next;
 		mes "[Food Distributer]";
-		mes "Bring me 160 <ITEM>Sweet Potatoes<INFO>516</INFO></ITEM> from Midgard. You can buy them from merchants in big cities.";
+		mes "Bring me 160 " + mesitemlink( 516, false, "Sweet Potatoes" ) + " from Midgard. You can buy them from merchants in big cities.";
 		close;
 	case 12384:
 		setquest 12384;// Meat Delivery
@@ -3356,7 +3356,7 @@ harboro1,357,163,3	script	Food Distributer	4_COOK,{
 		mes "What? I could always feed them veggies, you say? Sure, but all they want is meat.";
 		next;
 		mes "[Food Distributer]";
-		mes "Bring me 50 <ITEM>Meats<INFO>517</INFO></ITEM> from Midgard. You can buy them from merchants in big cities.";
+		mes "Bring me 50 " + mesitemlink( 517, false, "Meats" ) + " from Midgard. You can buy them from merchants in big cities.";
 		close;
 	case 12385:
 		setquest 12385;// Carrot Delivery
@@ -3367,7 +3367,7 @@ harboro1,357,163,3	script	Food Distributer	4_COOK,{
 		mes "They're as thin as fingers, and once I almost put my fingers into a stew instead of them.";
 		next;
 		mes "[Food Distributer]";
-		mes "Bring me 160 <ITEM>Carrots<INFO>515</INFO></ITEM> from Midgard. You can buy them from merchants in big cities.";
+		mes "Bring me 160 " + mesitemlink( 515, false, "Carrots" ) + " from Midgard. You can buy them from merchants in big cities.";
 		close;
 	case 12386:
 		setquest 12386;// Banana Delivery
@@ -3375,7 +3375,7 @@ harboro1,357,163,3	script	Food Distributer	4_COOK,{
 		mes "I shouldn't have put that banana bread on the menu. Who knew they wouldn't arrive in time?";
 		next;
 		mes "[Food Distributer]";
-		mes "Bring me 160 <ITEM>Bananas<INFO>513</INFO></ITEM> from Midgard. You can buy them from merchants in big cities.";
+		mes "Bring me 160 " + mesitemlink( 513, false, "Bananas" ) + " from Midgard. You can buy them from merchants in big cities.";
 		close;
 	case 12387:
 		setquest 12387;// Pumpkin Delivery
@@ -3383,7 +3383,7 @@ harboro1,357,163,3	script	Food Distributer	4_COOK,{
 		mes "I have to cook a pumpkin stew, but I don't have pumpkins. This is the equivalent of making toast without bread.";
 		next;
 		mes "[Food Distributer]";
-		mes "Bring me 160 <ITEM>Pumpkins<INFO>535</INFO></ITEM> from Midgard. You can buy them from merchants in big cities.";
+		mes "Bring me 160 " + mesitemlink( 535, false, "Pumpkins" ) + " from Midgard. You can buy them from merchants in big cities.";
 		close;
 	case 12388:
 		setquest 12388;// Mushroom Delivery
@@ -3391,7 +3391,7 @@ harboro1,357,163,3	script	Food Distributer	4_COOK,{
 		mes "The only thing I can cook with the ingredients I have is mushroom soup, but I don't have the main ingredient: mushrooms.";
 		next;
 		mes "[Food Distributer]";
-		mes "Bring me 60 <ITEM>Mushrooms<INFO>581</INFO></ITEM> from Midgard. You can buy them from merchants in big cities.";
+		mes "Bring me 60 " + mesitemlink( 581, false, "Mushrooms" ) + " from Midgard. You can buy them from merchants in big cities.";
 		close;
 	}
 	end;
@@ -3401,7 +3401,7 @@ S_Food:
 	.@amount = getarg(2);
 	if (countitem(.@item_id) < .@amount) {
 		mes "[Food Distributer]";
-		mes "Bring me " + .@amount + " <ITEM>" + getitemname(.@item_id) + "<INFO>" + .@item_id + "</INFO></ITEM> from Midgard. You can buy them from merchants in big cities.";
+		mes "Bring me " + .@amount + " " + mesitemlink( .@item_id, false ) + " from Midgard. You can buy them from merchants in big cities.";
 		close;
 	}
 	delitem .@item_id, .@amount;

+ 22 - 11
npc/test/ci/7291.txt

@@ -1,14 +1,18 @@
 -	script	itemlink#ci	-1,{
 OnInit:
 	if( checkre(0) ){
-		if( PACKETVER >= 20200916 ){
+		if( PACKETVER >= 20200724 ){
+			// Change of separators and add grade
 			.@expected$ = "<ITEML>0000213v0%0g&00'00)18X)1ck)00)00+2R,00-00</ITEML>";
-		}else if( PACKETVER >= 20150225 ){
-			// Grade does not exist (clientside) yet
-			.@expected$ = "<ITEMLINK>0000213v0%0g&00(18X(1ck(00(00*2R+00,00</ITEMLINK>";
-		}else if( PACKETVER >= 20100000 ){
-			// Random Options do not exist (clientside) yet
-			.@expected$ = "<ITEMLINK>0000213v0%0g&00(18X(1ck(00(00</ITEMLINK>";
+		}else if( PACKETVER >= 20161116 ){
+			// Change of separators and add equip preview
+			.@expected$ = "<ITEML>0000213v0%0g&00(18X(1ck(00(00*2R+00,00</ITEML>";
+		}else if( PACKETVER >= 20160113 ){
+			// Change from <ITEM> to <ITEML>
+			.@expected$ = "<ITEML>0000213v0%0g'18X'1ck'00'00)2R*00+00</ITEML>";
+		}else if( PACKETVER >= 20151104 ){
+			// Initial version
+			.@expected$ = "<ITEM>0000213v0%0g'18X'1ck'00'00)2R*00+00</ITEM>";
 		}else{
 			// Item Link does not exist (clientside) yet
 			.@expected$ = "Crimson Saber";
@@ -18,11 +22,18 @@ OnInit:
 		.@actual$ = itemlink(13454,16,4399,4608,0,0,0,.@opt_ids,.@opt_dummy,.@opt_dummy);
 		AssertEquals(.@expected$, .@actual$, "Generated itemlink for +16 Earth Crimson Saber");
 	}else{
-		if( PACKETVER >= 20200916 ){
+		if( PACKETVER >= 20200724 ){
+			// Change of separators and add grade (not used in pre-renewal)
 			.@expected$ = "<ITEML>000021hS%0a&00'00)18X)00)00)00</ITEML>";
-		}else if( PACKETVER >= 20100000 ){
-			// Grade does not exist (clientside) yet// Grade does not exist (clientside) yet
-			.@expected$ = "<ITEMLINK>000021hS%0a&00(18X(00(00(00</ITEMLINK>";
+		}else if( PACKETVER >= 20161116 ){
+			// Change of separators and add equip preview
+			.@expected$ = "<ITEML>000021hS%0a&00(18X(00(00(00</ITEML>";
+		}else if( PACKETVER >= 20160113 ){
+			// Change from <ITEM> to <ITEML>
+			.@expected$ = "<ITEML>000021hS%0a'18X'00'00'00</ITEML>";
+		}else if( PACKETVER >= 20151104 ){
+			// Initial version
+			.@expected$ = "<ITEM>000021hS%0a'18X'00'00'00</ITEM>";
 		}else{
 			// Item Link does not exist (clientside) yet
 			.@expected$ = "Blade";

+ 23 - 0
src/map/battle.cpp

@@ -10277,6 +10277,9 @@ static const struct _battle_data {
 	{ "feature.barter",                     &battle_config.feature_barter,                  1,      0,      1,              },
 	{ "feature.barter_extended",            &battle_config.feature_barter_extended,         1,      0,      1,              },
 	{ "feature.itemlink",                   &battle_config.feature_itemlink,                1,      0,      1,              },
+	{ "feature.mesitemlink",                &battle_config.feature_mesitemlink,             1,      0,      1,              },
+	{ "feature.mesitemlink_brackets",       &battle_config.feature_mesitemlink_brackets,    0,      0,      1,              },
+	{ "feature.mesitemlink_dbname",         &battle_config.feature_mesitemlink_dbname,      0,      0,      1,              },
 	{ "break_mob_equip",                    &battle_config.break_mob_equip,                 0,      0,      1,              },
 	{ "macro_detection_retry",              &battle_config.macro_detection_retry,           3,      1,      INT_MAX,        },
 	{ "macro_detection_timeout",            &battle_config.macro_detection_timeout,         60000,  0,      INT_MAX,        },
@@ -10366,6 +10369,19 @@ void battle_adjust_conf()
 	if (battle_config.night_duration && battle_config.night_duration < 60000) // added by [Yor]
 		battle_config.night_duration = 60000;
 
+#if PACKETVER < 20100000
+	if( battle_config.feature_mesitemlink ){
+		ShowWarning( "conf/battle/feature.conf:mesitemlink is enabled but it requires PACKETVER 2010-01-01 or newer, disabling...\n" );
+		battle_config.feature_mesitemlink = 0;
+	}
+#elif PACKETVER == 20151029 || PACKETVER == 20151104
+	// The feature is broken on those two clients or maybe even more. For more details check ItemDatabase::create_item_link_for_mes [Lemongrass]
+	if( battle_config.feature_mesitemlink ){
+		ShowWarning( "conf/battle/feature.conf:mesitemlink is enabled but it is broken on this specific PACKETVER, disabling...\n" );
+		battle_config.feature_mesitemlink = 0;
+	}
+#endif
+
 #if PACKETVER < 20100427
 	if (battle_config.feature_buying_store) {
 		ShowWarning("conf/battle/feature.conf:buying_store is enabled but it requires PACKETVER 2010-04-27 or newer, disabling...\n");
@@ -10429,6 +10445,13 @@ void battle_adjust_conf()
 	}
 #endif
 
+#if PACKETVER < 20151104
+	if( battle_config.feature_itemlink ){
+		ShowWarning( "conf/battle/feature.conf:itemlink is enabled but it requires PACKETVER 2015-11-04 or newer, disabling...\n" );
+		battle_config.feature_itemlink = 0;
+	}
+#endif
+
 #if PACKETVER < 20151104
 	if( battle_config.feature_stylist ){
 		ShowWarning("conf/battle/feature.conf stylist is enabled but it requires PACKETVER 2015-11-04 or newer, disabling...\n");

+ 3 - 0
src/map/battle.hpp

@@ -564,6 +564,9 @@ struct Battle_Config
 	int update_enemy_position;
 	int devotion_rdamage;
 	int feature_itemlink;
+	int feature_mesitemlink;
+	int feature_mesitemlink_brackets;
+	int feature_mesitemlink_dbname;
 
 	// autotrade persistency
 	int feature_autotrade;

+ 60 - 0
src/map/itemdb.cpp

@@ -1357,6 +1357,66 @@ std::string ItemDatabase::create_item_link(struct item& item) {
 	return this->create_item_link(item, data);
 }
 
+std::string ItemDatabase::create_item_link_for_mes( std::shared_ptr<item_data>& data, bool use_brackets, const char* name ){
+	if( data == nullptr ){
+		return "Unknown item";
+	}
+
+	std::string itemstr;
+
+// All these dates are unconfirmed
+#if PACKETVER >= 20100000
+	if( battle_config.feature_mesitemlink ){
+// It was changed in 2015-11-04, but Gravity actually broke the feature for this specific client, because they introduced the new itemlink feature [Lemongrass]
+// See the following github issues for more details:
+// * https://github.com/rathena/rathena/issues/1236
+// * https://github.com/rathena/rathena/issues/1873
+#if PACKETVER >= 20151104
+		const std::string start_tag = "<ITEM>";
+		const std::string closing_tag = "</ITEM>";
+#else
+		const std::string start_tag = "<ITEMLINK>";
+		const std::string closing_tag = "</ITEMLINK>";
+#endif
+
+		itemstr += start_tag;
+
+		if( use_brackets || battle_config.feature_mesitemlink_brackets ){
+			itemstr += "[";
+		}
+
+		if( name != nullptr && !battle_config.feature_mesitemlink_dbname ){
+			// Name was forcefully overwritten
+			itemstr += name;
+		}else{
+			// Use database name
+			itemstr += data->ename;
+		}
+
+		if( use_brackets || battle_config.feature_mesitemlink_brackets ){
+			itemstr += "]";
+		}
+
+		itemstr += "<INFO>";
+		itemstr += std::to_string( data->nameid );
+		itemstr += "</INFO>";
+
+		itemstr += closing_tag;
+
+		return itemstr;
+	}
+#endif
+
+	// This can be reached either because itemlinks are disabled via configuration or because the packet version does not support the feature
+	if( name != nullptr && !battle_config.feature_mesitemlink_dbname ){
+		// Name was forcefully overwritten
+		return name;
+	}else{
+		// Use database name
+		return data->ename;
+	}
+}
+
 ItemDatabase item_db;
 
 /**

+ 1 - 0
src/map/itemdb.hpp

@@ -2151,6 +2151,7 @@ public:
 	std::shared_ptr<item_data> search_aegisname( const char *name );
 	std::string create_item_link(struct item& item);
 	std::string create_item_link( std::shared_ptr<item_data>& data );
+	std::string create_item_link_for_mes( std::shared_ptr<item_data>& data, bool use_brackets, const char* name );
 
 private:
 	std::string create_item_link(struct item& item, std::shared_ptr<item_data>& data);

+ 32 - 0
src/map/script.cpp

@@ -26806,6 +26806,37 @@ BUILDIN_FUNC(itemlink)
 	return SCRIPT_CMD_SUCCESS;
 }
 
+BUILDIN_FUNC(mesitemlink){
+	t_itemid nameid = script_getnum( st, 2 );
+	std::shared_ptr<item_data> data = item_db.find( nameid );
+	
+	if( data == nullptr ){
+		ShowError( "buildin_mesitemlink: Item ID %u does not exists.\n", nameid );
+		script_pushconststr( st, "" );
+		return SCRIPT_CMD_FAILURE;
+	}
+
+	bool use_brackets = true;
+
+	if( script_hasdata( st, 3 ) ){
+		use_brackets = script_getnum( st, 3 ) != 0;
+	}
+
+	const char* name = nullptr;
+
+	if( script_hasdata( st, 4 ) ){
+		name = script_getstr( st, 4 );
+	}
+
+	// Create the link, depending on configuration and packet version
+	std::string itemlstr = item_db.create_item_link_for_mes( data, use_brackets, name );
+
+	// Push it to the script engine for further usage
+	script_pushstrcopy( st, itemlstr.c_str() );
+
+	return SCRIPT_CMD_SUCCESS;
+}
+
 BUILDIN_FUNC(addfame) {
 	map_session_data *sd;
 
@@ -27620,6 +27651,7 @@ struct script_function buildin_func[] = {
 	BUILDIN_DEF(item_reform, "??"),
 	BUILDIN_DEF(item_enchant, "i?"),
 	BUILDIN_DEF(itemlink, "i?????????"),
+	BUILDIN_DEF(mesitemlink, "i??"),
 	BUILDIN_DEF(addfame, "i?"),
 	BUILDIN_DEF(getfame, "?"),
 	BUILDIN_DEF(getfamerank, "?"),