diff options
Diffstat (limited to 'src/map')
-rw-r--r-- | src/map/clif.c | 87 | ||||
-rw-r--r-- | src/map/clif.h | 12 | ||||
-rw-r--r-- | src/map/map.c | 2 | ||||
-rw-r--r-- | src/map/map.h | 1 | ||||
-rw-r--r-- | src/map/messages_ad.h | 3 | ||||
-rw-r--r-- | src/map/messages_main.h | 24 | ||||
-rw-r--r-- | src/map/messages_re.h | 24 | ||||
-rw-r--r-- | src/map/messages_sak.h | 3 | ||||
-rw-r--r-- | src/map/messages_zero.h | 16 | ||||
-rw-r--r-- | src/map/npc.c | 269 | ||||
-rw-r--r-- | src/map/npc.h | 23 | ||||
-rw-r--r-- | src/map/packets.h | 5 | ||||
-rw-r--r-- | src/map/packets_keys_main.h | 11 | ||||
-rw-r--r-- | src/map/packets_keys_zero.h | 10 | ||||
-rw-r--r-- | src/map/packets_shuffle_main.h | 11 | ||||
-rw-r--r-- | src/map/packets_shuffle_re.h | 11 | ||||
-rw-r--r-- | src/map/packets_shuffle_zero.h | 10 | ||||
-rw-r--r-- | src/map/packets_struct.h | 62 | ||||
-rw-r--r-- | src/map/script.c | 138 |
19 files changed, 629 insertions, 93 deletions
diff --git a/src/map/clif.c b/src/map/clif.c index 28b953de5..eba2ddce3 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -3079,7 +3079,7 @@ static void clif_cartItems(struct map_session_data *sd, enum inventory_type type static void clif_inventoryExpansionInfo(struct map_session_data *sd) { -#if PACKETVER_ZERO_NUM >= 20181212 +#if PACKETVER_MAIN_NUM >= 20181219 || PACKETVER_RE_NUM >= 20181219 || PACKETVER_ZERO_NUM >= 20181212 nullpo_retv(sd); const int fd = sd->fd; @@ -3093,7 +3093,7 @@ static void clif_inventoryExpansionInfo(struct map_session_data *sd) static void clif_inventoryExpandAck(struct map_session_data *sd, enum expand_inventory result, int itemId) { -#if PACKETVER_ZERO_NUM >= 20181212 +#if PACKETVER_MAIN_NUM >= 20181219 || PACKETVER_RE_NUM >= 20181219 || PACKETVER_ZERO_NUM >= 20181212 nullpo_retv(sd); const int fd = sd->fd; @@ -3108,7 +3108,7 @@ static void clif_inventoryExpandAck(struct map_session_data *sd, enum expand_inv static void clif_inventoryExpandResult(struct map_session_data *sd, enum expand_inventory_result result) { -#if PACKETVER_ZERO_NUM >= 20181212 +#if PACKETVER_MAIN_NUM >= 20181219 || PACKETVER_RE_NUM >= 20181219 || PACKETVER_ZERO_NUM >= 20181212 nullpo_retv(sd); const int fd = sd->fd; @@ -11578,6 +11578,10 @@ static void clif_parse_NpcBuySellSelected(int fd, struct map_session_data *sd) /// 3 = "Out of the maximum capacity, you have too many items." /// 9 = "Amounts are exceeded the possession of the item is not available for purchase." /// 10 = "Props open-air store sales will be traded in RODEX" +/// 11 = "The exchange failed." +/// 12 = "The exchange was well done." +/// 13 = "The item is already sold and out of stock." +/// 14 = "There is not enough goods to exchange." static void clif_npc_buy_result(struct map_session_data *sd, unsigned char result) { int fd; @@ -19904,7 +19908,7 @@ static void clif_npc_market_open(struct map_session_data *sd, struct npc_data *n packet->list[c].price = shop[i].value; packet->list[c].qty = shop[i].qty; packet->list[c].type = itemtype(id->type); - packet->list[c].weight = id->weight; + packet->list[c].weight = id->weight * 10; c++; } } @@ -19921,6 +19925,12 @@ static void clif_parse_NPCMarketClosed(int fd, struct map_session_data *sd) sd->npc_shopid = 0; } +static void clif_parse_NPCBarterClosed(int fd, struct map_session_data *sd) __attribute__((nonnull (2))); +static void clif_parse_NPCBarterClosed(int fd, struct map_session_data *sd) +{ + sd->npc_shopid = 0; +} + static void clif_npc_market_purchase_ack(struct map_session_data *sd, const struct itemlist *item_list, unsigned char response) { #if PACKETVER >= 20131223 @@ -22215,6 +22225,71 @@ 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 +} + +static void clif_parse_NPCBarterPurchase(int fd, struct map_session_data *sd) __attribute__((nonnull (2))); +static void clif_parse_NPCBarterPurchase(int fd, struct map_session_data *sd) +{ +#if PACKETVER_ZERO_NUM >= 20181226 + const struct PACKET_CZ_NPC_BARTER_PURCHASE *p = RP2PTR(fd); + int count = (p->packetLength - sizeof(struct PACKET_CZ_NPC_BARTER_PURCHASE)) / sizeof p->list[0]; + struct barteritemlist item_list; + + Assert_retv(count >= 0 && count <= sd->status.inventorySize); + + VECTOR_INIT(item_list); + VECTOR_ENSURE(item_list, count, 1); + + for (int i = 0; i < count; i++) { + struct barter_itemlist_entry entry = { 0 }; + 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); + } + + int response = npc->barter_buylist(sd, &item_list); + clif->npc_buy_result(sd, response); + + VECTOR_CLEAR(item_list); +#endif +} + /*========================================== * Main client packet processing function *------------------------------------------*/ @@ -23400,4 +23475,8 @@ void clif_defaults(void) clif->pMemorialDungeonCommand = clif_parse_memorial_dungeon_command; clif->pReqRemainTime = clif_parse_reqRemainTime; + + clif->npc_barter_open = clif_npc_barter_open; + clif->pNPCBarterClosed = clif_parse_NPCBarterClosed; + clif->pNPCBarterPurchase = clif_parse_NPCBarterPurchase; } diff --git a/src/map/clif.h b/src/map/clif.h index 91a91b5d3..1aee11c33 100644 --- a/src/map/clif.h +++ b/src/map/clif.h @@ -665,6 +665,15 @@ struct stylist_data_entry { }; VECTOR_DECL(struct stylist_data_entry) stylist_data[MAX_STYLIST_TYPE]; +struct barter_itemlist_entry { + int addId; + int addAmount; + int removeIndex; + int shopIndex; +}; + +VECTOR_STRUCT_DECL(barteritemlist, struct barter_itemlist_entry); + /** * Stylist Shop Responds **/ @@ -1587,6 +1596,9 @@ 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); + void (*pNPCBarterClosed) (int fd, struct map_session_data *sd); + void (*pNPCBarterPurchase) (int fd, struct map_session_data *sd); }; #ifdef HERCULES_CORE 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/messages_ad.h b/src/map/messages_ad.h index 4345e078a..e0a4e5c98 100644 --- a/src/map/messages_ad.h +++ b/src/map/messages_ad.h @@ -2,7 +2,8 @@ * This file is part of Hercules. * http://herc.ws - http://github.com/HerculesWS/Hercules * - * Copyright (C) 2013-2018 Hercules Dev Team + * Copyright (C) 2013-2019 Hercules Dev Team + * Copyright (C) 2018-2019 Andrei Karas (4144) * * Hercules is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/map/messages_main.h b/src/map/messages_main.h index bb01d24cb..1ce77451e 100644 --- a/src/map/messages_main.h +++ b/src/map/messages_main.h @@ -2,8 +2,8 @@ * This file is part of Hercules. * http://herc.ws - http://github.com/HerculesWS/Hercules * - * Copyright (C) 2013-2018 Hercules Dev Team - * Copyright (C) 2018 Andrei Karas (4144) + * Copyright (C) 2013-2019 Hercules Dev Team + * Copyright (C) 2018-2019 Andrei Karas (4144) * * Hercules is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -24,7 +24,7 @@ /* This file is autogenerated, please do not commit manual changes -Latest version: 20181212 +Latest version: 20190109 */ enum clif_messages { @@ -21448,6 +21448,24 @@ PvP */ MSG_ID_DF4 = 0xdf4, #endif +#if PACKETVER >= 20190109 +/*20190109 to latest +Capture Monster +*/ + MSG_ID_DF5 = 0xdf5, +/*20190109 to latest +message +*/ + MSG_ID_DF6 = 0xdf6, +/*20190109 to latest +TITLE +*/ + MSG_ID_DF7 = 0xdf7, +/*20190109 to latest +데미지 표기 확장 +*/ + MSG_ID_DF8 = 0xdf8, +#endif }; #endif /* MAP_MESSAGES_MAIN_H */ diff --git a/src/map/messages_re.h b/src/map/messages_re.h index 8b75d608d..af66a8464 100644 --- a/src/map/messages_re.h +++ b/src/map/messages_re.h @@ -2,8 +2,8 @@ * This file is part of Hercules. * http://herc.ws - http://github.com/HerculesWS/Hercules * - * Copyright (C) 2013-2018 Hercules Dev Team - * Copyright (C) 2018 Andrei Karas (4144) + * Copyright (C) 2013-2019 Hercules Dev Team + * Copyright (C) 2018-2019 Andrei Karas (4144) * * Hercules is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -24,7 +24,7 @@ /* This file is autogenerated, please do not commit manual changes -Latest version: 20181212 +Latest version: 20190109 */ enum clif_messages { @@ -20927,6 +20927,24 @@ PvP */ MSG_ID_DF4 = 0xdf4, #endif +#if PACKETVER >= 20190109 +/*20190109 to latest +Capture Monster +*/ + MSG_ID_DF5 = 0xdf5, +/*20190109 to latest +message +*/ + MSG_ID_DF6 = 0xdf6, +/*20190109 to latest +TITLE +*/ + MSG_ID_DF7 = 0xdf7, +/*20190109 to latest +데미지 표기 확장 +*/ + MSG_ID_DF8 = 0xdf8, +#endif }; #endif /* MAP_MESSAGES_RE_H */ diff --git a/src/map/messages_sak.h b/src/map/messages_sak.h index 2cfe085c8..2c7bfd661 100644 --- a/src/map/messages_sak.h +++ b/src/map/messages_sak.h @@ -2,7 +2,8 @@ * This file is part of Hercules. * http://herc.ws - http://github.com/HerculesWS/Hercules * - * Copyright (C) 2013-2018 Hercules Dev Team + * Copyright (C) 2013-2019 Hercules Dev Team + * Copyright (C) 2018-2019 Andrei Karas (4144) * * Hercules is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/map/messages_zero.h b/src/map/messages_zero.h index f7f4cf360..c86c8c919 100644 --- a/src/map/messages_zero.h +++ b/src/map/messages_zero.h @@ -2,8 +2,8 @@ * This file is part of Hercules. * http://herc.ws - http://github.com/HerculesWS/Hercules * - * Copyright (C) 2013-2018 Hercules Dev Team - * Copyright (C) 2018 Andrei Karas (4144) + * Copyright (C) 2013-2019 Hercules Dev Team + * Copyright (C) 2018-2019 Andrei Karas (4144) * * Hercules is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -24,7 +24,7 @@ /* This file is autogenerated, please do not commit manual changes -Latest version: 20181212 +Latest version: 20181226 */ enum clif_messages { @@ -17529,6 +17529,16 @@ PvP */ MSG_ID_DF4 = 0xdf4, #endif +#if PACKETVER >= 20181226 +/*20181226 to latest +Capture Monster +*/ + MSG_ID_DF5 = 0xdf5, +/*20181226 to latest +message +*/ + MSG_ID_DF6 = 0xdf6, +#endif }; #endif /* MAP_MESSAGES_ZERO_H */ diff --git a/src/map/npc.c b/src/map/npc.c index fd11b6c5f..7e1dab1b2 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; @@ -1584,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 ) { + } 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; } @@ -1610,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); @@ -1621,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 { @@ -1635,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. **/ @@ -1673,6 +1777,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 +1906,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; @@ -2112,6 +2220,133 @@ static int npc_market_buylist(struct map_session_data *sd, struct itemlist *item return 0; } +/** + * Processes incoming npc barter purchase list + **/ +static int npc_barter_buylist(struct map_session_data *sd, struct barteritemlist *item_list) +{ + struct npc_data* nd; + struct npc_item_list *shop = NULL; + int w, new_; + unsigned short shop_size = 0; + + nullpo_retr(1, sd); + nullpo_retr(1, item_list); + + nd = npc->checknear(sd, map->id2bl(sd->npc_shopid)); + + if (nd == NULL || nd->subtype != SCRIPT || VECTOR_LENGTH(*item_list) == 0 || !nd->u.scr.shop || nd->u.scr.shop->type != NST_BARTER) + return 11; + + shop = nd->u.scr.shop->item; + shop_size = nd->u.scr.shop->items; + + w = 0; + new_ = 0; + + int items[MAX_INVENTORY] = { 0 }; + + // process entries in buy list, one by one + for (int i = 0; i < VECTOR_LENGTH(*item_list); ++i) { + struct barter_itemlist_entry *entry = &VECTOR_INDEX(*item_list, i); + + const int n = entry->removeIndex; + 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 removeAmount = shop[j].value2; + + 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) + return 14; // not enough item amount in inventory + + items[n] += removeAmount * entry->addAmount; + + if (items[n] > sd->status.inventory[n].amount) + return 14; // not enough item amount in inventory + + entry->addId = shop[j].nameid; //item_avail replacement + + npc_market_qty[i] = j; + + if (!itemdb->isstackable(entry->addId) && entry->addAmount > 1) { + //Exploit? You can't buy more than 1 of equipment types o.O + ShowWarning("Player %s (%d:%d) sent a hexed packet trying to buy %d of non-stackable item %d!\n", + sd->status.name, sd->status.account_id, sd->status.char_id, entry->addAmount, entry->addId); + entry->addAmount = 1; + } + + switch (pc->checkadditem(sd, entry->addId, entry->addAmount)) { + case ADDITEM_EXIST: + break; + case ADDITEM_NEW: + new_++; + break; + case ADDITEM_OVERAMOUNT: /* TODO find official response for this */ + return 1; + } + + w += itemdb_weight(entry->addId) * entry->addAmount; + w -= itemdb_weight(removeId) * removeAmount; + } + + if (w + sd->weight > sd->max_weight) + return 2; // Too heavy + + if (pc->inventoryblank(sd) < new_) + return 3; // Not enough space to store items + + for (int i = 0; i < sd->status.inventorySize; ++i) { + const int removeAmountTotal = items[i]; + if (removeAmountTotal == 0) + continue; + if (pc->delitem(sd, i, removeAmountTotal, 0, DELITEM_SOLD, LOG_TYPE_NPC) != 0) { + return 11; // unknown exploit + } + } + + for (int i = 0; i < VECTOR_LENGTH(*item_list); ++i) { + struct barter_itemlist_entry *entry = &VECTOR_INDEX(*item_list, i); + const int shopIdx = npc_market_qty[i]; + + 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; + } + + npc->barter_tosql(nd, shopIdx); + + if (itemdb_type(entry->addId) == IT_PETEGG) { + pet->create_egg(sd, entry->addId); + } else { + struct item item_tmp; + memset(&item_tmp, 0, sizeof(item_tmp)); + item_tmp.nameid = entry->addId; + item_tmp.identify = 1; + pc->additem(sd, &item_tmp, entry->addAmount, LOG_TYPE_NPC); + } + } + + return 12; +} + /// npc_selllist for script-controlled shops static int npc_selllist_sub(struct map_session_data *sd, struct itemlist *item_list, struct npc_data *nd) { @@ -4997,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() ) { @@ -5303,11 +5539,16 @@ void npc_defaults(void) npc->trader_pay = npc_trader_pay; npc->trader_update = npc_trader_update; npc->market_buylist = npc_market_buylist; + npc->barter_buylist = npc_barter_buylist; npc->trader_open = npc_trader_open; npc->market_fromsql = npc_market_fromsql; 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 ed5f4138d..d455a395b 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 */ @@ -306,11 +310,16 @@ struct npc_interface { bool (*trader_pay) (struct npc_data *nd, struct map_session_data *sd, int price, int points); void (*trader_update) (int master); int (*market_buylist) (struct map_session_data *sd, struct itemlist *item_list); + 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/packets.h b/src/map/packets.h index 81b861f78..44a49b387 100644 --- a/src/map/packets.h +++ b/src/map/packets.h @@ -1922,4 +1922,9 @@ packet(0x96e,clif->ackmergeitems); packet(0x0b19,clif->pInventoryExpansionRejected); #endif +#if PACKETVER_ZERO_NUM >= 20181226 + packet(0x0b0f,clif->pNPCBarterPurchase); + packet(0x0b12,clif->pNPCBarterClosed); +#endif + #endif /* MAP_PACKETS_H */ diff --git a/src/map/packets_keys_main.h b/src/map/packets_keys_main.h index 7a1f84faa..1bff5a738 100644 --- a/src/map/packets_keys_main.h +++ b/src/map/packets_keys_main.h @@ -2,8 +2,8 @@ * This file is part of Hercules. * http://herc.ws - http://github.com/HerculesWS/Hercules * - * Copyright (C) 2013-2018 Hercules Dev Team - * Copyright (C) 2018 Andrei Karas (4144) + * Copyright (C) 2013-2019 Hercules Dev Team + * Copyright (C) 2018-2019 Andrei Karas (4144) * * Hercules is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -37,7 +37,7 @@ packetKeys(0x49357d72,0x22c370a1,0x5f836591); #endif -// 2010-11-23aRagexeRE, 2010-11-24aRagexeRE, 2010-11-24bRagexeRE, 2010-11-25aRagexeRE, 2010-11-26aRagexeRE, 2010-11-30aRagexeRE, 2010-12-07aRagexeRE, 2010-12-14aRagexeRE, 2010-12-21aRagexeRE, 2010-12-23aRagexeRE, 2010-12-28aRagexeRE, 2011-01-04aRagexeRE, 2011-01-05aRagexeRE, 2011-01-11aRagexeRE, 2011-01-18aRagexeRE, 2011-01-25aRagexeRE, 2011-01-26aRagexeRE, 2011-01-26bRagexeRE, 2011-01-31aRagexeRE, 2011-01-31bRagexeRE, 2011-01-31cRagexeRE, 2011-02-08aRagexeRE, 2011-02-15aRagexeRE, 2011-02-22aRagexeRE, 2011-02-23aRagexeRE, 2011-02-23bRagexeRE, 2011-02-24aRagexeRE, 2011-02-25aRagexeRE, 2011-02-28aRagexeRE, 2011-03-08aRagexeRE, 2011-03-09aRagexeRE, 2011-03-09bRagexeRE, 2011-03-09cRagexeRE, 2011-03-09dRagexeRE, 2011-03-15aRagexeRE, 2011-03-22aRagexeRE, 2011-03-29aRagexeRE, 2011-03-30aRagexeRE, 2011-03-30cRagexeRE, 2011-04-05aRagexeRE, 2011-04-12aRagexeRE, 2011-04-19aRagexeRE, 2011-04-20aRagexeRE, 2011-04-26aRagexeRE, 2011-04-27aRagexeRE, 2011-05-03aRagexeRE, 2011-05-11aRagexeRE, 2011-05-17bRagexeRE, 2011-05-24aRagexeRE, 2011-05-26aRagexeRE, 2011-05-31aRagexeRE, 2011-06-07aRagexeRE, 2011-06-08aRagexeRE, 2011-06-08bRagexeRE, 2011-06-08cRagexeRE, 2011-06-09aRagexeRE, 2011-06-14bRagexeRE, 2011-06-22aRagexeRE, 2011-06-28aRagexeRE, 2011-07-06aRagexeRE, 2011-07-13aRagexeRE, 2011-07-13bRagexeRE, 2011-07-13cRagexeRE, 2011-07-19aRagexeRE, 2011-07-26aRagexeRE, 2011-08-03aRagexeRE, 2011-08-03bRagexeRE, 2011-08-10aRagexeRE, 2013-12-23aRagexeRE, 2014-05-08aRagexe, 2014-05-08aRagexeRE, 2014-06-11eRagexe, 2015-02-25hRagexe, 2018-03-15aRagexe, 2018-03-21aRagexe, 2018-03-21aRagexeRE, 2018-03-28bRagexe, 2018-03-28bRagexeRE, 2018-04-04bRagexe, 2018-04-04cRagexeRE, 2018-04-18aRagexe, 2018-04-18bRagexeRE, 2018-04-25cRagexe, 2018-04-25cRagexeRE, 2018-05-02bRagexe, 2018-05-02bRagexeRE, 2018-05-02dRagexeRE, 2018-05-09aRagexe, 2018-05-16cRagexe, 2018-05-16cRagexeRE, 2018-05-23aRagexe, 2018-05-23aRagexeRE, 2018-05-30aRagexe, 2018-05-30bRagexeRE, 2018-05-30cRagexeRE, 2018-06-05bRagexe, 2018-06-05bRagexeRE, 2018-06-12aRagexeRE, 2018-06-12bRagexeRE, 2018-06-20cRagexe, 2018-06-20dRagexeRE, 2018-06-20eRagexe, 2018-06-20eRagexeRE, 2018-06-21aRagexe, 2018-06-21aRagexeRE, 2018-07-04aRagexe, 2018-07-04aRagexeRE, 2018-07-11aRagexeRE, 2018-07-18bRagexe, 2018-07-18bRagexeRE, 2018-07-18bRagexeRE1, 2018-07-18cRagexe, 2018-07-18cRagexeRE, 2018-08-01cRagexe, 2018-08-01cRagexeRE, 2018-08-08bRagexe, 2018-08-08bRagexeRE, 2018-08-22cRagexe, 2018-08-22cRagexeRE, 2018-08-29aRagexe, 2018-08-29aRagexeRE, 2018-08-29bRagexeRE, 2018-08-31aRagexe, 2018-09-12dRagexe, 2018-09-12dRagexeRE, 2018-09-19aRagexe, 2018-09-19aRagexeRE, 2018-10-02aRagexe, 2018-10-02aRagexeRE, 2018-10-02bRagexe, 2018-10-02bRagexeRE, 2018-10-17_02aRagexe, 2018-10-17_02aRagexeRE, 2018-10-17_03aRagexe, 2018-10-17_03aRagexeRE, 2018-10-17bRagexe, 2018-10-17bRagexeRE, 2018-10-24bRagexe, 2018-10-31aRagexe, 2018-10-31bRagexe, 2018-10-31cRagexeRE, 2018-11-07aRagexe, 2018-11-07aRagexeRE, 2018-11-14cRagexe, 2018-11-14cRagexeRE, 2018-11-14dRagexe, 2018-11-14dRagexeRE, 2018-11-21bRagexe, 2018-11-21cRagexeRE, 2018-11-28aRagexe, 2018-11-28aRagexeRE, 2018-11-28bRagexe, 2018-11-28cRagexe, 2018-12-05aRagexe, 2018-12-05bRagexeRE, 2018-12-12aRagexe, 2018-12-12aRagexeRE, 2018-12-12bRagexe, 2018-12-12bRagexeRE +// 2010-11-23aRagexeRE, 2010-11-24aRagexeRE, 2010-11-24bRagexeRE, 2010-11-25aRagexeRE, 2010-11-26aRagexeRE, 2010-11-30aRagexeRE, 2010-12-07aRagexeRE, 2010-12-14aRagexeRE, 2010-12-21aRagexeRE, 2010-12-23aRagexeRE, 2010-12-28aRagexeRE, 2011-01-04aRagexeRE, 2011-01-05aRagexeRE, 2011-01-11aRagexeRE, 2011-01-18aRagexeRE, 2011-01-25aRagexeRE, 2011-01-26aRagexeRE, 2011-01-26bRagexeRE, 2011-01-31aRagexeRE, 2011-01-31bRagexeRE, 2011-01-31cRagexeRE, 2011-02-08aRagexeRE, 2011-02-15aRagexeRE, 2011-02-22aRagexeRE, 2011-02-23aRagexeRE, 2011-02-23bRagexeRE, 2011-02-24aRagexeRE, 2011-02-25aRagexeRE, 2011-02-28aRagexeRE, 2011-03-08aRagexeRE, 2011-03-09aRagexeRE, 2011-03-09bRagexeRE, 2011-03-09cRagexeRE, 2011-03-09dRagexeRE, 2011-03-15aRagexeRE, 2011-03-22aRagexeRE, 2011-03-29aRagexeRE, 2011-03-30aRagexeRE, 2011-03-30cRagexeRE, 2011-04-05aRagexeRE, 2011-04-12aRagexeRE, 2011-04-19aRagexeRE, 2011-04-20aRagexeRE, 2011-04-26aRagexeRE, 2011-04-27aRagexeRE, 2011-05-03aRagexeRE, 2011-05-11aRagexeRE, 2011-05-17bRagexeRE, 2011-05-24aRagexeRE, 2011-05-26aRagexeRE, 2011-05-31aRagexeRE, 2011-06-07aRagexeRE, 2011-06-08aRagexeRE, 2011-06-08bRagexeRE, 2011-06-08cRagexeRE, 2011-06-09aRagexeRE, 2011-06-14bRagexeRE, 2011-06-22aRagexeRE, 2011-06-28aRagexeRE, 2011-07-06aRagexeRE, 2011-07-13aRagexeRE, 2011-07-13bRagexeRE, 2011-07-13cRagexeRE, 2011-07-19aRagexeRE, 2011-07-26aRagexeRE, 2011-08-03aRagexeRE, 2011-08-03bRagexeRE, 2011-08-10aRagexeRE, 2013-12-23aRagexeRE, 2014-05-08aRagexe, 2014-05-08aRagexeRE, 2014-06-11eRagexe, 2015-02-25hRagexe, 2018-03-15aRagexe, 2018-03-21aRagexe, 2018-03-21aRagexeRE, 2018-03-28bRagexe, 2018-03-28bRagexeRE, 2018-04-04bRagexe, 2018-04-04cRagexeRE, 2018-04-18aRagexe, 2018-04-18bRagexeRE, 2018-04-25cRagexe, 2018-04-25cRagexeRE, 2018-05-02bRagexe, 2018-05-02bRagexeRE, 2018-05-02dRagexeRE, 2018-05-09aRagexe, 2018-05-16cRagexe, 2018-05-16cRagexeRE, 2018-05-23aRagexe, 2018-05-23aRagexeRE, 2018-05-30aRagexe, 2018-05-30bRagexeRE, 2018-05-30cRagexeRE, 2018-06-05bRagexe, 2018-06-05bRagexeRE, 2018-06-12aRagexeRE, 2018-06-12bRagexeRE, 2018-06-20cRagexe, 2018-06-20dRagexeRE, 2018-06-20eRagexe, 2018-06-20eRagexeRE, 2018-06-21aRagexe, 2018-06-21aRagexeRE, 2018-07-04aRagexe, 2018-07-04aRagexeRE, 2018-07-11aRagexeRE, 2018-07-18bRagexe, 2018-07-18bRagexeRE, 2018-07-18bRagexeRE1, 2018-07-18cRagexe, 2018-07-18cRagexeRE, 2018-08-01cRagexe, 2018-08-01cRagexeRE, 2018-08-08bRagexe, 2018-08-08bRagexeRE, 2018-08-22cRagexe, 2018-08-22cRagexeRE, 2018-08-29aRagexe, 2018-08-29aRagexeRE, 2018-08-29bRagexeRE, 2018-08-31aRagexe, 2018-09-12dRagexe, 2018-09-12dRagexeRE, 2018-09-19aRagexe, 2018-09-19aRagexeRE, 2018-10-02aRagexe, 2018-10-02aRagexeRE, 2018-10-02bRagexe, 2018-10-02bRagexeRE, 2018-10-17_02aRagexe, 2018-10-17_02aRagexeRE, 2018-10-17_03aRagexe, 2018-10-17_03aRagexeRE, 2018-10-17bRagexe, 2018-10-17bRagexeRE, 2018-10-24bRagexe, 2018-10-31aRagexe, 2018-10-31bRagexe, 2018-10-31cRagexeRE, 2018-11-07aRagexe, 2018-11-07aRagexeRE, 2018-11-14cRagexe, 2018-11-14cRagexeRE, 2018-11-14dRagexe, 2018-11-14dRagexeRE, 2018-11-21bRagexe, 2018-11-21cRagexeRE, 2018-11-28aRagexe, 2018-11-28aRagexeRE, 2018-11-28bRagexe, 2018-11-28cRagexe, 2018-12-05aRagexe, 2018-12-05bRagexeRE, 2018-12-12aRagexe, 2018-12-12aRagexeRE, 2018-12-12bRagexe, 2018-12-12bRagexeRE, 2018-12-19bRagexe, 2018-12-19bRagexeRE, 2018-12-26aRagexe, 2018-12-26aRagexeRE, 2019-01-09aRagexe, 2019-01-09bRagexeRE #if PACKETVER == 20101123 || \ PACKETVER == 20101124 || \ PACKETVER == 20101125 || \ @@ -130,7 +130,10 @@ PACKETVER == 20181121 || \ PACKETVER == 20181128 || \ PACKETVER == 20181205 || \ - PACKETVER >= 20181212 + PACKETVER == 20181212 || \ + PACKETVER == 20181219 || \ + PACKETVER == 20181226 || \ + PACKETVER >= 20190109 packetKeys(0x00000000,0x00000000,0x00000000); #endif diff --git a/src/map/packets_keys_zero.h b/src/map/packets_keys_zero.h index 1a592956e..574c69fcc 100644 --- a/src/map/packets_keys_zero.h +++ b/src/map/packets_keys_zero.h @@ -2,8 +2,8 @@ * This file is part of Hercules. * http://herc.ws - http://github.com/HerculesWS/Hercules * - * Copyright (C) 2013-2018 Hercules Dev Team - * Copyright (C) 2018 Andrei Karas (4144) + * Copyright (C) 2013-2019 Hercules Dev Team + * Copyright (C) 2018-2019 Andrei Karas (4144) * * Hercules is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -30,7 +30,7 @@ /* This file is autogenerated, please do not commit manual changes */ -// 2017-10-18aRagexe_zero, 2017-10-19aRagexe_zero, 2017-10-23aRagexe_zero, 2017-10-23bRagexe_zero, 2017-10-23cRagexe_zero, 2017-10-24aRagexe_2_zero, 2017-10-24aRagexe_zero, 2017-10-25bRagexe_zero, 2017-10-27aRagexe_zero, 2017-10-27bRagexe_zero, 2017-10-30aRagexe_zero, 2017-10-31aRagexe_zero, 2017-11-09aRagexe_zero, 2017-11-13aRagexe_zero, 2017-11-13bRagexe_zero, 2018-03-15aRagexe_zero, 2018-03-21aRagexe_zero, 2018-03-21bRagexe_zero, 2018-03-28_1aRagexe_zero, 2018-03-28cRagexe_zero, 2018-04-11aRagexe_zero, 2018-04-25_3aRagexe_zero, 2018-05-09_3aRagexe_zero, 2018-05-23aRagexe_zero, 2018-06-05bRagexe_zero, 2018-06-05cRagexe_zero, 2018-06-27aRagexe_zero, 2018-07-03aRagexe_zero, 2018-07-11_2aRagexe_zero, 2018-07-25_2aRagexe_zero, 2018-08-01aRagexe_zero, 2018-08-08_2aRagexe_zero, 2018-08-22aRagexe_zero, 2018-08-29aRagexe_zero, 2018-09-05aRagexe_zero, 2018-09-12aRagexe_zero, 2018-09-19aRagexe_zero, 2018-09-28aRagexe_zero, 2018-10-10_2aRagexe_zero, 2018-10-24_2aRagexe_zero, 2018-11-14aRagexe_zero, 2018-11-20aRagexe_zero, 2018-11-28aRagexe_zero, 2018-12-12aRagexe_zero +// 2017-10-18aRagexe_zero, 2017-10-19aRagexe_zero, 2017-10-23aRagexe_zero, 2017-10-23bRagexe_zero, 2017-10-23cRagexe_zero, 2017-10-24aRagexe_2_zero, 2017-10-24aRagexe_zero, 2017-10-25bRagexe_zero, 2017-10-27aRagexe_zero, 2017-10-27bRagexe_zero, 2017-10-30aRagexe_zero, 2017-10-31aRagexe_zero, 2017-11-09aRagexe_zero, 2017-11-13aRagexe_zero, 2017-11-13bRagexe_zero, 2018-03-15aRagexe_zero, 2018-03-21aRagexe_zero, 2018-03-21bRagexe_zero, 2018-03-28_1aRagexe_zero, 2018-03-28cRagexe_zero, 2018-04-11aRagexe_zero, 2018-04-25_3aRagexe_zero, 2018-05-09_3aRagexe_zero, 2018-05-23aRagexe_zero, 2018-06-05bRagexe_zero, 2018-06-05cRagexe_zero, 2018-06-27aRagexe_zero, 2018-07-03aRagexe_zero, 2018-07-11_2aRagexe_zero, 2018-07-25_2aRagexe_zero, 2018-08-01aRagexe_zero, 2018-08-08_2aRagexe_zero, 2018-08-22aRagexe_zero, 2018-08-29aRagexe_zero, 2018-09-05aRagexe_zero, 2018-09-12aRagexe_zero, 2018-09-19aRagexe_zero, 2018-09-28aRagexe_zero, 2018-10-10_2aRagexe_zero, 2018-10-24_2aRagexe_zero, 2018-11-14aRagexe_zero, 2018-11-20aRagexe_zero, 2018-11-28aRagexe_zero, 2018-12-12aRagexe_zero, 2018-12-19aRagexe_zero, 2018-12-26_2aRagexe_zero #if PACKETVER == 20171018 || \ PACKETVER == 20171019 || \ PACKETVER == 20171023 || \ @@ -66,7 +66,9 @@ PACKETVER == 20181114 || \ PACKETVER == 20181120 || \ PACKETVER == 20181128 || \ - PACKETVER >= 20181212 + PACKETVER == 20181212 || \ + PACKETVER == 20181219 || \ + PACKETVER >= 20181226 packetKeys(0x00000000,0x00000000,0x00000000); #endif diff --git a/src/map/packets_shuffle_main.h b/src/map/packets_shuffle_main.h index 940dbcf89..5bae987c9 100644 --- a/src/map/packets_shuffle_main.h +++ b/src/map/packets_shuffle_main.h @@ -2,8 +2,8 @@ * This file is part of Hercules. * http://herc.ws - http://github.com/HerculesWS/Hercules * - * Copyright (C) 2013-2018 Hercules Dev Team - * Copyright (C) 2018 Andrei Karas (4144) + * Copyright (C) 2013-2019 Hercules Dev Team + * Copyright (C) 2018-2019 Andrei Karas (4144) * * Hercules is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -9727,11 +9727,14 @@ packet(0x0967,clif->pSolveCharName,2); // CZ_REQNAME_BYGID // 6 #endif -// 2018-11-21bRagexe, 2018-11-28aRagexe, 2018-11-28bRagexe, 2018-11-28cRagexe, 2018-12-05aRagexe, 2018-12-12aRagexe, 2018-12-12bRagexe +// 2018-11-21bRagexe, 2018-11-28aRagexe, 2018-11-28bRagexe, 2018-11-28cRagexe, 2018-12-05aRagexe, 2018-12-12aRagexe, 2018-12-12bRagexe, 2018-12-19bRagexe, 2018-12-26aRagexe, 2019-01-09aRagexe #if PACKETVER == 20181121 || \ PACKETVER == 20181128 || \ PACKETVER == 20181205 || \ - PACKETVER >= 20181212 + PACKETVER == 20181212 || \ + PACKETVER == 20181219 || \ + PACKETVER == 20181226 || \ + PACKETVER >= 20190109 packet(0x0202,clif->pFriendsListAdd,2); // CZ_ADD_FRIENDS // 26 packet(0x022d,clif->pHomMenu,2,4); // CZ_COMMAND_MER // 5 packet(0x023b,clif->pStoragePassword,0); // CZ_ACK_STORE_PASSWORD // 36 diff --git a/src/map/packets_shuffle_re.h b/src/map/packets_shuffle_re.h index dabc2ce6c..ec1d3971f 100644 --- a/src/map/packets_shuffle_re.h +++ b/src/map/packets_shuffle_re.h @@ -2,8 +2,8 @@ * This file is part of Hercules. * http://herc.ws - http://github.com/HerculesWS/Hercules * - * Copyright (C) 2013-2018 Hercules Dev Team - * Copyright (C) 2018 Andrei Karas (4144) + * Copyright (C) 2013-2019 Hercules Dev Team + * Copyright (C) 2018-2019 Andrei Karas (4144) * * Hercules is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -9663,7 +9663,7 @@ packet(0x083c,clif->pSearchStoreInfoListItemClick,2,6,10); // CZ_SSILIST_ITEM_CLICK // 12 #endif -// 2018-07-04aRagexeRE, 2018-07-11aRagexeRE, 2018-07-18bRagexeRE, 2018-07-18bRagexeRE1, 2018-07-18cRagexeRE, 2018-08-01cRagexeRE, 2018-08-08bRagexeRE, 2018-08-22cRagexeRE, 2018-08-29aRagexeRE, 2018-08-29bRagexeRE, 2018-09-12dRagexeRE, 2018-09-19aRagexeRE, 2018-10-02aRagexeRE, 2018-10-02bRagexeRE, 2018-10-17_02aRagexeRE, 2018-10-17_03aRagexeRE, 2018-10-17bRagexeRE, 2018-10-31cRagexeRE, 2018-11-07aRagexeRE, 2018-11-14cRagexeRE, 2018-11-14dRagexeRE, 2018-11-21cRagexeRE, 2018-11-28aRagexeRE, 2018-12-05bRagexeRE, 2018-12-12aRagexeRE, 2018-12-12bRagexeRE +// 2018-07-04aRagexeRE, 2018-07-11aRagexeRE, 2018-07-18bRagexeRE, 2018-07-18bRagexeRE1, 2018-07-18cRagexeRE, 2018-08-01cRagexeRE, 2018-08-08bRagexeRE, 2018-08-22cRagexeRE, 2018-08-29aRagexeRE, 2018-08-29bRagexeRE, 2018-09-12dRagexeRE, 2018-09-19aRagexeRE, 2018-10-02aRagexeRE, 2018-10-02bRagexeRE, 2018-10-17_02aRagexeRE, 2018-10-17_03aRagexeRE, 2018-10-17bRagexeRE, 2018-10-31cRagexeRE, 2018-11-07aRagexeRE, 2018-11-14cRagexeRE, 2018-11-14dRagexeRE, 2018-11-21cRagexeRE, 2018-11-28aRagexeRE, 2018-12-05bRagexeRE, 2018-12-12aRagexeRE, 2018-12-12bRagexeRE, 2018-12-19bRagexeRE, 2018-12-26aRagexeRE, 2019-01-09bRagexeRE #if PACKETVER == 20180704 || \ PACKETVER == 20180711 || \ PACKETVER == 20180718 || \ @@ -9681,7 +9681,10 @@ PACKETVER == 20181121 || \ PACKETVER == 20181128 || \ PACKETVER == 20181205 || \ - PACKETVER >= 20181212 + PACKETVER == 20181212 || \ + PACKETVER == 20181219 || \ + PACKETVER == 20181226 || \ + PACKETVER >= 20190109 packet(0x0202,clif->pFriendsListAdd,2); // CZ_ADD_FRIENDS // 26 packet(0x022d,clif->pHomMenu,2,4); // CZ_COMMAND_MER // 5 packet(0x023b,clif->pStoragePassword,0); // CZ_ACK_STORE_PASSWORD // 36 diff --git a/src/map/packets_shuffle_zero.h b/src/map/packets_shuffle_zero.h index d38ed4008..4a85d619b 100644 --- a/src/map/packets_shuffle_zero.h +++ b/src/map/packets_shuffle_zero.h @@ -2,8 +2,8 @@ * This file is part of Hercules. * http://herc.ws - http://github.com/HerculesWS/Hercules * - * Copyright (C) 2013-2018 Hercules Dev Team - * Copyright (C) 2018 Andrei Karas (4144) + * Copyright (C) 2013-2019 Hercules Dev Team + * Copyright (C) 2018-2019 Andrei Karas (4144) * * Hercules is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -742,11 +742,13 @@ packet(0x0968,clif->pStoragePassword,0); // CZ_ACK_STORE_PASSWORD // 36 #endif -// 2018-11-14aRagexe_zero, 2018-11-20aRagexe_zero, 2018-11-28aRagexe_zero, 2018-12-12aRagexe_zero +// 2018-11-14aRagexe_zero, 2018-11-20aRagexe_zero, 2018-11-28aRagexe_zero, 2018-12-12aRagexe_zero, 2018-12-19aRagexe_zero, 2018-12-26_2aRagexe_zero #if PACKETVER == 20181114 || \ PACKETVER == 20181120 || \ PACKETVER == 20181128 || \ - PACKETVER >= 20181212 + PACKETVER == 20181212 || \ + PACKETVER == 20181219 || \ + PACKETVER >= 20181226 packet(0x0202,clif->pFriendsListAdd,2); // CZ_ADD_FRIENDS // 26 packet(0x022d,clif->pHomMenu,2,4); // CZ_COMMAND_MER // 5 packet(0x023b,clif->pStoragePassword,0); // CZ_ACK_STORE_PASSWORD // 36 diff --git a/src/map/packets_struct.h b/src/map/packets_struct.h index d648d262e..d20b20bee 100644 --- a/src/map/packets_struct.h +++ b/src/map/packets_struct.h @@ -308,7 +308,6 @@ enum packet_headers { monsterhpType = 0x977, maptypeproperty2Type = 0x99b, npcmarketresultackType = 0x9d7, - npcmarketopenType = 0x9d5, #if PACKETVER >= 20131223 // version probably can be 20131030 [4144] wisendType = 0x9df, #else @@ -3000,7 +2999,7 @@ struct PACKET_CZ_STOP_USE_SKILL { DEFINE_PACKET_HEADER(CZ_STOP_USE_SKILL, 0x0b11); #endif -#if PACKETVER_ZERO_NUM >= 20181212 +#if PACKETVER_MAIN_NUM >= 20181219 || PACKETVER_RE_NUM >= 20181219 || PACKETVER_ZERO_NUM >= 20181212 struct PACKET_ZC_INVENTORY_EXPANSION_INFO { int16 packetType; int16 expansionSize; @@ -3008,7 +3007,7 @@ struct PACKET_ZC_INVENTORY_EXPANSION_INFO { DEFINE_PACKET_HEADER(ZC_INVENTORY_EXPANSION_INFO, 0x0b18); #endif -#if PACKETVER_ZERO_NUM >= 20181212 +#if PACKETVER_MAIN_NUM >= 20181219 || PACKETVER_RE_NUM >= 20181219 || PACKETVER_ZERO_NUM >= 20181212 struct PACKET_ZC_ACK_INVENTORY_EXPAND { int16 packetType; uint8 result; @@ -3017,7 +3016,7 @@ struct PACKET_ZC_ACK_INVENTORY_EXPAND { DEFINE_PACKET_HEADER(ZC_ACK_INVENTORY_EXPAND, 0x0b15); #endif -#if PACKETVER_ZERO_NUM >= 20181212 +#if PACKETVER_MAIN_NUM >= 20181219 || PACKETVER_RE_NUM >= 20181219 || PACKETVER_ZERO_NUM >= 20181212 struct PACKET_ZC_ACK_INVENTORY_EXPAND_RESULT { int16 packetType; uint8 result; @@ -3057,6 +3056,61 @@ 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 PACKETVER_ZERO_NUM >= 20181226 +struct PACKET_CZ_NPC_BARTER_CLOSE { + int16 packetType; +} __attribute__((packed)); +DEFINE_PACKET_HEADER(CZ_NPC_BARTER_CLOSE, 0x0b12); +#endif + +#if PACKETVER_ZERO_NUM >= 20181226 +struct PACKET_CZ_NPC_BARTER_PURCHASE_sub { +#if PACKETVER_MAIN_NUM >= 20181121 || PACKETVER_RE_NUM >= 20180704 || PACKETVER_ZERO_NUM >= 20181114 + uint32 itemId; +#else + uint16 itemId; +#endif + uint32 amount; + uint16 invIndex; + uint32 shopIndex; +} __attribute__((packed)); + +struct PACKET_CZ_NPC_BARTER_PURCHASE { + int16 packetType; + int16 packetLength; + struct PACKET_CZ_NPC_BARTER_PURCHASE_sub list[]; +} __attribute__((packed)); +DEFINE_PACKET_HEADER(CZ_NPC_BARTER_PURCHASE, 0x0b0f); +#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..841e21169 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,19 +23889,45 @@ 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 */ - 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; + } + } } } + 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,19 +23940,29 @@ 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( i != nd->u.scr.shop->items ) { + if (nd->u.scr.shop->type == NST_BARTER) { + qty = script_getnum(st, 3); + 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) { 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); + 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; } @@ -23935,6 +23972,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; } @@ -23951,35 +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); + if (nd->u.scr.shop->type == NST_MARKET) + 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; } @@ -24045,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 @@ -24054,6 +24113,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 +24162,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,8 +25688,8 @@ static void script_parse_builtin(void) /* New Shop Support */ BUILDIN_DEF(openshop,"?"), - BUILDIN_DEF(sellitem,"i??"), - BUILDIN_DEF(stopselling,"i"), + BUILDIN_DEF(sellitem,"i???"), + BUILDIN_DEF(stopselling,"i??"), BUILDIN_DEF(setcurrency,"i?"), BUILDIN_DEF(tradertype,"i"), BUILDIN_DEF(purchaseok,""), @@ -26105,6 +26170,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); |