Просмотр исходного кода

Fixed vending_over_max behavior to match official (#8469)

Co-authored-by: Lemongrass3110 <lemongrass@kstp.at>
Daegaladh 10 месяцев назад
Родитель
Сommit
0a977c1fd7
4 измененных файлов с 53 добавлено и 9 удалено
  1. 4 2
      conf/battle/items.conf
  2. 3 6
      src/map/clif.cpp
  3. 19 0
      src/map/clif.hpp
  4. 27 1
      src/map/vending.cpp

+ 4 - 2
conf/battle/items.conf

@@ -12,8 +12,10 @@
 // The highest value at which an item can be sold via the merchant vend skill. (in zeny)
 vending_max_value: 1000000000
 
-// Whether to allow buying from vending chars that are at their max. zeny limit.
-// If set to yes, the rest of the zeny above the char's capacity will disappear.
+// Whether to allow placing items on a vending store when the player's zeny plus the total price
+// of the items exceeds the maximum zeny allowed. (Note 1)
+// If set to "yes", the items will be placed in the store but other players will not be able to buy them.
+// Official behavior is "yes", but on some official servers the client doesn't allow this.
 vending_over_max: yes
 
 // Tax to apply to all vending transactions (eg: 10000 = 100%, 50 = 0.50%)

+ 3 - 6
src/map/clif.cpp

@@ -7674,15 +7674,12 @@ void clif_buyvending( map_session_data& sd, uint16 index, uint16 amount, e_pc_pu
 
 /// Show's vending player its list of items for sale.
 /// 0a28 <result>.B (ZC_ACK_OPENSTORE2)
-/// result:
-///     0 = Success
-///     1 = Failed
-void clif_openvending_ack( map_session_data& sd, bool failure ){
+void clif_openvending_ack( map_session_data& sd, e_ack_openstore2 result ){
 #if PACKETVER >= 20141022
 	PACKET_ZC_ACK_OPENSTORE2 packet{};
 
 	packet.packetType = HEADER_ZC_ACK_OPENSTORE2;
-	packet.result = failure;
+	packet.result = static_cast<decltype(packet.result)>(result);
 
 	clif_send( &packet, sizeof( packet ), &sd.bl, SELF );
 #endif
@@ -7722,7 +7719,7 @@ void clif_openvending( map_session_data& sd ){
 
 	clif_send( p, p->packetLength, &sd.bl, SELF );
 
-	clif_openvending_ack( sd, false );
+	clif_openvending_ack( sd, OPENSTORE2_SUCCESS );
 }
 
 

+ 19 - 0
src/map/clif.hpp

@@ -639,6 +639,9 @@ enum clif_messages : uint16_t {
 	// Currently there is no attendance check event.
 	MSI_CHECK_ATTENDANCE_NOT_EVENT = 3474,
 
+	// The total amount of items to sell exceeds the amount of Zeny you can have. \nPlease modify the quantity and price.
+	MSI_MERCHANTSHOP_TOTA_LOVER_ZENY_ERR = 3826,
+
 	// It weighs more than 70%. Decrease the Weight and try again.
 	MSI_ENCHANT_FAILED_OVER_WEIGHT = 3837,
 
@@ -784,6 +787,21 @@ enum e_pc_purchase_result_frommc : uint8 {
 	PURCHASEMC_NO_SALES_INFO = 7,
 };
 
+enum e_ack_openstore2 : uint8 {
+	// Success
+	OPENSTORE2_SUCCESS = 0,
+
+	// (Pop-up) Failed to open stalls. (MSI_MERCHANTSHOP_MAKING_FAIL / 2639)
+	OPENSTORE2_FAILED = 1,
+
+	// 2 is unused
+
+#if PACKETVER >= 20170419
+	// Unable to open a shop at the current location. (MSI_MERCHANTSHOP_FAIL_POSITION / 3229)
+	OPENSTORE2_NOVENDING = 3,
+#endif
+};
+
 enum e_ack_whisper : uint8 {
 	ACKWHISPER_SUCCESS = 0,
 	ACKWHISPER_TARGET_OFFLINE = 1,
@@ -998,6 +1016,7 @@ void clif_closevendingboard(struct block_list* bl, int fd);
 void clif_vendinglist( map_session_data& sd, map_session_data& vsd );
 void clif_buyvending( map_session_data& sd, uint16 index, uint16 amount, e_pc_purchase_result_frommc result );
 void clif_openvending( map_session_data& sd );
+void clif_openvending_ack(map_session_data& sd, e_ack_openstore2 result);
 void clif_vendingreport( map_session_data& sd, uint16 index, uint16 amount, uint32 char_id, int32 zeny );
 
 void clif_movetoattack( map_session_data& sd, block_list& bl );

+ 27 - 1
src/map/vending.cpp

@@ -175,7 +175,7 @@ void vending_purchasereq(map_session_data* sd, int aid, int uid, const uint8* da
 			clif_buyvending( *sd, idx, amount, PURCHASEMC_NO_ZENY ); // you don't have enough zeny
 			return;
 		}
-		if( z + (double)vsd->status.zeny > (double)MAX_ZENY && !battle_config.vending_over_max ) {
+		if( z + (double)vsd->status.zeny > (double)MAX_ZENY ) {
 			clif_buyvending( *sd, idx, vsd->vending[j].amount, PURCHASEMC_OUT_OF_STOCK ); // too much zeny = overflow
 			return;
 
@@ -310,12 +310,18 @@ int8 vending_openvending( map_session_data& sd, const char* message, const uint8
 	// skill level and cart check
 	if( !vending_skill_lvl || !pc_iscarton(&sd) ) {
 		clif_skill_fail( sd, MC_VENDING );
+		sd.state.prevend = 0;
+		sd.state.workinprogress = WIP_DISABLE_NONE;
+		clif_openvending_ack( sd, OPENSTORE2_FAILED );
 		return 2;
 	}
 
 	// check number of items in shop
 	if( count < 1 || count > MAX_VENDING || count > 2 + vending_skill_lvl ) { // invalid item count
 		clif_skill_fail( sd, MC_VENDING );
+		sd.state.prevend = 0;
+		sd.state.workinprogress = WIP_DISABLE_NONE;
+		clif_openvending_ack( sd, OPENSTORE2_FAILED );
 		return 3;
 	}
 
@@ -324,6 +330,7 @@ int8 vending_openvending( map_session_data& sd, const char* message, const uint8
 
 	// filter out invalid items
 	i = 0;
+	int64 total = 0;
 	for( j = 0; j < count; j++ ) {
 		short index        = *(uint16*)(data + 8*j + 0);
 		short amount       = *(uint16*)(data + 8*j + 2);
@@ -344,17 +351,36 @@ int8 vending_openvending( map_session_data& sd, const char* message, const uint8
 		sd.vending[i].index = index;
 		sd.vending[i].amount = amount;
 		sd.vending[i].value = min(value, (unsigned int)battle_config.vending_max_value);
+		total += static_cast<int64>(sd.vending[i].value) * amount;
 		i++; // item successfully added
 	}
 
+	// check if the total value of the items plus the current zeny is over the limit
+	if ( !battle_config.vending_over_max && (static_cast<int64>(sd.status.zeny) + total) > MAX_ZENY ) {
+#if PACKETVER >= 20200819
+		clif_msg_color( &sd, MSI_MERCHANTSHOP_TOTA_LOVER_ZENY_ERR, color_table[COLOR_RED] );
+#endif
+		clif_skill_fail( sd, MC_VENDING );
+		sd.state.prevend = 0;
+		sd.state.workinprogress = WIP_DISABLE_NONE;
+		clif_openvending_ack( sd, OPENSTORE2_FAILED );
+		return 1;
+	}
+
 	if (i != j) {
 		clif_displaymessage(sd.fd, msg_txt(&sd, 266)); //"Some of your items cannot be vended and were removed from the shop."
 		clif_skill_fail( sd, MC_VENDING ); // custom reply packet
+		sd.state.prevend = 0;
+		sd.state.workinprogress = WIP_DISABLE_NONE;
+		clif_openvending_ack( sd, OPENSTORE2_FAILED );
 		return 5;
 	}
 
 	if( i == 0 ) { // no valid item found
 		clif_skill_fail( sd, MC_VENDING ); // custom reply packet
+		sd.state.prevend = 0;
+		sd.state.workinprogress = WIP_DISABLE_NONE;
+		clif_openvending_ack( sd, OPENSTORE2_FAILED );
 		return 5;
 	}