From fa1cb492536f2853c59a995dc54aa51ead420546 Mon Sep 17 00:00:00 2001 From: Andrei Karas Date: Thu, 27 Dec 2018 21:42:14 +0300 Subject: Add barter type shop and add packet ZC_NPC_BARTER_OPEN --- doc/script_commands.txt | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'doc') diff --git a/doc/script_commands.txt b/doc/script_commands.txt index 57d47b1b5..a545357aa 100644 --- a/doc/script_commands.txt +++ b/doc/script_commands.txt @@ -323,10 +323,12 @@ The types that a trader object can have are the following: - NST_MARKET (2) Normal NPC Market Shop (where items have limited availability and need to be refurbished) - NST_CUSTOM (3) Custom Shop (any currency, item/var/etca, check sample) +- NST_BARTER (4) Barter Shop (each item with own item currency) Unless otherwise specified via *tradertype an trader object will be defined as NST_ZENY. Note: NST_MARKET is only available with PACKETVER 20131223 or newer. +Note: NST_BARTER is only available with PACKETVER 20181226 zero or newer. See '12 - NPC Trader-Related Commands' and /doc/sample/npc_trader_sample.txt for more information regarding how to use this NPC type. @@ -9951,6 +9953,7 @@ when the optional NPC_Name param is used. --------------------------------------- *sellitem({, {, }}) +*sellitem(, , , ) adds (or modifies) data to the shop, when is not provided (or when it is -1) itemdb default is used. @@ -9959,6 +9962,8 @@ qty is only necessary for NST_MARKET trader types. when is already in the shop, the previous data (price/qty), is overwritten with the new. +currency_id and currency_amount can be used only with shop type NST_BARTER + --------------------------------------- *stopselling() -- cgit v1.2.3-60-g2f50 From 42c129494a2b9f9899fb28fb5ca5792ee850ce07 Mon Sep 17 00:00:00 2001 From: Andrei Karas Date: Sat, 29 Dec 2018 05:16:01 +0300 Subject: Add support for saving/loading barter shops from sql table. Also allow add duplicated item id to barter shops if price is different. --- conf/common/inter-server.conf | 1 + doc/script_commands.txt | 2 + sql-files/main.sql | 10 ++ sql-files/upgrades/2018-12-29--07-51.sql | 29 ++++++ sql-files/upgrades/index.txt | 1 + src/map/clif.c | 1 + src/map/clif.h | 1 + src/map/map.c | 2 + src/map/map.h | 1 + src/map/npc.c | 158 ++++++++++++++++++++++++++----- src/map/npc.h | 10 +- src/map/script.c | 102 +++++++++++++------- 12 files changed, 260 insertions(+), 58 deletions(-) create mode 100644 sql-files/upgrades/2018-12-29--07-51.sql (limited to 'doc') diff --git a/conf/common/inter-server.conf b/conf/common/inter-server.conf index 1e738c587..cbeb6617d 100644 --- a/conf/common/inter-server.conf +++ b/conf/common/inter-server.conf @@ -117,6 +117,7 @@ inter_configuration: { autotrade_merchants_db: "autotrade_merchants" autotrade_data_db: "autotrade_data" npc_market_data_db: "npc_market_data" + npc_barter_data_db: "npc_barter_data" } } diff --git a/doc/script_commands.txt b/doc/script_commands.txt index a545357aa..26a4fbfb8 100644 --- a/doc/script_commands.txt +++ b/doc/script_commands.txt @@ -9967,8 +9967,10 @@ currency_id and currency_amount can be used only with shop type NST_BARTER --------------------------------------- *stopselling() +*stopselling({, , }) attempts to remove from the current shop list. +currency_id and currency_amount can be used only with shop type NST_BARTER --------------------------------------- diff --git a/sql-files/main.sql b/sql-files/main.sql index f322d1cda..a08ec60ba 100644 --- a/sql-files/main.sql +++ b/sql-files/main.sql @@ -924,6 +924,7 @@ INSERT IGNORE INTO `sql_updates` (`timestamp`) VALUES (1528180320); -- 2018-06-0 INSERT IGNORE INTO `sql_updates` (`timestamp`) VALUES (1532403228); -- 2018-07-24--03-23.sql INSERT IGNORE INTO `sql_updates` (`timestamp`) VALUES (1535865732); -- 2018-09-01--05-22.sql INSERT IGNORE INTO `sql_updates` (`timestamp`) VALUES (1544738447); -- 2018-12-14--01-02.sql +INSERT IGNORE INTO `sql_updates` (`timestamp`) VALUES (1546059075); -- 2018-12-29--07-51.sql -- -- Table structure for table `storage` @@ -1012,3 +1013,12 @@ CREATE TABLE IF NOT EXISTS `rodex_mail` ( KEY `send_date` (`send_date`), KEY `expire_date` (`expire_date`) ) ENGINE=MyISAM; + +CREATE TABLE IF NOT EXISTS `npc_barter_data` ( + `name` VARCHAR(24) NOT NULL DEFAULT '', + `itemId` INT(11) UNSIGNED NOT NULL DEFAULT '0', + `amount` INT(11) UNSIGNED NOT NULL DEFAULT '0', + `priceId` INT(11) UNSIGNED NOT NULL DEFAULT '0', + `priceAmount` INT(11) UNSIGNED NOT NULL DEFAULT '0', + PRIMARY KEY (`name`, `itemid`, `priceId`, `priceAmount`) +) ENGINE=MyISAM; diff --git a/sql-files/upgrades/2018-12-29--07-51.sql b/sql-files/upgrades/2018-12-29--07-51.sql new file mode 100644 index 000000000..641179399 --- /dev/null +++ b/sql-files/upgrades/2018-12-29--07-51.sql @@ -0,0 +1,29 @@ +#1546059075 + +-- This file is part of Hercules. +-- http://herc.ws - http://github.com/HerculesWS/Hercules +-- +-- Copyright (C) 2013-2015 Hercules Dev Team +-- +-- Hercules is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see . + +CREATE TABLE IF NOT EXISTS `npc_barter_data` ( + `name` VARCHAR(24) NOT NULL DEFAULT '', + `itemId` INT(11) UNSIGNED NOT NULL DEFAULT '0', + `amount` INT(11) UNSIGNED NOT NULL DEFAULT '0', + `priceId` INT(11) UNSIGNED NOT NULL DEFAULT '0', + `priceAmount` INT(11) UNSIGNED NOT NULL DEFAULT '0', + PRIMARY KEY (`name`, `itemid`, `priceId`, `priceAmount`) +) ENGINE=MyISAM; +INSERT INTO `sql_updates` (`timestamp`) VALUES (1546059075); diff --git a/sql-files/upgrades/index.txt b/sql-files/upgrades/index.txt index ed892df12..3a2fc4c33 100644 --- a/sql-files/upgrades/index.txt +++ b/sql-files/upgrades/index.txt @@ -51,3 +51,4 @@ 2018-07-24--03-23.sql 2018-09-01--05-22.sql 2018-12-14--01-02.sql +2018-12-29--07-51.sql diff --git a/src/map/clif.c b/src/map/clif.c index 2eb60e2e3..eba2ddce3 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -22278,6 +22278,7 @@ static void clif_parse_NPCBarterPurchase(int fd, struct map_session_data *sd) entry.addId = p->list[i].itemId; entry.addAmount = p->list[i].amount; entry.removeIndex = p->list[i].invIndex - 2; + entry.shopIndex = p->list[i].shopIndex; VECTOR_PUSH(item_list, entry); } diff --git a/src/map/clif.h b/src/map/clif.h index 3ed6e8ea1..1aee11c33 100644 --- a/src/map/clif.h +++ b/src/map/clif.h @@ -669,6 +669,7 @@ struct barter_itemlist_entry { int addId; int addAmount; int removeIndex; + int shopIndex; }; VECTOR_STRUCT_DECL(barteritemlist, struct barter_itemlist_entry); diff --git a/src/map/map.c b/src/map/map.c index 93e86f80b..6212493c8 100644 --- a/src/map/map.c +++ b/src/map/map.c @@ -4479,6 +4479,7 @@ static bool inter_config_read_database_names(const char *filename, const struct libconfig->setting_lookup_mutable_string(setting, "autotrade_merchants_db", map->autotrade_merchants_db, sizeof(map->autotrade_merchants_db)); libconfig->setting_lookup_mutable_string(setting, "autotrade_data_db", map->autotrade_data_db, sizeof(map->autotrade_data_db)); libconfig->setting_lookup_mutable_string(setting, "npc_market_data_db", map->npc_market_data_db, sizeof(map->npc_market_data_db)); + libconfig->setting_lookup_mutable_string(setting, "npc_barter_data_db", map->npc_barter_data_db, sizeof(map->npc_barter_data_db)); if (!mapreg->config_read(filename, setting, imported)) retval = false; @@ -6742,6 +6743,7 @@ int do_init(int argc, char *argv[]) npc->event_do_oninit( false ); // Init npcs (OnInit) npc->market_fromsql(); /* after OnInit */ + npc->barter_fromsql(); /* after OnInit */ if (battle_config.pk_mode) ShowNotice("Server is running on '"CL_WHITE"PK Mode"CL_RESET"'.\n"); diff --git a/src/map/map.h b/src/map/map.h index 4267c2c88..d31ff4839 100644 --- a/src/map/map.h +++ b/src/map/map.h @@ -1167,6 +1167,7 @@ struct map_interface { char autotrade_merchants_db[32]; char autotrade_data_db[32]; char npc_market_data_db[32]; + char npc_barter_data_db[32]; char default_codepage[32]; char default_lang_str[64]; diff --git a/src/map/npc.c b/src/map/npc.c index 7f003c321..7e1dab1b2 100644 --- a/src/map/npc.c +++ b/src/map/npc.c @@ -1585,11 +1585,11 @@ static void npc_market_fromsql(void) if( !(nd = npc->name2id(name)) ) { ShowError("npc_market_fromsql: NPC '%s' not found! skipping...\n",name); - npc->market_delfromsql_sub(name, USHRT_MAX); + npc->market_delfromsql_sub(name, INT_MAX); continue; } else if (nd->subtype != SCRIPT || !nd->u.scr.shop || !nd->u.scr.shop->items || nd->u.scr.shop->type != NST_MARKET) { ShowError("npc_market_fromsql: NPC '%s' is not proper for market, skipping...\n",name); - npc->market_delfromsql_sub(name, USHRT_MAX); + npc->market_delfromsql_sub(name, INT_MAX); continue; } @@ -1611,10 +1611,10 @@ static void npc_market_fromsql(void) /** * Saves persistent NPC Market Data into SQL **/ -static void npc_market_tosql(struct npc_data *nd, unsigned short index) +static void npc_market_tosql(struct npc_data *nd, int index) { nullpo_retv(nd); - Assert_retv(index < nd->u.scr.shop->items); + Assert_retv(index >= 0 && index < nd->u.scr.shop->items); if (SQL_ERROR == SQL->Query(map->mysql_handle, "REPLACE INTO `%s` VALUES ('%s','%d','%u')", map->npc_market_data_db, nd->exname, nd->u.scr.shop->item[index].nameid, nd->u.scr.shop->item[index].qty)) Sql_ShowDebug(map->mysql_handle); @@ -1622,9 +1622,9 @@ static void npc_market_tosql(struct npc_data *nd, unsigned short index) /** * Removes persistent NPC Market Data from SQL */ -static void npc_market_delfromsql_sub(const char *npcname, unsigned short index) +static void npc_market_delfromsql_sub(const char *npcname, int index) { - if( index == USHRT_MAX ) { + if (index == INT_MAX ) { if( SQL_ERROR == SQL->Query(map->mysql_handle, "DELETE FROM `%s` WHERE `name`='%s'", map->npc_market_data_db, npcname) ) Sql_ShowDebug(map->mysql_handle); } else { @@ -1636,12 +1636,115 @@ static void npc_market_delfromsql_sub(const char *npcname, unsigned short index) /** * Removes persistent NPC Market Data from SQL **/ -static void npc_market_delfromsql(struct npc_data *nd, unsigned short index) +static void npc_market_delfromsql(struct npc_data *nd, int index) { nullpo_retv(nd); - Assert_retv(index == USHRT_MAX || index < nd->u.scr.shop->items); - npc->market_delfromsql_sub(nd->exname, index == USHRT_MAX ? index : nd->u.scr.shop->item[index].nameid); + Assert_retv(index == INT_MAX || (index >= 0 && index < nd->u.scr.shop->items)); + npc->market_delfromsql_sub(nd->exname, index == INT_MAX ? index : nd->u.scr.shop->item[index].nameid); } + +/** + * Loads persistent NPC Barter Data from SQL + **/ +static void npc_barter_fromsql(void) +{ + struct SqlStmt *stmt = SQL->StmtMalloc(map->mysql_handle); + char name[NAME_LENGTH + 1]; + int itemid; + int amount; + int removeId; + int removeAmount; + + if (SQL_ERROR == SQL->StmtPrepare(stmt, "SELECT `name`, `itemId`, `amount`, `priceId`, `priceAmount` FROM `%s`", map->npc_barter_data_db) + || SQL_ERROR == SQL->StmtExecute(stmt) + ) { + SqlStmt_ShowDebug(stmt); + SQL->StmtFree(stmt); + return; + } + + SQL->StmtBindColumn(stmt, 0, SQLDT_STRING, &name, sizeof name, NULL, NULL); + SQL->StmtBindColumn(stmt, 1, SQLDT_INT, &itemid, sizeof itemid, NULL, NULL); + SQL->StmtBindColumn(stmt, 2, SQLDT_UINT32, &amount, sizeof amount, NULL, NULL); + SQL->StmtBindColumn(stmt, 3, SQLDT_INT, &removeId, sizeof removeId, NULL, NULL); + SQL->StmtBindColumn(stmt, 4, SQLDT_INT, &removeAmount, sizeof removeAmount, NULL, NULL); + + while (SQL_SUCCESS == SQL->StmtNextRow(stmt)) { + struct npc_data *nd = NULL; + unsigned short i; + + if (!(nd = npc->name2id(name))) { + ShowError("npc_barter_fromsql: NPC '%s' not found! skipping...\n",name); + npc->barter_delfromsql_sub(name, INT_MAX, 0, 0); + continue; + } else if (nd->subtype != SCRIPT || !nd->u.scr.shop || !nd->u.scr.shop->items || nd->u.scr.shop->type != NST_BARTER) { + ShowError("npc_barter_fromsql: NPC '%s' is not proper for barter, skipping...\n",name); + npc->barter_delfromsql_sub(name, INT_MAX, 0, 0); + continue; + } + + for (i = 0; i < nd->u.scr.shop->items; i++) { + struct npc_item_list *const item = &nd->u.scr.shop->item[i]; + if (item->nameid == itemid && item->value == removeId && item->value2 == removeAmount) { + item->qty = amount; + break; + } + } + + if (i == nd->u.scr.shop->items) { + ShowError("npc_barter_fromsql: NPC '%s' does not sell item %d (qty %d), deleting...\n", name, itemid, amount); + npc->barter_delfromsql_sub(name, itemid, removeId, removeAmount); + continue; + } + } + SQL->StmtFree(stmt); +} + +/** + * Saves persistent NPC Barter Data into SQL + **/ +static void npc_barter_tosql(struct npc_data *nd, int index) +{ + nullpo_retv(nd); + Assert_retv(index >= 0 && index < nd->u.scr.shop->items); + const struct npc_item_list *const item = &nd->u.scr.shop->item[index]; + if (SQL_ERROR == SQL->Query(map->mysql_handle, "REPLACE INTO `%s` VALUES ('%s', '%d', '%u', '%u', '%d')", + map->npc_barter_data_db, nd->exname, item->nameid, item->qty, item->value, item->value2)) { + Sql_ShowDebug(map->mysql_handle); + } +} + +/** + * Removes persistent NPC Barter Data from SQL + */ +static void npc_barter_delfromsql_sub(const char *npcname, int itemId, int itemId2, int amount2) +{ + if (itemId == INT_MAX) { + if (SQL_ERROR == SQL->Query(map->mysql_handle, "DELETE FROM `%s` WHERE `name`='%s'", map->npc_barter_data_db, npcname)) + Sql_ShowDebug(map->mysql_handle); + } else { + if (SQL_ERROR == SQL->Query(map->mysql_handle, "DELETE FROM `%s` WHERE `name`='%s' AND `itemId`='%d' AND `priceId`='%d' AND `priceAmount`='%d' LIMIT 1", + map->npc_barter_data_db, npcname, itemId, itemId2, amount2)) { + Sql_ShowDebug(map->mysql_handle); + } + } +} + +/** + * Removes persistent NPC Barter Data from SQL + **/ +static void npc_barter_delfromsql(struct npc_data *nd, int index) +{ + nullpo_retv(nd); + if (index == INT_MAX) { + npc->barter_delfromsql_sub(nd->exname, INT_MAX, 0, 0); + } else { + Assert_retv(index >= 0 && index < nd->u.scr.shop->items); + const struct npc_item_list *const item = &nd->u.scr.shop->item[index]; + npc->barter_delfromsql_sub(nd->exname, item->nameid, item->value, item->value2); + } +} + /** * Judges whether to allow and spawn a trader's window. **/ @@ -2151,20 +2254,23 @@ static int npc_barter_buylist(struct map_session_data *sd, struct barteritemlist if (n < 0 || n >= sd->status.inventorySize) return 11; // wrong inventory index + int removeId = sd->status.inventory[n].nameid; + const int j = entry->shopIndex; + if (j < 0 || j >= shop_size) + return 13; // no such item in shop + if (entry->addId != shop[j].nameid && entry->addId != itemdb_viewid(shop[j].nameid)) + return 13; // no such item in shop + if (removeId != shop[j].value && removeId != itemdb_viewid(shop[j].value)) + return 13; // no such item in shop + entry->addId = shop[j].nameid; // item_avail replacement + removeId = shop[j].value; // item_avail replacement + if (!itemdb->exists(entry->addId)) return 13; // item no longer in itemdb - const int removeId = sd->status.inventory[n].nameid; - int j = shop_size; - // find this entry in the shop's sell list - ARR_FIND(0, shop_size, j, (entry->addId == shop[j].nameid || entry->addId == itemdb_viewid(shop[j].nameid)) && - (removeId == shop[j].value || removeId == itemdb_viewid(shop[j].value))); - if (j == shop_size) - return 13; // no such item in shop - const int removeAmount = shop[j].value2; - if (entry->addAmount > (int)shop[j].qty) + if ((int)shop[j].qty != -1 && entry->addAmount > (int)shop[j].qty) return 14; // not enough item amount in shop if (removeAmount * entry->addAmount > sd->status.inventory[n].amount) @@ -2219,12 +2325,13 @@ static int npc_barter_buylist(struct map_session_data *sd, struct barteritemlist struct barter_itemlist_entry *entry = &VECTOR_INDEX(*item_list, i); const int shopIdx = npc_market_qty[i]; - if (entry->addAmount > (int)shop[shopIdx].qty) /* wohoo someone tampered with the packet. */ - return 14; - - shop[shopIdx].qty -= entry->addAmount; + if ((int)shop[shopIdx].qty != -1) { + if (entry->addAmount > (int)shop[shopIdx].qty) /* wohoo someone tampered with the packet. */ + return 14; + shop[shopIdx].qty -= entry->addAmount; + } - // TODO: save to sql + npc->barter_tosql(nd, shopIdx); if (itemdb_type(entry->addId) == IT_PETEGG) { pet->create_egg(sd, entry->addId); @@ -5125,6 +5232,7 @@ static int npc_reload(void) // OnInit -> OnInterIfInit -> OnInterIfInitOnce -> OnAgitInit -> OnAgitInit2 npc->event_do_oninit( true ); npc->market_fromsql(); + npc->barter_fromsql(); // Execute rest of the startup events if connected to char-server. [Lance] // Executed when connection is established with char-server in chrif_connectack if( !intif->CheckForCharServer() ) { @@ -5437,6 +5545,10 @@ void npc_defaults(void) npc->market_tosql = npc_market_tosql; npc->market_delfromsql = npc_market_delfromsql; npc->market_delfromsql_sub = npc_market_delfromsql_sub; + npc->barter_fromsql = npc_barter_fromsql; + npc->barter_tosql = npc_barter_tosql; + npc->barter_delfromsql = npc_barter_delfromsql; + npc->barter_delfromsql_sub = npc_barter_delfromsql_sub; npc->db_checkid = npc_db_checkid; npc->refresh = npc_refresh; } diff --git a/src/map/npc.h b/src/map/npc.h index bd16938a3..d455a395b 100644 --- a/src/map/npc.h +++ b/src/map/npc.h @@ -313,9 +313,13 @@ struct npc_interface { int (*barter_buylist) (struct map_session_data *sd, struct barteritemlist *item_list); bool (*trader_open) (struct map_session_data *sd, struct npc_data *nd); void (*market_fromsql) (void); - void (*market_tosql) (struct npc_data *nd, unsigned short index); - void (*market_delfromsql) (struct npc_data *nd, unsigned short index); - void (*market_delfromsql_sub) (const char *npcname, unsigned short index); + void (*market_tosql) (struct npc_data *nd, int index); + void (*market_delfromsql) (struct npc_data *nd, int index); + void (*market_delfromsql_sub) (const char *npcname, int index); + void (*barter_fromsql) (void); + void (*barter_tosql) (struct npc_data *nd, int index); + void (*barter_delfromsql) (struct npc_data *nd, int index); + void (*barter_delfromsql_sub) (const char *npcname, int itemId, int itemId2, int amount2); bool (*db_checkid) (const int id); void (*refresh) (struct npc_data* nd); /** diff --git a/src/map/script.c b/src/map/script.c index d372d485e..841e21169 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -23889,12 +23889,36 @@ static BUILDIN(sellitem) return false; } - if( !nd->u.scr.shop ) - npc->trader_update(nd->src_id?nd->src_id:nd->bl.id); - else {/* no need to run this if its empty */ - for( i = 0; i < nd->u.scr.shop->items; i++ ) { - if( nd->u.scr.shop->item[i].nameid == id ) - break; + if (!nd->u.scr.shop) { + npc->trader_update(nd->src_id ? nd->src_id : nd->bl.id); + if (nd->u.scr.shop->type == NST_BARTER) { + if (!script_hasdata(st, 5)) { + ShowError("buildin_sellitem: invalid number of parameters for barter-type shop!\n"); + return false; + } + value = script_getnum(st, 4); + value2 = script_getnum(st, 5); + } + } else {/* no need to run this if its empty */ + if (nd->u.scr.shop->type == NST_BARTER) { + if (!script_hasdata(st, 5)) { + ShowError("buildin_sellitem: invalid number of parameters for barter-type shop!\n"); + return false; + } + value = script_getnum(st, 4); + value2 = script_getnum(st, 5); + for (i = 0; i < nd->u.scr.shop->items; i++) { + const struct npc_item_list *const item = &nd->u.scr.shop->item[i]; + if (item->nameid == id && item->value == value && item->value2 == value2) { + break; + } + } + } else { + for (i = 0; i < nd->u.scr.shop->items; i++) { + if (nd->u.scr.shop->item[i].nameid == id) { + break; + } + } } } @@ -23917,33 +23941,28 @@ static BUILDIN(sellitem) } if (nd->u.scr.shop->type == NST_BARTER) { - if (!script_hasdata(st, 5)) { - ShowError("buildin_sellitem: invalid number of parameters for barter-type shop!\n"); - return false; - } qty = script_getnum(st, 3); - value = script_getnum(st, 4); - value2 = script_getnum(st, 5); - if (qty <= 0 || value <= 0 || value2 <= 0) { + if (qty < -1 || value <= 0 || value2 <= 0) { ShowError("buildin_sellitem: invalid parameters for barter-type shop!\n"); return false; } } - if( i != nd->u.scr.shop->items ) { + if (i != nd->u.scr.shop->items) { nd->u.scr.shop->item[i].value = value; nd->u.scr.shop->item[i].qty = qty; if (nd->u.scr.shop->type == NST_MARKET) /* has been manually updated, make it reflect on sql */ npc->market_tosql(nd, i); - // TODO: saving barter shop to sql + else if (nd->u.scr.shop->type == NST_BARTER) /* has been manually updated, make it reflect on sql */ + npc->barter_tosql(nd, i); } else { - for( i = 0; i < nd->u.scr.shop->items; i++ ) { - if( nd->u.scr.shop->item[i].nameid == 0 ) + for (i = 0; i < nd->u.scr.shop->items; i++) { + if (nd->u.scr.shop->item[i].nameid == 0) break; } - if( i == nd->u.scr.shop->items ) { - if( nd->u.scr.shop->items == USHRT_MAX ) { + if (i == nd->u.scr.shop->items) { + if (nd->u.scr.shop->items == USHRT_MAX) { ShowWarning("buildin_sellitem: Can't add %s (%s/%s), shop list is full!\n", it->name, nd->exname, nd->path); return false; } @@ -23970,37 +23989,55 @@ static BUILDIN(sellitem) static BUILDIN(stopselling) { struct npc_data *nd; - int i, id = script_getnum(st,2); + int i, id = script_getnum(st, 2); - if( !(nd = map->id2nd(st->oid)) || !nd->u.scr.shop ) { + if (!(nd = map->id2nd(st->oid)) || !nd->u.scr.shop) { ShowWarning("buildin_stopselling: trying to run without a proper NPC!\n"); return false; } - for( i = 0; i < nd->u.scr.shop->items; i++ ) { - if( nd->u.scr.shop->item[i].nameid == id ) - break; + if (nd->u.scr.shop->type == NST_BARTER) { + if (!script_hasdata(st, 4)) { + ShowError("buildin_stopselling: called with wrong number of arguments\n"); + return false; + } + const int id2 = script_getnum(st, 3); + const int amount2 = script_getnum(st, 4); + for (i = 0; i < nd->u.scr.shop->items; i++) { + const struct npc_item_list *const item = &nd->u.scr.shop->item[i]; + if (item->nameid == id && item->value == id2 && item->value2 == amount2) { + break; + } + } + } else { + for (i = 0; i < nd->u.scr.shop->items; i++) { + if (nd->u.scr.shop->item[i].nameid == id) { + break; + } + } } - if( i != nd->u.scr.shop->items ) { + if (i != nd->u.scr.shop->items) { int cursor; if (nd->u.scr.shop->type == NST_MARKET) - npc->market_delfromsql(nd,i); - // TODO: remove barter shop from sql + npc->market_delfromsql(nd, i); + if (nd->u.scr.shop->type == NST_BARTER) + npc->barter_delfromsql(nd, i); nd->u.scr.shop->item[i].nameid = 0; nd->u.scr.shop->item[i].value = 0; nd->u.scr.shop->item[i].value2 = 0; nd->u.scr.shop->item[i].qty = 0; - for( i = 0, cursor = 0; i < nd->u.scr.shop->items; i++ ) { - if( nd->u.scr.shop->item[i].nameid == 0 ) + for (i = 0, cursor = 0; i < nd->u.scr.shop->items; i++) { + if (nd->u.scr.shop->item[i].nameid == 0) continue; - if( cursor != i ) { + if (cursor != i) { nd->u.scr.shop->item[cursor].nameid = nd->u.scr.shop->item[i].nameid; nd->u.scr.shop->item[cursor].value = nd->u.scr.shop->item[i].value; + nd->u.scr.shop->item[cursor].value2 = nd->u.scr.shop->item[i].value2; nd->u.scr.shop->item[cursor].qty = nd->u.scr.shop->item[i].qty; } @@ -24066,7 +24103,8 @@ static BUILDIN(tradertype) nd->u.scr.shop->item[i].value = 0; nd->u.scr.shop->item[i].qty = 0; } - npc->market_delfromsql(nd,USHRT_MAX); + npc->market_delfromsql(nd, INT_MAX); + npc->barter_delfromsql(nd, INT_MAX); } #if PACKETVER < 20131223 @@ -25651,7 +25689,7 @@ static void script_parse_builtin(void) /* New Shop Support */ BUILDIN_DEF(openshop,"?"), BUILDIN_DEF(sellitem,"i???"), - BUILDIN_DEF(stopselling,"i"), + BUILDIN_DEF(stopselling,"i??"), BUILDIN_DEF(setcurrency,"i?"), BUILDIN_DEF(tradertype,"i"), BUILDIN_DEF(purchaseok,""), -- cgit v1.2.3-60-g2f50 From 939568eb4adab9b1353b09885f9ea510a45eccc9 Mon Sep 17 00:00:00 2001 From: Andrei Karas Date: Sat, 29 Dec 2018 22:08:57 +0300 Subject: Add barter shop demo script. --- doc/sample/npc_trader_sample.txt | 8 ++++++++ npc/custom/bartershop.txt | 21 +++++++++++++++++++++ npc/scripts_custom.conf | 1 + 3 files changed, 30 insertions(+) create mode 100644 npc/custom/bartershop.txt (limited to 'doc') diff --git a/doc/sample/npc_trader_sample.txt b/doc/sample/npc_trader_sample.txt index 0d50af8c5..24c53330b 100644 --- a/doc/sample/npc_trader_sample.txt +++ b/doc/sample/npc_trader_sample.txt @@ -56,3 +56,11 @@ OnMyResupply: sellitem Red_Potion,-1,49; end; } +/* demonstrate barter shop */ +prontera,159,284,4 trader Barter Shop#prt 4_M_KID1,{ +OnInit: + tradertype(NST_BARTER); + sellitem White_Herb, 100, Red_Potion, 2; + sellitem Blue_Herb, 200, Orange_Potion, 3; + end; +} diff --git a/npc/custom/bartershop.txt b/npc/custom/bartershop.txt new file mode 100644 index 000000000..bcb61795e --- /dev/null +++ b/npc/custom/bartershop.txt @@ -0,0 +1,21 @@ +//===== Hercules Script ====================================== +//= Barter shop demo +//===== By: ================================================== +//= 4144 +//===== Current Version: ===================================== +//= 1.0 +//===== Description: ========================================= +//= Barter shop demo in prontera. +//============================================================ + +prontera,159,284,4 trader Barter Shop#prt 4_M_KID1,{ +OnInit: + tradertype(NST_BARTER); + sellitem White_Herb, 100, Red_Potion, 2; + sellitem Blue_Herb, 200, Orange_Potion, 3; + sellitem Green_Herb, 100, Red_Potion, 4; + sellitem White_Herb, 100, Orange_Potion, 1; + sellitem Apple, -1, Orange_Potion, 1; + sellitem Praetorian_Shield, 100, Berserk_Potion, 10; + end; +} diff --git a/npc/scripts_custom.conf b/npc/scripts_custom.conf index 14384fd17..a5aad9767 100644 --- a/npc/scripts_custom.conf +++ b/npc/scripts_custom.conf @@ -50,6 +50,7 @@ //"npc/custom/card_remover.txt", //"npc/custom/item_signer.txt", //"npc/custom/woe_controller.txt", +//"npc/custom/bartershop.txt", //================= Other Scripts ========================================= // -- MVP Arena -- cgit v1.2.3-60-g2f50