summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrei Karas <akaras@inbox.ru>2018-12-27 21:42:14 +0300
committerAndrei Karas <akaras@inbox.ru>2019-01-14 20:18:10 +0300
commitfa1cb492536f2853c59a995dc54aa51ead420546 (patch)
treeb0b3751721d688a4795ca7a8a7b5909dca09191a
parent93b9a86bed2eb3a54b49557f663e06804985654f (diff)
downloadhercules-fa1cb492536f2853c59a995dc54aa51ead420546.tar.gz
hercules-fa1cb492536f2853c59a995dc54aa51ead420546.tar.bz2
hercules-fa1cb492536f2853c59a995dc54aa51ead420546.tar.xz
hercules-fa1cb492536f2853c59a995dc54aa51ead420546.zip
Add barter type shop and add packet ZC_NPC_BARTER_OPEN
-rw-r--r--db/constants.conf6
-rw-r--r--doc/script_commands.txt5
-rw-r--r--src/map/clif.c38
-rw-r--r--src/map/clif.h1
-rw-r--r--src/map/npc.c15
-rw-r--r--src/map/npc.h12
-rw-r--r--src/map/packets_struct.h28
-rw-r--r--src/map/script.c54
8 files changed, 134 insertions, 25 deletions
diff --git a/db/constants.conf b/db/constants.conf
index 502091a0f..598bc89c4 100644
--- a/db/constants.conf
+++ b/db/constants.conf
@@ -3742,12 +3742,6 @@ constants_db: {
IOT_PARTY: 2
IOT_GUILD: 3
- comment__: "tradertype"
- NST_ZENY: 0
- NST_CASH: 1
- NST_MARKET: 2
- NST_CUSTOM: 3
-
comment__: "strcharinfo"
PC_NAME: 0
PC_PARTY: 1
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(<Item_ID>{, <price>{, <qty>}})
+*sellitem(<Item_ID>, <qty>, <currency_id>, <currency_amount>)
adds (or modifies) <Item_ID> data to the shop,
when <price> 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 <Item_ID> 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(<Item_ID>)
diff --git a/src/map/clif.c b/src/map/clif.c
index c25f5a9af..a0081ba6f 100644
--- a/src/map/clif.c
+++ b/src/map/clif.c
@@ -22215,6 +22215,41 @@ static bool clif_enchant_equipment(struct map_session_data *sd, enum equip_pos p
#endif
}
+static void clif_npc_barter_open(struct map_session_data *sd, struct npc_data *nd)
+{
+#if PACKETVER_ZERO_NUM >= 20181226
+ nullpo_retv(sd);
+ nullpo_retv(nd);
+ struct npc_item_list *shop = nd->u.scr.shop->item;
+ const int shop_size = nd->u.scr.shop->items;
+
+ int c = 0;
+ int maxCount = (sizeof(packet_buf) - sizeof(struct PACKET_ZC_NPC_BARTER_OPEN)) / sizeof(struct PACKET_ZC_NPC_BARTER_OPEN_sub);
+ struct PACKET_ZC_NPC_BARTER_OPEN *packet = (struct PACKET_ZC_NPC_BARTER_OPEN*)&packet_buf[0];
+ packet->packetType = HEADER_ZC_NPC_BARTER_OPEN;
+
+ for (int i = 0; i < shop_size && c < maxCount; i++) {
+ if (shop[i].nameid) {
+ struct item_data *id = itemdb->exists(shop[i].nameid);
+ if (id == NULL)
+ continue;
+
+ packet->list[c].nameid = shop[i].nameid;
+ packet->list[c].type = itemtype(id->type);
+ packet->list[c].amount = shop[i].qty;
+ packet->list[c].currencyNameid = shop[i].value;
+ packet->list[c].currencyAmount = shop[i].value2;
+ packet->list[c].weight = id->weight * 10;
+ packet->list[c].index = i;
+ c++;
+ }
+ }
+
+ packet->packetLength = sizeof(struct PACKET_ZC_NPC_BARTER_OPEN) + sizeof(struct PACKET_ZC_NPC_BARTER_OPEN_sub) * c;
+ clif->send(packet, packet->packetLength, &sd->bl, SELF);
+#endif
+}
+
/*==========================================
* Main client packet processing function
*------------------------------------------*/
@@ -23400,4 +23435,7 @@ void clif_defaults(void)
clif->pMemorialDungeonCommand = clif_parse_memorial_dungeon_command;
clif->pReqRemainTime = clif_parse_reqRemainTime;
+
+ clif->npc_barter_open = clif_npc_barter_open;
+
}
diff --git a/src/map/clif.h b/src/map/clif.h
index 91a91b5d3..f5c9f62e8 100644
--- a/src/map/clif.h
+++ b/src/map/clif.h
@@ -1587,6 +1587,7 @@ struct clif_interface {
void (*item_preview) (struct map_session_data *sd, int n);
bool (*enchant_equipment) (struct map_session_data *sd, enum equip_pos pos, int cardSlot, int cardId);
void (*pReqRemainTime) (int fd, struct map_session_data *sd);
+ void (*npc_barter_open) (struct map_session_data *sd, struct npc_data *nd);
};
#ifdef HERCULES_CORE
diff --git a/src/map/npc.c b/src/map/npc.c
index fd11b6c5f..4c4cd0bb5 100644
--- a/src/map/npc.c
+++ b/src/map/npc.c
@@ -1449,11 +1449,12 @@ static int npc_cashshop_buylist(struct map_session_data *sd, int points, struct
return ERROR_TYPE_NPC;
if( nd->subtype != CASHSHOP ) {
- if( nd->subtype == SCRIPT && nd->u.scr.shop && nd->u.scr.shop->type != NST_ZENY && nd->u.scr.shop->type != NST_MARKET ) {
+ if (nd->subtype == SCRIPT && nd->u.scr.shop && nd->u.scr.shop->type != NST_ZENY && nd->u.scr.shop->type != NST_MARKET && nd->u.scr.shop->type != NST_BARTER) {
shop = nd->u.scr.shop->item;
shop_size = nd->u.scr.shop->items;
- } else
+ } else {
return ERROR_TYPE_NPC;
+ }
} else {
shop = nd->u.shop.shop_item;
shop_size = nd->u.shop.count;
@@ -1586,7 +1587,7 @@ static void npc_market_fromsql(void)
ShowError("npc_market_fromsql: NPC '%s' not found! skipping...\n",name);
npc->market_delfromsql_sub(name, USHRT_MAX);
continue;
- } else if ( nd->subtype != SCRIPT || !nd->u.scr.shop || !nd->u.scr.shop->items || nd->u.scr.shop->type != NST_MARKET ) {
+ } 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);
continue;
@@ -1673,6 +1674,9 @@ static bool npc_trader_open(struct map_session_data *sd, struct npc_data *nd)
clif->npc_market_open(sd,nd);
}
break;
+ case NST_BARTER:
+ clif->npc_barter_open(sd, nd);
+ break;
default:
clif->cashshop_show(sd,nd);
break;
@@ -1799,11 +1803,12 @@ static int npc_cashshop_buy(struct map_session_data *sd, int nameid, int amount,
return ERROR_TYPE_ITEM_ID; // Invalid Item
if( nd->subtype != CASHSHOP ) {
- if( nd->subtype == SCRIPT && nd->u.scr.shop && nd->u.scr.shop->type != NST_ZENY && nd->u.scr.shop->type != NST_MARKET ) {
+ if (nd->subtype == SCRIPT && nd->u.scr.shop && nd->u.scr.shop->type != NST_ZENY && nd->u.scr.shop->type != NST_MARKET && nd->u.scr.shop->type != NST_BARTER) {
shop = nd->u.scr.shop->item;
shop_size = nd->u.scr.shop->items;
- } else
+ } else {
return ERROR_TYPE_NPC;
+ }
} else {
shop = nd->u.shop.shop_item;
shop_size = nd->u.shop.count;
diff --git a/src/map/npc.h b/src/map/npc.h
index ed5f4138d..2cd0c0e29 100644
--- a/src/map/npc.h
+++ b/src/map/npc.h
@@ -41,10 +41,11 @@ enum npc_parse_options {
};
enum npc_shop_types {
- NST_ZENY,/* default */
- NST_CASH,/* official npc cash shop */
- NST_MARKET,/* official npc market type */
+ NST_ZENY, /* default */
+ NST_CASH, /* official npc cash shop */
+ NST_MARKET, /* official npc market type */
NST_CUSTOM,
+ NST_BARTER, /* official npc barter type */
/* */
NST_MAX,
};
@@ -56,11 +57,14 @@ struct npc_label_list {
char name[NAME_LENGTH];
int pos;
};
+
struct npc_item_list {
int nameid;
- unsigned int value;
+ unsigned int value; // price or barter currency item id
+ int value2; // barter currency item amount
unsigned int qty;
};
+
struct npc_shop_data {
unsigned char type;/* what am i */
struct npc_item_list *item;/* list */
diff --git a/src/map/packets_struct.h b/src/map/packets_struct.h
index 9fd30c0f6..1e11eadd7 100644
--- a/src/map/packets_struct.h
+++ b/src/map/packets_struct.h
@@ -3056,6 +3056,34 @@ struct PACKET_CZ_PARTY_CONFIG {
} __attribute__((packed));
DEFINE_PACKET_HEADER(CZ_PARTY_CONFIG, 0x02c8);
+#if PACKETVER_ZERO_NUM >= 20181226
+struct PACKET_ZC_NPC_BARTER_OPEN_sub {
+#if PACKETVER_MAIN_NUM >= 20181121 || PACKETVER_RE_NUM >= 20180704 || PACKETVER_ZERO_NUM >= 20181114
+ uint32 nameid;
+#else
+ uint16 nameid;
+#endif
+ uint8 type;
+ uint32 amount;
+#if PACKETVER_MAIN_NUM >= 20181121 || PACKETVER_RE_NUM >= 20180704 || PACKETVER_ZERO_NUM >= 20181114
+ uint32 currencyNameid;
+#else
+ uint16 currencyNameid;
+#endif
+ uint32 currencyAmount;
+ uint32 weight;
+ uint32 index;
+} __attribute__((packed));
+
+struct PACKET_ZC_NPC_BARTER_OPEN {
+ int16 packetType;
+ int16 packetLength;
+ struct PACKET_ZC_NPC_BARTER_OPEN_sub list[];
+} __attribute__((packed));
+
+DEFINE_PACKET_HEADER(ZC_NPC_BARTER_OPEN, 0x0b0e);
+#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(pop)
#endif // not NetBSD < 6 / Solaris
diff --git a/src/map/script.c b/src/map/script.c
index 25bf59839..d372d485e 100644
--- a/src/map/script.c
+++ b/src/map/script.c
@@ -23878,6 +23878,7 @@ static BUILDIN(sellitem)
struct item_data *it;
int i = 0, id = script_getnum(st,2);
int value = 0;
+ int value2 = 0;
int qty = 0;
if( !(nd = map->id2nd(st->oid)) ) {
@@ -23888,10 +23889,6 @@ static BUILDIN(sellitem)
return false;
}
- value = script_hasdata(st,3) ? script_getnum(st, 3) : it->value_buy;
- if( value == -1 )
- value = it->value_buy;
-
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 */
@@ -23901,6 +23898,12 @@ static BUILDIN(sellitem)
}
}
+ if (nd->u.scr.shop->type != NST_BARTER) {
+ value = script_hasdata(st,3) ? script_getnum(st, 3) : it->value_buy;
+ if( value == -1 )
+ value = it->value_buy;
+ }
+
if( nd->u.scr.shop->type == NST_MARKET ) {
if( !script_hasdata(st,4) || ( qty = script_getnum(st, 4) ) <= 0 ) {
ShowError("buildin_sellitem: invalid 'qty' for market-type shop!\n");
@@ -23913,11 +23916,26 @@ static BUILDIN(sellitem)
it->name, id, value, (int)(value*0.75), it->value_sell, (int)(it->value_sell*1.24), nd->exname, nd->path);
}
+ 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) {
+ ShowError("buildin_sellitem: invalid parameters for barter-type shop!\n");
+ return false;
+ }
+ }
+
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);
+ 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 {
for( i = 0; i < nd->u.scr.shop->items; i++ ) {
if( nd->u.scr.shop->item[i].nameid == 0 )
@@ -23935,6 +23953,7 @@ static BUILDIN(sellitem)
nd->u.scr.shop->item[i].nameid = it->nameid;
nd->u.scr.shop->item[i].value = value;
+ nd->u.scr.shop->item[i].value2 = value2;
nd->u.scr.shop->item[i].qty = qty;
}
@@ -23966,11 +23985,13 @@ static BUILDIN(stopselling)
if( i != nd->u.scr.shop->items ) {
int cursor;
- if( nd->u.scr.shop->type == NST_MARKET )
+ if (nd->u.scr.shop->type == NST_MARKET)
npc->market_delfromsql(nd,i);
+ // TODO: remove barter shop from sql
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++ ) {
@@ -24054,6 +24075,12 @@ static BUILDIN(tradertype)
script->reportsrc(st);
}
#endif
+#if PACKETVER_ZERO_NUM < 20181226
+ if (type == NST_BARTER) {
+ ShowWarning("buildin_tradertype: NST_BARTER is only available with PACKETVER_ZERO_NUM 20181226 or newer!\n");
+ script->reportsrc(st);
+ }
+#endif
if( nd->u.scr.shop )
nd->u.scr.shop->type = type;
@@ -24097,8 +24124,8 @@ static BUILDIN(shopcount)
} else if ( !nd->u.scr.shop || !nd->u.scr.shop->items ) {
ShowWarning("buildin_shopcount(%d): trying to use without any items!\n",id);
return false;
- } else if ( nd->u.scr.shop->type != NST_MARKET ) {
- ShowWarning("buildin_shopcount(%d): trying to use on a non-NST_MARKET shop!\n",id);
+ } else if (nd->u.scr.shop->type != NST_MARKET && nd->u.scr.shop->type != NST_BARTER) {
+ ShowWarning("buildin_shopcount(%d): trying to use on a non-NST_MARKET and non-NST_BARTER shop!\n",id);
return false;
}
@@ -25623,7 +25650,7 @@ static void script_parse_builtin(void)
/* New Shop Support */
BUILDIN_DEF(openshop,"?"),
- BUILDIN_DEF(sellitem,"i??"),
+ BUILDIN_DEF(sellitem,"i???"),
BUILDIN_DEF(stopselling,"i"),
BUILDIN_DEF(setcurrency,"i?"),
BUILDIN_DEF(tradertype,"i"),
@@ -26105,6 +26132,13 @@ static void script_hardcoded_constants(void)
script->set_constant("EXPAND_INV_RESULT_MISSING_ITEM", EXPAND_INVENTORY_RESULT_MISSING_ITEM, false, false);
script->set_constant("EXPAND_INV_RESULT_MAX_SIZE", EXPAND_INVENTORY_RESULT_MAX_SIZE, false, false);
+ script->constdb_comment("trader type");
+ script->set_constant("NST_ZENY", NST_ZENY, false, false);
+ script->set_constant("NST_CASH", NST_CASH, false, false);
+ script->set_constant("NST_MARKET", NST_MARKET, false, false);
+ script->set_constant("NST_CUSTOM", NST_CUSTOM, false, false);
+ script->set_constant("NST_BARTER", NST_BARTER, false, false);
+
script->constdb_comment("Renewal");
#ifdef RENEWAL
script->set_constant("RENEWAL", 1, false, false);