diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/char/char.c | 17 | ||||
-rw-r--r-- | src/char/int_guild.c | 1 | ||||
-rw-r--r-- | src/char/int_homun.c | 1 | ||||
-rw-r--r-- | src/char/int_mail.c | 1 | ||||
-rw-r--r-- | src/char/inter.c | 2 | ||||
-rw-r--r-- | src/char/pincode.c | 3 | ||||
-rw-r--r-- | src/common/HPMDataCheck.h | 1 | ||||
-rw-r--r-- | src/login/account_sql.c | 12 | ||||
-rw-r--r-- | src/login/login.c | 11 | ||||
-rw-r--r-- | src/map/battle.c | 6 | ||||
-rw-r--r-- | src/map/clif.c | 215 | ||||
-rw-r--r-- | src/map/clif.h | 21 | ||||
-rw-r--r-- | src/map/itemdb.c | 64 | ||||
-rw-r--r-- | src/map/itemdb.h | 3 | ||||
-rw-r--r-- | src/map/packets.h | 2 | ||||
-rw-r--r-- | src/map/pc.c | 105 | ||||
-rw-r--r-- | src/map/pc.h | 2 | ||||
-rw-r--r-- | src/map/script.c | 31 | ||||
-rw-r--r-- | src/map/skill.c | 4 | ||||
-rw-r--r-- | src/map/status.c | 4 | ||||
-rw-r--r-- | src/map/storage.c | 4 | ||||
-rw-r--r-- | src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc | 24 | ||||
-rw-r--r-- | src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc | 6 | ||||
-rw-r--r-- | src/plugins/HPMHooking/HPMHooking_map.Hooks.inc | 159 | ||||
-rw-r--r-- | src/plugins/db2sql.c | 6 |
25 files changed, 584 insertions, 121 deletions
diff --git a/src/char/char.c b/src/char/char.c index 5e3c34684..5f5dad539 100644 --- a/src/char/char.c +++ b/src/char/char.c @@ -850,6 +850,7 @@ int char_inventory_to_sql(const struct item items[], int max, int id) { bool found; int errors = 0; + nullpo_ret(items); // The following code compares inventory with current database values // and performs modification/deletion/insertion only on relevant rows. @@ -1479,6 +1480,7 @@ bool char_char_slotchange(struct char_session_data *sd, int fd, unsigned short f struct mmo_charstatus char_dat; int from_id = 0; + nullpo_ret(sd); if( from >= MAX_CHARS || to >= MAX_CHARS || ( sd->char_slots && to > sd->char_slots ) || sd->found_char[from] <= 0 ) return false; @@ -1649,6 +1651,8 @@ int char_make_new_char_sql(struct char_session_data* sd, char* name_, int str, i char esc_name[NAME_LENGTH*2+1]; int char_id, flag, k, l; + nullpo_retr(-2, sd); + nullpo_retr(-2, name_); safestrncpy(name, name_, NAME_LENGTH); normalize_name(name,TRIM_CHARS); SQL->EscapeStringLen(inter->sql_handle, esc_name, name, strnlen(name, NAME_LENGTH)); @@ -4256,6 +4260,7 @@ static void char_delete2_req(int fd, struct char_session_data* sd) time_t delete_date; char_id = RFIFOL(fd,2); + nullpo_retv(sd); ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == char_id ); if( i == MAX_CHARS ) @@ -4327,6 +4332,7 @@ static void char_delete2_accept(int fd, struct char_session_data* sd) char* data; time_t delete_date; + nullpo_retv(sd); char_id = RFIFOL(fd,2); ShowInfo(CL_RED"Request Char Deletion: "CL_GREEN"%d (%d)"CL_RESET"\n", sd->account_id, char_id); @@ -4394,6 +4400,7 @@ static void char_delete2_cancel(int fd, struct char_session_data* sd) {// CH: <082b>.W <char id>.L int char_id, i; + nullpo_retv(sd); char_id = RFIFOL(fd,2); ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == char_id ); @@ -4542,6 +4549,7 @@ int char_search_default_maps_mapserver(struct mmo_charstatus *cd) return i; } +void char_parse_char_select(int fd, struct char_session_data* sd, uint32 ipl) __attribute__((nonnull (2))); void char_parse_char_select(int fd, struct char_session_data* sd, uint32 ipl) { struct mmo_charstatus char_dat; @@ -4706,6 +4714,7 @@ void char_creation_ok(int fd, struct mmo_charstatus *char_dat) WFIFOSET(fd,len); } +void char_parse_char_create_new_char(int fd, struct char_session_data* sd) __attribute__((nonnull (2))); void char_parse_char_create_new_char(int fd, struct char_session_data* sd) { int result; @@ -4756,6 +4765,7 @@ void char_delete_char_ok(int fd) WFIFOSET(fd,2); } +void char_parse_char_delete_char(int fd, struct char_session_data* sd, unsigned short cmd) __attribute__((nonnull (2))); void char_parse_char_delete_char(int fd, struct char_session_data* sd, unsigned short cmd) { char email[40]; @@ -4823,6 +4833,7 @@ void char_allow_rename(int fd, int flag) WFIFOSET(fd,4); } +void char_parse_char_rename_char(int fd, struct char_session_data* sd) __attribute__((nonnull (2))); void char_parse_char_rename_char(int fd, struct char_session_data* sd) { int i, cid =RFIFOL(fd,2); @@ -4847,6 +4858,7 @@ void char_parse_char_rename_char(int fd, struct char_session_data* sd) chr->allow_rename(fd, i); } +void char_parse_char_rename_char2(int fd, struct char_session_data* sd) __attribute__((nonnull (2))); void char_parse_char_rename_char2(int fd, struct char_session_data* sd) { int i, aid = RFIFOL(fd,2), cid =RFIFOL(fd,6); @@ -4882,6 +4894,7 @@ void char_rename_char_ack(int fd, int flag) WFIFOSET(fd,4); } +void char_parse_char_rename_char_confirm(int fd, struct char_session_data* sd) __attribute__((nonnull (2))); void char_parse_char_rename_char_confirm(int fd, struct char_session_data* sd) { int i; @@ -4977,6 +4990,7 @@ void char_parse_char_login_map_server(int fd) RFIFOSKIP(fd,60); } +void char_parse_char_pincode_check(int fd, struct char_session_data* sd) __attribute__((nonnull (2))); void char_parse_char_pincode_check(int fd, struct char_session_data* sd) { if (RFIFOL(fd,2) == sd->account_id) @@ -4985,6 +4999,7 @@ void char_parse_char_pincode_check(int fd, struct char_session_data* sd) RFIFOSKIP(fd, 10); } +void char_parse_char_pincode_window(int fd, struct char_session_data* sd) __attribute__((nonnull (2))); void char_parse_char_pincode_window(int fd, struct char_session_data* sd) { if (RFIFOL(fd,2) == sd->account_id) @@ -4993,6 +5008,7 @@ void char_parse_char_pincode_window(int fd, struct char_session_data* sd) RFIFOSKIP(fd, 6); } +void char_parse_char_pincode_change(int fd, struct char_session_data* sd) __attribute__((nonnull (2))); void char_parse_char_pincode_change(int fd, struct char_session_data* sd) { if (RFIFOL(fd,2) == sd->account_id) @@ -5001,6 +5017,7 @@ void char_parse_char_pincode_change(int fd, struct char_session_data* sd) RFIFOSKIP(fd, 14); } +void char_parse_char_pincode_first_pin(int fd, struct char_session_data* sd) __attribute__((nonnull (2))); void char_parse_char_pincode_first_pin(int fd, struct char_session_data* sd) { if (RFIFOL(fd,2) == sd->account_id) diff --git a/src/char/int_guild.c b/src/char/int_guild.c index 96a78203f..24561fe21 100644 --- a/src/char/int_guild.c +++ b/src/char/int_guild.c @@ -882,7 +882,6 @@ int inter_guild_calcinfo(struct guild *g) int mapif_guild_created(int fd, int account_id, struct guild *g) { - nullpo_ret(g); WFIFOHEAD(fd, 10); WFIFOW(fd,0)=0x3830; WFIFOL(fd,2)=account_id; diff --git a/src/char/int_homun.c b/src/char/int_homun.c index 2ec589eaf..eda2afe69 100644 --- a/src/char/int_homun.c +++ b/src/char/int_homun.c @@ -54,7 +54,6 @@ void mapif_homunculus_deleted(int fd, int flag) void mapif_homunculus_loaded(int fd, int account_id, struct s_homunculus *hd) { - nullpo_retv(hd); WFIFOHEAD(fd, sizeof(struct s_homunculus)+9); WFIFOW(fd,0) = 0x3891; WFIFOW(fd,2) = sizeof(struct s_homunculus)+9; diff --git a/src/char/int_mail.c b/src/char/int_mail.c index 0d46339e0..d4bfe14e4 100644 --- a/src/char/int_mail.c +++ b/src/char/int_mail.c @@ -459,7 +459,6 @@ void inter_mail_sendmail(int send_id, const char* send_name, int dest_id, const nullpo_retv(dest_name); nullpo_retv(title); nullpo_retv(body); - nullpo_retv(item); memset(&msg, 0, sizeof(struct mail_message)); msg.send_id = send_id; diff --git a/src/char/inter.c b/src/char/inter.c index ca041d581..dbb782093 100644 --- a/src/char/inter.c +++ b/src/char/inter.c @@ -503,7 +503,7 @@ void mapif_parse_accinfo2(bool success, int map_fd, int u_fd, int u_aid, int acc inter->msg_to_fd(map_fd, u_fd, u_aid, "-- Account %d --", account_id); inter->msg_to_fd(map_fd, u_fd, u_aid, "User: %s | GM Group: %d | State: %d", userid, group_id, state); - if (user_pass && *user_pass != '\0') { /* password is only received if your gm level is greater than the one you're searching for */ + if (*user_pass != '\0') { /* password is only received if your gm level is greater than the one you're searching for */ if (pin_code && *pin_code != '\0') inter->msg_to_fd(map_fd, u_fd, u_aid, "Password: %s (PIN:%s)", user_pass, pin_code); else diff --git a/src/char/pincode.c b/src/char/pincode.c index 43958af8a..5085349cc 100644 --- a/src/char/pincode.c +++ b/src/char/pincode.c @@ -21,9 +21,10 @@ struct pincode_interface pincode_s; void pincode_handle (int fd, struct char_session_data* sd) { - struct online_char_data* character = (struct online_char_data*)idb_get(chr->online_char_db, sd->account_id); + struct online_char_data* character; nullpo_retv(sd); + character = (struct online_char_data*)idb_get(chr->online_char_db, sd->account_id); if( character && character->pincode_enable > pincode->charselect ){ character->pincode_enable = pincode->charselect * 2; }else{ diff --git a/src/common/HPMDataCheck.h b/src/common/HPMDataCheck.h index 43dc9ee5c..be798ceb5 100644 --- a/src/common/HPMDataCheck.h +++ b/src/common/HPMDataCheck.h @@ -301,6 +301,7 @@ HPExport const struct s_HPMDataCheck HPMDataCheck[] = { { "cdelayed_damage", sizeof(struct cdelayed_damage), SERVER_TYPE_MAP }, { "clif_interface", sizeof(struct clif_interface), SERVER_TYPE_MAP }, { "hCSData", sizeof(struct hCSData), SERVER_TYPE_MAP }, + { "merge_item", sizeof(struct merge_item), SERVER_TYPE_MAP }, { "s_packet_db", sizeof(struct s_packet_db), SERVER_TYPE_MAP }, #else #define MAP_CLIF_H diff --git a/src/login/account_sql.c b/src/login/account_sql.c index 3f72e6867..37837fc35 100644 --- a/src/login/account_sql.c +++ b/src/login/account_sql.c @@ -363,12 +363,13 @@ static bool account_db_sql_set_property(AccountDB* self, const char* key, const static bool account_db_sql_create(AccountDB* self, struct mmo_account* acc) { AccountDB_SQL* db = (AccountDB_SQL*)self; - Sql* sql_handle = db->accounts; + Sql* sql_handle; // decide on the account id to assign int account_id; nullpo_ret(db); nullpo_ret(acc); + sql_handle = db->accounts; if( acc->account_id != -1 ) {// caller specifies it manually account_id = acc->account_id; @@ -416,10 +417,11 @@ static bool account_db_sql_create(AccountDB* self, struct mmo_account* acc) static bool account_db_sql_remove(AccountDB* self, const int account_id) { AccountDB_SQL* db = (AccountDB_SQL*)self; - Sql* sql_handle = db->accounts; + Sql* sql_handle; bool result = false; nullpo_ret(db); + sql_handle = db->accounts; if( SQL_SUCCESS != SQL->QueryStr(sql_handle, "START TRANSACTION") || SQL_SUCCESS != SQL->Query(sql_handle, "DELETE FROM `%s` WHERE `account_id` = %d", db->account_db, account_id) || SQL_SUCCESS != SQL->Query(sql_handle, "DELETE FROM `%s` WHERE `account_id` = %d", db->global_acc_reg_num_db, account_id) @@ -607,6 +609,7 @@ static bool mmo_auth_tosql(AccountDB_SQL* db, const struct mmo_account* acc, boo bool result = false; nullpo_ret(db); + nullpo_ret(acc); sql_handle = db->accounts; stmt = SQL->StmtMalloc(sql_handle); @@ -687,11 +690,12 @@ Sql* account_db_sql_up(AccountDB* self) { return db ? db->accounts : NULL; } void mmo_save_accreg2(AccountDB* self, int fd, int account_id, int char_id) { - Sql* sql_handle = ((AccountDB_SQL*)self)->accounts; + Sql* sql_handle; AccountDB_SQL* db = (AccountDB_SQL*)self; int count = RFIFOW(fd, 12); nullpo_retv(db); + sql_handle = db->accounts; if (count) { int cursor = 14, i; char key[32], sval[254]; @@ -742,7 +746,7 @@ void mmo_send_accreg2(AccountDB* self, int fd, int account_id, int char_id) { size_t len; nullpo_retv(db); - sql_handle = ((AccountDB_SQL*)self)->accounts; + sql_handle = db->accounts; if( SQL_ERROR == SQL->Query(sql_handle, "SELECT `key`, `index`, `value` FROM `%s` WHERE `account_id`='%d'", db->global_acc_reg_str_db, account_id) ) Sql_ShowDebug(sql_handle); diff --git a/src/login/login.c b/src/login/login.c index 1fdf2d198..bb8ba51b3 100644 --- a/src/login/login.c +++ b/src/login/login.c @@ -1230,15 +1230,15 @@ void login_kick(struct login_session_data* sd) void login_auth_ok(struct login_session_data* sd) { - int fd = sd->fd; + int fd = 0; uint32 ip; - uint8 server_num, n; uint32 subnet_char_ip; struct login_auth_node* node; int i; nullpo_retv(sd); + fd = sd->fd; ip = session[fd]->client_addr; if( runflag != LOGINSERVER_ST_RUNNING ) { @@ -1431,11 +1431,13 @@ void login_login_error(int fd, uint8 status) WFIFOSET(fd,23); } +void login_parse_ping(int fd, struct login_session_data* sd) __attribute__((nonnull (2))); void login_parse_ping(int fd, struct login_session_data* sd) { RFIFOSKIP(fd,26); } +void login_parse_client_md5(int fd, struct login_session_data* sd) __attribute__((nonnull (2))); void login_parse_client_md5(int fd, struct login_session_data* sd) { sd->has_client_hash = 1; @@ -1444,6 +1446,7 @@ void login_parse_client_md5(int fd, struct login_session_data* sd) RFIFOSKIP(fd,18); } +bool login_parse_client_login(int fd, struct login_session_data* sd, const char *const ip) __attribute__((nonnull (2))); bool login_parse_client_login(int fd, struct login_session_data* sd, const char *const ip) { uint32 version; @@ -1523,6 +1526,7 @@ bool login_parse_client_login(int fd, struct login_session_data* sd, const char return false; } +void login_send_coding_key(int fd, struct login_session_data* sd) __attribute__((nonnull (2))); void login_send_coding_key(int fd, struct login_session_data* sd) { WFIFOHEAD(fd,4 + sd->md5keylen); @@ -1532,6 +1536,7 @@ void login_send_coding_key(int fd, struct login_session_data* sd) WFIFOSET(fd,WFIFOW(fd,2)); } +void login_parse_request_coding_key(int fd, struct login_session_data* sd) __attribute__((nonnull (2))); void login_parse_request_coding_key(int fd, struct login_session_data* sd) { memset(sd->md5key, '\0', sizeof(sd->md5key)); @@ -1541,6 +1546,7 @@ void login_parse_request_coding_key(int fd, struct login_session_data* sd) login->send_coding_key(fd, sd); } +void login_char_server_connection_status(int fd, struct login_session_data* sd, uint8 status) __attribute__((nonnull (2))); void login_char_server_connection_status(int fd, struct login_session_data* sd, uint8 status) { WFIFOHEAD(fd,3); @@ -1549,6 +1555,7 @@ void login_char_server_connection_status(int fd, struct login_session_data* sd, WFIFOSET(fd,3); } +void login_parse_request_connection(int fd, struct login_session_data* sd, const char *const ip) __attribute__((nonnull (2, 3))); void login_parse_request_connection(int fd, struct login_session_data* sd, const char *const ip) { char server_name[20]; diff --git a/src/map/battle.c b/src/map/battle.c index 8a834574b..3575dea6f 100644 --- a/src/map/battle.c +++ b/src/map/battle.c @@ -3627,7 +3627,7 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list } } #ifndef HMAP_ZONE_DAMAGE_CAP_TYPE - if( target && skill_id ) { + if (skill_id) { for(i = 0; i < map->list[target->m].zone->capped_skills_count; i++) { if( skill_id == map->list[target->m].zone->capped_skills[i]->nameid && (map->list[target->m].zone->capped_skills[i]->type & target->type) ) { if( target->type == BL_MOB && map->list[target->m].zone->capped_skills[i]->subtype != MZS_NONE ) { @@ -4101,7 +4101,7 @@ struct Damage battle_calc_misc_attack(struct block_list *src,struct block_list * } } #ifndef HMAP_ZONE_DAMAGE_CAP_TYPE - if( target && skill_id ) { + if (skill_id) { for(i = 0; i < map->list[target->m].zone->capped_skills_count; i++) { if( skill_id == map->list[target->m].zone->capped_skills[i]->nameid && (map->list[target->m].zone->capped_skills[i]->type & target->type) ) { if( target->type == BL_MOB && map->list[target->m].zone->capped_skills[i]->subtype != MZS_NONE ) { @@ -5314,7 +5314,7 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list if(skill_id == CR_GRANDCROSS || skill_id == NPC_GRANDDARKNESS) return wd; //Enough, rest is not needed. #ifndef HMAP_ZONE_DAMAGE_CAP_TYPE - if( target && skill_id ) { + if (skill_id) { for(i = 0; i < map->list[target->m].zone->capped_skills_count; i++) { if( skill_id == map->list[target->m].zone->capped_skills[i]->nameid && (map->list[target->m].zone->capped_skills[i]->type & target->type) ) { if( target->type == BL_MOB && map->list[target->m].zone->capped_skills[i]->subtype != MZS_NONE ) { diff --git a/src/map/clif.c b/src/map/clif.c index d9b20e570..cc517c24f 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -5715,54 +5715,30 @@ void clif_solved_charname(int fd, int charid, const char* name) /// 017b <packet len>.W { <name id>.W }* void clif_use_card(struct map_session_data *sd,int idx) { - int i,c,ep; - int fd=sd->fd; + int i, c; + int fd; nullpo_retv(sd); - if (idx < 0 || idx >= MAX_INVENTORY) //Crash-fix from bad packets. + fd = sd->fd; + if (sd->state.trading != 0) + return; + if (!pc->can_insert_card(sd, idx)) return; - if (!sd->inventory_data[idx] || sd->inventory_data[idx]->type != IT_CARD) - return; //Avoid parsing invalid item indexes (no card/no item) - - ep=sd->inventory_data[idx]->equip; - WFIFOHEAD(fd,MAX_INVENTORY * 2 + 4); - WFIFOW(fd,0)=0x17b; - - for(i=c=0;i<MAX_INVENTORY;i++){ - int j; - - if(sd->inventory_data[i] == NULL) - continue; - if(sd->inventory_data[i]->type!=IT_WEAPON && sd->inventory_data[i]->type!=IT_ARMOR) - continue; - if(itemdb_isspecial(sd->status.inventory[i].card[0])) //Can't slot it - continue; - - if (sd->status.inventory[i].identify == 0) //Not identified - continue; - - if ((sd->inventory_data[i]->equip&ep) == 0) //Not equippable on this part. - continue; - - if(sd->inventory_data[i]->type==IT_WEAPON && ep==EQP_SHIELD) //Shield card won't go on left weapon. - continue; - - ARR_FIND( 0, sd->inventory_data[i]->slot, j, sd->status.inventory[i].card[j] == 0 ); - if (j == sd->inventory_data[i]->slot) // No room - continue; + WFIFOHEAD(fd, MAX_INVENTORY * 2 + 4); + WFIFOW(fd, 0) = 0x17b; - if( sd->status.inventory[i].equip > 0 ) // Do not check items that are already equipped + for (i = c = 0; i < MAX_INVENTORY; i++) { + if (!pc->can_insert_card_into(sd, idx, i)) continue; - - WFIFOW(fd,4+c*2)=i+2; + WFIFOW(fd, 4 + c * 2) = i + 2; c++; } - if( !c ) return; // no item is available for card insertion + if (!c) return; // no item is available for card insertion - WFIFOW(fd,2)=4+c*2; - WFIFOSET(fd,WFIFOW(fd,2)); + WFIFOW(fd, 2) = 4 + c * 2; + WFIFOSET(fd, WFIFOW(fd, 2)); } @@ -11394,8 +11370,6 @@ void clif_parse_AutoSpell(int fd,struct map_session_data *sd) /// 017a <card index>.W void clif_parse_UseCard(int fd,struct map_session_data *sd) { - if (sd->state.trading != 0) - return; clif->use_card(sd,RFIFOW(fd,2)-2); } @@ -11404,8 +11378,6 @@ void clif_parse_UseCard(int fd,struct map_session_data *sd) /// 017c <card index>.W <equip index>.W void clif_parse_InsertCard(int fd,struct map_session_data *sd) { - if (sd->state.trading != 0) - return; pc->insert_card(sd,RFIFOW(fd,2)-2,RFIFOW(fd,4)-2); } @@ -12746,7 +12718,7 @@ bool clif_sub_guild_invite(int fd, struct map_session_data *sd, struct map_sessi return false; } - if ( t_sd && t_sd->state.noask ) {// @noask [LuzZza] + if (t_sd->state.noask) {// @noask [LuzZza] clif->noask_sub(sd, t_sd, 2); return false; } @@ -18123,6 +18095,157 @@ void clif_roulette_generate_ack(struct map_session_data *sd, unsigned char resul clif->send(&p,sizeof(p), &sd->bl, SELF); } +/** +* Stackable items merger +**/ +void clif_openmergeitem(int fd, struct map_session_data *sd) +{ + int i = 0, n = 0, j = 0; + struct merge_item merge_items[MAX_INVENTORY]; + struct merge_item *merge_items_[MAX_INVENTORY] = {0}; + + memset(&merge_items,'\0',sizeof(merge_items)); + + for (i = 0; i < MAX_INVENTORY; i++) { + struct item *item_data = &sd->status.inventory[i]; + + if (item_data->nameid == 0 || !itemdb->isstackable(item_data->nameid)) + continue; + + merge_items[n].nameid = item_data->nameid; + merge_items[n].position = i + 2; + n++; + + + } + + qsort(merge_items,n,sizeof(struct merge_item),clif->comparemergeitem); + + for (i = 0, j = 0; i < n; i++) { + if (i > 0 && merge_items[i].nameid == merge_items[i-1].nameid) + { + merge_items_[j] = &merge_items[i]; + j++; + continue; + } + + if (i < n - 1 && merge_items[i].nameid == merge_items[i+1].nameid) + { + merge_items_[j] = &merge_items[i]; + j++; + continue; + } + } + + WFIFOHEAD(fd,2*j+4); + WFIFOW(fd,0) = 0x96d; + WFIFOW(fd,2) = 2*j+4; + for ( i = 0; i < j; i++ ) + WFIFOW(fd,i*2+4) = merge_items_[i]->position; + WFIFOSET(fd,2*j+4); +} + +int clif_comparemergeitem(const void *a, const void *b) +{ + const struct merge_item *a_ = a; + const struct merge_item *b_ = b; + + if (a_->nameid == b_->nameid) + return 0; + return a_->nameid > b_->nameid ? -1 : 1; +} + +void clif_ackmergeitems(int fd, struct map_session_data *sd) +{ + int i = 0, n = 0, length = 0, count = 0; + int16 nameid = 0, indexes[MAX_INVENTORY] = {0}, amounts[MAX_INVENTORY] = {0}; + struct item item_data; + + length = (RFIFOW(fd,2) - 4)/2; + + if (length >= MAX_INVENTORY || length < 2) { + WFIFOHEAD(fd,7); + WFIFOW(fd,0) = 0x96f; + WFIFOW(fd,2) = 0; + WFIFOW(fd,4) = 0; + WFIFOB(fd,6) = MERGEITEM_FAILD; + WFIFOSET(fd,7); + return; + } + + for (i = 0, n = 0; i < length; i++) { + int16 idx = RFIFOW(fd,i*2+4) - 2; + struct item *it = NULL; + + if (idx < 0 || idx >= MAX_INVENTORY) + continue; + + it = &sd->status.inventory[idx]; + + if (it->nameid == 0 || !itemdb->isstackable(it->nameid)) + continue; + + if (nameid == 0) + nameid = it->nameid; + + if (nameid != it->nameid) + continue; + + count += it->amount; + indexes[n] = idx; + amounts[n] = it->amount; + n++; + } + + + if (n < 2 || count == 0) { + WFIFOHEAD(fd,7); + WFIFOW(fd,0) = 0x96f; + WFIFOW(fd,2) = 0; + WFIFOW(fd,4) = 0; + WFIFOB(fd,6) = MERGEITEM_FAILD; + WFIFOSET(fd,7); + return; + } + + if (count > MAX_AMOUNT) { + WFIFOHEAD(fd,7); + WFIFOW(fd,0) = 0x96f; + WFIFOW(fd,2) = 0; + WFIFOW(fd,4) = 0; + WFIFOB(fd,6) = MERGEITEM_MAXCOUNTFAILD; + WFIFOSET(fd,7); + return; + } + + for (i = 0; i < n; i++) + pc->delitem(sd,indexes[i],amounts[i],0,DELITEM_NORMAL,LOG_TYPE_NPC); + + + memset(&item_data,'\0',sizeof(item_data)); + + item_data.nameid = nameid; + item_data.identify = 1; + item_data.unique_id = itemdb->unique_id(sd); + pc->additem(sd,&item_data,count,LOG_TYPE_NPC); + + ARR_FIND(0,MAX_INVENTORY,i,item_data.unique_id == sd->status.inventory[i].unique_id); + + WFIFOHEAD(fd,7); + WFIFOW(fd,0) = 0x96f; + WFIFOW(fd,2) = i+2; + WFIFOW(fd,4) = count; + WFIFOB(fd,6) = MERGEITEM_SUCCESS; + WFIFOSET(fd,7); + +} + +void clif_cancelmergeitem (int fd, struct map_session_data *sd) +{ + //Track The merge item cancelation ? + return; +} + /* */ unsigned short clif_decrypt_cmd( int cmd, struct map_session_data *sd ) { if( sd ) { @@ -18912,6 +19035,12 @@ void clif_defaults(void) { /* */ clif->parse_roulette_db = clif_parse_roulette_db; clif->roulette_generate_ack = clif_roulette_generate_ack; + /* Merge Items */ + clif->openmergeitem = clif_openmergeitem; + clif->cancelmergeitem = clif_cancelmergeitem; + clif->comparemergeitem = clif_comparemergeitem; + clif->ackmergeitems = clif_ackmergeitems; + /*------------------------ *- Parse Incoming Packet *------------------------*/ diff --git a/src/map/clif.h b/src/map/clif.h index 66dd13304..c827406ca 100644 --- a/src/map/clif.h +++ b/src/map/clif.h @@ -522,6 +522,16 @@ enum delitem_reason { DELITEM_ANALYSIS = 7, /// Consumed by Four Spirit Analysis (SO_EL_ANALYSIS) skill }; +/* +* Merge items reasons +*/ + +enum mergeitem_reason { + MERGEITEM_SUCCESS = 0x0, + MERGEITEM_FAILD = 0x1, + MERGEITEM_MAXCOUNTFAILD = 0x2, +}; + /** * Structures **/ @@ -542,6 +552,11 @@ struct cdelayed_damage { struct block_list bl; }; +struct merge_item { + int16 position; + int16 nameid; +}; + /** * Vars **/ @@ -1062,6 +1077,12 @@ struct clif_interface { /* */ bool (*parse_roulette_db) (void); void (*roulette_generate_ack) (struct map_session_data *sd, unsigned char result, short stage, short prizeIdx, short bonusItemID); + /* Merge Items */ + void (*openmergeitem) (int fd, struct map_session_data *sd); + void (*cancelmergeitem) (int fd, struct map_session_data *sd); + int (*comparemergeitem) (const void *a, const void *b); + void (*ackmergeitems) (int fd, struct map_session_data *sd); + /*------------------------ *- Parse Incoming Packet *------------------------*/ diff --git a/src/map/itemdb.c b/src/map/itemdb.c index b02da1e0d..4ebe282a2 100644 --- a/src/map/itemdb.c +++ b/src/map/itemdb.c @@ -199,6 +199,9 @@ void itemdb_package_item(struct map_session_data *sd, struct item_package *packa if( package->must_items[i].announce ) clif->package_announce(sd,package->must_items[i].id,package->id); + if ( package->must_items[i].force_serial ) + it.unique_id = itemdb->unique_id(sd); + get_count = itemdb->isstackable(package->must_items[i].id) ? package->must_items[i].qty : 1; it.amount = get_count == 1 ? 1 : get_count; @@ -719,7 +722,7 @@ void itemdb_write_cached_packages(const char *config_filename) { //now we loop into must for(c = 0; c < must_qty; c++) { struct item_package_must_entry *entry = &itemdb->packages[i].must_items[c]; - unsigned char announce = entry->announce == 1 ? 1 : 0, named = entry->named == 1 ? 1 : 0; + unsigned char announce = entry->announce == 1 ? 1 : 0, named = entry->named == 1 ? 1 : 0, force_serial = entry->force_serial == 1 ? 1 : 0; //first 2 byte = item id hwrite(&entry->id,sizeof(entry->id),1,file); //next 2 byte = qty @@ -729,7 +732,9 @@ void itemdb_write_cached_packages(const char *config_filename) { //next 1 byte = announce (1:0) hwrite(&announce,sizeof(announce),1,file); //next 1 byte = named (1:0) - hwrite(&named,sizeof(announce),1,file); + hwrite(&named,sizeof(named),1,file); + //next 1 byte = ForceSerial (1:0) + hwrite(&force_serial,sizeof(force_serial),1,file); } //now we loop into random groups for(c = 0; c < random_qty; c++) { @@ -741,7 +746,7 @@ void itemdb_write_cached_packages(const char *config_filename) { //now we loop into the group's list for(h = 0; h < group_qty; h++) { struct item_package_rand_entry *entry = &itemdb->packages[i].random_groups[c].random_list[h]; - unsigned char announce = entry->announce == 1 ? 1 : 0, named = entry->named == 1 ? 1 : 0; + unsigned char announce = entry->announce == 1 ? 1 : 0, named = entry->named == 1 ? 1 : 0, force_serial = entry->force_serial == 1 ? 1 : 0; //first 2 byte = item id hwrite(&entry->id,sizeof(entry->id),1,file); //next 2 byte = qty @@ -753,7 +758,9 @@ void itemdb_write_cached_packages(const char *config_filename) { //next 1 byte = announce (1:0) hwrite(&announce,sizeof(announce),1,file); //next 1 byte = named (1:0) - hwrite(&named,sizeof(announce),1,file); + hwrite(&named,sizeof(named),1,file); + //next 1 byte = ForceSerial (1:0) + hwrite(&force_serial,sizeof(force_serial),1,file); } } } @@ -807,7 +814,7 @@ bool itemdb_read_cached_packages(const char *config_filename) { for(c = 0; c < package->must_qty; c++) { struct item_package_must_entry *entry = &itemdb->packages[i].must_items[c]; unsigned short mid = 0, qty = 0, hours = 0; - unsigned char announce = 0, named = 0; + unsigned char announce = 0, named = 0, force_serial = 0; struct item_data *data; //first 2 byte = item id hread(&mid,sizeof(mid),1,file); @@ -818,8 +825,10 @@ bool itemdb_read_cached_packages(const char *config_filename) { //next 1 byte = announce (1:0) hread(&announce,sizeof(announce),1,file); //next 1 byte = named (1:0) - hread(&named,sizeof(announce),1,file); - + hread(&named,sizeof(named),1,file); + //next 1 byte = ForceSerial (1:0) + hread(&force_serial,sizeof(force_serial),1,file); + if( !(data = itemdb->exists(mid)) ) ShowWarning("itemdb_read_cached_packages: unknown item '%d' in package '%s'!\n",mid,itemdb_name(package->id)); @@ -828,6 +837,7 @@ bool itemdb_read_cached_packages(const char *config_filename) { entry->qty = qty; entry->announce = announce ? 1 : 0; entry->named = named ? 1 : 0; + entry->force_serial = force_serial ? 1 : 0; } } if( package->random_qty ) { @@ -847,7 +857,7 @@ bool itemdb_read_cached_packages(const char *config_filename) { for(h = 0; h < group_qty; h++) { struct item_package_rand_entry *entry = &itemdb->packages[i].random_groups[c].random_list[h]; unsigned short mid = 0, qty = 0, hours = 0, rate = 0; - unsigned char announce = 0, named = 0; + unsigned char announce = 0, named = 0, force_serial = 0; struct item_data *data; if( prev ) prev->next = entry; @@ -863,8 +873,10 @@ bool itemdb_read_cached_packages(const char *config_filename) { //next 1 byte = announce (1:0) hread(&announce,sizeof(announce),1,file); //next 1 byte = named (1:0) - hread(&named,sizeof(announce),1,file); - + hread(&named,sizeof(named),1,file); + //next 1 byte = ForceSerial (1:0) + hread(&force_serial,sizeof(force_serial),1,file); + if( !(data = itemdb->exists(mid)) ) ShowWarning("itemdb_read_cached_packages: unknown item '%d' in package '%s'!\n",mid,itemdb_name(package->id)); @@ -874,7 +886,7 @@ bool itemdb_read_cached_packages(const char *config_filename) { entry->qty = qty; entry->announce = announce ? 1 : 0; entry->named = named ? 1 : 0; - + entry->force_serial = force_serial ? 1 : 0; prev = entry; } if( prev ) @@ -1020,7 +1032,7 @@ void itemdb_read_packages(void) { c = 0; while( (it = libconfig->setting_get_elem(itg,c++)) ) { int icount = 1, expire = 0, rate = 10000, gid = 0; - bool announce = false, named = false; + bool announce = false, named = false, force_serial = false; itname = config_setting_name(it); @@ -1049,6 +1061,9 @@ void itemdb_read_packages(void) { if( ( t = libconfig->setting_get_member(it, "Named")) && libconfig->setting_get_bool(t) ) named = true; + if( ( t = libconfig->setting_get_member(it, "ForceSerial")) && libconfig->setting_get_bool(t) ) + force_serial = true; + if( !( t = libconfig->setting_get_member(it, "Random") ) ) { ShowWarning("itemdb_read_packages: missing 'Random' field for item '%s' in package '%s', defaulting to must!\n",itname,config_setting_name(itg)); gid = 0; @@ -1061,6 +1076,7 @@ void itemdb_read_packages(void) { itemdb->packages[count].must_items[m].hours = expire; itemdb->packages[count].must_items[m].announce = announce == true ? 1 : 0; itemdb->packages[count].must_items[m].named = named == true ? 1 : 0; + itemdb->packages[count].must_items[m].force_serial = force_serial == true ? 1 : 0; m++; } else { int gidx = gid - 1; @@ -1078,6 +1094,7 @@ void itemdb_read_packages(void) { itemdb->packages[count].random_groups[gidx].random_list[r].hours = expire; itemdb->packages[count].random_groups[gidx].random_list[r].announce = announce == true ? 1 : 0; itemdb->packages[count].random_groups[gidx].random_list[r].named = named == true ? 1 : 0; + itemdb->packages[count].random_groups[gidx].random_list[r].force_serial = force_serial == true ? 1 : 0; itemdb->packages[count].random_groups[gidx].random_qty += 1; prev[gidx] = &itemdb->packages[count].random_groups[gidx].random_list[r]; @@ -1583,14 +1600,15 @@ int itemdb_readdb_sql_sub(Sql *handle, int n, const char *source) { SQL->GetData(handle, 19, &data, NULL); id.flag.no_refine = data && atoi(data) ? 0 : 1; SQL->GetData(handle, 20, &data, NULL); id.look = data ? atoi(data) : 0; SQL->GetData(handle, 21, &data, NULL); id.flag.bindonequip = data && atoi(data) ? 1 : 0; - SQL->GetData(handle, 22, &data, NULL); id.flag.buyingstore = data && atoi(data) ? 1 : 0; - SQL->GetData(handle, 23, &data, NULL); id.delay = data ? atoi(data) : 0; - SQL->GetData(handle, 24, &data, NULL); id.flag.trade_restriction = data ? atoi(data) : ITR_NONE; - SQL->GetData(handle, 25, &data, NULL); id.gm_lv_trade_override = data ? atoi(data) : 0; - SQL->GetData(handle, 26, &data, NULL); id.item_usage.flag = data ? atoi(data) : INR_NONE; - SQL->GetData(handle, 27, &data, NULL); id.item_usage.override = data ? atoi(data) : 0; - SQL->GetData(handle, 28, &data, NULL); id.stack.amount = data ? atoi(data) : 0; - SQL->GetData(handle, 29, &data, NULL); + SQL->GetData(handle, 22, &data, NULL); id.flag.force_serial = data && atoi(data) ? 1 : 0; + SQL->GetData(handle, 23, &data, NULL); id.flag.buyingstore = data && atoi(data) ? 1 : 0; + SQL->GetData(handle, 24, &data, NULL); id.delay = data ? atoi(data) : 0; + SQL->GetData(handle, 25, &data, NULL); id.flag.trade_restriction = data ? atoi(data) : ITR_NONE; + SQL->GetData(handle, 26, &data, NULL); id.gm_lv_trade_override = data ? atoi(data) : 0; + SQL->GetData(handle, 27, &data, NULL); id.item_usage.flag = data ? atoi(data) : INR_NONE; + SQL->GetData(handle, 28, &data, NULL); id.item_usage.override = data ? atoi(data) : 0; + SQL->GetData(handle, 29, &data, NULL); id.stack.amount = data ? atoi(data) : 0; + SQL->GetData(handle, 30, &data, NULL); if (data) { int stack_flag = atoi(data); id.stack.inventory = (stack_flag&1)!=0; @@ -1657,6 +1675,7 @@ int itemdb_readdb_libconfig_sub(config_setting_t *it, int n, const char *source) * BindOnEquip: (true or false) * BuyingStore: (true or false) * Delay: Delay to use item + * ForceSerial: (true or false) * Trade: { * override: Group to override * nodrop: (true or false) @@ -1790,6 +1809,9 @@ int itemdb_readdb_libconfig_sub(config_setting_t *it, int n, const char *source) if( (t = libconfig->setting_get_member(it, "BindOnEquip")) ) id.flag.bindonequip = libconfig->setting_get_bool(t) ? 1 : 0; + + if( (t = libconfig->setting_get_member(it, "ForceSerial")) ) + id.flag.force_serial = libconfig->setting_get_bool(t) ? 1 : 0; if ( (t = libconfig->setting_get_member(it, "BuyingStore")) ) id.flag.buyingstore = libconfig->setting_get_bool(t) ? 1 : 0; @@ -1992,7 +2014,7 @@ int itemdb_readdb_sql(const char *tablename) { " `matk`, `defence`, `range`, `slots`," " `equip_jobs`, `equip_upper`, `equip_genders`, `equip_locations`," " `weapon_level`, `equip_level_min`, `equip_level_max`, `refineable`," - " `view`, `bindonequip`, `buyingstore`, `delay`," + " `view`, `bindonequip`, `forceserial`, `buyingstore`, `delay`," " `trade_flag`, `trade_group`, `nouse_flag`, `nouse_group`," " `stack_amount`, `stack_flag`, `sprite`, `script`," " `equip_script`, `unequip_script`" diff --git a/src/map/itemdb.h b/src/map/itemdb.h index 624080c3a..e50ebfd3d 100644 --- a/src/map/itemdb.h +++ b/src/map/itemdb.h @@ -398,6 +398,7 @@ struct item_package_rand_entry { unsigned short hours; unsigned int announce : 1; unsigned int named : 1; + unsigned int force_serial: 1; struct item_package_rand_entry *next; }; @@ -407,6 +408,7 @@ struct item_package_must_entry { unsigned short hours; unsigned int announce : 1; unsigned int named : 1; + unsigned int force_serial : 1; }; struct item_package_rand_group { @@ -466,6 +468,7 @@ struct item_data { unsigned buyingstore : 1; unsigned bindonequip : 1; unsigned keepafteruse : 1; + unsigned force_serial : 1; } flag; struct {// item stacking limitation unsigned short amount; diff --git a/src/map/packets.h b/src/map/packets.h index 53278f66e..6623c091c 100644 --- a/src/map/packets.h +++ b/src/map/packets.h @@ -448,6 +448,8 @@ packet(0x020a,10); //packet(0x020b,-1); //packet(0x020c,-1); packet(0x020d,-1); +packet(0x974,2,clif->cancelmergeitem); +packet(0x96e,-1,clif->ackmergeitems); //2004-07-05aSakexe #if PACKETVER >= 20040705 diff --git a/src/map/pc.c b/src/map/pc.c index 9e9f993d0..b9ef479dc 100644 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -4059,42 +4059,78 @@ int pc_skill(TBL_PC* sd, int id, int level, int flag) } return 1; } + +/** + * Checks if the given card can be inserted into the given equipment piece. + * + * @param sd The current character. + * @param idx_card The card's inventory index (note: it must be a valid index and can be checked by pc_can_insert_card) + * @param idx_equip The target equipment's inventory index. + * @retval true if the card can be inserted. + */ +bool pc_can_insert_card_into(struct map_session_data* sd, int idx_card, int idx_equip) +{ + int i; + + nullpo_ret(sd); + + if (idx_equip < 0 || idx_equip >= MAX_INVENTORY || sd->inventory_data[idx_equip] == NULL) + return false; //Invalid item index. + if (sd->status.inventory[idx_equip].nameid <= 0 || sd->status.inventory[idx_equip].amount < 1) + return false; // target item missing + if (sd->inventory_data[idx_equip]->type != IT_WEAPON && sd->inventory_data[idx_equip]->type != IT_ARMOR) + return false; // only weapons and armor are allowed + if (sd->status.inventory[idx_equip].identify == 0) + return false; // target must be identified + if (itemdb_isspecial(sd->status.inventory[idx_equip].card[0])) + return false; // card slots reserved for other purposes + if (sd->status.inventory[idx_equip].equip != 0) + return false; // item must be unequipped + if ((sd->inventory_data[idx_equip]->equip & sd->inventory_data[idx_card]->equip) == 0) + return false; // card cannot be compounded on this item type + if (sd->inventory_data[idx_equip]->type == IT_WEAPON && sd->inventory_data[idx_card]->equip == EQP_SHIELD) + return false; // attempted to place shield card on left-hand weapon. + + ARR_FIND( 0, sd->inventory_data[idx_equip]->slot, i, sd->status.inventory[idx_equip].card[i] == 0); + if (i == sd->inventory_data[idx_equip]->slot) + return false; // no free slots + return true; +} + +/** + * Checks if the given item is card and it can be inserted into some equipment. + * + * @param sd The current character. + * @param idx_card The card's inventory index. + * @retval true if the card can be inserted. + */ +bool pc_can_insert_card(struct map_session_data* sd, int idx_card) +{ + nullpo_ret(sd); + + if (idx_card < 0 || idx_card >= MAX_INVENTORY || sd->inventory_data[idx_card] == NULL) + return false; //Invalid card index. + if (sd->status.inventory[idx_card].nameid <= 0 || sd->status.inventory[idx_card].amount < 1) + return false; // target card missing + if (sd->inventory_data[idx_card]->type != IT_CARD) + return false; // must be a card + return true; +} + /*========================================== * Append a card to an item ? *------------------------------------------*/ int pc_insert_card(struct map_session_data* sd, int idx_card, int idx_equip) { - int i; int nameid; nullpo_ret(sd); - if( idx_equip < 0 || idx_equip >= MAX_INVENTORY || sd->inventory_data[idx_equip] == NULL ) - return 0; //Invalid item index. - if( idx_card < 0 || idx_card >= MAX_INVENTORY || sd->inventory_data[idx_card] == NULL ) - return 0; //Invalid card index. - if( sd->status.inventory[idx_equip].nameid <= 0 || sd->status.inventory[idx_equip].amount < 1 ) - return 0; // target item missing - if( sd->status.inventory[idx_card].nameid <= 0 || sd->status.inventory[idx_card].amount < 1 ) - return 0; // target card missing - if( sd->inventory_data[idx_equip]->type != IT_WEAPON && sd->inventory_data[idx_equip]->type != IT_ARMOR ) - return 0; // only weapons and armor are allowed - if( sd->inventory_data[idx_card]->type != IT_CARD ) - return 0; // must be a card - if( sd->status.inventory[idx_equip].identify == 0 ) - return 0; // target must be identified - if( itemdb_isspecial(sd->status.inventory[idx_equip].card[0]) ) - return 0; // card slots reserved for other purposes - if( (sd->inventory_data[idx_equip]->equip & sd->inventory_data[idx_card]->equip) == 0 ) - return 0; // card cannot be compounded on this item type - if( sd->inventory_data[idx_equip]->type == IT_WEAPON && sd->inventory_data[idx_card]->equip == EQP_SHIELD ) - return 0; // attempted to place shield card on left-hand weapon. - if( sd->status.inventory[idx_equip].equip != 0 ) - return 0; // item must be unequipped - - ARR_FIND( 0, sd->inventory_data[idx_equip]->slot, i, sd->status.inventory[idx_equip].card[i] == 0 ); - if( i == sd->inventory_data[idx_equip]->slot ) - return 0; // no free slots + if (sd->state.trading != 0) + return 0; + + if (!pc->can_insert_card(sd, idx_card) || !pc->can_insert_card_into(sd, idx_card, idx_equip)) + return 0; // remember the card id to insert nameid = sd->status.inventory[idx_card].nameid; @@ -4105,6 +4141,10 @@ int pc_insert_card(struct map_session_data* sd, int idx_card, int idx_equip) } else {// success + int i; + ARR_FIND( 0, sd->inventory_data[idx_equip]->slot, i, sd->status.inventory[idx_equip].card[i] == 0); + if (i == sd->inventory_data[idx_equip]->slot) + return 0; // no free slots logs->pick_pc(sd, LOG_TYPE_OTHER, -1, &sd->status.inventory[idx_equip],sd->inventory_data[idx_equip]); sd->status.inventory[idx_equip].card[i] = nameid; logs->pick_pc(sd, LOG_TYPE_OTHER, 1, &sd->status.inventory[idx_equip],sd->inventory_data[idx_equip]); @@ -4448,6 +4488,7 @@ int pc_additem(struct map_session_data *sd,struct item *item_data,int amount,e_l if( sd->status.inventory[i].nameid == item_data->nameid && sd->status.inventory[i].bound == item_data->bound && sd->status.inventory[i].expire_time == 0 && + sd->status.inventory[i].unique_id == item_data->unique_id && memcmp(&sd->status.inventory[i].card, &item_data->card, sizeof(item_data->card)) == 0 ) { if( amount > MAX_AMOUNT - sd->status.inventory[i].amount || ( data->stack.inventory && amount > data->stack.amount - sd->status.inventory[i].amount ) ) return 5; @@ -4475,8 +4516,8 @@ int pc_additem(struct map_session_data *sd,struct item *item_data,int amount,e_l clif->additem(sd,i,amount,0); } - if( !itemdb->isstackable2(data) && !item_data->unique_id ) - sd->status.inventory[i].unique_id = itemdb->unique_id(sd); + if( ( !itemdb->isstackable2(data) || data->flag.force_serial || data->type == IT_CASH) && !item_data->unique_id ) + sd->status.inventory[i].unique_id = itemdb->unique_id(sd); logs->pick_pc(sd, log_type, amount, &sd->status.inventory[i],sd->inventory_data[i]); @@ -5028,7 +5069,7 @@ int pc_cart_additem(struct map_session_data *sd,struct item *item_data,int amoun sd->status.cart[i].card[2] == item_data->card[2] && sd->status.cart[i].card[3] == item_data->card[3] ); }; - if( i < MAX_CART ) + if( i < MAX_CART && item_data->unique_id == sd->status.cart[i].unique_id) {// item already in cart, stack it if( amount > MAX_AMOUNT - sd->status.cart[i].amount || ( data->stack.cart && amount > data->stack.amount - sd->status.cart[i].amount ) ) return 2; // no room @@ -11496,7 +11537,9 @@ void pc_defaults(void) { pc->skill = pc_skill; pc->insert_card = pc_insert_card; - + pc->can_insert_card = pc_can_insert_card; + pc->can_insert_card_into = pc_can_insert_card_into; + pc->steal_item = pc_steal_item; pc->steal_coin = pc_steal_coin; diff --git a/src/map/pc.h b/src/map/pc.h index 4dea27693..c370f9956 100644 --- a/src/map/pc.h +++ b/src/map/pc.h @@ -880,6 +880,8 @@ END_ZEROED_BLOCK; /* End */ int (*skill) (struct map_session_data *sd, int id, int level, int flag); int (*insert_card) (struct map_session_data *sd,int idx_card,int idx_equip); + bool (*can_insert_card) (struct map_session_data* sd, int idx_card); + bool (*can_insert_card_into) (struct map_session_data* sd, int idx_card, int idx_equip); int (*steal_item) (struct map_session_data *sd,struct block_list *bl, uint16 skill_lv); int (*steal_coin) (struct map_session_data *sd,struct block_list *bl); diff --git a/src/map/script.c b/src/map/script.c index 47ac151ed..30af4d0f7 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -17177,18 +17177,27 @@ BUILDIN(changequest) { BUILDIN(questactive) { struct map_session_data *sd = script->rid2sd(st); - int quest_progress = 0; + int qid, i; - if (sd == NULL) + if (sd == NULL) { + ShowError("questactive: no player attached!"); return false; + } + + qid = script_getnum(st, 2); + + ARR_FIND(0, sd->avail_quests, i, sd->quest_log[i].quest_id == qid ); - if (quest->check(sd, script_getnum(st, 2), HAVEQUEST) == Q_ACTIVE) + if( i >= sd->avail_quests ) { + script_pushint(st, 0); + return true; + } + + if(sd->quest_log[i].state == Q_ACTIVE) script_pushint(st, 1); else script_pushint(st, 0); - script_pushint(st, quest_progress); - return true; } @@ -19691,6 +19700,17 @@ BUILDIN(showscript) { return true; } +BUILDIN(mergeitem) +{ + struct map_session_data *sd = script->rid2sd(st); + + if (sd == NULL) + return true; + + clif->openmergeitem(sd->fd, sd); + + return true; +} /** place holder for the translation macro **/ BUILDIN(_) { return true; @@ -20329,6 +20349,7 @@ void script_parse_builtin(void) { BUILDIN_DEF(channelmes, "ss"), BUILDIN_DEF(showscript, "s?"), + BUILDIN_DEF(mergeitem,""), BUILDIN_DEF(_,"s"), }; int i, len = ARRAYLENGTH(BUILDIN); diff --git a/src/map/skill.c b/src/map/skill.c index 666af315a..d8f967c6c 100644 --- a/src/map/skill.c +++ b/src/map/skill.c @@ -2714,7 +2714,7 @@ int skill_attack(int attack_type, struct block_list* src, struct block_list *dsr } /* monsters with skill lv higher than MAX_SKILL_LEVEL may get this value beyond the max depending on conditions, we cap to the system's limit */ - if( dsrc && dsrc->type == BL_MOB && skill_lv > MAX_SKILL_LEVEL && dmg.blewcount > 25 ) + if (dsrc->type == BL_MOB && skill_lv > MAX_SKILL_LEVEL && dmg.blewcount > 25) dmg.blewcount = 25; //blown-specific handling @@ -15495,7 +15495,6 @@ int skill_graffitiremover (struct block_list *bl, va_list ap) { struct skill_unit *su=NULL; nullpo_ret(bl); - nullpo_ret(ap); if(bl->type != BL_SKILL) return 0; @@ -15526,7 +15525,6 @@ int skill_detonator(struct block_list *bl, va_list ap) { int unit_id; nullpo_ret(bl); - nullpo_ret(ap); src = va_arg(ap,struct block_list *); if( bl->type != BL_SKILL ) diff --git a/src/map/status.c b/src/map/status.c index bfe606bca..d88bcf146 100644 --- a/src/map/status.c +++ b/src/map/status.c @@ -5145,7 +5145,7 @@ signed short status_calc_mdef2(struct block_list *bl, struct status_change *sc, if(sc->data[SC_MINDBREAKER]) mdef2 -= mdef2 * sc->data[SC_MINDBREAKER]->val3/100; #ifdef RENEWAL - if(sc && sc->data[SC_ASSUMPTIO]) + if (sc->data[SC_ASSUMPTIO]) mdef2 <<= 1; return (short)cap_value(mdef2,SHRT_MIN,SHRT_MAX); #else @@ -6233,7 +6233,7 @@ void status_set_viewdata(struct block_list *bl, int class_) if (vd) nd->vd = vd; else - ShowError("status_set_viewdata (NPC): No view data for class %d\n", class_); + ShowError("status_set_viewdata (NPC): No view data for class %d (name=%s)\n", class_, nd->name); } break; case BL_HOM: //[blackhole89] diff --git a/src/map/storage.c b/src/map/storage.c index 0a22b9ec6..95194bc47 100644 --- a/src/map/storage.c +++ b/src/map/storage.c @@ -109,7 +109,8 @@ int compare_item(struct item *a, struct item *b) a->refine == b->refine && a->attribute == b->attribute && a->expire_time == b->expire_time && - a->bound == b->bound ) + a->bound == b->bound && + a->unique_id == b->unique_id) { int i; for (i = 0; i < MAX_SLOTS && (a->card[i] == b->card[i]); i++); @@ -155,6 +156,7 @@ int storage_additem(struct map_session_data* sd, struct item* item_data, int amo {// existing items found, stack them if( amount > MAX_AMOUNT - stor->items[i].amount || ( data->stack.storage && amount > data->stack.amount - stor->items[i].amount ) ) return 1; + stor->items[i].amount += amount; clif->storageitemadded(sd,&stor->items[i],i,amount); return 0; diff --git a/src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc b/src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc index 09f33bff6..f3e3711c1 100644 --- a/src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc +++ b/src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc @@ -1345,6 +1345,14 @@ struct { struct HPMHookPoint *HP_clif_parse_roulette_db_post; struct HPMHookPoint *HP_clif_roulette_generate_ack_pre; struct HPMHookPoint *HP_clif_roulette_generate_ack_post; + struct HPMHookPoint *HP_clif_openmergeitem_pre; + struct HPMHookPoint *HP_clif_openmergeitem_post; + struct HPMHookPoint *HP_clif_cancelmergeitem_pre; + struct HPMHookPoint *HP_clif_cancelmergeitem_post; + struct HPMHookPoint *HP_clif_comparemergeitem_pre; + struct HPMHookPoint *HP_clif_comparemergeitem_post; + struct HPMHookPoint *HP_clif_ackmergeitems_pre; + struct HPMHookPoint *HP_clif_ackmergeitems_post; struct HPMHookPoint *HP_clif_pWantToConnection_pre; struct HPMHookPoint *HP_clif_pWantToConnection_post; struct HPMHookPoint *HP_clif_pLoadEndAck_pre; @@ -3689,6 +3697,10 @@ struct { struct HPMHookPoint *HP_pc_skill_post; struct HPMHookPoint *HP_pc_insert_card_pre; struct HPMHookPoint *HP_pc_insert_card_post; + struct HPMHookPoint *HP_pc_can_insert_card_pre; + struct HPMHookPoint *HP_pc_can_insert_card_post; + struct HPMHookPoint *HP_pc_can_insert_card_into_pre; + struct HPMHookPoint *HP_pc_can_insert_card_into_post; struct HPMHookPoint *HP_pc_steal_item_pre; struct HPMHookPoint *HP_pc_steal_item_post; struct HPMHookPoint *HP_pc_steal_coin_pre; @@ -6552,6 +6564,14 @@ struct { int HP_clif_parse_roulette_db_post; int HP_clif_roulette_generate_ack_pre; int HP_clif_roulette_generate_ack_post; + int HP_clif_openmergeitem_pre; + int HP_clif_openmergeitem_post; + int HP_clif_cancelmergeitem_pre; + int HP_clif_cancelmergeitem_post; + int HP_clif_comparemergeitem_pre; + int HP_clif_comparemergeitem_post; + int HP_clif_ackmergeitems_pre; + int HP_clif_ackmergeitems_post; int HP_clif_pWantToConnection_pre; int HP_clif_pWantToConnection_post; int HP_clif_pLoadEndAck_pre; @@ -8896,6 +8916,10 @@ struct { int HP_pc_skill_post; int HP_pc_insert_card_pre; int HP_pc_insert_card_post; + int HP_pc_can_insert_card_pre; + int HP_pc_can_insert_card_post; + int HP_pc_can_insert_card_into_pre; + int HP_pc_can_insert_card_into_post; int HP_pc_steal_item_pre; int HP_pc_steal_item_post; int HP_pc_steal_coin_pre; diff --git a/src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc b/src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc index 8c1456412..4e23425ec 100644 --- a/src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc +++ b/src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc @@ -683,6 +683,10 @@ struct HookingPointData HookingPoints[] = { { HP_POP(clif->npc_market_purchase_ack, HP_clif_npc_market_purchase_ack) }, { HP_POP(clif->parse_roulette_db, HP_clif_parse_roulette_db) }, { HP_POP(clif->roulette_generate_ack, HP_clif_roulette_generate_ack) }, + { HP_POP(clif->openmergeitem, HP_clif_openmergeitem) }, + { HP_POP(clif->cancelmergeitem, HP_clif_cancelmergeitem) }, + { HP_POP(clif->comparemergeitem, HP_clif_comparemergeitem) }, + { HP_POP(clif->ackmergeitems, HP_clif_ackmergeitems) }, { HP_POP(clif->pWantToConnection, HP_clif_pWantToConnection) }, { HP_POP(clif->pLoadEndAck, HP_clif_pLoadEndAck) }, { HP_POP(clif->pTickSend, HP_clif_pTickSend) }, @@ -1876,6 +1880,8 @@ struct HookingPointData HookingPoints[] = { { HP_POP(pc->bonus5, HP_pc_bonus5) }, { HP_POP(pc->skill, HP_pc_skill) }, { HP_POP(pc->insert_card, HP_pc_insert_card) }, + { HP_POP(pc->can_insert_card, HP_pc_can_insert_card) }, + { HP_POP(pc->can_insert_card_into, HP_pc_can_insert_card_into) }, { HP_POP(pc->steal_item, HP_pc_steal_item) }, { HP_POP(pc->steal_coin, HP_pc_steal_coin) }, { HP_POP(pc->modifybuyvalue, HP_pc_modifybuyvalue) }, diff --git a/src/plugins/HPMHooking/HPMHooking_map.Hooks.inc b/src/plugins/HPMHooking/HPMHooking_map.Hooks.inc index c623747aa..85f477bec 100644 --- a/src/plugins/HPMHooking/HPMHooking_map.Hooks.inc +++ b/src/plugins/HPMHooking/HPMHooking_map.Hooks.inc @@ -17751,6 +17751,111 @@ void HP_clif_roulette_generate_ack(struct map_session_data *sd, unsigned char re } return; } +void HP_clif_openmergeitem(int fd, struct map_session_data *sd) { + int hIndex = 0; + if( HPMHooks.count.HP_clif_openmergeitem_pre ) { + void (*preHookFunc) (int *fd, struct map_session_data *sd); + *HPMforce_return = false; + for(hIndex = 0; hIndex < HPMHooks.count.HP_clif_openmergeitem_pre; hIndex++ ) { + preHookFunc = HPMHooks.list.HP_clif_openmergeitem_pre[hIndex].func; + preHookFunc(&fd, sd); + } + if( *HPMforce_return ) { + *HPMforce_return = false; + return; + } + } + { + HPMHooks.source.clif.openmergeitem(fd, sd); + } + if( HPMHooks.count.HP_clif_openmergeitem_post ) { + void (*postHookFunc) (int *fd, struct map_session_data *sd); + for(hIndex = 0; hIndex < HPMHooks.count.HP_clif_openmergeitem_post; hIndex++ ) { + postHookFunc = HPMHooks.list.HP_clif_openmergeitem_post[hIndex].func; + postHookFunc(&fd, sd); + } + } + return; +} +void HP_clif_cancelmergeitem(int fd, struct map_session_data *sd) { + int hIndex = 0; + if( HPMHooks.count.HP_clif_cancelmergeitem_pre ) { + void (*preHookFunc) (int *fd, struct map_session_data *sd); + *HPMforce_return = false; + for(hIndex = 0; hIndex < HPMHooks.count.HP_clif_cancelmergeitem_pre; hIndex++ ) { + preHookFunc = HPMHooks.list.HP_clif_cancelmergeitem_pre[hIndex].func; + preHookFunc(&fd, sd); + } + if( *HPMforce_return ) { + *HPMforce_return = false; + return; + } + } + { + HPMHooks.source.clif.cancelmergeitem(fd, sd); + } + if( HPMHooks.count.HP_clif_cancelmergeitem_post ) { + void (*postHookFunc) (int *fd, struct map_session_data *sd); + for(hIndex = 0; hIndex < HPMHooks.count.HP_clif_cancelmergeitem_post; hIndex++ ) { + postHookFunc = HPMHooks.list.HP_clif_cancelmergeitem_post[hIndex].func; + postHookFunc(&fd, sd); + } + } + return; +} +int HP_clif_comparemergeitem(const void *a, const void *b) { + int hIndex = 0; + int retVal___ = 0; + if( HPMHooks.count.HP_clif_comparemergeitem_pre ) { + int (*preHookFunc) (const void *a, const void *b); + *HPMforce_return = false; + for(hIndex = 0; hIndex < HPMHooks.count.HP_clif_comparemergeitem_pre; hIndex++ ) { + preHookFunc = HPMHooks.list.HP_clif_comparemergeitem_pre[hIndex].func; + retVal___ = preHookFunc(a, b); + } + if( *HPMforce_return ) { + *HPMforce_return = false; + return retVal___; + } + } + { + retVal___ = HPMHooks.source.clif.comparemergeitem(a, b); + } + if( HPMHooks.count.HP_clif_comparemergeitem_post ) { + int (*postHookFunc) (int retVal___, const void *a, const void *b); + for(hIndex = 0; hIndex < HPMHooks.count.HP_clif_comparemergeitem_post; hIndex++ ) { + postHookFunc = HPMHooks.list.HP_clif_comparemergeitem_post[hIndex].func; + retVal___ = postHookFunc(retVal___, a, b); + } + } + return retVal___; +} +void HP_clif_ackmergeitems(int fd, struct map_session_data *sd) { + int hIndex = 0; + if( HPMHooks.count.HP_clif_ackmergeitems_pre ) { + void (*preHookFunc) (int *fd, struct map_session_data *sd); + *HPMforce_return = false; + for(hIndex = 0; hIndex < HPMHooks.count.HP_clif_ackmergeitems_pre; hIndex++ ) { + preHookFunc = HPMHooks.list.HP_clif_ackmergeitems_pre[hIndex].func; + preHookFunc(&fd, sd); + } + if( *HPMforce_return ) { + *HPMforce_return = false; + return; + } + } + { + HPMHooks.source.clif.ackmergeitems(fd, sd); + } + if( HPMHooks.count.HP_clif_ackmergeitems_post ) { + void (*postHookFunc) (int *fd, struct map_session_data *sd); + for(hIndex = 0; hIndex < HPMHooks.count.HP_clif_ackmergeitems_post; hIndex++ ) { + postHookFunc = HPMHooks.list.HP_clif_ackmergeitems_post[hIndex].func; + postHookFunc(&fd, sd); + } + } + return; +} void HP_clif_pWantToConnection(int fd, struct map_session_data *sd) { int hIndex = 0; if( HPMHooks.count.HP_clif_pWantToConnection_pre ) { @@ -49356,6 +49461,60 @@ int HP_pc_insert_card(struct map_session_data *sd, int idx_card, int idx_equip) } return retVal___; } +bool HP_pc_can_insert_card(struct map_session_data *sd, int idx_card) { + int hIndex = 0; + bool retVal___ = false; + if( HPMHooks.count.HP_pc_can_insert_card_pre ) { + bool (*preHookFunc) (struct map_session_data *sd, int *idx_card); + *HPMforce_return = false; + for(hIndex = 0; hIndex < HPMHooks.count.HP_pc_can_insert_card_pre; hIndex++ ) { + preHookFunc = HPMHooks.list.HP_pc_can_insert_card_pre[hIndex].func; + retVal___ = preHookFunc(sd, &idx_card); + } + if( *HPMforce_return ) { + *HPMforce_return = false; + return retVal___; + } + } + { + retVal___ = HPMHooks.source.pc.can_insert_card(sd, idx_card); + } + if( HPMHooks.count.HP_pc_can_insert_card_post ) { + bool (*postHookFunc) (bool retVal___, struct map_session_data *sd, int *idx_card); + for(hIndex = 0; hIndex < HPMHooks.count.HP_pc_can_insert_card_post; hIndex++ ) { + postHookFunc = HPMHooks.list.HP_pc_can_insert_card_post[hIndex].func; + retVal___ = postHookFunc(retVal___, sd, &idx_card); + } + } + return retVal___; +} +bool HP_pc_can_insert_card_into(struct map_session_data *sd, int idx_card, int idx_equip) { + int hIndex = 0; + bool retVal___ = false; + if( HPMHooks.count.HP_pc_can_insert_card_into_pre ) { + bool (*preHookFunc) (struct map_session_data *sd, int *idx_card, int *idx_equip); + *HPMforce_return = false; + for(hIndex = 0; hIndex < HPMHooks.count.HP_pc_can_insert_card_into_pre; hIndex++ ) { + preHookFunc = HPMHooks.list.HP_pc_can_insert_card_into_pre[hIndex].func; + retVal___ = preHookFunc(sd, &idx_card, &idx_equip); + } + if( *HPMforce_return ) { + *HPMforce_return = false; + return retVal___; + } + } + { + retVal___ = HPMHooks.source.pc.can_insert_card_into(sd, idx_card, idx_equip); + } + if( HPMHooks.count.HP_pc_can_insert_card_into_post ) { + bool (*postHookFunc) (bool retVal___, struct map_session_data *sd, int *idx_card, int *idx_equip); + for(hIndex = 0; hIndex < HPMHooks.count.HP_pc_can_insert_card_into_post; hIndex++ ) { + postHookFunc = HPMHooks.list.HP_pc_can_insert_card_into_post[hIndex].func; + retVal___ = postHookFunc(retVal___, sd, &idx_card, &idx_equip); + } + } + return retVal___; +} int HP_pc_steal_item(struct map_session_data *sd, struct block_list *bl, uint16 skill_lv) { int hIndex = 0; int retVal___ = 0; diff --git a/src/plugins/db2sql.c b/src/plugins/db2sql.c index 7cef173d2..2741ce468 100644 --- a/src/plugins/db2sql.c +++ b/src/plugins/db2sql.c @@ -139,7 +139,10 @@ int db2sql(config_setting_t *entry, int n, const char *source) { // bindonequip StrBuf->Printf(&buf, "'%u',", it->flag.bindonequip?1:0); - + + // forceserial + StrBuf->Printf(&buf, "'%u',", it->flag.force_serial?1:0); + // buyingstore StrBuf->Printf(&buf, "'%u',", it->flag.buyingstore?1:0); @@ -269,6 +272,7 @@ void totable(void) { " `refineable` tinyint(1) UNSIGNED DEFAULT NULL,\n" " `view` smallint(3) UNSIGNED DEFAULT NULL,\n" " `bindonequip` tinyint(1) UNSIGNED DEFAULT NULL,\n" + " `forceserial` tinyint(1) UNSIGNED DEFAULT NULL,\n" " `buyingstore` tinyint(1) UNSIGNED DEFAULT NULL,\n" " `delay` mediumint(9) UNSIGNED DEFAULT NULL,\n" " `trade_flag` smallint(4) UNSIGNED DEFAULT NULL,\n" |