diff --git a/src/char/char_mapif.c b/src/char/char_mapif.c index 88a72c1c9a4..6bf2368c752 100644 --- a/src/char/char_mapif.c +++ b/src/char/char_mapif.c @@ -1328,6 +1328,9 @@ int chmapif_bonus_script_save(int fd) { uint32 cid = RFIFOL(fd,4); uint8 count = RFIFOB(fd,8); + if (SQL_ERROR == Sql_Query(sql_handle,"DELETE FROM `%s` WHERE `char_id` = '%d'", schema_config.bonus_script_db, cid)) + Sql_ShowDebug(sql_handle); + if (count > 0) { char esc_script[MAX_BONUS_SCRIPT_LENGTH*2]; struct bonus_script_data bsdata; @@ -1346,9 +1349,9 @@ int chmapif_bonus_script_save(int fd) { if (SQL_ERROR == Sql_QueryStr(sql_handle,StringBuf_Value(&buf))) Sql_ShowDebug(sql_handle); - ShowInfo("Bonus Script saved for CID=%d. Total: %d.\n", cid, count); StringBuf_Destroy(&buf); } + ShowInfo("Bonus Script saved for CID=%d. Total: %d.\n", cid, count); RFIFOSKIP(fd,RFIFOW(fd,2)); } return 1; diff --git a/src/common/db.c b/src/common/db.c index 04aff81245f..915aa580f0b 100644 --- a/src/common/db.c +++ b/src/common/db.c @@ -2717,18 +2717,29 @@ void linkdb_insert( struct linkdb_node** head, void *key, void* data) node->data = data; } -void linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ) -{ +int linkdb_vforeach( struct linkdb_node** head, LinkDBFunc func, va_list ap) { struct linkdb_node *node; - if( head == NULL ) return; + int retCount = 0; + if( head == NULL ) + return 0; node = *head; while ( node ) { - va_list args; - va_start(args, func); - func( node->key, node->data, args ); - va_end(args); + va_list argscopy; + va_copy(argscopy, ap); + retCount += func(node->key, node->data, argscopy); + va_end(argscopy); node = node->next; } + return retCount; +} + +int linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ) { + va_list ap; + int retCount = 0; + va_start(ap, func); + retCount = linkdb_vforeach(head, func, ap); + va_end(ap); + return retCount; } void* linkdb_search( struct linkdb_node** head, void *key) diff --git a/src/common/db.h b/src/common/db.h index 041bf5b7376..55bcee9aa2a 100644 --- a/src/common/db.h +++ b/src/common/db.h @@ -875,14 +875,15 @@ struct linkdb_node { void *data; }; -typedef void (*LinkDBFunc)(void* key, void* data, va_list args); +typedef int (*LinkDBFunc)(void* key, void* data, va_list args); void linkdb_insert ( struct linkdb_node** head, void *key, void* data); // 重複を考慮しない void linkdb_replace( struct linkdb_node** head, void *key, void* data); // 重複を考慮する void* linkdb_search ( struct linkdb_node** head, void *key); void* linkdb_erase ( struct linkdb_node** head, void *key); void linkdb_final ( struct linkdb_node** head ); -void linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ); +int linkdb_vforeach(struct linkdb_node** head, LinkDBFunc func, va_list ap); +int linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ); diff --git a/src/map/chrif.c b/src/map/chrif.c index 937a0b76621..eabe7856768 100644 --- a/src/map/chrif.c +++ b/src/map/chrif.c @@ -282,8 +282,6 @@ int chrif_save(struct map_session_data *sd, int flag) { if (chrif_isconnected()) { chrif_save_scdata(sd); chrif_skillcooldown_save(sd); - if (flag != 3) - chrif_bsdata_save(sd); chrif_req_login_operation(sd->status.account_id, sd->status.name, CHRIF_OP_LOGIN_BANK, 0, 2, sd->status.bank_vault); //save Bank data } if ( flag != 3 && !chrif_auth_logout(sd,flag == 1 ? ST_LOGOUT : ST_MAPCHANGE) ) @@ -292,6 +290,8 @@ int chrif_save(struct map_session_data *sd, int flag) { chrif_check(-1); //Character is saved on reconnect. + chrif_bsdata_save(sd, (flag && (flag != 3))); + //For data sync if (sd->state.storage_flag == 2) gstorage_storagesave(sd->status.account_id, sd->status.guild_id, flag); @@ -1619,63 +1619,63 @@ int chrif_bsdata_request(uint32 char_id) { /** * ZA 0x2b2e * .W .W .L .B { .?B } - * Stores bonus_script data(s) to the table when player log out + * Stores bonus_script data(s) to the table * @param sd * @author [Cydh] **/ -int chrif_bsdata_save(struct map_session_data *sd) { - uint16 i; - uint8 count = 0; - unsigned int tick; +int chrif_bsdata_save(struct map_session_data *sd, bool quit) { + uint8 i = 0; chrif_check(-1); - if (!sd || !sd->bonus_script_num) + if (!sd) return 0; - tick = gettick(); + // Removing... + if (quit && sd->bonus_script.head) { + uint16 flag = BSF_REM_ON_LOGOUT; //Remove bonus when logout + if (battle_config.debuff_on_logout&1) //Remove negative buffs + flag |= BSF_REM_DEBUFF; + if (battle_config.debuff_on_logout&2) //Remove positive buffs + flag |= BSF_REM_BUFF; + pc_bonus_script_clear(sd, flag); + } + + //ShowInfo("Saving %d bonus script for CID=%d\n", sd->bonus_script.count, sd->status.char_id); - WFIFOHEAD(char_fd, 9 + sd->bonus_script_num * sizeof(struct bonus_script_data)); + WFIFOHEAD(char_fd, 9 + sd->bonus_script.count * sizeof(struct bonus_script_data)); WFIFOW(char_fd, 0) = 0x2b2e; WFIFOL(char_fd, 4) = sd->status.char_id; - i = BSF_REM_ON_LOGOUT; //Remove bonus with this flag - if (battle_config.debuff_on_logout&1) //Remove negative buffs - i |= BSF_REM_DEBUFF; - if (battle_config.debuff_on_logout&2) //Remove positive buffs - i |= BSF_REM_BUFF; + if (sd->bonus_script.count) { + unsigned int tick = gettick(); + struct linkdb_node *node = NULL; - //Clear data that won't be stored - pc_bonus_script_clear(sd, i); + for (node = sd->bonus_script.head; node && i < MAX_PC_BONUS_SCRIPT; node = node->next) { + const struct TimerData *timer = NULL; + struct bonus_script_data bs; + struct s_bonus_script_entry *entry = (struct s_bonus_script_entry *)node->data; - if (!sd->bonus_script_num) - return 0; - - for (i = 0; i < sd->bonus_script_num; i++) { - const struct TimerData *timer = get_timer(sd->bonus_script[i]->tid); - struct bonus_script_data bs; - - if (timer == NULL || DIFF_TICK(timer->tick,tick) < 0) - continue; + if (!entry || !(timer = get_timer(entry->tid)) || DIFF_TICK(timer->tick,tick) < 0) + continue; - memset(&bs, 0, sizeof(bs)); - safestrncpy(bs.script_str, StringBuf_Value(sd->bonus_script[i]->script_buf), StringBuf_Length(sd->bonus_script[i]->script_buf)+1); - bs.tick = DIFF_TICK(timer->tick, tick); - bs.flag = sd->bonus_script[i]->flag; - bs.type = sd->bonus_script[i]->type; - bs.icon = sd->bonus_script[i]->icon; - memcpy(WFIFOP(char_fd, 9 + count * sizeof(struct bonus_script_data)), &bs, sizeof(struct bonus_script_data)); - count++; - } + memset(&bs, 0, sizeof(bs)); + safestrncpy(bs.script_str, StringBuf_Value(entry->script_buf), StringBuf_Length(entry->script_buf)+1); + bs.tick = DIFF_TICK(timer->tick, tick); + bs.flag = entry->flag; + bs.type = entry->type; + bs.icon = entry->icon; + memcpy(WFIFOP(char_fd, 9 + i * sizeof(struct bonus_script_data)), &bs, sizeof(struct bonus_script_data)); + i++; + } - if (count > 0) { - WFIFOB(char_fd, 8) = count; - WFIFOW(char_fd, 2) = 9 + sd->bonus_script_num * sizeof(struct bonus_script_data); - WFIFOSET(char_fd, WFIFOW(char_fd, 2)); + if (i != sd->bonus_script.count && sd->bonus_script.count > MAX_PC_BONUS_SCRIPT) + ShowWarning("Only allowed to save %d (mmo.h::MAX_PC_BONUS_SCRIPT) bonus script each player.\n", MAX_PC_BONUS_SCRIPT); } - // Clear All - pc_bonus_script_clear_all(sd,3); + WFIFOB(char_fd, 8) = i; + WFIFOW(char_fd, 2) = 9 + sd->bonus_script.count * sizeof(struct bonus_script_data); + WFIFOSET(char_fd, WFIFOW(char_fd, 2)); return 0; } @@ -1690,8 +1690,7 @@ int chrif_bsdata_save(struct map_session_data *sd) { int chrif_bsdata_received(int fd) { struct map_session_data *sd; uint32 cid = RFIFOL(fd,4); - uint8 i, count = 0; - bool calc = false; + uint8 count = 0; sd = map_charid2sd(cid); @@ -1700,19 +1699,28 @@ int chrif_bsdata_received(int fd) { return -1; } - count = RFIFOB(fd,8); + if ((count = RFIFOB(fd,8))) { + struct s_bonus_script *list = NULL; + uint8 i = 0; - for (i = 0; i < count; i++) { - struct bonus_script_data *bs = (struct bonus_script_data*)RFIFOP(fd,9 + i*sizeof(struct bonus_script_data)); + //ShowInfo("Loaded %d bonus script for CID=%d\n", count, sd->status.char_id); - if (bs->script_str[0] == '\0' || !bs->tick) - continue; + for (i = 0; i < count; i++) { + struct bonus_script_data *bs = (struct bonus_script_data*)RFIFOP(fd,9 + i*sizeof(struct bonus_script_data)); + struct s_bonus_script_entry *entry = NULL; + + if (bs->script_str[0] == '\0' || !bs->tick) + continue; + + if (!(entry = pc_bonus_script_add(sd, bs->script_str, bs->tick, (enum si_type)bs->icon, bs->flag, bs->type))) + continue; + + linkdb_insert(&sd->bonus_script.head, (void *)((intptr_t)entry), entry); + } - if (pc_bonus_script_add(sd, bs->script_str, bs->tick, (enum si_type)bs->icon, bs->flag, bs->type)) - calc = true; + if (sd->bonus_script.head) + status_calc_pc(sd,SCO_NONE); } - if (calc) - status_calc_pc(sd,SCO_NONE); return 0; } diff --git a/src/map/chrif.h b/src/map/chrif.h index 942443de89c..e2d296e3e0d 100644 --- a/src/map/chrif.h +++ b/src/map/chrif.h @@ -89,7 +89,7 @@ int chrif_req_charunban(int aid, const char* character_name); int chrif_load_bankdata(int fd); int chrif_bsdata_request(uint32 char_id); -int chrif_bsdata_save(struct map_session_data *sd); +int chrif_bsdata_save(struct map_session_data *sd, bool quit); void do_final_chrif(void); void do_init_chrif(void); diff --git a/src/map/guild.c b/src/map/guild.c index 5e0b8c8cab8..38fa9cf3367 100644 --- a/src/map/guild.c +++ b/src/map/guild.c @@ -1945,11 +1945,12 @@ int guild_castledatasave(int castle_id, int index, int value) { return 0; } -void guild_castle_reconnect_sub(void *key, void *data, va_list ap) { +int guild_castle_reconnect_sub(void *key, void *data, va_list ap) { int castle_id = GetWord((int)__64BPRTSIZE(key), 0); int index = GetWord((int)__64BPRTSIZE(key), 1); intif_guild_castle_datasave(castle_id, index, *(int *)data); aFree(data); + return 1; } /** diff --git a/src/map/pc.c b/src/map/pc.c index 7bfed3901e3..5fdf01a9763 100755 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -1263,9 +1263,9 @@ bool pc_authok(struct map_session_data *sd, uint32 login_id2, time_t expiration_ sd->status.cashshop_sent = false; sd->last_addeditem_index = -1; - - sd->bonus_script = NULL; - sd->bonus_script_num = 0; + + sd->bonus_script.head = NULL; + sd->bonus_script.count = 0; // Request all registries (auth is considered completed whence they arrive) intif_request_registry(sd,7); @@ -11039,6 +11039,16 @@ void pc_show_version(struct map_session_data *sd) { clif_displaymessage(sd->fd,buf); } +int pc_bonus_script_list(void *key, void *data, va_list ap) { + struct s_bonus_script_entry *entry = (struct s_bonus_script_entry *)data; + struct map_session_data *sd = va_arg(ap, struct map_session_data *); + struct linkdb_node *node = (struct linkdb_node *)key; + if (sd) + ShowDebug(" cid=%d aid=%d\n",sd->status.char_id, sd->status.account_id); + ShowDebug(" key:%d e:0x%08X n:0x%08X nn:0x%08X np:0x%08X\n",(intptr_t)key, entry, key, node->next, node->prev); + return 1; +} + /** * Run bonus_script on player * @param sd @@ -11047,22 +11057,32 @@ void pc_show_version(struct map_session_data *sd) { void pc_bonus_script(struct map_session_data *sd) { uint8 i = 0; int now = gettick(); + struct linkdb_node *node = NULL, *next = NULL; - if (!sd || !sd->bonus_script_num) + if (!sd || !(node = sd->bonus_script.head)) return; - for (i = 0; i < sd->bonus_script_num; i++) { - if (sd->bonus_script[i]->tid == INVALID_TIMER) { // Start new timer for new bonus_script - sd->bonus_script[i]->tick += now; - sd->bonus_script[i]->tid = add_timer(sd->bonus_script[i]->tick, pc_bonus_script_timer, sd->bl.id, 0); - if (sd->bonus_script[i]->icon != SI_BLANK) //Gives status icon if exist - clif_status_change(&sd->bl, sd->bonus_script[i]->icon, 1, sd->bonus_script[i]->tick, 1, 0, 0); - } - if (!sd->bonus_script[i]->script) { - ShowError("pc_bonus_script: The script has been removed somewhere. \"%s\"\n", StringBuf_Value(sd->bonus_script[i]->script_buf)); - continue; + while (node) { + struct s_bonus_script_entry *entry = NULL; + next = node->next; + + if ((entry = (struct s_bonus_script_entry *)node->data)) { + // Only start timer for new bonus_script + if (entry->tid == INVALID_TIMER) { + if (entry->icon != SI_BLANK) // Gives status icon if exist + clif_status_change(&sd->bl, entry->icon, 1, entry->tick, 1, 0, 0); + + entry->tick += now; + entry->tid = add_timer(entry->tick, pc_bonus_script_timer, sd->bl.id, (intptr_t)entry); + } + + if (entry->script) + run_script(entry->script, 0, sd->bl.id, 0); + else + ShowError("pc_bonus_script: The script has been removed somewhere. \"%s\"\n", StringBuf_Value(entry->script_buf)); } - run_script(sd->bonus_script[i]->script, 0, sd->bl.id, 0); + + node = next; } } @@ -11074,126 +11094,93 @@ void pc_bonus_script(struct map_session_data *sd) { * @param icon SI * @param flag Flags @see enum e_bonus_script_flags * @param type 0 - None, 1 - Buff, 2 - Debuff - * @return True if added, False if cannot + * @return New created entry pointer or NULL if failed or NULL if duplicate fail * @author [Cydh] **/ -bool pc_bonus_script_add(struct map_session_data *sd, const char *script_str, uint32 dur, enum si_type icon, uint16 flag, uint8 type) { +struct s_bonus_script_entry *pc_bonus_script_add(struct map_session_data *sd, const char *script_str, uint32 dur, enum si_type icon, uint16 flag, uint8 type) { struct script_code *script = NULL; + struct linkdb_node *node = NULL; + struct s_bonus_script_entry *entry = NULL; if (!sd) - return false; + return NULL; if (!(script = parse_script(script_str, "bonus_script", 0, SCRIPT_IGNORE_EXTERNAL_BRACKETS))) { ShowError("pc_bonus_script_add: Failed to parse script '%s' (CID:%d).\n", script_str, sd->status.char_id); - return false; + return NULL; } - if (!sd->bonus_script_num) - CREATE(sd->bonus_script, struct s_bonus_script *, 1); - else { - uint8 i = 0; - for (i = 0; i < sd->bonus_script_num; i++) { - if (strcmpi(script_str, StringBuf_Value(sd->bonus_script[i]->script_buf)) == 0) - break; - } - - // Duplication checks - if (i < sd->bonus_script_num) { - int newdur = gettick() + dur; - if (flag&BSF_FORCE_REPLACE && sd->bonus_script[i]->tick < newdur) { - settick_timer(sd->bonus_script[i]->tid, newdur); - script_free_code(script); - return true; - } - else if (flag&BSF_FORCE_DUPLICATE) { - ; - } - else { - // No duplicate bonus - script_free_code(script); - return false; + // Duplication checks + if ((node = sd->bonus_script.head)) { + while (node) { + entry = (struct s_bonus_script_entry *)node->data; + if (strcmpi(script_str, StringBuf_Value(entry->script_buf)) == 0) { + int newdur = gettick() + dur; + if (flag&BSF_FORCE_REPLACE && entry->tick < newdur) { // Change duration + settick_timer(entry->tid, newdur); + script_free_code(script); + return NULL; + } + else if (flag&BSF_FORCE_DUPLICATE) // Allow duplicate + break; + else { // No duplicate bonus + script_free_code(script); + return NULL; + } } + node = node->next; } - - if (i >= UINT8_MAX) { - ShowError("pc_bonus_script_add: Reached max (%d) possible bonuses for this player %d\n", UINT8_MAX); - script_free_code(script); - return false; - } - - RECREATE(sd->bonus_script, struct s_bonus_script *, sd->bonus_script_num+1); } - CREATE(sd->bonus_script[sd->bonus_script_num], struct s_bonus_script, 1); - - sd->bonus_script[sd->bonus_script_num]->script_buf = StringBuf_Malloc(); - StringBuf_AppendStr(sd->bonus_script[sd->bonus_script_num]->script_buf, script_str); - sd->bonus_script[sd->bonus_script_num]->tid = INVALID_TIMER; - sd->bonus_script[sd->bonus_script_num]->flag = flag; - sd->bonus_script[sd->bonus_script_num]->icon = icon; - sd->bonus_script[sd->bonus_script_num]->tick = dur; // Use duration first, on run change to expire time - sd->bonus_script[sd->bonus_script_num]->type = type; - sd->bonus_script[sd->bonus_script_num]->script = script; - - sd->bonus_script_num++; - return true; -} - -/** - * Move bonus_script allocation to empty space - * @param sd - * @author [Cydh] - **/ -static void pc_bonus_script_move(struct map_session_data *sd) { - if (sd && sd->bonus_script_num) { - uint8 i, cur; - - for (i = 0, cur = 0; i < sd->bonus_script_num; i++) { - if (sd->bonus_script[i] == NULL) - continue; - - if (i != cur) - sd->bonus_script[cur] = sd->bonus_script[i]; + CREATE(entry, struct s_bonus_script_entry, 1); - cur++; - } - - if (!(sd->bonus_script_num = cur)) { - aFree(sd->bonus_script); - sd->bonus_script = NULL; - sd->bonus_script_num = 0; - } - } + entry->script_buf = StringBuf_Malloc(); + StringBuf_AppendStr(entry->script_buf, script_str); + entry->tid = INVALID_TIMER; + entry->flag = flag; + entry->icon = icon; + entry->tick = dur; // Use duration first, on run change to expire time + entry->type = type; + entry->script = script; + sd->bonus_script.count++; + return entry; } /** * Remove bonus_script data from player * @param sd: Target player -* @param idx: Bonus script idx in player array +* @param list: Bonus script entry from player * @author [Cydh] **/ -static void pc_bonus_script_remove(struct map_session_data *sd, uint8 idx) { - uint8 i = 0, cursor = 0; +void pc_bonus_script_free_entry(struct map_session_data *sd, struct s_bonus_script_entry *entry) { + if (entry->tid != INVALID_TIMER) + delete_timer(entry->tid, pc_bonus_script_timer); - if (!sd || !sd->bonus_script_num) - return; + if (entry->script) + script_free_code(entry->script); - if (idx >= sd->bonus_script_num) { - ShowError("pc_bonus_script_remove: Invalid index: %d\n", idx); - return; - } - - if (sd->bonus_script[idx]->tid != INVALID_TIMER) - delete_timer(sd->bonus_script[idx]->tid, pc_bonus_script_timer); - - if (sd->bonus_script[idx]->icon != SI_BLANK) - clif_status_load(&sd->bl, sd->bonus_script[idx]->icon, 0); + if (entry->script_buf) + StringBuf_Free(entry->script_buf); - script_free_code(sd->bonus_script[idx]->script); - StringBuf_Free(sd->bonus_script[idx]->script_buf); + if (sd) { + if (entry->icon != SI_BLANK) + clif_status_load(&sd->bl, entry->icon, 0); + if (sd->bonus_script.count > 0) + sd->bonus_script.count--; + } + aFree(entry); +} - aFree(sd->bonus_script[idx]); - sd->bonus_script[idx] = NULL; +/** + * Do final process if no entry left + * @param sd + **/ +static void inline pc_bonus_script_check_final(struct map_session_data *sd) { + if (sd->bonus_script.count == 0) { + if (sd->bonus_script.head && sd->bonus_script.head->data) + pc_bonus_script_free_entry(sd, (struct s_bonus_script_entry *)sd->bonus_script.head->data); + linkdb_final(&sd->bonus_script.head); + } } /** @@ -11205,8 +11192,8 @@ static void pc_bonus_script_remove(struct map_session_data *sd, uint8 idx) { * @author [Cydh] **/ int pc_bonus_script_timer(int tid, unsigned int tick, int id, intptr_t data) { - uint8 i; struct map_session_data *sd; + struct s_bonus_script_entry *entry = (struct s_bonus_script_entry *)data; sd = map_id2sd(id); if (!sd) { @@ -11214,21 +11201,17 @@ int pc_bonus_script_timer(int tid, unsigned int tick, int id, intptr_t data) { return 0; } - if (tid == INVALID_TIMER || !sd->bonus_script_num) + if (tid == INVALID_TIMER) return 0; - for (i = 0; i < sd->bonus_script_num; i++) { - if (sd->bonus_script[i]->tid == tid) - break; - } - - if (i == sd->bonus_script_num) { - ShowError("pc_bonus_script_timer: Timer %d is not found.\n", tid); + if (!sd->bonus_script.head || entry == NULL) { + ShowError("pc_bonus_script_timer: Invalid entry pointer 0x%08X!\n", entry); return 0; } - pc_bonus_script_remove(sd, i); - pc_bonus_script_move(sd); + linkdb_erase(&sd->bonus_script.head, (void *)((intptr_t)entry)); + pc_bonus_script_free_entry(sd, entry); + pc_bonus_script_check_final(sd); status_calc_pc(sd,SCO_NONE); return 0; } @@ -11240,27 +11223,37 @@ int pc_bonus_script_timer(int tid, unsigned int tick, int id, intptr_t data) { * @author [Cydh] **/ void pc_bonus_script_clear(struct map_session_data *sd, uint16 flag) { - uint8 i, count = 0; - if (!sd || !sd->bonus_script_num) + struct linkdb_node *node = NULL; + uint16 count = 0; + + if (!sd || !(node = sd->bonus_script.head)) return; - for (i = 0; i < sd->bonus_script_num; i++) { - if ((flag&sd->bonus_script[i]->flag) || // Matched flag - (sd->bonus_script[i]->type && ( - (flag&BSF_REM_BUFF && sd->bonus_script[i]->type == 1) || // Buff type - (flag&BSF_REM_DEBUFF && sd->bonus_script[i]->type == 2)) // Debuff type - )) + while (node) { + struct linkdb_node *next = node->next; + struct s_bonus_script_entry *entry = (struct s_bonus_script_entry *)node->data; + + if (entry && ( + (flag == BSF_PERMANENT) || // Remove all with permanent bonus + (!flag && !(entry->flag&BSF_PERMANENT)) || // Remove all WITHOUT permanent bonus + (flag&entry->flag) || // Matched flag + (flag&BSF_REM_BUFF && entry->type == 1) || // Remove buff + (flag&BSF_REM_DEBUFF && entry->type == 2) // Remove debuff + ) + ) { - pc_bonus_script_remove(sd, i); + linkdb_erase(&sd->bonus_script.head, (void *)((intptr_t)entry)); + pc_bonus_script_free_entry(sd, entry); count++; } + + node = next; } - if (count) { - pc_bonus_script_move(sd); - if (!(flag&BSF_REM_ON_LOGOUT)) { //Don't need to do this if log out - status_calc_pc(sd,SCO_NONE); - } - } + + pc_bonus_script_check_final(sd); + + if (count && !(flag&BSF_REM_ON_LOGOUT)) //Don't need to do this if log out + status_calc_pc(sd,SCO_NONE); } /** @@ -11270,21 +11263,34 @@ void pc_bonus_script_clear(struct map_session_data *sd, uint16 flag) { * @author [Cydh] **/ void pc_bonus_script_clear_all(struct map_session_data *sd, uint8 flag) { - uint8 i, count = 0; - if (!sd || !sd->bonus_script_num) + struct linkdb_node *node = NULL; + uint16 count = 0; + + if (!sd || !(node = sd->bonus_script.head)) return; - for (i = 0; i < sd->bonus_script_num; i++) { - if (!(flag&1) && (sd->bonus_script[i]->flag&BSF_PERMANENT)) - continue; - pc_bonus_script_remove(sd, i); - count++; - } - if (count) { - pc_bonus_script_move(sd); - if (!(flag&2)) - status_calc_pc(sd,SCO_NONE); + while (node) { + struct linkdb_node *next = node->next; + struct s_bonus_script_entry *entry = (struct s_bonus_script_entry *)node->data; + + if (entry && ( + !(entry->flag&BSF_PERMANENT) || + ((flag&1) && entry->flag&BSF_PERMANENT) + ) + ) + { + linkdb_erase(&sd->bonus_script.head, (void *)((intptr_t)entry)); + pc_bonus_script_free_entry(sd, entry); + count++; + } + + node = next; } + + pc_bonus_script_check_final(sd); + + if (count && !(flag&2)) + status_calc_pc(sd,SCO_NONE); } /** [Cydh] diff --git a/src/map/pc.h b/src/map/pc.h index dfd4d052a17..de18dfd0a9c 100644 --- a/src/map/pc.h +++ b/src/map/pc.h @@ -158,7 +158,7 @@ struct s_pc_itemgrouphealrate { }; ///Timed bonus 'bonus_script' struct [Cydh] -struct s_bonus_script { +struct s_bonus_script_entry { struct script_code *script; StringBuf *script_buf; //Used for comparing and storing on table uint32 tick; @@ -604,9 +604,13 @@ struct map_session_data { struct vip_info vip; bool disableshowrate; //State to disable clif_display_pinfo(). [Cydh] #endif - struct s_bonus_script **bonus_script; ///Bonus Script [Cydh] - uint8 bonus_script_num; - + + /// Bonus Script [Cydh] + struct s_bonus_script_list { + struct linkdb_node *head; ///< Bonus script head node. data: struct s_bonus_script_entry *entry, key: (intptr_t)entry + uint16 count; + } bonus_script; + struct s_pc_itemgrouphealrate **itemgrouphealrate; /// List of Item Group Heal rate bonus uint8 itemgrouphealrate_count; /// Number of rate bonuses @@ -1121,9 +1125,9 @@ void pc_show_version(struct map_session_data *sd); int pc_bonus_script_timer(int tid, unsigned int tick, int id, intptr_t data); void pc_bonus_script(struct map_session_data *sd); -bool pc_bonus_script_add(struct map_session_data *sd, const char *script_str, uint32 dur, enum si_type icon, uint16 flag, uint8 type); +struct s_bonus_script_entry *pc_bonus_script_add(struct map_session_data *sd, const char *script_str, uint32 dur, enum si_type icon, uint16 flag, uint8 type); void pc_bonus_script_clear(struct map_session_data *sd, uint16 flag); -void pc_bonus_script_clear_all(struct map_session_data *sd, uint8 flag); +int pc_bonus_script_list(void *key, void *data, va_list ap); void pc_cell_basilica(struct map_session_data *sd); diff --git a/src/map/script.c b/src/map/script.c index 9a8f3539b70..1a993050d24 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -18909,6 +18909,7 @@ BUILDIN_FUNC(bonus_script) { uint8 type = 0; TBL_PC* sd; const char *script_str = NULL; + struct s_bonus_script_entry *entry = NULL; if (script_hasdata(st,7)) { if (!(sd = map_charid2sd(script_getnum(st,7)))) { @@ -18942,8 +18943,10 @@ BUILDIN_FUNC(bonus_script) { if (icon <= SI_BLANK || icon >= SI_MAX) icon = SI_BLANK; - if (pc_bonus_script_add(sd, script_str, dur, (enum si_type)icon, flag, type)) + if ((entry = pc_bonus_script_add(sd, script_str, dur, (enum si_type)icon, flag, type))) { + linkdb_insert(&sd->bonus_script.head, (void *)((intptr_t)entry), entry); status_calc_pc(sd,SCO_NONE); + } return SCRIPT_CMD_SUCCESS; } @@ -18969,7 +18972,7 @@ BUILDIN_FUNC(bonus_script_clear) { if (sd == NULL) return SCRIPT_CMD_FAILURE; - pc_bonus_script_clear_all(sd,(flag ? 1 : 0)); + pc_bonus_script_clear(sd,(flag ? BSF_PERMANENT : BSF_REM_ALL)); return SCRIPT_CMD_SUCCESS; } diff --git a/src/map/status.h b/src/map/status.h index 48f9a0f64c3..01ae9bb0a62 100644 --- a/src/map/status.h +++ b/src/map/status.h @@ -1762,7 +1762,7 @@ enum e_bonus_script_flags { BSF_FORCE_DUPLICATE = 0x800, ///< Force to add duplicated script // These flags aren't part of 'bonus_script' scripting flags - + BSF_REM_ALL = 0x0, ///< Remove all bonus script BSF_REM_BUFF = 0x4000, ///< Remove positive buff if battle_config.debuff_on_logout&1 BSF_REM_DEBUFF = 0x8000, ///< Remove negative buff if battle_config.debuff_on_logout&2 }; diff --git a/src/map/unit.c b/src/map/unit.c index ad1fcbed32a..b3029e9acad 100644 --- a/src/map/unit.c +++ b/src/map/unit.c @@ -3169,6 +3169,10 @@ int unit_free(struct block_list *bl, clr_type clrtype) sd->num_quests = sd->avail_quests = 0; } + // Clearing... + if (sd->bonus_script.head) + pc_bonus_script_clear(sd, BSF_REM_ALL); + pc_itemgrouphealrate_clear(sd); break; }