Added support for unlimited supplies in market shops (#6571)

Fixes #6569

Thanks to @JohnnyPlayy, @Balferian and @Toshiro90

Co-authored-by: Aleos <aleos89@users.noreply.github.com>
This commit is contained in:
Lemongrass3110 2022-02-04 16:17:30 +01:00 committed by GitHub
parent 3da8426fe7
commit 6ccf15330e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 124 additions and 84 deletions

View File

@ -291,7 +291,7 @@ these floating NPC objects are for. More on that below.
-%TAB%pointshop%TAB%<NPC Name>%TAB%<sprite id>,<costvariable>{:<discount>},<itemid>:<price>{,<itemid>:<price>...}
<map name>,<x>,<y>,<facing>%TAB%pointshop%TAB%<NPC Name>%TAB%<sprite id>,<costvariable>{:<discount>},<itemid>:<price>{,<itemid>:<price>...}
<map name>,<x>,<y>,<facing>%TAB%marketshop%TAB%<NPC Name>%TAB%<sprite id>,<itemid>:<price>:<quantity>{,<itemid>:<price>:<quantity>...}
<map name>,<x>,<y>,<facing>%TAB%marketshop%TAB%<NPC Name>%TAB%<sprite id>,<itemid>:<price>:<stock>{,<itemid>:<price>:<stock>...}
Note: Additionally barter shops can be defined in npc/barters.yml
@ -320,6 +320,9 @@ temporary character variables, permanent local account variables or permanent gl
variables. These variables must be of integer type, not string. 'discount' flag is an
optional value which makes the price at that shop become affected by discount skill.
"marketshop" can have limited quantity of an item in stock.
Use -1 in the stock field to have unlimited stock in a marketshop.
** Define an warp/shop/cashshop/itemshop/pointshop/NPC duplicate.
warp/warp2: <map name>,<x>,<y>,<facing>%TAB%duplicate(<label>)%TAB%<NPC Name>%TAB%<spanx>,<spany>
@ -7254,6 +7257,7 @@ A full example of a dynamic shop can be found in doc/sample/npc_dynamic_shop.txt
---------------------------------------
*npcshopitem "<name>",<item id>,<price>{,<item id>,<price>{,<item id>,<price>{,...}}};
*npcshopitem "<name>",<item id>,<price>,<stock>{,<item id>,<price>,<stock>{,<item id>,<price>,<stock>{,...}}};
This command lets you override the contents of an existing NPC shop or cashshop. The
current sell list will be wiped, and only the items specified with the price
@ -7263,12 +7267,12 @@ The function returns 1 if shop was updated successfully, or 0 if not found.
NOTES:
- That you cannot use -1 to specify default selling price!
- If attached shop type is market shop, need an extra param after price, it's <qty>
and make sure don't add duplication item!
- If the attached shop type is a market shop, notice that there is an extra parameter after price, <stock>. Make sure to not add duplicate items! For unlimited stock use -1.
---------------------------------------
*npcshopadditem "<name>",<item id>,<price>{,<item id>,<price>{,<item id>,<price>{,...}}};
*npcshopadditem "<name>",<item id>,<price>,<stock>{,<item id>,<price>,<stock>{,<item id>,<price>,<stock>{,...}}};
This command will add more items at the end of the selling list for the
specified NPC shop or cashshop. If you specify an item already for sell, that item will
@ -7278,8 +7282,8 @@ The function returns 1 if shop was updated successfully, or 0 if not found.
NOTES:
- That you cannot use -1 to specify default selling price!
- If attached shop type is market shop, need an extra param after price, it's <qty>
and make sure don't add duplication item!
- If attached shop type is market shop, need an extra param after price, it's <stock>
and make sure don't add duplication item! For unlimited stock use -1.
---------------------------------------
@ -7317,9 +7321,9 @@ NOTES:
*npcshopupdate "<name>",<item_id>,<price>{,<stock>}
Update an entry from shop. If price is 0 means don't change the price, maybe used for
marketshop to update the stock quantity. Except marketshop type, 'stock' value means
nothing.
Update an entry from a shop. If the price is 0 it won't be changed. May also be used for
marketshop to update the stock quantity. For unlimited stock, use -1.
For other shop types, the stock value has no effect.
---------------------------------------

View File

@ -867,7 +867,7 @@ CREATE TABLE IF NOT EXISTS `market` (
`name` varchar(50) NOT NULL DEFAULT '',
`nameid` int(10) UNSIGNED NOT NULL,
`price` INT(11) UNSIGNED NOT NULL,
`amount` SMALLINT(5) UNSIGNED NOT NULL,
`amount` INT(11) NOT NULL,
`flag` TINYINT(2) UNSIGNED NOT NULL DEFAULT '0',
PRIMARY KEY (`name`,`nameid`)
) ENGINE = MyISAM;

View File

@ -0,0 +1,3 @@
ALTER TABLE `market`
MODIFY `amount` INT(11) NOT NULL
;

View File

@ -2283,6 +2283,11 @@ void clif_npc_market_open(struct map_session_data *sd, struct npc_data *nd) {
continue;
}
// Out of stock
if( item->qty == 0 ){
continue;
}
p->list[count].nameid = client_nameid( item->nameid );
p->list[count].type = itemtype( item->nameid );
p->list[count].price = item->value;
@ -2312,20 +2317,18 @@ void clif_parse_NPCMarketClosed(int fd, struct map_session_data *sd) {
/// Purchase item from Market shop.
/// 0x9d7 <packet len>.W <count>.B { <name id>.W <qty>.W <price>.L }* (ZC_NPC_MARKET_PURCHASE_RESULT)
void clif_npc_market_purchase_ack(struct map_session_data *sd, e_purchase_result res, uint8 n, struct s_npc_buy_list *list) {
void clif_npc_market_purchase_ack( struct map_session_data *sd, e_purchase_result res, std::vector<s_npc_buy_list>& list ){
#if PACKETVER >= 20131223
nullpo_retv( sd );
nullpo_retv( list );
struct npc_data *nd = map_id2nd( sd->npc_shopid );
nullpo_retv( nd );
int fd = sd->fd;
struct PACKET_ZC_NPC_MARKET_PURCHASE_RESULT *p = (struct PACKET_ZC_NPC_MARKET_PURCHASE_RESULT *)packet_buffer;
WFIFOHEAD( fd, sizeof( struct PACKET_ZC_NPC_MARKET_PURCHASE_RESULT ) + n * sizeof( struct PACKET_ZC_NPC_MARKET_PURCHASE_RESULT_sub ) );
struct PACKET_ZC_NPC_MARKET_PURCHASE_RESULT *p = (struct PACKET_ZC_NPC_MARKET_PURCHASE_RESULT *)WFIFOP( fd, 0 );
p->PacketType = HEADER_ZC_NPC_MARKET_PURCHASE_RESULT;
p->PacketLength = sizeof( struct PACKET_ZC_NPC_MARKET_PURCHASE_RESULT );
#if PACKETVER_MAIN_NUM >= 20190807 || PACKETVER_RE_NUM >= 20190807 || PACKETVER_ZERO_NUM >= 20190814
p->result = ( res == e_purchase_result::PURCHASE_SUCCEED ? 0 : -1 );
@ -2333,10 +2336,8 @@ void clif_npc_market_purchase_ack(struct map_session_data *sd, e_purchase_result
p->result = ( res == e_purchase_result::PURCHASE_SUCCEED ? 1 : 0 );
#endif
int count = 0;
if( p->result ){
for( int i = 0, j; i < n; i++ ){
for( int i = 0, j, count = 0; i < list.size(); i++ ){
ARR_FIND( 0, nd->u.shop.count, j, list[i].nameid == nd->u.shop.shop_item[j].nameid );
// Not found
@ -2347,12 +2348,12 @@ void clif_npc_market_purchase_ack(struct map_session_data *sd, e_purchase_result
p->list[count].ITID = client_nameid( list[i].nameid );
p->list[count].qty = list[i].qty;
p->list[count].price = nd->u.shop.shop_item[j].value;
p->PacketLength += sizeof( struct PACKET_ZC_NPC_MARKET_PURCHASE_RESULT_sub );
count++;
}
}
p->PacketLength = sizeof( struct PACKET_ZC_NPC_MARKET_PURCHASE_RESULT ) + count * sizeof( struct PACKET_ZC_NPC_MARKET_PURCHASE_RESULT_sub );
WFIFOSET( fd, p->PacketLength );
clif_send( p, p->PacketLength, &sd->bl, SELF );
#endif
}
@ -2371,20 +2372,21 @@ void clif_parse_NPCMarketPurchase(int fd, struct map_session_data *sd) {
int count = ( p->PacketLength - sizeof( struct packet_npc_market_purchase ) ) / sizeof( struct packet_npc_market_purchase_sub );
struct s_npc_buy_list *list;
std::vector<s_npc_buy_list> items;
CREATE( list, struct s_npc_buy_list, count );
items.reserve( count );
// Sadly order is reverse
for( int i = 0; i < count; i++ ){
list[i].nameid = p->list[i].ITID;
list[i].qty = p->list[i].qty;
s_npc_buy_list item = {};
item.nameid = p->list[i].ITID;
item.qty = p->list[i].qty;
items.push_back( item );
}
e_purchase_result res = npc_buylist( sd, count, list );
clif_npc_market_purchase_ack( sd, res, count, list );
aFree( list );
e_purchase_result res = npc_buylist( sd, items );
clif_npc_market_purchase_ack( sd, res, items );
#endif
}
@ -12319,8 +12321,22 @@ void clif_parse_NpcBuyListSend( int fd, struct map_session_data* sd ){
if( sd->state.trading || !sd->npc_shopid )
result = e_purchase_result::PURCHASE_FAIL_MONEY;
else
result = npc_buylist( sd, n, (struct s_npc_buy_list*)p->items );
else{
std::vector<s_npc_buy_list> items = {};
items.reserve( n );
for( uint16 i = 0; i < n; i++ ){
s_npc_buy_list item = {};
item.nameid = p->items[i].itemId;
item.qty = p->items[i].amount;
items.push_back( item );
}
result = npc_buylist( sd, items );
}
sd->npc_shopid = 0; //Clear shop data.
clif_npc_buy_result(sd, result);
@ -17321,7 +17337,20 @@ void clif_parse_npccashshop_buy( int fd, struct map_session_data *sd ){
return;
}
clif_cashshop_ack( sd, npc_cashshop_buylist( sd, p->kafraPoints, p->count, p->items ) );
std::vector<s_npc_buy_list> item_list = {};
item_list.reserve( p->count );
for( int i = 0; i < p->count; i++ ){
s_npc_buy_list item = {};
item.nameid = p->items[i].itemId;
item.qty = p->items[i].amount;
item_list.push_back( item );
}
clif_cashshop_ack( sd, npc_cashshop_buylist( sd, p->kafraPoints, item_list ) );
#endif
}

View File

@ -2411,8 +2411,7 @@ static enum e_CASHSHOP_ACK npc_cashshop_process_payment(struct npc_data *nd, int
* @param item_list: List of items to purchase
* @return clif_cashshop_ack value to display
*/
int npc_cashshop_buylist(struct map_session_data *sd, int points, int count, struct PACKET_CZ_PC_BUY_CASH_POINT_ITEM_sub* item_list)
{
int npc_cashshop_buylist( struct map_session_data *sd, int points, std::vector<s_npc_buy_list>& item_list ){
int i, j, amount, new_, w, vt;
t_itemid nameid;
struct npc_data *nd = (struct npc_data *)map_id2bl(sd->npc_shopid);
@ -2429,10 +2428,10 @@ int npc_cashshop_buylist(struct map_session_data *sd, int points, int count, str
vt = 0; // Global Value
// Validating Process ----------------------------------------------------
for( i = 0; i < count; i++ )
for( i = 0; i < item_list.size(); i++ )
{
nameid = item_list[i].itemId;
amount = item_list[i].amount;
nameid = item_list[i].nameid;
amount = item_list[i].qty;
id = itemdb_exists(nameid);
if( !id || amount <= 0 )
@ -2442,12 +2441,12 @@ int npc_cashshop_buylist(struct map_session_data *sd, int points, int count, str
if( j == nd->u.shop.count || nd->u.shop.shop_item[j].value <= 0 )
return ERROR_TYPE_ITEM_ID;
nameid = item_list[i].itemId = nd->u.shop.shop_item[j].nameid; //item_avail replacement
nameid = item_list[i].nameid = nd->u.shop.shop_item[j].nameid; //item_avail replacement
if( !itemdb_isstackable2(id) && amount > 1 )
{
ShowWarning("Player %s (%d:%d) sent a hexed packet trying to buy %d of nonstackable item %u!\n", sd->status.name, sd->status.account_id, sd->status.char_id, amount, nameid);
amount = item_list[i].amount = 1;
amount = item_list[i].qty = 1;
}
if( nd->master_nd ) { // Script-controlled shops decide by themselves, what can be bought and for what price.
@ -2468,7 +2467,7 @@ int npc_cashshop_buylist(struct map_session_data *sd, int points, int count, str
}
if (nd->master_nd) //Script-based shops.
return npc_buylist_sub(sd,count,(struct s_npc_buy_list*)item_list,nd->master_nd);
return npc_buylist_sub(sd,item_list,nd->master_nd);
if( w + sd->weight > sd->max_weight )
return ERROR_TYPE_INVENTORY_WEIGHT;
@ -2480,9 +2479,9 @@ int npc_cashshop_buylist(struct map_session_data *sd, int points, int count, str
return res;
// Delivery Process ----------------------------------------------------
for( i = 0; i < count; i++ ) {
nameid = item_list[i].itemId;
amount = item_list[i].amount;
for( i = 0; i < item_list.size(); i++ ) {
nameid = item_list[i].nameid;
amount = item_list[i].qty;
if( !pet_create_egg(sd,nameid) ) {
struct item item_tmp;
@ -2663,16 +2662,16 @@ int npc_cashshop_buy(struct map_session_data *sd, t_itemid nameid, int amount, i
* @param item_list: List of items
* @param nd: Attached NPC
*/
static int npc_buylist_sub(struct map_session_data* sd, uint16 n, struct s_npc_buy_list *item_list, struct npc_data* nd) {
static int npc_buylist_sub(struct map_session_data* sd, std::vector<s_npc_buy_list>& item_list, struct npc_data* nd) {
char npc_ev[EVENT_NAME_LENGTH];
int i, key_nameid = 0, key_amount = 0;
int key_nameid = 0, key_amount = 0;
// discard old contents
script_cleararray_pc( sd, "@bought_nameid" );
script_cleararray_pc( sd, "@bought_quantity" );
// save list of bought items
for (i = 0; i < n; i++) {
for( int i = 0; i < item_list.size(); i++ ){
script_setarray_pc( sd, "@bought_nameid", i, item_list[i].nameid, &key_nameid );
script_setarray_pc( sd, "@bought_quantity", i, item_list[i].qty, &key_amount );
}
@ -2691,23 +2690,23 @@ static int npc_buylist_sub(struct map_session_data* sd, uint16 n, struct s_npc_b
* @param item_list: List of items
* @return result code for clif_parse_NpcBuyListSend/clif_npc_market_purchase_ack
*/
e_purchase_result npc_buylist(struct map_session_data* sd, uint16 n, struct s_npc_buy_list *item_list) {
e_purchase_result npc_buylist( struct map_session_data* sd, std::vector<s_npc_buy_list>& item_list ){
struct npc_data* nd;
struct npc_item_list *shop = NULL;
double z;
int i,j,k,w,skill,new_;
int j,k,w,skill,new_;
uint8 market_index[MAX_INVENTORY];
nullpo_retr(e_purchase_result::PURCHASE_FAIL_COUNT, sd);
nullpo_retr(e_purchase_result::PURCHASE_FAIL_COUNT, item_list);
nd = npc_checknear(sd,map_id2bl(sd->npc_shopid));
if( nd == NULL )
return e_purchase_result::PURCHASE_FAIL_COUNT;
if( nd->subtype != NPCTYPE_SHOP && nd->subtype != NPCTYPE_MARKETSHOP )
return e_purchase_result::PURCHASE_FAIL_COUNT;
if (!item_list || !n)
if( item_list.empty() ){
return e_purchase_result::PURCHASE_FAIL_COUNT;
}
z = 0;
w = 0;
@ -2717,7 +2716,7 @@ e_purchase_result npc_buylist(struct map_session_data* sd, uint16 n, struct s_np
memset(market_index, 0, sizeof(market_index));
// process entries in buy list, one by one
for( i = 0; i < n; ++i ) {
for( int i = 0; i < item_list.size(); ++i ){
t_itemid nameid;
unsigned short amount;
int value;
@ -2734,7 +2733,7 @@ e_purchase_result npc_buylist(struct map_session_data* sd, uint16 n, struct s_np
#if PACKETVER >= 20131223
if (nd->subtype == NPCTYPE_MARKETSHOP) {
if (item_list[i].qty > shop[j].qty)
if (shop[j].qty >= 0 && item_list[i].qty > shop[j].qty)
return e_purchase_result::PURCHASE_FAIL_COUNT;
market_index[i] = j;
}
@ -2778,7 +2777,7 @@ e_purchase_result npc_buylist(struct map_session_data* sd, uint16 n, struct s_np
}
if (nd->master_nd){ //Script-based shops.
npc_buylist_sub(sd,n,item_list,nd->master_nd);
npc_buylist_sub(sd,item_list,nd->master_nd);
return e_purchase_result::PURCHASE_SUCCEED;
}
@ -2792,17 +2791,20 @@ e_purchase_result npc_buylist(struct map_session_data* sd, uint16 n, struct s_np
pc_payzeny(sd, (int)z, LOG_TYPE_NPC, NULL);
for( i = 0; i < n; ++i ) {
for( int i = 0; i < item_list.size(); ++i ) {
t_itemid nameid = item_list[i].nameid;
unsigned short amount = item_list[i].qty;
#if PACKETVER >= 20131223
if (nd->subtype == NPCTYPE_MARKETSHOP) {
j = market_index[i];
if (amount > shop[j].qty)
return e_purchase_result::PURCHASE_FAIL_MONEY;
shop[j].qty -= amount;
npc_market_tosql(nd->exname, &shop[j]);
if( shop[j].qty >= 0 ){
if (amount > shop[j].qty)
return e_purchase_result::PURCHASE_FAIL_COUNT;
shop[j].qty -= amount;
npc_market_tosql(nd->exname, &shop[j]);
}
}
#endif
@ -3979,7 +3981,7 @@ static const char* npc_parse_shop(char* w1, char* w2, char* w3, char* w4, const
nd->u.shop.count = 0;
while ( p ) {
t_itemid nameid2;
unsigned short qty = 0;
int32 qty = -1;
int value;
struct item_data* id;
bool skip = false;
@ -3989,7 +3991,7 @@ static const char* npc_parse_shop(char* w1, char* w2, char* w3, char* w4, const
switch(type) {
case NPCTYPE_MARKETSHOP:
#if PACKETVER >= 20131223
if (sscanf(p, ",%u:%11d:%6hu", &nameid2, &value, &qty) != 3) {
if (sscanf(p, ",%u:%11d:%11d", &nameid2, &value, &qty) != 3) {
ShowError("npc_parse_shop: (MARKETSHOP) Invalid item definition in file '%s', line '%d'. Ignoring the rest of the line...\n * w1=%s\n * w2=%s\n * w3=%s\n * w4=%s\n", filepath, strline(buffer, start - buffer), w1, w2, w3, w4);
skip = true;
}
@ -4023,10 +4025,10 @@ static const char* npc_parse_shop(char* w1, char* w2, char* w3, char* w4, const
ShowWarning("npc_parse_shop: Item %s [%u] discounted buying price (%d->%d) is less than overcharged selling price (%d->%d) at file '%s', line '%d'.\n",
id->name.c_str(), nameid2, value, (int)(value*0.75), id->value_sell, (int)(id->value_sell*1.24), filepath, strline(buffer,start-buffer));
}
if (type == NPCTYPE_MARKETSHOP && (!qty || qty > UINT16_MAX)) {
ShowWarning("npc_parse_shop: Item %s [%u] is stocked with invalid value %d, changed to 1. File '%s', line '%d'.\n",
if (type == NPCTYPE_MARKETSHOP && qty < -1) {
ShowWarning("npc_parse_shop: Item %s [%u] is stocked with invalid value %hd, changed to unlimited (-1). File '%s', line '%d'.\n",
id->name.c_str(), nameid2, qty, filepath, strline(buffer,start-buffer));
qty = 1;
qty = -1;
}
//for logs filters, atcommands and iteminfo script command
if( id->maxchance == 0 )
@ -4626,7 +4628,7 @@ int npc_instancedestroy(struct npc_data* nd)
**/
void npc_market_tosql(const char *exname, struct npc_item_list *list) {
SqlStmt* stmt = SqlStmt_Malloc(mmysql_handle);
if (SQL_ERROR == SqlStmt_Prepare(stmt, "REPLACE INTO `%s` (`name`,`nameid`,`price`,`amount`,`flag`) VALUES ('%s','%u','%d','%hu','%" PRIu8 "')",
if (SQL_ERROR == SqlStmt_Prepare(stmt, "REPLACE INTO `%s` (`name`,`nameid`,`price`,`amount`,`flag`) VALUES ('%s','%u','%d','%d','%" PRIu8 "')",
market_table, exname, list->nameid, list->value, list->qty, list->flag) ||
SQL_ERROR == SqlStmt_Execute(stmt))
SqlStmt_ShowDebug(stmt);
@ -4709,7 +4711,7 @@ static int npc_market_checkall_sub(DBKey key, DBData *data, va_list ap) {
npc_market_tosql(nd->exname, &nd->u.shop.shop_item[j]);
}
else { // Removing "out-of-date" entry
ShowError("npc_market_checkall_sub: NPC '%s' does not sell item %u (qty %hu), deleting...\n", nd->exname, list->nameid, list->qty);
ShowError("npc_market_checkall_sub: NPC '%s' does not sell item %u (qty %d), deleting...\n", nd->exname, list->nameid, list->qty);
npc_market_delfromsql(nd->exname, list->nameid);
}
}

View File

@ -33,28 +33,16 @@ struct npc_item_list {
t_itemid nameid;
unsigned int value;
#if PACKETVER >= 20131223
unsigned short qty; ///< Stock counter (Market shop)
int32 qty; ///< Stock counter (Market shop)
uint8 flag; ///< 1: Item added by npcshopitem/npcshopadditem, force load! (Market shop)
#endif
};
#if !defined(sun) && (!defined(__NETBSD__) || __NetBSD_Version__ >= 600000000) // NetBSD 5 and Solaris don't like pragma pack but accept the packed attribute
#pragma pack(push, 1)
#endif // not NetBSD < 6 / Solaris
/// List of bought/sold item for NPC shops
struct s_npc_buy_list {
unsigned short qty; ///< Amount of item will be bought
#if PACKETVER_MAIN_NUM >= 20181121 || PACKETVER_RE_NUM >= 20180704 || PACKETVER_ZERO_NUM >= 20181114
int32 qty; ///< Amount of item will be bought
uint32 nameid; ///< ID of item will be bought
#else
uint16 nameid; ///< ID of item will be bought
#endif
} __attribute__((packed));
#if !defined(sun) && (!defined(__NETBSD__) || __NetBSD_Version__ >= 600000000) // NetBSD 5 and Solaris don't like pragma pack but accept the packed attribute
#pragma pack(pop)
#endif // not NetBSD < 6 / Solaris
};
struct s_stylist_costs{
uint32 price;
@ -1491,8 +1479,8 @@ int npc_click(struct map_session_data* sd, struct npc_data* nd);
bool npc_scriptcont(struct map_session_data* sd, int id, bool closing);
struct npc_data* npc_checknear(struct map_session_data* sd, struct block_list* bl);
int npc_buysellsel(struct map_session_data* sd, int id, int type);
e_purchase_result npc_buylist(struct map_session_data* sd, uint16 n, struct s_npc_buy_list *item_list);
static int npc_buylist_sub(struct map_session_data* sd, uint16 n, struct s_npc_buy_list *item_list, struct npc_data* nd);
e_purchase_result npc_buylist(struct map_session_data* sd, std::vector<s_npc_buy_list>& item_list);
static int npc_buylist_sub(struct map_session_data* sd, std::vector<s_npc_buy_list>& item_list, struct npc_data* nd);
uint8 npc_selllist(struct map_session_data* sd, int n, unsigned short *item_list);
e_purchase_result npc_barter_purchase( struct map_session_data& sd, std::shared_ptr<s_npc_barter> barter, std::vector<s_barter_purchase>& purchases );
void npc_parse_mob2(struct spawn_data* mob);
@ -1550,7 +1538,7 @@ void npc_shop_currency_type(struct map_session_data *sd, struct npc_data *nd, in
extern struct npc_data* fake_nd;
int npc_cashshop_buylist(struct map_session_data *sd, int points, int count, struct PACKET_CZ_PC_BUY_CASH_POINT_ITEM_sub* item_list);
int npc_cashshop_buylist( struct map_session_data *sd, int points, std::vector<s_npc_buy_list>& item_list );
bool npc_shop_discount(struct npc_data* nd);
#if PACKETVER >= 20131223

View File

@ -17653,9 +17653,17 @@ BUILDIN_FUNC(npcshopadditem)
nd->u.shop.count++;
}
int32 stock = script_getnum( st, i + 2 );
if( stock < -1 ){
ShowError( "builtin_npcshopadditem: Invalid stock amount in marketshop '%s'.\n", nd->exname );
script_pushint( st, 0 );
return SCRIPT_CMD_FAILURE;
}
nd->u.shop.shop_item[j].nameid = nameid;
nd->u.shop.shop_item[j].value = script_getnum(st,i+1);
nd->u.shop.shop_item[j].qty = script_getnum(st,i+2);
nd->u.shop.shop_item[j].qty = stock;
npc_market_tosql(nd->exname, &nd->u.shop.shop_item[j]);
}
@ -23299,7 +23307,13 @@ BUILDIN_FUNC(npcshopupdate) {
t_itemid nameid = script_getnum(st, 3);
int price = script_getnum(st, 4);
#if PACKETVER >= 20131223
uint16 stock = script_hasdata(st,5) ? script_getnum(st,5) : 0;
int32 stock = script_hasdata(st,5) ? script_getnum(st,5) : -1;
if( stock < -1 ){
ShowError( "buildin_npcshopupdate: Invalid stock amount in marketshop '%s'.\n", nd->exname );
script_pushint( st, 0 );
return SCRIPT_CMD_FAILURE;
}
#endif
int i;