Browse Source

Fixed searchstores and added a map parameter (#8456)

Co-authored-by: Aleos <aleos89@users.noreply.github.com>
Co-authored-by: Atemo <Atemo@users.noreply.github.com>
Co-authored-by: Lemongrass3110 <lemongrass@kstp.at>
Daegaladh 10 months ago
parent
commit
549fc3f860

+ 3 - 3
db/pre-re/item_db_usable.yml

@@ -8637,21 +8637,21 @@ Body:
     Type: Usable
     Weight: 10
     Script: |
-      searchstores 10,0;
+      searchstores 10, SEARCHSTORE_EFFECT_NORMAL;
   - Id: 12581
     AegisName: Vending_Search_Scroll2
     Name: Universal Catalog Gold
     Type: Usable
     Weight: 10
     Script: |
-      searchstores 10,1;
+      searchstores 10, SEARCHSTORE_EFFECT_REMOTE;
   - Id: 12591
     AegisName: Uni_Catalog_Bz
     Name: Universal Catalog Bronze
     Type: Usable
     Weight: 10
     Script: |
-      searchstores 10,1;
+      searchstores 10, SEARCHSTORE_EFFECT_REMOTE;
   - Id: 12609
     AegisName: Old_Ore_Box
     Name: Old Ore Box

+ 5 - 5
db/re/item_db_usable.yml

@@ -11333,7 +11333,7 @@ Body:
     Type: Usable
     Weight: 10
     Script: |
-      searchstores 10,0;
+      searchstores 10, SEARCHSTORE_EFFECT_NORMAL;
   - Id: 12581
     AegisName: Vending_Search_Scroll2
     Name: Universal Catalog Gold
@@ -11348,7 +11348,7 @@ Body:
       NoMail: true
       NoAuction: true
     Script: |
-      searchstores 10,1;
+      searchstores 10, SEARCHSTORE_EFFECT_REMOTE;
   - Id: 12582
     AegisName: Siege_Supply_Box
     Name: WoE Supply Box
@@ -11492,7 +11492,7 @@ Body:
       NoMail: true
       NoAuction: true
     Script: |
-      searchstores 10,1;
+      searchstores 10, SEARCHSTORE_EFFECT_REMOTE;
   - Id: 12592
     AegisName: Cyclops_Box1
     Name: Cyclops Box1
@@ -63371,8 +63371,8 @@ Body:
     Name: Special Shopper Catalog
     Type: Usable
     Weight: 10
-#   Script: |
-#     /* TODO */
+    Script: |
+      searchstores 3, SEARCHSTORE_EFFECT_NORMAL;
   - Id: 23374
     AegisName: Fire_Armor_S
     Name: Fire Armor Scroll

+ 25 - 12
doc/script_commands.txt

@@ -5694,22 +5694,35 @@ Example:
 
 ---------------------------------------
 
-*searchstores <uses>,<effect>;
+*searchstores <uses>,<effect>{,"<map name>"};
 
 Invokes the store search window, which allows to search for both vending
-and buying stores. Parameter uses indicates, how many searches can be
-started, before the window has to be reopened. Effect value affects,
-what happens, when a result item is double-clicked and can be one of the
-following:
+and buying stores.
 
-	0 = Shows the store's position on the mini-map and highlights the
-	    shop sign with yellow color, when the store is on same map
-	    as the invoking player.
-	1 = Directly opens the shop, regardless of distance.
+Parameter <uses> indicates how many searches can be started
+before the window has to be reopened.
 
-Example:
-	// Item Universal_Catalog_Gold (10 uses, effect: open shop)
-	searchstores 10,1;
+Parameter <effect> affects what happens when a result item is double-clicked
+and can be one of the following:
+
+	SEARCHSTORE_EFFECT_NORMAL : Shows the store's position on the mini-map and highlights the
+								shop sign with yellow color, when the store is on same map
+								as the invoking player.
+	SEARCHSTORE_EFFECT_REMOTE : Directly opens the shop, regardless of distance.
+	
+Optional parameter <map name> indicates the name of map where the stores will be searched.
+If not set, the search will be on the map the invoking character is currently on.
+Special values for <map name> are:
+
+	"this" : Will search for stores on the map where the invoking character is currently on. (default)
+	"all"  : Will search for stores on all maps.
+
+Examples:
+	// Item Vending_Search_Scroll (10 uses, effect: show mark on minimap, current map)
+	searchstores 10, SEARCHSTORE_EFFECT_NORMAL;
+	
+	// Search stores (1 use, effect: open shop, all maps on the server)
+	searchstores 1, SEARCHSTORE_EFFECT_REMOTE, "all";
 
 ---------------------------------------
 

+ 3 - 3
src/map/buyingstore.cpp

@@ -307,7 +307,7 @@ void buyingstore_open(map_session_data* sd, uint32 account_id)
 		return;
 	}
 
-	if( !searchstore_queryremote(sd, account_id) && ( sd->bl.m != pl_sd->bl.m || !check_distance_bl(&sd->bl, &pl_sd->bl, AREA_SIZE) ) )
+	if( !searchstore_queryremote(*sd, account_id) && ( sd->bl.m != pl_sd->bl.m || !check_distance_bl(&sd->bl, &pl_sd->bl, AREA_SIZE) ) )
 	{// out of view range
 		return;
 	}
@@ -354,13 +354,13 @@ void buyingstore_trade( map_session_data* sd, uint32 account_id, unsigned int bu
 		return;
 	}
 
