Follow up 95705d41bee8d15d50d34c484617790e4aae9b21

* Changed bonus script list to link list
* Merged 'pc_bonus_script_clear_all' to 'pc_bonus_script_clear'
* Now bonus script will be saved on auto-save timer or other save request, prevent losing the bonus when "something" happen. But, saving when player is quiting, will removes the bonus that won't be saved on logout.

Signed-off-by: Cydh Ramdh <house.bad@gmail.com>
This commit is contained in:
Cydh Ramdh 2015-02-03 11:56:09 +07:00
parent 95705d41be
commit 148353eed9
11 changed files with 261 additions and 220 deletions

View File

@ -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;

View File

@ -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)

View File

@ -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, ... );

View File

@ -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
* <cmd>.W <len>.W <char_id>.L <count>.B { <bonus_script>.?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);
}
WFIFOHEAD(char_fd, 9 + sd->bonus_script_num * sizeof(struct bonus_script_data));
//ShowInfo("Saving %d bonus script for CID=%d\n", sd->bonus_script.count, sd->status.char_id);
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;
if (!entry || !(timer = get_timer(entry->tid)) || DIFF_TICK(timer->tick,tick) < 0)
continue;
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;
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 (timer == NULL || 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++;
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);
}
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));
}
// 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 (pc_bonus_script_add(sd, bs->script_str, bs->tick, (enum si_type)bs->icon, bs->flag, bs->type))
calc = true;
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 (sd->bonus_script.head)
status_calc_pc(sd,SCO_NONE);
}
if (calc)
status_calc_pc(sd,SCO_NONE);
return 0;
}

View File

@ -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);

View File

@ -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;
}
/**

View File

@ -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);
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));
}
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;
}
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);
CREATE(entry, struct s_bonus_script_entry, 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];
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 (entry->script_buf)
StringBuf_Free(entry->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);
}
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);
script_free_code(sd->bonus_script[idx]->script);
StringBuf_Free(sd->bonus_script[idx]->script_buf);
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]

View File

@ -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);

View File

@ -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;
}

View File

@ -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
};

View File

@ -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;
}