diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/map/clif.c | 107 | ||||
-rw-r--r-- | src/map/clif.h | 10 | ||||
-rw-r--r-- | src/map/itemdb.c | 102 | ||||
-rw-r--r-- | src/map/itemdb.h | 14 | ||||
-rw-r--r-- | src/map/packets.h | 8 | ||||
-rw-r--r-- | src/map/packets_struct.h | 39 | ||||
-rw-r--r-- | src/map/pc.h | 5 | ||||
-rw-r--r-- | src/map/script.c | 37 | ||||
-rw-r--r-- | src/map/script.h | 1 |
9 files changed, 320 insertions, 3 deletions
diff --git a/src/map/clif.c b/src/map/clif.c index 1ed5e1d9f..f6caa502e 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -23332,6 +23332,109 @@ static void clif_parse_GuildCastleInfoRequest(int fd, struct map_session_data *s #endif } +static bool clif_lapineDdukDdak_open(struct map_session_data *sd, int item_id) +{ +#if PACKETVER_MAIN_NUM >= 20160601 || PACKETVER_RE_NUM >= 20160525 || defined(PACKETVER_ZERO) + nullpo_retr(false, sd); + nullpo_retr(false, itemdb->exists(item_id)); + struct PACKET_ZC_LAPINEDDUKDDAK_OPEN p; + + p.packetType = HEADER_ZC_LAPINEDDUKDDAK_OPEN; + p.itemId = item_id; + clif->send(&p, sizeof(p), &sd->bl, SELF); + + sd->state.lapine_ui = 1; + return true; +#else + return false; +#endif // PACKETVER_MAIN_NUM >= 20160601 || PACKETVER_RE_NUM >= 20160525 || defined(PACKETVER_ZERO) +} + +static bool clif_lapineDdukDdak_result(struct map_session_data *sd, enum lapineddukddak_result result) +{ +#if PACKETVER_MAIN_NUM >= 20160601 || PACKETVER_RE_NUM >= 20160525 || defined(PACKETVER_ZERO) + nullpo_retr(false, sd); + struct PACKET_ZC_LAPINEDDUKDDAK_RESULT p; + + p.packetType = HEADER_ZC_LAPINEDDUKDDAK_RESULT; + p.result = result; + clif->send(&p, sizeof(p), &sd->bl, SELF); + return true; +#else + return false; +#endif // PACKETVER_MAIN_NUM >= 20160601 || PACKETVER_RE_NUM >= 20160525 || defined(PACKETVER_ZERO) +} + +static void clif_parse_lapineDdukDdak_ack(int fd, struct map_session_data *sd) __attribute__((nonnull (2))); +static void clif_parse_lapineDdukDdak_ack(int fd, struct map_session_data *sd) +{ +#if PACKETVER >= 20160302 + const struct PACKET_CZ_LAPINEDDUKDDAK_ACK *p = RP2PTR(fd); + struct item_data *it = itemdb->exists(p->itemId); + + if (it == NULL || it->lapineddukddak == NULL) + return; + if (pc_cant_act(sd)) + return; + if (pc->search_inventory(sd, it->nameid) == INDEX_NOT_FOUND) + return; + + if (((p->packetLength - sizeof(struct PACKET_CZ_LAPINEDDUKDDAK_ACK)) / sizeof(struct PACKET_CZ_LAPINEDDUKDDAK_ACK_sub)) != it->lapineddukddak->NeedCount) + return; + + for (int i = 0; i < it->lapineddukddak->NeedCount; ++i) { + int16 idx = p->items[i].index - 2; + Assert_retv(idx >= 0 && idx < sd->status.inventorySize); + + struct item itr = sd->status.inventory[idx]; + int j = 0; + for (j = 0; j < VECTOR_LENGTH(it->lapineddukddak->SourceItems); ++j) { + if (itr.nameid == VECTOR_INDEX(it->lapineddukddak->SourceItems, j).id) { + // Validate that the amount sent in the packet is matching the database + if (p->items[i].count != VECTOR_INDEX(it->lapineddukddak->SourceItems, j).amount) { + clif->lapineDdukDdak_result(sd, LAPINEDDKUKDDAK_INSUFFICIENT_AMOUNT); + return; + } + + // Validate that the player have enough of the item + if (itr.amount < VECTOR_INDEX(it->lapineddukddak->SourceItems, j).amount) { + clif->lapineDdukDdak_result(sd, LAPINEDDKUKDDAK_INSUFFICIENT_AMOUNT); + return; + } + + // Validate refine rate requirement + if ((itemdb_type(itr.nameid) == IT_ARMOR || itemdb_type(itr.nameid) == IT_WEAPON) + && (itr.refine < it->lapineddukddak->NeedRefineMin || itr.refine > it->lapineddukddak->NeedRefineMax)) + return; + + // All requirements are met, move to the next one + break; + } + } + // The item is not in sources list + if (j == VECTOR_LENGTH(it->lapineddukddak->SourceItems)) { + clif->lapineDdukDdak_result(sd, LAPINEDDKUKDDAK_INVALID_ITEM); + return; + } + } + + for (int i = 0; i < it->lapineddukddak->NeedCount; ++i) + pc->delitem(sd, p->items[i].index - 2, p->items[i].count, 0, DELITEM_NORMAL, LOG_TYPE_SCRIPT); + if (it->lapineddukddak->script != NULL) + script->run_item_lapineddukddak_script(sd, it, npc->fake_nd->bl.id); + clif->lapineDdukDdak_result(sd, LAPINEDDKUKDDAK_SUCCESS); + return; +#endif // PACKETVER >= 20160302 +} + +static void clif_parse_lapineDdukDdak_close(int fd, struct map_session_data *sd) __attribute__((nonnull (2))); +static void clif_parse_lapineDdukDdak_close(int fd, struct map_session_data *sd) +{ +#if PACKETVER >= 20160504 + sd->state.lapine_ui = 0; +#endif // PACKETVER >= 20160504 +} + /*========================================== * Main client packet processing function *------------------------------------------*/ @@ -24562,4 +24665,8 @@ void clif_defaults(void) clif->pGuildCastleTeleportRequest = clif_parse_GuildCastleTeleportRequest; clif->pGuildCastleInfoRequest = clif_parse_GuildCastleInfoRequest; clif->guild_castleteleport_res = clif_guild_castleteleport_res; + clif->lapineDdukDdak_open = clif_lapineDdukDdak_open; + clif->lapineDdukDdak_result = clif_lapineDdukDdak_result; + clif->plapineDdukDdak_ack = clif_parse_lapineDdukDdak_ack; + clif->plapineDdukDdak_close = clif_parse_lapineDdukDdak_close; } diff --git a/src/map/clif.h b/src/map/clif.h index 245352b9c..4bc3abdeb 100644 --- a/src/map/clif.h +++ b/src/map/clif.h @@ -727,6 +727,12 @@ enum market_buy_result { }; #endif +enum lapineddukddak_result { + LAPINEDDKUKDDAK_SUCCESS = 0, + LAPINEDDKUKDDAK_INSUFFICIENT_AMOUNT = 5, + LAPINEDDKUKDDAK_INVALID_ITEM = 7, +}; + /** * Clif.c Interface **/ @@ -1659,6 +1665,10 @@ struct clif_interface { void (*pGuildCastleTeleportRequest) (int fd, struct map_session_data *sd); void (*pGuildCastleInfoRequest) (int fd, struct map_session_data *sd); void (*guild_castleteleport_res) (struct map_session_data *sd, enum siege_teleport_result result); + bool (*lapineDdukDdak_open) (struct map_session_data *sd, int item_id); + bool (*lapineDdukDdak_result) (struct map_session_data *sd, enum lapineddukddak_result result); + void (*plapineDdukDdak_ack) (int fd, struct map_session_data *sd); + void (*plapineDdukDdak_close) (int fd, struct map_session_data *sd); }; #ifdef HERCULES_CORE diff --git a/src/map/itemdb.c b/src/map/itemdb.c index e5e7b9478..a97325e57 100644 --- a/src/map/itemdb.c +++ b/src/map/itemdb.c @@ -2451,6 +2451,98 @@ static uint64 itemdb_unique_id(struct map_session_data *sd) return ((uint64)sd->status.char_id << 32) | sd->status.uniqueitem_counter++; } +static bool itemdb_read_libconfig_lapineddukddak(void) +{ + struct config_t item_lapineddukddak; + struct config_setting_t *it = NULL; + char filepath[256]; + + int i = 0; + int count = 0; + + safesnprintf(filepath, sizeof(filepath), "%s/%s", map->db_path, DBPATH"item_lapineddukddak.conf"); + if (libconfig->load_file(&item_lapineddukddak, filepath) == CONFIG_FALSE) + return false; + + while ((it = libconfig->setting_get_elem(item_lapineddukddak.root, i++)) != NULL) { + if (itemdb->read_libconfig_lapineddukddak_sub(it, filepath)) + ++count; + } + + libconfig->destroy(&item_lapineddukddak); + ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", count, filepath); + return true; +} + +static bool itemdb_read_libconfig_lapineddukddak_sub(struct config_setting_t *it, const char *source) +{ + nullpo_retr(false, it); + nullpo_retr(false, source); + + struct item_data *data = NULL; + const char *name = config_setting_name(it); + const char *str = NULL; + int i32 = 0; + + if ((data = itemdb->name2id(name)) == NULL) { + ShowWarning("itemdb_read_libconfig_lapineddukddak_sub: unknown item '%s', skipping..\n", name); + return false; + } + + data->lapineddukddak = aCalloc(1, sizeof(struct item_lapineddukddak)); + if (libconfig->setting_lookup_int(it, "NeedCount", &i32) == CONFIG_TRUE) + data->lapineddukddak->NeedCount = (int16)i32; + + if (libconfig->setting_lookup_int(it, "NeedRefineMin", &i32) == CONFIG_TRUE) + data->lapineddukddak->NeedRefineMin = (int8)i32; + + if (libconfig->setting_lookup_int(it, "NeedRefineMax", &i32) == CONFIG_TRUE) + data->lapineddukddak->NeedRefineMax = (int8)i32; + + struct config_setting_t *sources = libconfig->setting_get_member(it, "SourceItems"); + itemdb->read_libconfig_lapineddukddak_sub_sources(sources, data); + + if (libconfig->setting_lookup_string(it, "Script", &str) == CONFIG_TRUE) + data->lapineddukddak->script = *str ? script->parse(str, source, -data->nameid, SCRIPT_IGNORE_EXTERNAL_BRACKETS, NULL) : NULL; + return true; +} + +static bool itemdb_read_libconfig_lapineddukddak_sub_sources(struct config_setting_t *sources, struct item_data *data) +{ + nullpo_retr(false, data); + nullpo_retr(false, data->lapineddukddak); + + int i = 0; + struct config_setting_t *entry = NULL; + + if (sources == NULL || !config_setting_is_group(sources)) + return false; + + VECTOR_INIT(data->lapineddukddak->SourceItems); + while ((entry = libconfig->setting_get_elem(sources, i++)) != NULL) { + struct item_data *edata = NULL; + struct itemlist_entry item = { 0 }; + const char *name = config_setting_name(entry); + int i32 = 0; + + if ((edata = itemdb->name2id(name)) == NULL) { + ShowWarning("itemdb_read_libconfig_lapineddukddak_sub: unknown item '%s', skipping..\n", name); + continue; + } + item.id = edata->nameid; + + if ((i32 = libconfig->setting_get_int(entry)) == CONFIG_TRUE && (i32 <= 0 || i32 > MAX_AMOUNT)) { + ShowWarning("itemdb_read_libconfig_lapineddukddak_sub: invalid amount (%d) for source item '%s', skipping..\n", i32, name); + continue; + } + item.amount = i32; + + VECTOR_ENSURE(data->lapineddukddak->SourceItems, 1, 1); + VECTOR_PUSH(data->lapineddukddak->SourceItems, item); + } + return true; +} + /** * Reads all item-related databases. */ @@ -2489,6 +2581,7 @@ static void itemdb_read(bool minimal) itemdb->read_groups(); itemdb->read_chains(); itemdb->read_packages(); + itemdb->read_libconfig_lapineddukddak(); } /** @@ -2549,6 +2642,12 @@ static void destroy_item_data(struct item_data *self, int free_self) script->free_code(self->rental_end_script); if( self->combos ) aFree(self->combos); + if (self->lapineddukddak != NULL) { + if (self->lapineddukddak->script != NULL) + script->free_code(self->lapineddukddak->script); + VECTOR_CLEAR(self->lapineddukddak->SourceItems); + aFree(self->lapineddukddak); + } HPM->data_store_destroy(&self->hdata); #if defined(DEBUG) // trash item @@ -2853,4 +2952,7 @@ void itemdb_defaults(void) itemdb->lookup_const = itemdb_lookup_const; itemdb->lookup_const_mask = itemdb_lookup_const_mask; itemdb->addname_sub = itemdb_addname_sub; + itemdb->read_libconfig_lapineddukddak = itemdb_read_libconfig_lapineddukddak; + itemdb->read_libconfig_lapineddukddak_sub = itemdb_read_libconfig_lapineddukddak_sub; + itemdb->read_libconfig_lapineddukddak_sub_sources = itemdb_read_libconfig_lapineddukddak_sub_sources; } diff --git a/src/map/itemdb.h b/src/map/itemdb.h index e3264d7d8..14ead7707 100644 --- a/src/map/itemdb.h +++ b/src/map/itemdb.h @@ -39,7 +39,7 @@ struct hplugin_data_store; #ifndef MAX_ITEM_ID #if PACKETVER_MAIN_NUM >= 20181121 || PACKETVER_RE_NUM >= 20180704 || PACKETVER_ZERO_NUM >= 20181114 -#define MAX_ITEM_ID 0x20000 +#define MAX_ITEM_ID INT32_MAX #else #define MAX_ITEM_ID 0xFFFF #endif @@ -492,6 +492,14 @@ struct itemdb_option { struct script_code *script; }; +struct item_lapineddukddak { + int16 NeedCount; + int8 NeedRefineMin; + int8 NeedRefineMax; + VECTOR_DECL(struct itemlist_entry) SourceItems; + struct script_code *script; +}; + struct item_data { int nameid; char name[ITEM_NAME_LENGTH],jname[ITEM_NAME_LENGTH]; @@ -561,6 +569,7 @@ struct item_data { /* TODO add a pointer to some sort of (struct extra) and gather all the not-common vals into it to save memory */ struct item_group *group; struct item_package *package; + struct item_lapineddukddak *lapineddukddak; struct hplugin_data_store *hdata; ///< HPM Plugin Data Store }; @@ -698,6 +707,9 @@ struct itemdb_interface { bool (*lookup_const) (const struct config_setting_t *it, const char *name, int *value); bool (*lookup_const_mask) (const struct config_setting_t *it, const char *name, int *value); int (*addname_sub) (union DBKey key, struct DBData *data, va_list ap); + bool (*read_libconfig_lapineddukddak) (void); + bool (*read_libconfig_lapineddukddak_sub) (struct config_setting_t *it, const char *source); + bool (*read_libconfig_lapineddukddak_sub_sources) (struct config_setting_t *sources, struct item_data *data); }; #ifdef HERCULES_CORE diff --git a/src/map/packets.h b/src/map/packets.h index e91421cfc..8fb47eb7a 100644 --- a/src/map/packets.h +++ b/src/map/packets.h @@ -1959,4 +1959,12 @@ packet(0x96e,clif->ackmergeitems); packet(0x0b2c,clif->pGuildCastleInfoRequest); #endif +#if PACKETVER >= 20160302 + packet(0x0a4f,clif->plapineDdukDdak_ack); +#endif + +#if PACKETVER >= 20160504 + packet(0x0a70,clif->plapineDdukDdak_close); +#endif + #endif /* MAP_PACKETS_H */ diff --git a/src/map/packets_struct.h b/src/map/packets_struct.h index 24bb718da..9c8c93865 100644 --- a/src/map/packets_struct.h +++ b/src/map/packets_struct.h @@ -3669,6 +3669,45 @@ struct PACKET_CZ_CASTLE_INFO_REQUEST { DEFINE_PACKET_HEADER(CZ_CASTLE_INFO_REQUEST, 0x0b2c); #endif +#if PACKETVER_MAIN_NUM >= 20160601 || PACKETVER_RE_NUM >= 20160525 || defined(PACKETVER_ZERO) +struct PACKET_ZC_LAPINEDDUKDDAK_OPEN { + int16 packetType; +#if PACKETVER_MAIN_NUM >= 20181121 || PACKETVER_RE_NUM >= 20180704 || PACKETVER_ZERO_NUM >= 20181114 + int32 itemId; +#else + int16 itemId; +#endif +} __attribute__((packed)); +DEFINE_PACKET_HEADER(ZC_LAPINEDDUKDDAK_OPEN, 0x0a4e); +#endif // PACKETVER_MAIN_NUM >= 20160601 || PACKETVER_RE_NUM >= 20160525 || defined(PACKETVER_ZERO) + +#if PACKETVER >= 20160302 +struct PACKET_CZ_LAPINEDDUKDDAK_ACK_sub { + int16 index; + int16 count; +} __attribute__((packed)); + +struct PACKET_CZ_LAPINEDDUKDDAK_ACK { + int16 packetType; + int16 packetLength; +#if PACKETVER_MAIN_NUM >= 20181121 || PACKETVER_RE_NUM >= 20180704 || PACKETVER_ZERO_NUM >= 20181114 + int32 itemId; +#else + int16 itemId; +#endif + struct PACKET_CZ_LAPINEDDUKDDAK_ACK_sub items[]; +} __attribute__((packed)); +DEFINE_PACKET_HEADER(CZ_LAPINEDDUKDDAK_ACK, 0x0a4f); +#endif // PACKETVER >= 20160302 + +#if PACKETVER_MAIN_NUM >= 20160601 || PACKETVER_RE_NUM >= 20160525 || defined(PACKETVER_ZERO) +struct PACKET_ZC_LAPINEDDUKDDAK_RESULT { + int16 packetType; + int16 result; +} __attribute__((packed)); +DEFINE_PACKET_HEADER(ZC_LAPINEDDUKDDAK_RESULT, 0x0a50); +#endif // PACKETVER_MAIN_NUM >= 20160601 || PACKETVER_RE_NUM >= 20160525 || defined(PACKETVER_ZERO) + #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/pc.h b/src/map/pc.h index 2d21dabf6..7a42be5be 100644 --- a/src/map/pc.h +++ b/src/map/pc.h @@ -239,6 +239,7 @@ struct map_session_data { unsigned int warp_clean : 1; unsigned int refine_ui : 1; unsigned int npc_unloaded : 1; ///< The player is talking with an unloaded NPCs (respawned tombstones) + unsigned int lapine_ui : 1; } state; struct { unsigned char no_weapon_damage, no_magic_damage, no_misc_damage; @@ -665,10 +666,10 @@ END_ZEROED_BLOCK; #define pc_issit(sd) ( (sd)->vd.dead_sit == 2 ) #define pc_isidle(sd) ( (sd)->chat_id != 0 || (sd)->state.vending || (sd)->state.buyingstore || DIFF_TICK(sockt->last_tick, (sd)->idletime) >= battle->bc->idle_no_share ) #define pc_istrading(sd) ( (sd)->npc_id || (sd)->state.vending || (sd)->state.buyingstore || (sd)->state.trading ) -#define pc_cant_act(sd) ( (sd)->npc_id || (sd)->state.vending || (sd)->state.buyingstore || (sd)->chat_id != 0 || ((sd)->sc.opt1 && (sd)->sc.opt1 != OPT1_BURNING) || (sd)->state.trading || (sd)->state.storage_flag || (sd)->state.prevend || (sd)->state.refine_ui == 1) +#define pc_cant_act(sd) ( (sd)->npc_id || (sd)->state.vending || (sd)->state.buyingstore || (sd)->chat_id != 0 || ((sd)->sc.opt1 && (sd)->sc.opt1 != OPT1_BURNING) || (sd)->state.trading || (sd)->state.storage_flag || (sd)->state.prevend || (sd)->state.refine_ui == 1 || (sd)->state.lapine_ui == 1) /* equals pc_cant_act except it doesn't check for chat rooms */ -#define pc_cant_act2(sd) ( (sd)->npc_id || (sd)->state.buyingstore || ((sd)->sc.opt1 && (sd)->sc.opt1 != OPT1_BURNING) || (sd)->state.trading || (sd)->state.storage_flag || (sd)->state.prevend || (sd)->state.refine_ui == 1) +#define pc_cant_act2(sd) ( (sd)->npc_id || (sd)->state.buyingstore || ((sd)->sc.opt1 && (sd)->sc.opt1 != OPT1_BURNING) || (sd)->state.trading || (sd)->state.storage_flag || (sd)->state.prevend || (sd)->state.refine_ui == 1 || (sd)->state.lapine_ui == 1) #define pc_setdir(sd,b,h) ( (sd)->ud.dir = (b) ,(sd)->head_dir = (h) ) #define pc_setchatid(sd,n) ( (sd)->chat_id = (n) ) diff --git a/src/map/script.c b/src/map/script.c index df6e0d329..0fe97574c 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -25755,6 +25755,25 @@ static BUILDIN(identifyidx) return true; } +static BUILDIN(openlapineddukddakboxui) +{ + struct map_session_data *sd = script_rid2sd(st); + if (sd == NULL) + return false; + const int item_id = script_getnum(st, 2); + struct item_data *it = itemdb->exists(item_id); + if (it == NULL) { + ShowError("buildin_openlapineddukddakboxui: Item %d is not valid\n", item_id); + script->reportfunc(st); + script->reportsrc(st); + script_pushint(st, false); + return true; + } + clif->lapineDdukDdak_open(sd, item_id); + script_pushint(st, true); + return true; +} + /** * Adds a built-in script function. * @@ -25934,6 +25953,22 @@ static void script_run_item_rental_end_script(struct map_session_data *sd, struc script->current_item_id = 0; } +static void script_run_item_lapineddukddak_script(struct map_session_data *sd, struct item_data *data, int oid) __attribute__((nonnull (1, 2))); + +/** + * Run item lapineddukddak script for item. + * + * @param sd player session data. Must be correct and checked before. + * @param data unequipped item data. Must be correct and checked before. + * @param oid npc id. Can be also 0 or fake npc id. + */ +static void script_run_item_lapineddukddak_script(struct map_session_data *sd, struct item_data *data, int oid) +{ + script->current_item_id = data->nameid; + script->run(data->lapineddukddak->script, 0, sd->bl.id, oid); + script->current_item_id = 0; +} + #define BUILDIN_DEF(x,args) { buildin_ ## x , #x , args, false } #define BUILDIN_DEF2(x,x2,args) { buildin_ ## x , x2 , args, false } #define BUILDIN_DEF_DEPRECATED(x,args) { buildin_ ## x , #x , args, true } @@ -26549,6 +26584,7 @@ static void script_parse_builtin(void) BUILDIN_DEF(identify, "i"), BUILDIN_DEF(identifyidx, "i"), + BUILDIN_DEF(openlapineddukddakboxui, "i"), }; int i, len = ARRAYLENGTH(BUILDIN); RECREATE(script->buildin, char *, script->buildin_count + len); // Pre-alloc to speed up @@ -27489,4 +27525,5 @@ void script_defaults(void) script->run_item_unequip_script = script_run_item_unequip_script; script->run_item_rental_start_script = script_run_item_rental_start_script; script->run_item_rental_end_script = script_run_item_rental_end_script; + script->run_item_lapineddukddak_script = script_run_item_lapineddukddak_script; } diff --git a/src/map/script.h b/src/map/script.h index a75b948ab..57652e77a 100644 --- a/src/map/script.h +++ b/src/map/script.h @@ -1051,6 +1051,7 @@ struct script_interface { void (*run_item_unequip_script) (struct map_session_data *sd, struct item_data *data, int oid); void (*run_item_rental_end_script) (struct map_session_data *sd, struct item_data *data, int oid); void (*run_item_rental_start_script) (struct map_session_data *sd, struct item_data *data, int oid); + void (*run_item_lapineddukddak_script) (struct map_session_data *sd, struct item_data *data, int oid); }; #ifdef HERCULES_CORE |