-	if( !searchstore_queryremote(sd, account_id) && ( sd->bl.m != pl_sd->bl.m || !check_distance_bl(&sd->bl, &pl_sd->bl, AREA_SIZE) ) )
+	if( !searchstore_queryremote(*sd, account_id) && ( sd->bl.m != pl_sd->bl.m || !check_distance_bl(&sd->bl, &pl_sd->bl, AREA_SIZE) ) )
 	{// out of view range
 		clif_buyingstore_trade_failed_seller(sd, BUYINGSTORE_TRADE_SELLER_FAILED, 0);
 		return;
 	}
 
-	searchstore_clearremote(sd);
+	searchstore_clearremote(*sd);
 
 	// buyer lost zeny in the mean time? fix the limit
 	if( pl_sd->status.zeny < pl_sd->buyingstore.zenylimit ){

+ 58 - 49
src/map/clif.cpp

@@ -19171,7 +19171,22 @@ static void clif_parse_SearchStoreInfo( int fd, map_session_data *sd ){
 		return;
 	}
 
-	searchstore_query( sd, p->searchType, p->minPrice, p->maxPrice, &p->items[0], p->itemsCount, &p->items[p->itemsCount], p->cardsCount );
+	if ( p->searchType > SEARCHTYPE_BUYING_STORE ) {
+		ShowError( "clif_parse_SearchStoreInfo: Invalid search type %u (account_id=%d).\n", p->searchType, sd->bl.id );
+		return;
+	}
+
+	if ( p->minPrice > battle_config.vending_max_value ) {
+		ShowError( "clif_parse_SearchStoreInfo: Invalid min price %u (account_id=%d).\n", p->minPrice, sd->bl.id );
+		return;
+	}
+
+	if ( p->maxPrice > battle_config.vending_max_value ) {
+		ShowError( "clif_parse_SearchStoreInfo: Invalid max price %u (account_id=%d).\n", p->maxPrice, sd->bl.id );
+		return;
+	}
+
+	searchstore_query( *sd, static_cast<e_searchstore_searchtype>(p->searchType), p->minPrice, p->maxPrice, &p->items[0], p->itemsCount, &p->items[p->itemsCount], p->cardsCount );
 }
 
 
