|
@@ -1143,8 +1143,6 @@ bool pc_authok(struct map_session_data *sd, uint32 login_id2, time_t expiration_
|
|
|
sd->autobonus2[i].active = INVALID_TIMER;
|
|
|
for(i = 0; i < ARRAYLENGTH(sd->autobonus3); i++)
|
|
|
sd->autobonus3[i].active = INVALID_TIMER;
|
|
|
- for(i = 0; i < ARRAYLENGTH(sd->bonus_script); i++)
|
|
|
- sd->bonus_script[i].tid = INVALID_TIMER;
|
|
|
|
|
|
if (battle_config.item_auto_get)
|
|
|
sd->state.autoloot = 10000;
|
|
@@ -1265,6 +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.head = NULL;
|
|
|
+ sd->bonus_script.count = 0;
|
|
|
|
|
|
// Request all registries (auth is considered completed whence they arrive)
|
|
|
intif_request_registry(sd,7);
|
|
@@ -11038,80 +11039,208 @@ void pc_show_version(struct map_session_data *sd) {
|
|
|
clif_displaymessage(sd->fd,buf);
|
|
|
}
|
|
|
|
|
|
-/** [Cydh]
|
|
|
+/**
|
|
|
+ * Run bonus_script on player
|
|
|
+ * @param sd
|
|
|
+ * @author [Cydh]
|
|
|
+ **/
|
|
|
+void pc_bonus_script(struct map_session_data *sd) {
|
|
|
+ int now = gettick();
|
|
|
+ struct linkdb_node *node = NULL, *next = NULL;
|
|
|
+
|
|
|
+ if (!sd || !(node = sd->bonus_script.head))
|
|
|
+ return;
|
|
|
+
|
|
|
+ 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));
|
|
|
+ }
|
|
|
+
|
|
|
+ node = next;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Add bonus_script to player
|
|
|
+ * @param sd Player
|
|
|
+ * @param script_str Script string
|
|
|
+ * @param dur Duration in ms
|
|
|
+ * @param icon SI
|
|
|
+ * @param flag Flags @see enum e_bonus_script_flags
|
|
|
+ * @param type 0 - None, 1 - Buff, 2 - Debuff
|
|
|
+ * @return New created entry pointer or NULL if failed or NULL if duplicate fail
|
|
|
+ * @author [Cydh]
|
|
|
+ **/
|
|
|
+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 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 NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 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;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ CREATE(entry, struct s_bonus_script_entry, 1);
|
|
|
+
|
|
|
+ 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 list: Bonus script entry from player
|
|
|
+* @author [Cydh]
|
|
|
+**/
|
|
|
+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 (entry->script)
|
|
|
+ script_free_code(entry->script);
|
|
|
+
|
|
|
+ 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);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 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);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
* Timer for bonus_script
|
|
|
* @param tid
|
|
|
* @param tick
|
|
|
* @param id
|
|
|
* @param data
|
|
|
+* @author [Cydh]
|
|
|
**/
|
|
|
int pc_bonus_script_timer(int tid, unsigned int tick, int id, intptr_t data) {
|
|
|
- uint8 i = (uint8)data;
|
|
|
struct map_session_data *sd;
|
|
|
+ struct s_bonus_script_entry *entry = (struct s_bonus_script_entry *)data;
|
|
|
|
|
|
sd = map_id2sd(id);
|
|
|
if (!sd) {
|
|
|
- ShowDebug("pc_bonus_script_timer: Null pointer id: %d data: %d\n",id,data);
|
|
|
+ ShowError("pc_bonus_script_timer: Null pointer id: %d tid: %d\n", id, tid);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
- if (i >= MAX_PC_BONUS_SCRIPT || !(&sd->bonus_script[i]) || !sd->bonus_script[i].script) {
|
|
|
- ShowDebug("pc_bonus_script_timer: Invalid index %d\n",i);
|
|
|
+ if (tid == INVALID_TIMER)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ if (!sd->bonus_script.head || entry == NULL) {
|
|
|
+ ShowError("pc_bonus_script_timer: Invalid entry pointer 0x%08X!\n", entry);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
- if (sd->bonus_script[i].icon != SI_BLANK)
|
|
|
- clif_status_load(&sd->bl, sd->bonus_script[i].icon, 0);
|
|
|
- pc_bonus_script_remove(&sd->bonus_script[i]);
|
|
|
+ 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;
|
|
|
}
|
|
|
|
|
|
-/** [Cydh]
|
|
|
-* Remove bonus_script data from player
|
|
|
-* @param sd: Target player
|
|
|
-* @param i: Bonus script index
|
|
|
-**/
|
|
|
-void pc_bonus_script_remove(struct s_bonus_script *bscript) {
|
|
|
- if (!bscript)
|
|
|
- return;
|
|
|
-
|
|
|
- if (bscript->script)
|
|
|
- script_free_code(bscript->script);
|
|
|
- bscript->script = NULL;
|
|
|
- memset(bscript->script_str, '\0', sizeof(bscript->script_str));
|
|
|
- bscript->tick = 0;
|
|
|
- bscript->flag = 0;
|
|
|
- bscript->icon = SI_BLANK;
|
|
|
- if (bscript->tid != INVALID_TIMER)
|
|
|
- delete_timer(bscript->tid,pc_bonus_script_timer);
|
|
|
- bscript->tid = INVALID_TIMER;
|
|
|
-}
|
|
|
-
|
|
|
-/** [Cydh]
|
|
|
+/**
|
|
|
* Check then clear all active timer(s) of bonus_script data from player based on reason
|
|
|
* @param sd: Target player
|
|
|
* @param flag: Reason to remove the bonus_script. e_bonus_script_flags or e_bonus_script_types
|
|
|
+* @author [Cydh]
|
|
|
**/
|
|
|
void pc_bonus_script_clear(struct map_session_data *sd, uint16 flag) {
|
|
|
- uint8 i, count = 0;
|
|
|
- if (!sd)
|
|
|
+ struct linkdb_node *node = NULL;
|
|
|
+ uint16 count = 0;
|
|
|
+
|
|
|
+ if (!sd || !(node = sd->bonus_script.head))
|
|
|
return;
|
|
|
|
|
|
- for (i = 0; i < MAX_PC_BONUS_SCRIPT; i++) {
|
|
|
- if (&sd->bonus_script[i] && sd->bonus_script[i].script &&
|
|
|
- (sd->bonus_script[i].flag&flag || //Remove bonus script based on e_bonus_script_flags
|
|
|
- (sd->bonus_script[i].type && (
|
|
|
- (flag&BSF_REM_BUFF && sd->bonus_script[i].type == 1) || //Remove bonus script based on buff type
|
|
|
- (flag&BSF_REM_DEBUFF && sd->bonus_script[i].type == 2)) //Remove bonus script based on 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
|
|
|
+ )
|
|
|
+ )
|
|
|
{
|
|
|
- if (sd->bonus_script[i].icon != SI_BLANK)
|
|
|
- clif_status_load(&sd->bl, sd->bonus_script[i].icon, 0);
|
|
|
- pc_bonus_script_remove(&sd->bonus_script[i]);
|
|
|
+ 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&BSF_REM_ON_LOGOUT)) //Don't need to do this if log out
|
|
|
status_calc_pc(sd,SCO_NONE);
|
|
|
}
|
|
@@ -11119,25 +11248,38 @@ void pc_bonus_script_clear(struct map_session_data *sd, uint16 flag) {
|
|
|
/**
|
|
|
* Clear all bonus script from player
|
|
|
* @param sd
|
|
|
-* @param permanent If true, will removes permanent bonus script.
|
|
|
+* @param flag &1 - Remove permanent bonus_script, &2 - Logout
|
|
|
* @author [Cydh]
|
|
|
-*/
|
|
|
-void pc_bonus_script_clear_all(struct map_session_data *sd, bool permanent) {
|
|
|
- uint8 i, count = 0;
|
|
|
- if (!sd)
|
|
|
+**/
|
|
|
+void pc_bonus_script_clear_all(struct map_session_data *sd, uint8 flag) {
|
|
|
+ struct linkdb_node *node = NULL;
|
|
|
+ uint16 count = 0;
|
|
|
+
|
|
|
+ if (!sd || !(node = sd->bonus_script.head))
|
|
|
return;
|
|
|
|
|
|
- for (i = 0; i < MAX_PC_BONUS_SCRIPT; i++) {
|
|
|
- if (!&sd->bonus_script[i] && !sd->bonus_script[i].script)
|
|
|
- continue;
|
|
|
- if (!permanent && sd->bonus_script[i].flag&BSF_PERMANENT)
|
|
|
- continue;
|
|
|
- if (sd->bonus_script[i].icon != SI_BLANK)
|
|
|
- clif_status_load(&sd->bl, sd->bonus_script[i].icon, 0);
|
|
|
- pc_bonus_script_remove(&sd->bonus_script[i]);
|
|
|
- count++;
|
|
|
+ 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;
|
|
|
}
|
|
|
- status_calc_pc(sd,SCO_NONE);
|
|
|
+
|
|
|
+ pc_bonus_script_check_final(sd);
|
|
|
+
|
|
|
+ if (count && !(flag&2))
|
|
|
+ status_calc_pc(sd,SCO_NONE);
|
|
|
}
|
|
|
|
|
|
/** [Cydh]
|