@@ -19193,8 +19208,8 @@ void clif_search_store_info_ack( map_session_data& sd ){
 	p->packetType = HEADER_ZC_SEARCH_STORE_INFO_ACK;
 	p->packetLength = sizeof( *p );
 	p->firstPage = !sd.searchstore.pages;
-	p->nextPage = searchstore_querynext( &sd );
-	p->usesCount = (uint8)umin( sd.searchstore.uses, UINT8_MAX );
+	p->nextPage = searchstore_querynext( sd );
+	p->usesCount = static_cast<decltype(p->usesCount)>( std::min<decltype(sd.searchstore.uses)>( sd.searchstore.uses, std::numeric_limits<decltype(p->usesCount)>::max() ) );
 
 	for( int i = 0, count = 0; i < end - start; i++ ){
 		std::shared_ptr<s_search_store_info_item> ssitem = sd.searchstore.items[start + i];
@@ -19241,57 +19256,50 @@ void clif_search_store_info_ack( map_session_data& sd ){
 }
 
 
-/// Notification of failure when searching for stores (ZC_SEARCH_STORE_INFO_FAILED).
-/// 0837 <reason>.B
-/// reason:
-///     0 = "No matching stores were found." (0x70b)
-///     1 = "There are too many results. Please enter more detailed search term." (0x6f8)
-///     2 = "You cannot search anymore." (0x706)
-///     3 = "You cannot search yet." (0x708)
-///     4 = "No sale (purchase) information available." (0x705)
-void clif_search_store_info_failed(map_session_data* sd, unsigned char reason)
-{
-	int fd = sd->fd;
+/// Notification of failure when searching for stores.
+/// 0837 <reason>.B (ZC_SEARCH_STORE_INFO_FAILED)
+void clif_search_store_info_failed(map_session_data& sd, e_searchstore_failure reason){
+#if PACKETVER_MAIN_NUM >= 20100601 || PACKETVER_RE_NUM >= 20100601 || defined(PACKETVER_ZERO)
+	PACKET_ZC_SEARCH_STORE_INFO_FAILED packet{};
+
+	packet.packetType = HEADER_ZC_SEARCH_STORE_INFO_FAILED;
+	packet.reason = static_cast<decltype(packet.reason)>(reason);
 
-	WFIFOHEAD(fd,packet_len(0x837));
-	WFIFOW(fd,0) = 0x837;
-	WFIFOB(fd,2) = reason;
-	WFIFOSET(fd,packet_len(0x837));
+	clif_send(&packet, sizeof(packet), &sd.bl, SELF);
+#endif
 }
 
 
-/// Request to display next page of results (CZ_SEARCH_STORE_INFO_NEXT_PAGE).
-/// 0838
+/// Request to display next page of results.
+/// 0838  (CZ_SEARCH_STORE_INFO_NEXT_PAGE)
 static void clif_parse_SearchStoreInfoNextPage(int fd, map_session_data* sd)
 {
-	searchstore_next(sd);
+	searchstore_next(*sd);
 }
 
 
-/// Opens the search store window (ZC_OPEN_SEARCH_STORE_INFO).
-/// 083a <type>.W <remaining uses>.B
-/// type:
-///     0 = Search Stores
-///     1 = Search Stores (Cash), asks for confirmation, when clicking a store
-void clif_open_search_store_info(map_session_data* sd)
-{
-	int fd = sd->fd;
+/// Opens the search store window.
+/// 083a <effect>.W <remaining uses>.B (ZC_OPEN_SEARCH_STORE_INFO)
+void clif_open_search_store_info(map_session_data& sd){
+#if PACKETVER_MAIN_NUM >= 20100701 || PACKETVER_RE_NUM >= 20100701 || defined(PACKETVER_ZERO)
+	PACKET_ZC_OPEN_SEARCH_STORE_INFO packet{};
+
+	packet.packetType = HEADER_ZC_OPEN_SEARCH_STORE_INFO;
+	packet.effect = static_cast<decltype(packet.effect)>(sd.searchstore.effect);
+#if PACKETVER_MAIN_NUM >= 20100701 || PACKETVER_RE_NUM >= 20100701 || defined(PACKETVER_ZERO)
+	packet.remainingUses = static_cast<decltype(packet.remainingUses)>( std::min<decltype(sd.searchstore.uses)>( sd.searchstore.uses, std::numeric_limits<decltype(packet.remainingUses)>::max() ) );
+#endif
 
-	WFIFOHEAD(fd,packet_len(0x83a));
-	WFIFOW(fd,0) = 0x83a;
-	WFIFOW(fd,2) = sd->searchstore.effect;
-#if PACKETVER > 20100701
-	WFIFOB(fd,4) = (unsigned char)umin(sd->searchstore.uses, UINT8_MAX);
+	clif_send(&packet, sizeof(packet), &sd.bl, SELF);
 #endif
-	WFIFOSET(fd,packet_len(0x83a));
 }
 
 
-/// Request to close the store search window (CZ_CLOSE_SEARCH_STORE_INFO).
-/// 083b
+/// Request to close the store search window.
+/// 083b (CZ_CLOSE_SEARCH_STORE_INFO)
 static void clif_parse_CloseSearchStoreInfo(int fd, map_session_data* sd)
 {
-	searchstore_close(sd);
+	searchstore_close(*sd);
 }
 
 
@@ -19300,21 +19308,22 @@ static void clif_parse_CloseSearchStoreInfo(int fd, map_session_data* sd)
 static void clif_parse_SearchStoreInfoListItemClick( int fd, map_session_data* sd ){
 	const PACKET_CZ_SSILIST_ITEM_CLICK* p = reinterpret_cast<PACKET_CZ_SSILIST_ITEM_CLICK*>( RFIFOP( fd, 0 ) );
 
-	searchstore_click( sd, p->AID, p->storeId, p->itemId );
+	searchstore_click( *sd, p->AID, p->storeId, p->itemId );
 }
 
 
-/// Notification of the store position on current map (ZC_SSILIST_ITEM_CLICK_ACK).
-/// 083d <xPos>.W <yPos>.W
-void clif_search_store_info_click_ack(map_session_data* sd, short x, short y)
-{
-	int fd = sd->fd;
+/// Notification of the store position on current map.
+/// 083d <xPos>.W <yPos>.W (ZC_SSILIST_ITEM_CLICK_ACK)
+void clif_search_store_info_click_ack(map_session_data& sd, int16 x, int16 y){
+#if PACKETVER_MAIN_NUM >= 20100608 || PACKETVER_RE_NUM >= 20100608 || defined(PACKETVER_ZERO)
+	PACKET_ZC_SSILIST_ITEM_CLICK_ACK packet{};
 
-	WFIFOHEAD(fd,packet_len(0x83d));
-	WFIFOW(fd,0) = 0x83d;
-	WFIFOW(fd,2) = x;
-	WFIFOW(fd,4) = y;
-	WFIFOSET(fd,packet_len(0x83d));
+	packet.packetType = HEADER_ZC_SSILIST_ITEM_CLICK_ACK;
+	packet.x = x;
+	packet.y = y;
+
+	clif_send(&packet, sizeof(packet), &sd.bl, SELF);
+#endif
 }
 
 

+ 4 - 3
src/map/clif.hpp

@@ -51,6 +51,7 @@ enum e_macro_detect_status : uint8;
 enum e_macro_report_status : uint8;
 enum e_hom_state2 : uint8;
 enum _sp;
+enum e_searchstore_failure : uint16;
 
 enum e_PacketDBVersion { // packet DB
 	MIN_PACKET_DB  = 0x064,
@@ -1249,9 +1250,9 @@ void clif_buyingstore_trade_failed_seller(map_session_data* sd, short result, t_
 
 /// Search Store System
 void clif_search_store_info_ack( map_session_data& sd );
-void clif_search_store_info_failed(map_session_data* sd, unsigned char reason);
-void clif_open_search_store_info(map_session_data* sd);
-void clif_search_store_info_click_ack(map_session_data* sd, short x, short y);
+void clif_search_store_info_failed(map_session_data& sd, e_searchstore_failure reason);
+void clif_open_search_store_info(map_session_data& sd);
+void clif_search_store_info_click_ack(map_session_data& sd, int16 x, int16 y);
 
 /// Cash Shop
 void clif_cashshop_result( map_session_data* sd, t_itemid item_id, uint16 result );

+ 0 - 8
src/map/clif_packetdb.hpp

@@ -1586,10 +1586,8 @@
 // 2010-06-08aRagexeRE
 #if PACKETVER >= 20100608
 	parseable_packet(0x0838,2,clif_parse_SearchStoreInfoNextPage,0);
-	packet(0x083A,4); // Search Stalls Feature
 	parseable_packet(0x083B,2,clif_parse_CloseSearchStoreInfo,0);
 	parseable_packet( HEADER_CZ_SSILIST_ITEM_CLICK, sizeof( struct PACKET_CZ_SSILIST_ITEM_CLICK ), clif_parse_SearchStoreInfoListItemClick, 0 );
-	packet(0x083D,6);
 #endif
 
 // 2010-06-15aRagexeRE
@@ -1609,16 +1607,10 @@
 	//packet(0x07F3,6);
 #endif
 
-// 2010-07-01aRagexeRE
-#if PACKETVER >= 20100701
-	packet(0x083A,5); // Search Stalls Feature
-#endif
-
 // 2010-07-06aRagexeRE
 #if PACKETVER_MAIN_NUM >= 20100817 || PACKETVER_RE_NUM >= 20100706 || defined(PACKETVER_ZERO)
 	parseable_packet(0x0835, -1, clif_parse_SearchStoreInfo, 2, 4, 5, 9, 13, 14, 15);
 	packet(HEADER_ZC_SEARCH_STORE_INFO_ACK, -1);
-	packet(0x0837, 3);
 #endif
 
 // 2010-07-13aRagexeRE

+ 22 - 0
src/map/packets_struct.hpp

@@ -3435,6 +3435,28 @@ struct PACKET_CZ_SEARCH_STORE_INFO {
 */
 } __attribute__((packed));
 
+struct PACKET_ZC_SEARCH_STORE_INFO_FAILED {
+	int16 packetType;
+	uint8 reason;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(ZC_SEARCH_STORE_INFO_FAILED, 0x837);
+
+struct PACKET_ZC_OPEN_SEARCH_STORE_INFO {
+	int16 packetType;
+	uint16 effect;
+#if PACKETVER_MAIN_NUM >= 20100701 || PACKETVER_RE_NUM >= 20100701 || defined(PACKETVER_ZERO)
+	uint8 remainingUses;
+#endif
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(ZC_OPEN_SEARCH_STORE_INFO, 0x83a);
+
+struct PACKET_ZC_SSILIST_ITEM_CLICK_ACK {
+	int16 packetType;
+	int16 x;
+	int16 y;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(ZC_SSILIST_ITEM_CLICK_ACK, 0x83d);
+
 #if PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723 || PACKETVER_ZERO_NUM >= 20221024
 struct PACKET_ZC_SEARCH_STORE_INFO_ACK_sub {
 	uint32 storeId;

+ 35 - 12
src/map/script.cpp

@@ -22458,34 +22458,57 @@ BUILDIN_FUNC(buyingstore)
 
 
 /// Invokes search store info window
-/// searchstores <uses>,<effect>;
+/// searchstores <uses>,<effect>{,<map name>};
 BUILDIN_FUNC(searchstores)
 {
-	unsigned short effect;
-	unsigned int uses;
 	map_session_data* sd;
 
 	if( !script_rid2sd(sd) )
 	{
-		return SCRIPT_CMD_SUCCESS;
+		return SCRIPT_CMD_FAILURE;
 	}
 
-	uses   = script_getnum(st,2);
-	effect = script_getnum(st,3);
+	int32 uses = script_getnum(st,2);
 
-	if( !uses )
+	if (uses < 1 || uses > UINT8_MAX)
 	{
-		ShowError("buildin_searchstores: Amount of uses cannot be zero.\n");
+		ShowError("buildin_searchstores: The amount of uses must be a number between 1 and %u.\n", UINT8_MAX);
 		return SCRIPT_CMD_FAILURE;
 	}
 
-	if( effect > 1 )
+	int32 effect = script_getnum(st,3);
+
+	if( effect < SEARCHSTORE_EFFECT_NORMAL || effect >= SEARCHSTORE_EFFECT_MAX )
 	{
-		ShowError("buildin_searchstores: Invalid effect id %hu, specified.\n", effect);
+		ShowError("buildin_searchstores: Invalid effect id %d, specified.\n", effect);
 		return SCRIPT_CMD_FAILURE;
 	}
 
-	searchstore_open(sd, uses, effect);
+	int16 m;
+
+	if (script_hasdata(st, 4)) {
+		const char* mapname = script_getstr(st, 4);
+
+		if (stricmp(mapname, "all") == 0)
+			m = 0;
+		else if (stricmp(mapname, "this") == 0) {
+			m = sd->bl.m;
+		}
+		else {
+			m = map_mapname2mapid(mapname);
+
+			// TODO: Support multi map-server
+			if (m < 0) {
+				ShowError("buildin_searchstores: Invalid map name %s.\n", mapname);
+				return SCRIPT_CMD_FAILURE;
+			}
+		}
+	}
+	else {
+		m = sd->bl.m;
+	}
+
+	searchstore_open(*sd, static_cast<uint8>(uses), static_cast<e_searchstore_effecttype>(effect), m);
 	return SCRIPT_CMD_SUCCESS;
 }
 /// Displays a number as large digital clock.
@@ -27902,7 +27925,7 @@ struct script_function buildin_func[] = {
 	BUILDIN_DEF(progressbar_npc, "si?"),
 	BUILDIN_DEF(pushpc,"ii"),
 	BUILDIN_DEF(buyingstore,"i"),
-	BUILDIN_DEF(searchstores,"ii"),
+	BUILDIN_DEF(searchstores,"ii?"),
 	BUILDIN_DEF(showdigit,"i?"),
 	// WoE SE
 	BUILDIN_DEF(agitstart2,""),

+ 4 - 0
src/map/script_constants.hpp

@@ -11326,6 +11326,10 @@
 	export_constant(MER_DIETER);
 	export_constant(MER_ELEANOR);
 
+	/* searchstore constants */
+	export_constant(SEARCHSTORE_EFFECT_NORMAL);
+	export_constant(SEARCHSTORE_EFFECT_REMOTE);
+
 	#undef export_constant
 	#undef export_constant2
 	#undef export_parameter

+ 66 - 87
src/map/searchstore.cpp

@@ -12,31 +12,6 @@
 #include "clif.hpp"  // clif_open_search_store_info, clif_search_store_info_*
 #include "pc.hpp"  // map_session_data
 
-/// Failure constants for clif functions
-enum e_searchstore_failure
-{
-	SSI_FAILED_NOTHING_SEARCH_ITEM         = 0,  // "No matching stores were found."
-	SSI_FAILED_OVER_MAXCOUNT               = 1,  // "There are too many results. Please enter more detailed search term."
-	SSI_FAILED_SEARCH_CNT                  = 2,  // "You cannot search anymore."
-	SSI_FAILED_LIMIT_SEARCH_TIME           = 3,  // "You cannot search yet."
-	SSI_FAILED_SSILIST_CLICK_TO_OPEN_STORE = 4,  // "No sale (purchase) information available."
-};
-
-/// Search type constants
-enum e_searchstore_searchtype
-{
-	SEARCHTYPE_VENDING      = 0,
-	SEARCHTYPE_BUYING_STORE = 1,
-};
-
-/// Search effect constants
-enum e_searchstore_effecttype
-{
-	EFFECTTYPE_NORMAL = 0,
-	EFFECTTYPE_CASH   = 1,
-	EFFECTTYPE_MAX
-};
-
 /// Type for shop search function
 typedef bool (*searchstore_search_t)(map_session_data* sd, t_itemid nameid);
 typedef bool (*searchstore_searchall_t)(map_session_data* sd, const struct s_search_store_search* s);
@@ -46,7 +21,7 @@ typedef bool (*searchstore_searchall_t)(map_session_data* sd, const struct s_sea
  * @param type : type of search to conduct
  * @return : search type
  */
-static searchstore_search_t searchstore_getsearchfunc(unsigned char type)
+static searchstore_search_t searchstore_getsearchfunc(e_searchstore_searchtype type)
 {
 	switch( type ) {
 		case SEARCHTYPE_VENDING:      return &vending_search;
@@ -61,7 +36,7 @@ static searchstore_search_t searchstore_getsearchfunc(unsigned char type)
  * @param type : type of search to conduct
  * @return : search type
  */
-static searchstore_searchall_t searchstore_getsearchallfunc(unsigned char type)
+static searchstore_searchall_t searchstore_getsearchallfunc(e_searchstore_searchtype type)
 {
 	switch( type ) {
 		case SEARCHTYPE_VENDING:      return &vending_searchall;
@@ -77,11 +52,11 @@ static searchstore_searchall_t searchstore_getsearchallfunc(unsigned char type)
  * @param type : type of search to conduct
  * @return : store type
  */
-static bool searchstore_hasstore(map_session_data* sd, unsigned char type)
+static bool searchstore_hasstore(map_session_data& sd, e_searchstore_searchtype type)
 {
 	switch( type ) {
-		case SEARCHTYPE_VENDING:      return sd->state.vending;
-		case SEARCHTYPE_BUYING_STORE: return sd->state.buyingstore;
+		case SEARCHTYPE_VENDING:      return sd.state.vending;
+		case SEARCHTYPE_BUYING_STORE: return sd.state.buyingstore;
 	}
 
 	return false;
@@ -93,11 +68,11 @@ static bool searchstore_hasstore(map_session_data* sd, unsigned char type)
  * @param type : type of search to conduct
  * @return : store ID
  */
-static int searchstore_getstoreid(map_session_data* sd, unsigned char type)
+static int searchstore_getstoreid(map_session_data& sd, e_searchstore_searchtype type)
 {
 	switch( type ) {
-		case SEARCHTYPE_VENDING:      return sd->vender_id;
-		case SEARCHTYPE_BUYING_STORE: return sd->buyer_id;
+		case SEARCHTYPE_VENDING:      return sd.vender_id;
+		case SEARCHTYPE_BUYING_STORE: return sd.buyer_id;
 	}
 
 	return 0;
@@ -110,17 +85,16 @@ static int searchstore_getstoreid(map_session_data* sd, unsigned char type)
  * @param effect : shop type
  * @return : true : opened, false : failed to open
  */
-bool searchstore_open(map_session_data* sd, unsigned int uses, unsigned short effect)
+bool searchstore_open(map_session_data& sd, uint16 uses, e_searchstore_effecttype effect, int16 mapid)
 {
-	if( !battle_config.feature_search_stores || sd->searchstore.open )
+	if( !battle_config.feature_search_stores || sd.searchstore.open )
 		return false;
 
-	if( !uses || effect >= EFFECTTYPE_MAX ) // invalid input
-		return false;
 
-	sd->searchstore.open   = true;
-	sd->searchstore.uses   = uses;
-	sd->searchstore.effect = effect;
+	sd.searchstore.open   = true;
+	sd.searchstore.uses   = uses;
+	sd.searchstore.effect = effect;
+	sd.searchstore.mapid  = mapid;
 
 	clif_open_search_store_info(sd);
 
@@ -138,7 +112,7 @@ bool searchstore_open(map_session_data* sd, unsigned int uses, unsigned short ef
  * @param cardlist : list with stored cards (cards attached to items)
  * @param card_count : amount of items in cardlist
  */
-void searchstore_query(map_session_data* sd, unsigned char type, unsigned int min_price, unsigned int max_price, const struct PACKET_CZ_SEARCH_STORE_INFO_item* itemlist, unsigned int item_count, const struct PACKET_CZ_SEARCH_STORE_INFO_item* cardlist, unsigned int card_count)
+void searchstore_query(map_session_data& sd, e_searchstore_searchtype type, unsigned int min_price, unsigned int max_price, const struct PACKET_CZ_SEARCH_STORE_INFO_item* itemlist, unsigned int item_count, const struct PACKET_CZ_SEARCH_STORE_INFO_item* cardlist, unsigned int card_count)
 {
 	unsigned int i;
 	map_session_data* pl_sd;
@@ -150,22 +124,22 @@ void searchstore_query(map_session_data* sd, unsigned char type, unsigned int mi
 	if( !battle_config.feature_search_stores )
 		return;
 
-	if( !sd->searchstore.open )
+	if( !sd.searchstore.open )
 		return;
 
 	if( ( store_searchall = searchstore_getsearchallfunc(type) ) == nullptr ) {
-		ShowError("searchstore_query: Unknown search type %u (account_id=%d).\n", (unsigned int)type, sd->bl.id);
+		ShowError("searchstore_query: Unknown search type %u (account_id=%d).\n", type, sd.bl.id);
 		return;
 	}
 
 	time(&querytime);
 
-	if( sd->searchstore.nextquerytime > querytime ) {
+	if( sd.searchstore.nextquerytime > querytime ) {
 		clif_search_store_info_failed(sd, SSI_FAILED_LIMIT_SEARCH_TIME);
 		return;
 	}
 
-	if( !sd->searchstore.uses ) {
+	if( !sd.searchstore.uses ) {
 		clif_search_store_info_failed(sd, SSI_FAILED_SEARCH_CNT);
 		return;
 	}
@@ -189,15 +163,15 @@ void searchstore_query(map_session_data* sd, unsigned char type, unsigned int mi
 	if( max_price < min_price )
 		std::swap(min_price, max_price);
 
-	sd->searchstore.uses--;
-	sd->searchstore.type = type;
-	sd->searchstore.nextquerytime = querytime+battle_config.searchstore_querydelay;
+	sd.searchstore.uses--;
+	sd.searchstore.type = type;
+	sd.searchstore.nextquerytime = querytime+battle_config.searchstore_querydelay;
 
 	// drop previous results
 	searchstore_clear(sd);
 
 	// search
-	s.search_sd  = sd;
+	s.search_sd  = &sd;
 	s.itemlist   = itemlist;
 	s.cardlist   = cardlist;
 	s.item_count = item_count;
@@ -207,8 +181,13 @@ void searchstore_query(map_session_data* sd, unsigned char type, unsigned int mi
 	iter         = db_iterator((type == SEARCHTYPE_VENDING) ? vending_getdb() : buyingstore_getdb());
 
 	for( pl_sd = (map_session_data*)dbi_first(iter); dbi_exists(iter);  pl_sd = (map_session_data*)dbi_next(iter) ) {
-		if( sd == pl_sd ) // skip own shop, if any
+		if( &sd == pl_sd ) // skip own shop, if any
+			continue;
+
+		// Skip stores that are not in the map defined by the search
+		if (sd.searchstore.mapid != 0 && pl_sd->bl.m != sd.searchstore.mapid) {
 			continue;
+		}
 
 		if( !store_searchall(pl_sd, &s) ) { // exceeded result size
 			clif_search_store_info_failed(sd, SSI_FAILED_OVER_MAXCOUNT);
@@ -218,18 +197,18 @@ void searchstore_query(map_session_data* sd, unsigned char type, unsigned int mi
 
 	dbi_destroy(iter);
 
-	if( !sd->searchstore.items.empty() ) {
+	if( !sd.searchstore.items.empty() ) {
 		// present results
-		clif_search_store_info_ack( *sd );
+		clif_search_store_info_ack( sd );
 
 		// one page displayed
-		sd->searchstore.pages++;
+		sd.searchstore.pages++;
 	} else {
 		// cleanup
 		searchstore_clear(sd);
 
 		// update uses
-		clif_search_store_info_ack( *sd );
+		clif_search_store_info_ack( sd );
 
 		// notify of failure
 		clif_search_store_info_failed(sd, SSI_FAILED_NOTHING_SEARCH_ITEM);
@@ -241,9 +220,9 @@ void searchstore_query(map_session_data* sd, unsigned char type, unsigned int mi
  * @param sd : player requesting
  * @return : true : more items to search, false : no more items
  */
-bool searchstore_querynext(map_session_data* sd)
+bool searchstore_querynext(map_session_data& sd)
 {
-	if( !sd->searchstore.items.empty() && ( sd->searchstore.items.size()-1 )/SEARCHSTORE_RESULTS_PER_PAGE > sd->searchstore.pages )
+	if( !sd.searchstore.items.empty() && ( sd.searchstore.items.size()-1 )/SEARCHSTORE_RESULTS_PER_PAGE > sd.searchstore.pages )
 		return true;
 
 	return false;
@@ -253,41 +232,41 @@ bool searchstore_querynext(map_session_data* sd)
  * Get and display the results for the next page.
  * @param sd : player requesting
  */
-void searchstore_next(map_session_data* sd)
+void searchstore_next(map_session_data& sd)
 {
-	if( !battle_config.feature_search_stores || !sd->searchstore.open || sd->searchstore.items.size() <= sd->searchstore.pages*SEARCHSTORE_RESULTS_PER_PAGE ) // nothing (more) to display
+	if( !battle_config.feature_search_stores || !sd.searchstore.open || sd.searchstore.items.size() <= sd.searchstore.pages*SEARCHSTORE_RESULTS_PER_PAGE ) // nothing (more) to display
 		return;
 
 	// present results
-	clif_search_store_info_ack( *sd );
+	clif_search_store_info_ack( sd );
 
 	// one more page displayed
-	sd->searchstore.pages++;
+	sd.searchstore.pages++;
 }
 
 /**
  * Prepare to clear information for closing of window.
  * @param sd : player requesting
  */
-void searchstore_clear(map_session_data* sd)
+void searchstore_clear(map_session_data& sd)
 {
 	searchstore_clearremote(sd);
 
-	sd->searchstore.items.clear();
-	sd->searchstore.pages = 0;
+	sd.searchstore.items.clear();
+	sd.searchstore.pages = 0;
 }
 
 /**
  * Close the Search Store window.
  * @param sd : player requesting
  */
-void searchstore_close(map_session_data* sd)
+void searchstore_close(map_session_data& sd)
 {
-	if( sd->searchstore.open ) {
+	if( sd.searchstore.open ) {
 		searchstore_clear(sd);
 
-		sd->searchstore.uses = 0;
-		sd->searchstore.open = false;
+		sd.searchstore.uses = 0;
+		sd.searchstore.open = false;
 	}
 }
 
@@ -298,20 +277,20 @@ void searchstore_close(map_session_data* sd)
  * @param store_id : store ID created by client
  * @param nameid : item being searched
  */
-void searchstore_click(map_session_data* sd, uint32 account_id, int store_id, t_itemid nameid)
+void searchstore_click(map_session_data& sd, uint32 account_id, int store_id, t_itemid nameid)
 {
 	unsigned int i;
 	map_session_data* pl_sd;
 	searchstore_search_t store_search;
 
-	if( !battle_config.feature_search_stores || !sd->searchstore.open || sd->searchstore.items.empty() )
+	if( !battle_config.feature_search_stores || !sd.searchstore.open || sd.searchstore.items.empty() )
 		return;
 
 	searchstore_clearremote(sd);
 
-	ARR_FIND( 0, sd->searchstore.items.size(), i, sd->searchstore.items[i]->store_id == store_id && sd->searchstore.items[i]->account_id == account_id && sd->searchstore.items[i]->nameid == nameid );
-	if( i == sd->searchstore.items.size() ) { // no such result, crafted
-		ShowWarning("searchstore_click: Received request with item %u of account %d, which is not part of current result set (account_id=%d, char_id=%d).\n", nameid, account_id, sd->bl.id, sd->status.char_id);
+	ARR_FIND( 0, sd.searchstore.items.size(), i, sd.searchstore.items[i]->store_id == store_id && sd.searchstore.items[i]->account_id == account_id && sd.searchstore.items[i]->nameid == nameid );
+	if( i == sd.searchstore.items.size() ) { // no such result, crafted
+		ShowWarning("searchstore_click: Received request with item %u of account %d, which is not part of current result set (account_id=%d, char_id=%d).\n", nameid, account_id, sd.bl.id, sd.status.char_id);
 		clif_search_store_info_failed(sd, SSI_FAILED_SSILIST_CLICK_TO_OPEN_STORE);
 		return;
 	}
@@ -321,39 +300,39 @@ void searchstore_click(map_session_data* sd, uint32 account_id, int store_id, t_
 		return;
 	}
 
-	if( !searchstore_hasstore(pl_sd, sd->searchstore.type) || searchstore_getstoreid(pl_sd, sd->searchstore.type) != store_id ) { // no longer vending/buying or not same shop
+	if( !searchstore_hasstore(*pl_sd, sd.searchstore.type) || searchstore_getstoreid(*pl_sd, sd.searchstore.type) != store_id ) { // no longer vending/buying or not same shop
 		clif_search_store_info_failed(sd, SSI_FAILED_SSILIST_CLICK_TO_OPEN_STORE);
 		return;
 	}
 
-	store_search = searchstore_getsearchfunc(sd->searchstore.type);
+	store_search = searchstore_getsearchfunc(sd.searchstore.type);
 
 	if( !store_search(pl_sd, nameid) ) {// item no longer being sold/bought
 		clif_search_store_info_failed(sd, SSI_FAILED_SSILIST_CLICK_TO_OPEN_STORE);
 		return;
 	}
 
-	switch( sd->searchstore.effect ) {
-		case EFFECTTYPE_NORMAL:
+	switch( sd.searchstore.effect ) {
+		case SEARCHSTORE_EFFECT_NORMAL:
 			// display coords
-			if( sd->bl.m != pl_sd->bl.m ) // not on same map, wipe previous marker
+			if( sd.bl.m != pl_sd->bl.m ) // not on same map, wipe previous marker
 				clif_search_store_info_click_ack(sd, -1, -1);
 			else
 				clif_search_store_info_click_ack(sd, pl_sd->bl.x, pl_sd->bl.y);
 			break;
-		case EFFECTTYPE_CASH:
+		case SEARCHSTORE_EFFECT_REMOTE:
 			// open remotely
 			// to bypass range checks
-			sd->searchstore.remote_id = account_id;
+			sd.searchstore.remote_id = account_id;
 
-			switch( sd->searchstore.type ) {
-				case SEARCHTYPE_VENDING:      vending_vendinglistreq(sd, account_id); break;
-				case SEARCHTYPE_BUYING_STORE: buyingstore_open(sd, account_id);       break;
+			switch( sd.searchstore.type ) {
+				case SEARCHTYPE_VENDING:      vending_vendinglistreq(&sd, account_id); break;
+				case SEARCHTYPE_BUYING_STORE: buyingstore_open(&sd, account_id);       break;
 			}
 			break;
 		default:
 			// unknown
-			ShowError("searchstore_click: Unknown search store effect %u (account_id=%d).\n", (unsigned int)sd->searchstore.effect, sd->bl.id);
+			ShowError("searchstore_click: Unknown search store effect %u (account_id=%d).\n", sd.searchstore.effect, sd.bl.id);
 	}
 }
 
@@ -363,16 +342,16 @@ void searchstore_click(map_session_data* sd, uint32 account_id, int store_id, t_
  * @param account_id : account ID of owner's shop
  * @return : true : shop opened, false : shop not opened
  */
-bool searchstore_queryremote(map_session_data* sd, uint32 account_id)
+bool searchstore_queryremote(map_session_data& sd, uint32 account_id)
 {
-	return (bool)( sd->searchstore.open && !sd->searchstore.items.empty() && sd->searchstore.remote_id == account_id );
+	return (bool)( sd.searchstore.open && !sd.searchstore.items.empty() && sd.searchstore.remote_id == account_id );
 }
 
 /**
  * Removes range-check bypassing for remotely opened stores.
  * @param sd : player requesting
  */
-void searchstore_clearremote(map_session_data* sd)
+void searchstore_clearremote(map_session_data& sd)
 {
-	sd->searchstore.remote_id = 0;
+	sd.searchstore.remote_id = 0;
 }

+ 54 - 12
src/map/searchstore.hpp

@@ -15,6 +15,47 @@
 
 #define SEARCHSTORE_RESULTS_PER_PAGE 10
 
+/// Failure constants for clif functions
+enum e_searchstore_failure : uint16
+{
+	// "No matching stores were found." (1803)
+	SSI_FAILED_NOTHING_SEARCH_ITEM = 0,
+
+	// "There are too many results. Please enter more detailed search term." (1784)
+	SSI_FAILED_OVER_MAXCOUNT,
+
+	// "You cannot search anymore." (1798)
+	SSI_FAILED_SEARCH_CNT,
+
+	// "You cannot search yet." (1800)
+	SSI_FAILED_LIMIT_SEARCH_TIME,
+
+	// "No sale (purchase) information available." (1797)
+	SSI_FAILED_SSILIST_CLICK_TO_OPEN_STORE,
+};
+
+/// Search type constants
+enum e_searchstore_searchtype : uint16
+{
+	// Search for vending stores
+	SEARCHTYPE_VENDING = 0,
+
+	// Search for buying stores
+	SEARCHTYPE_BUYING_STORE,
+};
+
+/// Search effect constants
+enum e_searchstore_effecttype : uint16
+{
+	// Displays the coordinates of the store
+	SEARCHSTORE_EFFECT_NORMAL = 0,
+
+	// Opens the store remotely
+	SEARCHSTORE_EFFECT_REMOTE,
+
+	SEARCHSTORE_EFFECT_MAX
+};
+
 /// information about the search being performed
 struct s_search_store_search {
 	map_session_data* search_sd;  // sd of the searching player
@@ -41,22 +82,23 @@ struct s_search_store_info_item {
 struct s_search_store_info {
 	std::vector<std::shared_ptr<s_search_store_info_item>> items;
 	unsigned int pages;  // amount of pages already sent to client
-	unsigned int uses;
+	uint16 uses;
 	int remote_id;
 	time_t nextquerytime;
-	unsigned short effect;  // 0 = Normal (display coords), 1 = Cash (remote open store)
-	unsigned char type;  // 0 = Vending, 1 = Buying Store
+	e_searchstore_effecttype effect;
+	e_searchstore_searchtype type;
+	int16 mapid;
 	bool open;
 };
 
-bool searchstore_open(map_session_data* sd, unsigned int uses, unsigned short effect);
-void searchstore_query(map_session_data* sd, unsigned char type, unsigned int min_price, unsigned int max_price, const struct PACKET_CZ_SEARCH_STORE_INFO_item* itemlist, unsigned int item_count, const struct PACKET_CZ_SEARCH_STORE_INFO_item* cardlist, unsigned int card_count);
-bool searchstore_querynext(map_session_data* sd);
-void searchstore_next(map_session_data* sd);
-void searchstore_clear(map_session_data* sd);
-void searchstore_close(map_session_data* sd);
-void searchstore_click(map_session_data* sd, uint32 account_id, int store_id, t_itemid nameid);
-bool searchstore_queryremote(map_session_data* sd, uint32 account_id);
-void searchstore_clearremote(map_session_data* sd);
+bool searchstore_open(map_session_data& sd, uint16 uses, e_searchstore_effecttype effect, int16 mapid);
+void searchstore_query(map_session_data& sd, e_searchstore_searchtype type, unsigned int min_price, unsigned int max_price, const struct PACKET_CZ_SEARCH_STORE_INFO_item* itemlist, unsigned int item_count, const struct PACKET_CZ_SEARCH_STORE_INFO_item* cardlist, unsigned int card_count);
+bool searchstore_querynext(map_session_data& sd);
+void searchstore_next(map_session_data& sd);
+void searchstore_clear(map_session_data& sd);
+void searchstore_close(map_session_data& sd);
+void searchstore_click(map_session_data& sd, uint32 account_id, int store_id, t_itemid nameid);
+bool searchstore_queryremote(map_session_data& sd, uint32 account_id);
+void searchstore_clearremote(map_session_data& sd);
 
 #endif /* SEARCHSTORE_HPP */

+ 1 - 1
src/map/unit.cpp

@@ -3151,7 +3151,7 @@ int unit_remove_map_(struct block_list *bl, clr_type clrtype, const char* file,
 			if(sd->trade_partner)
 				trade_tradecancel(sd);
 
-			searchstore_close(sd);
+			searchstore_close(*sd);
 
 			if (sd->menuskill_id != AL_TELEPORT) { //bugreport:8027
 				if (sd->state.storage_flag == 1)

+ 2 - 2
src/map/vending.cpp

@@ -136,10 +136,10 @@ void vending_purchasereq(map_session_data* sd, int aid, int uid, const uint8* da
 		return;
 	}
 
-	if( !searchstore_queryremote(sd, aid) && ( sd->bl.m != vsd->bl.m || !check_distance_bl(&sd->bl, &vsd->bl, AREA_SIZE) ) )
+	if( !searchstore_queryremote(*sd, aid) && ( sd->bl.m != vsd->bl.m || !check_distance_bl(&sd->bl, &vsd->bl, AREA_SIZE) ) )
 		return; // shop too far away
 
-	searchstore_clearremote(sd);
+	searchstore_clearremote(*sd);
 
 	if( count < 1 || count > MAX_VENDING || count > vsd->vend_num )
 		return; // invalid amount of purchased items