diff options
author | Haru <haru@dotalux.com> | 2017-07-27 10:39:40 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-07-27 10:39:40 +0200 |
commit | b04ce31b952c75d5206fbfec68f2a2712da833c3 (patch) | |
tree | 9031210c2158e437dec26b26f1135934fe692dbf | |
parent | 45d2d465591d89d927aadf398cdb6166afe9cd9a (diff) | |
parent | 08121dbcef6b6a70e39ba6c5391d605d1f3e3944 (diff) | |
download | hercules-b04ce31b952c75d5206fbfec68f2a2712da833c3.tar.gz hercules-b04ce31b952c75d5206fbfec68f2a2712da833c3.tar.bz2 hercules-b04ce31b952c75d5206fbfec68f2a2712da833c3.tar.xz hercules-b04ce31b952c75d5206fbfec68f2a2712da833c3.zip |
Merge pull request #1811 from 4144/refactor
Refactor status_change_start and fix some issues in other code
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | src/char/int_mail.c | 2 | ||||
-rw-r--r-- | src/map/clif.c | 2 | ||||
-rw-r--r-- | src/map/homunculus.c | 2 | ||||
-rw-r--r-- | src/map/itemdb.c | 4 | ||||
-rw-r--r-- | src/map/map.c | 4 | ||||
-rw-r--r-- | src/map/mob.c | 8 | ||||
-rw-r--r-- | src/map/npc.c | 4 | ||||
-rw-r--r-- | src/map/quest.c | 2 | ||||
-rw-r--r-- | src/map/script.c | 2 | ||||
-rw-r--r-- | src/map/status.c | 1399 | ||||
-rw-r--r-- | src/map/status.h | 8 |
12 files changed, 792 insertions, 647 deletions
diff --git a/configure.ac b/configure.ac index 6fef4ee4e..7539b0890 100644 --- a/configure.ac +++ b/configure.ac @@ -1313,6 +1313,8 @@ case $enable_renewal in ;; esac +AC_CHECK_FLAG(-fno-var-tracking) + # # Host specific stuff # diff --git a/src/char/int_mail.c b/src/char/int_mail.c index 1d00b0fdf..7f054eda1 100644 --- a/src/char/int_mail.c +++ b/src/char/int_mail.c @@ -426,7 +426,7 @@ void mapif_parse_mail_return(int fd) safestrncpy(msg.dest_name, temp_, NAME_LENGTH); // set reply message title - snprintf(temp_, MAIL_TITLE_LENGTH, "RE:%s", msg.title); + safesnprintf(temp_, MAIL_TITLE_LENGTH, "RE:%s", msg.title); safestrncpy(msg.title, temp_, MAIL_TITLE_LENGTH); msg.status = MAIL_NEW; diff --git a/src/map/clif.c b/src/map/clif.c index 905b6a3ce..bb4d53a99 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -17726,7 +17726,7 @@ void clif_cashshop_db(void) { if( cashshop != NULL && (cats = libconfig->setting_get_elem(cashshop, 0)) != NULL ) { for(i = 0; i < CASHSHOP_TAB_MAX; i++) { struct config_setting_t *cat; - char entry_name[10]; + char entry_name[15]; sprintf(entry_name,"cat_%d",i); diff --git a/src/map/homunculus.c b/src/map/homunculus.c index 91a455416..ddaf3443a 100644 --- a/src/map/homunculus.c +++ b/src/map/homunculus.c @@ -1215,7 +1215,7 @@ void homunculus_read_db(void) { if( i > 0 ) { char filepath[256]; - snprintf(filepath, 256, "%s/%s", map->db_path, filename[i]); + safesnprintf(filepath, 256, "%s/%s", map->db_path, filename[i]); if( !exists(filepath) ) { continue; diff --git a/src/map/itemdb.c b/src/map/itemdb.c index 9a43bae14..2b0847e1a 100644 --- a/src/map/itemdb.c +++ b/src/map/itemdb.c @@ -1527,7 +1527,7 @@ void itemdb_read_combos(void) char filepath[256]; FILE* fp; - snprintf(filepath, 256, "%s/%s", map->db_path, DBPATH"item_combo_db.txt"); + safesnprintf(filepath, 256, "%s/%s", map->db_path, DBPATH"item_combo_db.txt"); if ((fp = fopen(filepath, "r")) == NULL) { ShowError("itemdb_read_combos: File not found \"%s\".\n", filepath); @@ -2231,7 +2231,7 @@ int itemdb_readdb_libconfig(const char *filename) { nullpo_ret(filename); - sprintf(filepath, "%s/%s", map->db_path, filename); + safesnprintf(filepath, sizeof(filepath), "%s/%s", map->db_path, filename); if (!libconfig->load_file(&item_db_conf, filepath)) return 0; diff --git a/src/map/map.c b/src/map/map.c index 16d5e645d..17156f631 100644 --- a/src/map/map.c +++ b/src/map/map.c @@ -3741,7 +3741,7 @@ int map_readallmaps (void) { ShowStatus("Loading maps (using GRF files)...\n"); else { char mapcachefilepath[256]; - snprintf(mapcachefilepath, 256, "%s/%s%s", map->db_path, DBPATH, "map_cache.dat"); + safesnprintf(mapcachefilepath, 256, "%s/%s%s", map->db_path, DBPATH, "map_cache.dat"); ShowStatus("Loading maps (using %s as map cache)...\n", mapcachefilepath); if( (fp = fopen(mapcachefilepath, "rb")) == NULL ) { ShowFatalError("Unable to open map cache file "CL_WHITE"%s"CL_RESET"\n", mapcachefilepath); @@ -4396,7 +4396,7 @@ struct map_zone_data *map_merge_zone(struct map_zone_data *main, struct map_zone nullpo_retr(NULL, main); nullpo_retr(NULL, other); - snprintf(newzone, MAP_ZONE_NAME_LENGTH, "%s+%s", main->name, other->name); + safesnprintf(newzone, MAP_ZONE_NAME_LENGTH, "%s+%s", main->name, other->name); if( (zone = strdb_get(map->zone_db, newzone)) ) return zone;/* this zone has already been merged */ diff --git a/src/map/mob.c b/src/map/mob.c index 52705cf4d..98f8865a9 100644 --- a/src/map/mob.c +++ b/src/map/mob.c @@ -3350,7 +3350,7 @@ int mobskill_use(struct mob_data *md, int64 tick, int event) { char name[NAME_LENGTH]; snprintf(name, sizeof name,"%s", md->name); strtok(name, "#"); // discard extra name identifier if present [Daegaladh] - snprintf(temp, sizeof temp,"%s : %s", name, mc->msg); + safesnprintf(temp, sizeof temp,"%s : %s", name, mc->msg); clif->messagecolor(&md->bl, mc->color, temp); } if(!(battle_config.mob_ai&0x200)) { //pass on delay to same skill. @@ -4494,7 +4494,7 @@ int mob_read_libconfig(const char *filename, bool ignore_missing) int i = 0, count = 0; nullpo_ret(filename); - sprintf(filepath, "%s/%s", map->db_path, filename); + safesnprintf(filepath, sizeof(filepath), "%s/%s", map->db_path, filename); if (ignore_missing && !exists(filepath)) return 0; @@ -4720,7 +4720,7 @@ void mob_readchatdb(void) { char line[1024], filepath[256]; int i, tmp=0; FILE *fp; - sprintf(filepath, "%s/%s", map->db_path, arc); + safesnprintf(filepath, sizeof(filepath), "%s/%s", map->db_path, arc); fp=fopen(filepath, "r"); if(fp == NULL) { ShowWarning("mob_readchatdb: File not found \"%s\", skipping.\n", filepath); @@ -5046,7 +5046,7 @@ void mob_readskilldb(void) { for( fi = 0; fi < ARRAYLENGTH(filename); ++fi ) { if(fi > 0) { char filepath[256]; - snprintf(filepath, 256, "%s/%s", map->db_path, filename[fi]); + safesnprintf(filepath, 256, "%s/%s", map->db_path, filename[fi]); if(!exists(filepath)) { continue; } diff --git a/src/map/npc.c b/src/map/npc.c index a358fd2fb..38996a0a3 100644 --- a/src/map/npc.c +++ b/src/map/npc.c @@ -2724,10 +2724,10 @@ struct npc_data* npc_add_warp(char* name, short from_mapid, short from_x, short flag = 1; if (flag == 1) - snprintf(nd->exname, ARRAYLENGTH(nd->exname), "warp_%d_%d_%d", from_mapid, from_x, from_y); + safesnprintf(nd->exname, ARRAYLENGTH(nd->exname), "warp_%d_%d_%d", from_mapid, from_x, from_y); for( i = 0; npc->name2id(nd->exname) != NULL; ++i ) - snprintf(nd->exname, ARRAYLENGTH(nd->exname), "warp%d_%d_%d_%d", i, from_mapid, from_x, from_y); + safesnprintf(nd->exname, ARRAYLENGTH(nd->exname), "warp%d_%d_%d_%d", i, from_mapid, from_x, from_y); safestrncpy(nd->name, nd->exname, ARRAYLENGTH(nd->name)); nd->u.warp.mapindex = to_mapindex; diff --git a/src/map/quest.c b/src/map/quest.c index 4e3362adb..4c5dcb59f 100644 --- a/src/map/quest.c +++ b/src/map/quest.c @@ -544,7 +544,7 @@ int quest_read_db(void) int i = 0, count = 0; const char *filename = "quest_db.conf"; - snprintf(filepath, 256, "%s/%s", map->db_path, filename); + safesnprintf(filepath, 256, "%s/%s", map->db_path, filename); if (!libconfig->load_file(&quest_db_conf, filepath)) return -1; diff --git a/src/map/script.c b/src/map/script.c index c23a335c3..31af59891 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -2296,7 +2296,7 @@ void read_constdb(void) struct config_setting_t *t; int i = 0; - snprintf(filepath, 256, "%s/constants.conf", map->db_path); + safesnprintf(filepath, 256, "%s/constants.conf", map->db_path); if (!libconfig->load_file(&constants_conf, filepath)) return; diff --git a/src/map/status.c b/src/map/status.c index 7982b15eb..166b33e6f 100644 --- a/src/map/status.c +++ b/src/map/status.c @@ -7416,6 +7416,7 @@ void status_display_remove(struct map_session_data *sd, enum sc_type type) } } } + /** * Starts a status change. * @@ -7467,73 +7468,8 @@ int status_change_start(struct block_list *src, struct block_list *bl, enum sc_t #endif // 0 } - if( sc->data[SC_REFRESH] ) { - if( type >= SC_COMMON_MIN && type <= SC_COMMON_MAX) // Confirmed. - return 0; // Immune to status ailements - switch( type ) { - case SC_DEEP_SLEEP: - case SC__CHAOS: - case SC_BURNING: - case SC_STUN: - case SC_SLEEP: - case SC_CURSE: - case SC_STONE: - case SC_POISON: - case SC_BLIND: - case SC_SILENCE: - case SC_BLOODING: - case SC_FREEZE: - case SC_FROSTMISTY: - case SC_COLD: - case SC_TOXIN: - case SC_PARALYSE: - case SC_VENOMBLEED: - case SC_MAGICMUSHROOM: - case SC_DEATHHURT: - case SC_PYREXIA: - case SC_OBLIVIONCURSE: - case SC_MARSHOFABYSS: - case SC_MANDRAGORA: - return 0; - } - } else if( sc->data[SC_INSPIRATION] ) { - if( type >= SC_COMMON_MIN && type <= SC_COMMON_MAX ) - return 0; // Immune to status ailements - switch( type ) { - case SC_POISON: - case SC_BLIND: - case SC_STUN: - case SC_SILENCE: - case SC__CHAOS: - case SC_STONE: - case SC_SLEEP: - case SC_BLOODING: - case SC_CURSE: - case SC_BURNING: - case SC_FROSTMISTY: - case SC_FREEZE: - case SC_COLD: - case SC_FEAR: - case SC_TOXIN: - case SC_PARALYSE: - case SC_VENOMBLEED: - case SC_MAGICMUSHROOM: - case SC_DEATHHURT: - case SC_PYREXIA: - case SC_OBLIVIONCURSE: - case SC_LEECHESEND: - case SC_DEEP_SLEEP: - case SC_SATURDAY_NIGHT_FEVER: - case SC__BODYPAINT: - case SC__ENERVATION: - case SC__GROOMY: - case SC__IGNORANCE: - case SC__LAZINESS: - case SC__UNLUCKY: - case SC__WEAKNESS: - return 0; - } - } + if (status->is_immune_to_status(sc, type)) + return 0; sd = BL_CAST(BL_PC, bl); @@ -7543,8 +7479,8 @@ int status_change_start(struct block_list *src, struct block_list *bl, enum sc_t if( !tick ) return 0; } - undead_flag = battle->check_undead(st->race,st->def_ele); - //Check for inmunities / sc fails + undead_flag = battle->check_undead(st->race, st->def_ele); + // Check for inmunities / sc fails switch (type) { case SC_DRUMBATTLE: case SC_NIBELUNGEN: @@ -7809,316 +7745,14 @@ int status_change_start(struct block_list *src, struct block_list *bl, enum sc_t } //Check for BOSS resistances - if(st->mode&MD_BOSS && !(flag&SCFLAG_NOAVOID)) { - if (type>=SC_COMMON_MIN && type <= SC_COMMON_MAX) + if (st->mode & MD_BOSS && !(flag & SCFLAG_NOAVOID)) { + if (status->is_boss_resist_sc(type)) return 0; - switch (type) { - case SC_BLESSING: - case SC_DEC_AGI: - case SC_PROVOKE: - case SC_COMA: - case SC_GRAVITATION: - case SC_NJ_SUITON: - case SC_RICHMANKIM: - case SC_ROKISWEIL: - case SC_FOGWALL: - case SC_FROSTMISTY: - case SC_BURNING: - case SC_MARSHOFABYSS: - case SC_ADORAMUS: - case SC_NEEDLE_OF_PARALYZE: - case SC_DEEP_SLEEP: - case SC_COLD: - - // Exploit prevention - kRO Fix - case SC_PYREXIA: - case SC_DEATHHURT: - case SC_TOXIN: - case SC_PARALYSE: - case SC_VENOMBLEED: - case SC_MAGICMUSHROOM: - case SC_OBLIVIONCURSE: - case SC_LEECHESEND: - - // Ranger Effects - case SC_WUGBITE: - case SC_ELECTRICSHOCKER: - case SC_MAGNETICFIELD: - - // Masquerades - case SC__ENERVATION: - case SC__GROOMY: - case SC__LAZINESS: - case SC__UNLUCKY: - case SC__WEAKNESS: - case SC__IGNORANCE: - - // Other Effects - case SC_VACUUM_EXTREME: - case SC_NETHERWORLD: - case SC_FRESHSHRIMP: - case SC_SV_ROOTTWIST: - case SC_BITESCAR: - return 0; - } } //Before overlapping fail, one must check for status cured. - switch (type) { - case SC_BLESSING: - //TO-DO Blessing and Agi up should do 1 damage against players on Undead Status, even on PvM - //but cannot be plagiarized (this requires aegis investigation on packets and official behavior) [Brainstorm] - if ((!undead_flag && st->race!=RC_DEMON) || bl->type == BL_PC) { - status_change_end(bl, SC_CURSE, INVALID_TIMER); - if (sc->data[SC_STONE] && sc->opt1 == OPT1_STONE) - status_change_end(bl, SC_STONE, INVALID_TIMER); - } - if(sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_HIGH) - status_change_end(bl, SC_SOULLINK, INVALID_TIMER); - break; - case SC_INC_AGI: - status_change_end(bl, SC_DEC_AGI, INVALID_TIMER); - if(sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_HIGH) - status_change_end(bl, SC_SOULLINK, INVALID_TIMER); - break; - case SC_QUAGMIRE: - status_change_end(bl, SC_CONCENTRATION, INVALID_TIMER); - status_change_end(bl, SC_TRUESIGHT, INVALID_TIMER); - status_change_end(bl, SC_WINDWALK, INVALID_TIMER); - FALLTHROUGH - //Also blocks the ones below... - case SC_DEC_AGI: - case SC_ADORAMUS: - status_change_end(bl, SC_CARTBOOST, INVALID_TIMER); - //Also blocks the ones below... - FALLTHROUGH - case SC_DONTFORGETME: - status_change_end(bl, SC_INC_AGI, INVALID_TIMER); - status_change_end(bl, SC_ADRENALINE, INVALID_TIMER); - status_change_end(bl, SC_ADRENALINE2, INVALID_TIMER); - status_change_end(bl, SC_SPEARQUICKEN, INVALID_TIMER); - status_change_end(bl, SC_TWOHANDQUICKEN, INVALID_TIMER); - status_change_end(bl, SC_ONEHANDQUICKEN, INVALID_TIMER); - status_change_end(bl, SC_MER_QUICKEN, INVALID_TIMER); - status_change_end(bl, SC_ACCELERATION, INVALID_TIMER); - break; - case SC_ONEHANDQUICKEN: - //Removes the Aspd potion effect, as reported by Vicious. [Skotlex] - status_change_end(bl, SC_ATTHASTE_POTION1, INVALID_TIMER); - status_change_end(bl, SC_ATTHASTE_POTION2, INVALID_TIMER); - status_change_end(bl, SC_ATTHASTE_POTION3, INVALID_TIMER); - status_change_end(bl, SC_ATTHASTE_INFINITY, INVALID_TIMER); - break; - case SC_OVERTHRUSTMAX: - //Cancels Normal Overthrust. [Skotlex] - status_change_end(bl, SC_OVERTHRUST, INVALID_TIMER); - break; - case SC_KYRIE: - //Cancels Assumptio - status_change_end(bl, SC_ASSUMPTIO, INVALID_TIMER); - break; - case SC_MAGNIFICAT: - //Cancels Offertorium - status_change_end(bl, SC_OFFERTORIUM, INVALID_TIMER); - break; - case SC_OFFERTORIUM: - //Cancels Magnificat - status_change_end(bl, SC_MAGNIFICAT, INVALID_TIMER); - break; - case SC_DELUGE: - if (sc->data[SC_FOGWALL] && sc->data[SC_BLIND]) - status_change_end(bl, SC_BLIND, INVALID_TIMER); - break; - case SC_SILENCE: - if (sc->data[SC_GOSPEL] && sc->data[SC_GOSPEL]->val4 == BCT_SELF) - status_change_end(bl, SC_GOSPEL, INVALID_TIMER); - break; - case SC_HIDING: - status_change_end(bl, SC_RG_CCONFINE_M, INVALID_TIMER); - status_change_end(bl, SC_RG_CCONFINE_S, INVALID_TIMER); - break; - case SC_BERSERK: - if( val3 == SC__BLOODYLUST ) - break; - if(battle_config.berserk_cancels_buffs) { - status_change_end(bl, SC_ONEHANDQUICKEN, INVALID_TIMER); - status_change_end(bl, SC_TWOHANDQUICKEN, INVALID_TIMER); - status_change_end(bl, SC_LKCONCENTRATION, INVALID_TIMER); - status_change_end(bl, SC_PARRYING, INVALID_TIMER); - status_change_end(bl, SC_AURABLADE, INVALID_TIMER); - status_change_end(bl, SC_MER_QUICKEN, INVALID_TIMER); - } - #ifdef RENEWAL - else { - status_change_end(bl, SC_TWOHANDQUICKEN, INVALID_TIMER); - } - #endif - break; - case SC_ASSUMPTIO: - status_change_end(bl, SC_KYRIE, INVALID_TIMER); - status_change_end(bl, SC_KAITE, INVALID_TIMER); - break; - case SC_KAITE: - status_change_end(bl, SC_ASSUMPTIO, INVALID_TIMER); - break; - case SC_CARTBOOST: - if (sc->data[SC_DEC_AGI] || sc->data[SC_ADORAMUS]) { - //Cancel Decrease Agi, but take no further effect [Skotlex] - status_change_end(bl, SC_DEC_AGI, INVALID_TIMER); - status_change_end(bl, SC_ADORAMUS, INVALID_TIMER); - return 0; - } - break; - case SC_FUSION: - status_change_end(bl, SC_SOULLINK, INVALID_TIMER); - break; - case SC_GS_ADJUSTMENT: - status_change_end(bl, SC_GS_MADNESSCANCEL, INVALID_TIMER); - break; - case SC_GS_MADNESSCANCEL: - status_change_end(bl, SC_GS_ADJUSTMENT, INVALID_TIMER); - break; - //NPC_CHANGEUNDEAD will debuff Blessing and Agi Up - case SC_PROPERTYUNDEAD: - status_change_end(bl, SC_BLESSING, INVALID_TIMER); - status_change_end(bl, SC_INC_AGI, INVALID_TIMER); - break; - case SC_FOOD_STR: - status_change_end(bl, SC_FOOD_STR, INVALID_TIMER); - break; - case SC_FOOD_AGI: - status_change_end(bl, SC_FOOD_AGI, INVALID_TIMER); - break; - case SC_FOOD_VIT: - status_change_end(bl, SC_FOOD_VIT, INVALID_TIMER); - break; - case SC_FOOD_INT: - status_change_end(bl, SC_FOOD_INT, INVALID_TIMER); - break; - case SC_FOOD_DEX: - status_change_end(bl, SC_FOOD_DEX, INVALID_TIMER); - break; - case SC_FOOD_LUK: - status_change_end(bl, SC_FOOD_LUK, INVALID_TIMER); - break; - case SC_FOOD_STR_CASH: - status_change_end(bl, SC_FOOD_STR, INVALID_TIMER); - status_change_end(bl, SC_FOOD_STR_CASH, INVALID_TIMER); - break; - case SC_FOOD_AGI_CASH: - status_change_end(bl, SC_FOOD_AGI, INVALID_TIMER); - status_change_end(bl, SC_FOOD_AGI_CASH, INVALID_TIMER); - break; - case SC_FOOD_VIT_CASH: - status_change_end(bl, SC_FOOD_VIT, INVALID_TIMER); - status_change_end(bl, SC_FOOD_VIT_CASH, INVALID_TIMER); - break; - case SC_FOOD_INT_CASH: - status_change_end(bl, SC_FOOD_INT, INVALID_TIMER); - status_change_end(bl, SC_FOOD_INT_CASH, INVALID_TIMER); - break; - case SC_FOOD_DEX_CASH: - status_change_end(bl, SC_FOOD_DEX, INVALID_TIMER); - status_change_end(bl, SC_FOOD_DEX_CASH, INVALID_TIMER); - break; - case SC_FOOD_LUK_CASH: - status_change_end(bl, SC_FOOD_LUK, INVALID_TIMER); - status_change_end(bl, SC_FOOD_LUK_CASH, INVALID_TIMER); - break; - case SC_GM_BATTLE: - status_change_end(bl, SC_GM_BATTLE2, INVALID_TIMER); - break; - case SC_GM_BATTLE2: - status_change_end(bl, SC_GM_BATTLE, INVALID_TIMER); - break; - case SC_ENDURE: - if( val4 == 1 ) - status_change_end(bl, SC_LKCONCENTRATION, INVALID_TIMER); - break; - case SC_FIGHTINGSPIRIT: - case SC_OVERED_BOOST: - status_change_end(bl, type, INVALID_TIMER); // Remove previous one. - break; - case SC_MARSHOFABYSS: - status_change_end(bl, SC_INCAGI, INVALID_TIMER); - status_change_end(bl, SC_WINDWALK, INVALID_TIMER); - status_change_end(bl, SC_ATTHASTE_POTION1, INVALID_TIMER); - status_change_end(bl, SC_ATTHASTE_POTION2, INVALID_TIMER); - status_change_end(bl, SC_ATTHASTE_POTION3, INVALID_TIMER); - status_change_end(bl, SC_ATTHASTE_INFINITY, INVALID_TIMER); - break; - //Group A Status (doesn't overlap) - case SC_SWING: - case SC_SYMPHONY_LOVE: - case SC_MOONLIT_SERENADE: - case SC_RUSH_WINDMILL: - case SC_ECHOSONG: - case SC_HARMONIZE: - case SC_FRIGG_SONG: - if (type != SC_SWING) status_change_end(bl, SC_SWING, INVALID_TIMER); - if (type != SC_SYMPHONY_LOVE) status_change_end(bl, SC_SYMPHONY_LOVE, INVALID_TIMER); - if (type != SC_MOONLIT_SERENADE) status_change_end(bl, SC_MOONLIT_SERENADE, INVALID_TIMER); - if (type != SC_RUSH_WINDMILL) status_change_end(bl, SC_RUSH_WINDMILL, INVALID_TIMER); - if (type != SC_ECHOSONG) status_change_end(bl, SC_ECHOSONG, INVALID_TIMER); - if (type != SC_HARMONIZE) status_change_end(bl, SC_HARMONIZE, INVALID_TIMER); - if (type != SC_FRIGG_SONG) status_change_end(bl, SC_FRIGG_SONG, INVALID_TIMER); - break; - //Group B Status - case SC_SIREN: - case SC_DEEP_SLEEP: - case SC_SIRCLEOFNATURE: - case SC_LERADS_DEW: - case SC_MELODYOFSINK: - case SC_BEYOND_OF_WARCRY: - case SC_UNLIMITED_HUMMING_VOICE: - case SC_GLOOMYDAY: - case SC_SONG_OF_MANA: - case SC_DANCE_WITH_WUG: - if (type != SC_SIREN) status_change_end(bl, SC_SIREN, INVALID_TIMER); - if (type != SC_DEEP_SLEEP) status_change_end(bl, SC_DEEP_SLEEP, INVALID_TIMER); - if (type != SC_SIRCLEOFNATURE) status_change_end(bl, SC_SIRCLEOFNATURE, INVALID_TIMER); - if (type != SC_LERADS_DEW) status_change_end(bl, SC_LERADS_DEW, INVALID_TIMER); - if (type != SC_MELODYOFSINK) status_change_end(bl, SC_MELODYOFSINK, INVALID_TIMER); - if (type != SC_BEYOND_OF_WARCRY) status_change_end(bl, SC_BEYOND_OF_WARCRY, INVALID_TIMER); - if (type != SC_UNLIMITED_HUMMING_VOICE) status_change_end(bl, SC_UNLIMITED_HUMMING_VOICE, INVALID_TIMER); - if (type != SC_GLOOMYDAY) status_change_end(bl, SC_GLOOMYDAY, INVALID_TIMER); - if (type != SC_SONG_OF_MANA) status_change_end(bl, SC_SONG_OF_MANA, INVALID_TIMER); - if (type != SC_DANCE_WITH_WUG) status_change_end(bl, SC_DANCE_WITH_WUG, INVALID_TIMER); - break; - case SC_REFLECTSHIELD: - status_change_end(bl, SC_LG_REFLECTDAMAGE, INVALID_TIMER); - break; - case SC_LG_REFLECTDAMAGE: - status_change_end(bl, SC_REFLECTSHIELD, INVALID_TIMER); - break; - case SC_SHIELDSPELL_DEF: - case SC_SHIELDSPELL_MDEF: - case SC_SHIELDSPELL_REF: - status_change_end(bl, SC_MAGNIFICAT, INVALID_TIMER); - status_change_end(bl, SC_SHIELDSPELL_DEF, INVALID_TIMER); - status_change_end(bl, SC_SHIELDSPELL_MDEF, INVALID_TIMER); - status_change_end(bl, SC_SHIELDSPELL_REF, INVALID_TIMER); - break; - case SC_GENTLETOUCH_ENERGYGAIN: - case SC_GENTLETOUCH_CHANGE: - case SC_GENTLETOUCH_REVITALIZE: - if( type != SC_GENTLETOUCH_REVITALIZE ) - status_change_end(bl, SC_GENTLETOUCH_REVITALIZE, INVALID_TIMER); - if( type != SC_GENTLETOUCH_ENERGYGAIN ) - status_change_end(bl, SC_GENTLETOUCH_ENERGYGAIN, INVALID_TIMER); - if( type != SC_GENTLETOUCH_CHANGE ) - status_change_end(bl, SC_GENTLETOUCH_CHANGE, INVALID_TIMER); - break; - case SC_INVINCIBLE: - status_change_end(bl, SC_INVINCIBLEOFF, INVALID_TIMER); - break; - case SC_INVINCIBLEOFF: - status_change_end(bl, SC_INVINCIBLE, INVALID_TIMER); - break; - case SC_MAGICPOWER: - status_change_end(bl, type, INVALID_TIMER); - break; - } + if (status->end_sc_before_start(bl, st, sc, type, undead_flag, val1, val2, val3, val4)) + return 0; //Check for overlapping fails if( (sce = sc->data[type]) ) { @@ -9866,9 +9500,7 @@ int status_change_start(struct block_list *src, struct block_list *bl, enum sc_t val3 = 25 * val1; // Move speed reduction break; default: - if (calc_flag == SCB_NONE && status->dbs->SkillChangeTable[type] == 0 && status->dbs->IconChangeTable[type] == 0) { - //Status change with no calc, no icon, and no skill associated...? - ShowError("UnknownStatusChange [%d]\n", type); + if (status->change_start_unknown_sc(src, bl, type, calc_flag, rate, val1, val2, val3, val4, tick, flag)) { return 0; } } @@ -9895,27 +9527,239 @@ int status_change_start(struct block_list *src, struct block_list *bl, enum sc_t } /* values that must be set regardless of SCFLAG_LOADED e.g. val_flag */ - switch(type) { + val_flag = status->get_val_flag(type); + + /* [Ind/Hercules] */ + status->change_start_display(sd, type, val1, val2, val3, val4); + + //Those that make you stop attacking/walking.... + status->change_start_stop_action(bl, type); + + // Set option as needed. + opt_flag = status->change_start_set_option(bl, sc, type, val1, val2, val3, val4); + + //On Aegis, when turning on a status change, first goes the option packet, then the sc packet. + if(opt_flag) { + clif->changeoption(bl); + if( sd && opt_flag&0x4 ) { + if (vd) + clif->changelook(bl, LOOK_BASE, vd->class); + clif->changelook(bl,LOOK_WEAPON,0); + clif->changelook(bl,LOOK_SHIELD,0); + if (vd) + clif->changelook(bl,LOOK_CLOTHES_COLOR,vd->cloth_color); + } + } + if (calc_flag&SCB_DYE) { + //Reset DYE color + if (vd && vd->cloth_color) { + val4 = vd->cloth_color; + clif->changelook(bl,LOOK_CLOTHES_COLOR,0); + } + calc_flag&=~SCB_DYE; + } + +#if 0 //Currently No SC's use this + if (calc_flag&SCB_BODY) { + //Reset Body Style + if (vd && vd->body_style) { + val4 = vd->body_style; + clif->changelook(bl,LOOK_BODY2,0); + } + calc_flag&=~SCB_BODY; + } +#endif + + if(!(flag&SCFLAG_NOICON) && !(flag&SCFLAG_LOADED && status->dbs->DisplayType[type])) + clif->status_change(bl,status->dbs->IconChangeTable[type],1,tick,(val_flag&1)?val1:1,(val_flag&2)?val2:0,(val_flag&4)?val3:0); + + /** + * used as temporary storage for scs with interval ticks, so that the actual duration is sent to the client first. + **/ + if( tick_time ) + tick = tick_time; + + //Don't trust the previous sce assignment, in case the SC ended somewhere between there and here. + if((sce=sc->data[type])) {// reuse old sc + if( sce->timer != INVALID_TIMER ) + timer->delete(sce->timer, status->change_timer); + } else {// new sc + ++(sc->count); + sce = sc->data[type] = ers_alloc(status->data_ers, struct status_change_entry); + } + + sce->val1 = val1; + sce->val2 = val2; + sce->val3 = val3; + sce->val4 = val4; + + if (tick >= 0) { + sce->timer = timer->add(timer->gettick() + tick, status->change_timer, bl->id, type); + sce->infinite_duration = false; + } else { + sce->timer = INVALID_TIMER; //Infinite duration + sce->infinite_duration = true; + if( sd ) + chrif->save_scdata_single(sd->status.account_id,sd->status.char_id,type,sce); + } + + if (calc_flag) + status_calc_bl(bl,calc_flag); + + if(sd && sd->pd) + pet->sc_check(sd, type); //Skotlex: Pet Status Effect Healing + + switch (type) { + case SC_BERSERK: + if (!(sce->val2)) { //don't heal if already set + status->heal(bl, st->max_hp, 0, 1); //Do not use percent_heal as this healing must override BERSERK's block. + status->set_sp(bl, 0, 0); //Damage all SP + } + sce->val2 = 5 * st->max_hp / 100; + break; + case SC_HLIF_CHANGE: + status_percent_heal(bl, 100, 100); + break; + case SC_RUN: + { + struct unit_data *ud = unit->bl2ud(bl); + if( ud ) + ud->state.running = unit->run(bl, NULL, SC_RUN); + } + break; + case SC_CASH_BOSS_ALARM: + if( sd ) + clif->bossmapinfo(sd->fd, map->id2boss(sce->val1), 0); // First Message + break; + case SC_MER_HP: + status_percent_heal(bl, 100, 0); // Recover Full HP + break; + case SC_MER_SP: + status_percent_heal(bl, 0, 100); // Recover Full SP + break; + case SC_PROMOTE_HEALTH_RESERCH: + status_percent_heal(bl, sce->val4, 0); + break; + case SC_ENERGY_DRINK_RESERCH: + status_percent_heal(bl, 0, sce->val4); + break; + /** + * Ranger + **/ + case SC_WUGDASH: + { + struct unit_data *ud = unit->bl2ud(bl); + if( ud ) + ud->state.running = unit->run(bl, sd, SC_WUGDASH); + } + break; + case SC_COMBOATTACK: + switch (sce->val1) { + case TK_STORMKICK: + clif->skill_nodamage(bl,bl,TK_READYSTORM,1,1); + break; + case TK_DOWNKICK: + clif->skill_nodamage(bl,bl,TK_READYDOWN,1,1); + break; + case TK_TURNKICK: + clif->skill_nodamage(bl,bl,TK_READYTURN,1,1); + break; + case TK_COUNTER: + clif->skill_nodamage(bl,bl,TK_READYCOUNTER,1,1); + break; + case MO_COMBOFINISH: + case CH_TIGERFIST: + case CH_CHAINCRUSH: + if (sd) + clif->skillinfo(sd,MO_EXTREMITYFIST, INF_SELF_SKILL); + break; + case TK_JUMPKICK: + if (sd) + clif->skillinfo(sd,TK_JUMPKICK, INF_SELF_SKILL); + break; + case MO_TRIPLEATTACK: + if (sd && pc->checkskill(sd, SR_DRAGONCOMBO) > 0) + clif->skillinfo(sd,SR_DRAGONCOMBO, INF_SELF_SKILL); + break; + case SR_FALLENEMPIRE: + if (sd){ + clif->skillinfo(sd,SR_GATEOFHELL, INF_SELF_SKILL); + clif->skillinfo(sd,SR_TIGERCANNON, INF_SELF_SKILL); + } + break; + } + break; + case SC_RAISINGDRAGON: + sce->val2 = st->max_hp / 100;// Officially tested its 1%hp drain. [Jobbie] + break; + } + + if( opt_flag&2 && sd && sd->touching_id ) + npc->touchnext_areanpc(sd,false); // run OnTouch_ on next char in range + + return 1; +} + +bool status_change_start_unknown_sc(struct block_list *src, struct block_list *bl, enum sc_type type, int calc_flag, int rate, int val1, int val2, int val3, int val4, int tick, int flag) +{ + Assert_retr(false, type >= SC_NONE && type < SC_MAX); + if (calc_flag == SCB_NONE && status->dbs->SkillChangeTable[type] == 0 && status->dbs->IconChangeTable[type] == 0) { + //Status change with no calc, no icon, and no skill associated...? + ShowError("UnknownStatusChange [%d]\n", type); + return true; + } + return false; +} + +void status_change_start_display(struct map_session_data *sd, enum sc_type type, int val1, int val2, int val3, int val4) +{ + Assert_retv(type >= SC_NONE && type < SC_MAX); + + if (sd && status->dbs->DisplayType[type]) { + int dval1 = 0, dval2 = 0, dval3 = 0; + switch (type) { + case SC_ALL_RIDING: + dval1 = 1; + break; + default: /* all others: just copy val1 */ + dval1 = val1; + break; + } + status->display_add(sd, type, dval1, dval2, dval3); + } +} + +/** + * Return val_flag based on sc type. + * + * @param type Status change type. + * + * @retval val_flag. + */ +int status_get_val_flag(enum sc_type type) +{ + int val_flag = 0; + switch (type) { case SC_FIGHTINGSPIRIT: - val_flag |= 1|2; + val_flag |= 1 | 2; break; case SC_VENOMIMPRESS: - val_flag |= 1|2; + val_flag |= 1 | 2; break; case SC_POISONINGWEAPON: - val_flag |= 1|2|4; + val_flag |= 1 | 2 | 4; break; case SC_WEAPONBLOCKING: - val_flag |= 1|2; + val_flag |= 1 | 2; break; case SC_ROLLINGCUTTER: val_flag |= 1; break; case SC_CLOAKINGEXCEED: - val_flag |= 1|2|4; + val_flag |= 1 | 2 | 4; break; case SC_HALLUCINATIONWALK: - val_flag |= 1|2|4; + val_flag |= 1 | 2 | 4; break; case SC_SUMMON1: case SC_SUMMON2: @@ -9925,34 +9769,34 @@ int status_change_start(struct block_list *src, struct block_list *bl, enum sc_t val_flag |= 1; break; case SC__SHADOWFORM: - val_flag |= 1|2|4; + val_flag |= 1 | 2 | 4; break; case SC__INVISIBILITY: - val_flag |= 1|2; + val_flag |= 1 | 2; break; case SC__ENERVATION: - val_flag |= 1|2; + val_flag |= 1 | 2; break; case SC__GROOMY: - val_flag |= 1|2|4; + val_flag |= 1 | 2 | 4; break; case SC__LAZINESS: - val_flag |= 1|2|4; + val_flag |= 1 | 2 | 4; break; case SC__UNLUCKY: - val_flag |= 1|2|4; + val_flag |= 1 | 2 | 4; break; case SC__WEAKNESS: - val_flag |= 1|2; + val_flag |= 1 | 2; break; case SC_PROPERTYWALK: - val_flag |= 1|2; + val_flag |= 1 | 2; break; case SC_FORCEOFVANGUARD: - val_flag |= 1|2|4; + val_flag |= 1 | 2 | 4; break; case SC_PRESTIGE: - val_flag |= 1|2; + val_flag |= 1 | 2; break; case SC_BANDING: val_flag |= 1; @@ -9960,56 +9804,56 @@ int status_change_start(struct block_list *src, struct block_list *bl, enum sc_t case SC_SHIELDSPELL_DEF: case SC_SHIELDSPELL_MDEF: case SC_SHIELDSPELL_REF: - val_flag |= 1|2; + val_flag |= 1 | 2; break; case SC_SPELLFIST: case SC_CURSEDCIRCLE_ATKER: - val_flag |= 1|2|4; + val_flag |= 1 | 2 | 4; break; case SC_CRESCENTELBOW: - val_flag |= 1|2; + val_flag |= 1 | 2; break; case SC_LIGHTNINGWALK: val_flag |= 1; break; case SC_PYROTECHNIC_OPTION: - val_flag |= 1|2|4; + val_flag |= 1 | 2 | 4; break; case SC_HEATER_OPTION: - val_flag |= 1|2|4; + val_flag |= 1 | 2 | 4; break; case SC_AQUAPLAY_OPTION: - val_flag |= 1|2|4; + val_flag |= 1 | 2 | 4; break; case SC_COOLER_OPTION: - val_flag |= 1|2|4; + val_flag |= 1 | 2 | 4; break; case SC_CHILLY_AIR_OPTION: - val_flag |= 1|2; + val_flag |= 1 | 2; break; case SC_GUST_OPTION: - val_flag |= 1|2; + val_flag |= 1 | 2; break; case SC_BLAST_OPTION: - val_flag |= 1|2|4; + val_flag |= 1 | 2 | 4; break; case SC_WILD_STORM_OPTION: - val_flag |= 1|2; + val_flag |= 1 | 2; break; case SC_PETROLOGY_OPTION: - val_flag |= 1|2|4; + val_flag |= 1 | 2 | 4; break; case SC_CURSED_SOIL_OPTION: - val_flag |= 1|2|4; + val_flag |= 1 | 2 | 4; break; case SC_UPHEAVAL_OPTION: - val_flag |= 1|2; + val_flag |= 1 | 2; break; case SC_CIRCLE_OF_FIRE_OPTION: - val_flag |= 1|2; + val_flag |= 1 | 2; break; case SC_WATER_BARRIER: - val_flag |= 1|2|4; + val_flag |= 1 | 2 | 4; break; case SC_KYOUGAKU: val_flag |= 1; @@ -10022,90 +9866,29 @@ int status_change_start(struct block_list *src, struct block_list *bl, enum sc_t val_flag |= 1; break; } + return val_flag; +} - /* [Ind/Hercules] */ - if( sd && status->dbs->DisplayType[type] ) { - int dval1 = 0, dval2 = 0, dval3 = 0; - switch( type ) { - case SC_ALL_RIDING: - dval1 = 1; - break; - default: /* all others: just copy val1 */ - dval1 = val1; - break; - } - status->display_add(sd,type,dval1,dval2,dval3); - } +/** + * Set new status values. + * + * @param bl Status change target bl. + * @param sc Current statuses. + * @param type Status change type. + * @param val1 Additional value (meaning depends on type). + * @param val2 Additional value (meaning depends on type). + * @param val3 Additional value (meaning depends on type). + * @param val4 Additional value (meaning depends on type). + * + * @retval option flag. + */ +int status_change_start_set_option(struct block_list *bl, struct status_change* sc, enum sc_type type, int val1, int val2, int val3, int val4) +{ + int opt_flag = 1; - //Those that make you stop attacking/walking.... + nullpo_retr(true, bl); + nullpo_retr(true, sc); switch (type) { - case SC_VACUUM_EXTREME: - if(!map_flag_gvg(bl->m)) - unit->stop_walking(bl,1); - break; - case SC_FREEZE: - case SC_STUN: - case SC_SLEEP: - case SC_STONE: - case SC_DEEP_SLEEP: - if (sd && pc_issit(sd)) //Avoid sprite sync problems. - pc->setstand(sd); - FALLTHROUGH - case SC_TRICKDEAD: - status_change_end(bl, SC_DANCING, INVALID_TIMER); - // Cancel cast when get status [LuzZza] - if (battle_config.sc_castcancel&bl->type) - unit->skillcastcancel(bl, 0); - FALLTHROUGH - case SC_FALLENEMPIRE: - case SC_WHITEIMPRISON: - unit->stop_attack(bl); - FALLTHROUGH - case SC_STOP: - case SC_CONFUSION: - case SC_RG_CCONFINE_M: - case SC_RG_CCONFINE_S: - case SC_SPIDERWEB: - case SC_ELECTRICSHOCKER: - case SC_WUGBITE: - case SC_THORNS_TRAP: - case SC__MANHOLE: - case SC__CHAOS: - case SC_COLD: - case SC_CURSEDCIRCLE_ATKER: - case SC_CURSEDCIRCLE_TARGET: - case SC_FEAR: - case SC_MEIKYOUSISUI: - case SC_NEEDLE_OF_PARALYZE: - case SC_DEATHBOUND: - case SC_NETHERWORLD: - case SC_SV_ROOTTWIST: - unit->stop_walking(bl, STOPWALKING_FLAG_FIXPOS); - break; - case SC_ANKLESNARE: - if( battle_config.skill_trap_type || !map_flag_gvg(bl->m) ) - unit->stop_walking(bl, STOPWALKING_FLAG_FIXPOS); - break; - case SC_HIDING: - case SC_CLOAKING: - case SC_CLOAKINGEXCEED: - case SC_CHASEWALK: - case SC_WEIGHTOVER90: - case SC_CAMOUFLAGE: - case SC_SIREN: - case SC_ALL_RIDING: - case SC_SUHIDE: - unit->stop_attack(bl); - break; - case SC_SILENCE: - if (battle_config.sc_castcancel&bl->type) - unit->skillcastcancel(bl, 0); - break; - } - - // Set option as needed. - opt_flag = 1; - switch(type) { //OPT1 case SC_STONE: sc->opt1 = OPT1_STONEWAIT; break; case SC_FREEZE: sc->opt1 = OPT1_FREEZE; break; @@ -10183,7 +9966,7 @@ int status_change_start(struct block_list *src, struct block_list *bl, enum sc_t break; #endif // 0 case SC_DANCING: - if ((val1&0xFFFF) == CG_MOONLIT) + if ((val1 & 0xFFFF) == CG_MOONLIT) sc->opt3 |= OPT3_MOONLIT; opt_flag = 0; break; @@ -10280,167 +10063,511 @@ int status_change_start(struct block_list *src, struct block_list *bl, enum sc_t default: opt_flag = 0; } + return opt_flag; +} - //On Aegis, when turning on a status change, first goes the option packet, then the sc packet. - if(opt_flag) { - clif->changeoption(bl); - if( sd && opt_flag&0x4 ) { - if (vd) - clif->changelook(bl, LOOK_BASE, vd->class); - clif->changelook(bl,LOOK_WEAPON,0); - clif->changelook(bl,LOOK_SHIELD,0); - if (vd) - clif->changelook(bl,LOOK_CLOTHES_COLOR,vd->cloth_color); - } - } - if (calc_flag&SCB_DYE) { - //Reset DYE color - if (vd && vd->cloth_color) { - val4 = vd->cloth_color; - clif->changelook(bl,LOOK_CLOTHES_COLOR,0); - } - calc_flag&=~SCB_DYE; - } - -#if 0 //Currently No SC's use this - if (calc_flag&SCB_BODY) { - //Reset Body Style - if (vd && vd->body_style) { - val4 = vd->body_style; - clif->changelook(bl,LOOK_BODY2,0); +/** + * Stop actions before start new sc. + * + * @param bl Status change target bl. + * @param type Status change type. + */ +void status_change_start_stop_action(struct block_list *bl, enum sc_type type) +{ + nullpo_retv(bl); + switch (type) { + case SC_VACUUM_EXTREME: + if (!map_flag_gvg(bl->m)) + unit->stop_walking(bl,1); + break; + case SC_FREEZE: + case SC_STUN: + case SC_SLEEP: + case SC_STONE: + case SC_DEEP_SLEEP: { + struct map_session_data *sd = BL_CAST(BL_PC, bl); + if (sd && pc_issit(sd)) //Avoid sprite sync problems. + pc->setstand(sd); + FALLTHROUGH } - calc_flag&=~SCB_BODY; - } -#endif - - if(!(flag&SCFLAG_NOICON) && !(flag&SCFLAG_LOADED && status->dbs->DisplayType[type])) - clif->status_change(bl,status->dbs->IconChangeTable[type],1,tick,(val_flag&1)?val1:1,(val_flag&2)?val2:0,(val_flag&4)?val3:0); - - /** - * used as temporary storage for scs with interval ticks, so that the actual duration is sent to the client first. - **/ - if( tick_time ) - tick = tick_time; - - //Don't trust the previous sce assignment, in case the SC ended somewhere between there and here. - if((sce=sc->data[type])) {// reuse old sc - if( sce->timer != INVALID_TIMER ) - timer->delete(sce->timer, status->change_timer); - } else {// new sc - ++(sc->count); - sce = sc->data[type] = ers_alloc(status->data_ers, struct status_change_entry); - } - - sce->val1 = val1; - sce->val2 = val2; - sce->val3 = val3; - sce->val4 = val4; - - if (tick >= 0) { - sce->timer = timer->add(timer->gettick() + tick, status->change_timer, bl->id, type); - sce->infinite_duration = false; - } else { - sce->timer = INVALID_TIMER; //Infinite duration - sce->infinite_duration = true; - if( sd ) - chrif->save_scdata_single(sd->status.account_id,sd->status.char_id,type,sce); + case SC_TRICKDEAD: + status_change_end(bl, SC_DANCING, INVALID_TIMER); + // Cancel cast when get status [LuzZza] + if (battle_config.sc_castcancel&bl->type) + unit->skillcastcancel(bl, 0); + FALLTHROUGH + case SC_FALLENEMPIRE: + case SC_WHITEIMPRISON: + unit->stop_attack(bl); + FALLTHROUGH + case SC_STOP: + case SC_CONFUSION: + case SC_RG_CCONFINE_M: + case SC_RG_CCONFINE_S: + case SC_SPIDERWEB: + case SC_ELECTRICSHOCKER: + case SC_WUGBITE: + case SC_THORNS_TRAP: + case SC__MANHOLE: + case SC__CHAOS: + case SC_COLD: + case SC_CURSEDCIRCLE_ATKER: + case SC_CURSEDCIRCLE_TARGET: + case SC_FEAR: + case SC_MEIKYOUSISUI: + case SC_NEEDLE_OF_PARALYZE: + case SC_DEATHBOUND: + case SC_NETHERWORLD: + case SC_SV_ROOTTWIST: + unit->stop_walking(bl, STOPWALKING_FLAG_FIXPOS); + break; + case SC_ANKLESNARE: + if (battle_config.skill_trap_type || !map_flag_gvg(bl->m)) + unit->stop_walking(bl, STOPWALKING_FLAG_FIXPOS); + break; + case SC_HIDING: + case SC_CLOAKING: + case SC_CLOAKINGEXCEED: + case SC_CHASEWALK: + case SC_WEIGHTOVER90: + case SC_CAMOUFLAGE: + case SC_SIREN: + case SC_ALL_RIDING: + case SC_SUHIDE: + unit->stop_attack(bl); + break; + case SC_SILENCE: + if (battle_config.sc_castcancel & bl->type) + unit->skillcastcancel(bl, 0); + break; } +} - if (calc_flag) - status_calc_bl(bl,calc_flag); - - if(sd && sd->pd) - pet->sc_check(sd, type); //Skotlex: Pet Status Effect Healing +/** + * End sc before starting other sc. + * + * @param bl Status change target bl. + * @param st Status change data. + * @param sc Current statuses. + * @param type Status change type. + * @param undead_flag is bl undead. + * @param val1 Additional value (meaning depends on type). + * @param val2 Additional value (meaning depends on type). + * @param val3 Additional value (meaning depends on type). + * @param val4 Additional value (meaning depends on type). + * + * @retval 0 if no status change happened. + * @retval 1 if the status change was successfully applied. + */ +bool status_end_sc_before_start(struct block_list *bl, struct status_data *st, struct status_change* sc, enum sc_type type, int undead_flag, int val1, int val2, int val3, int val4) +{ + nullpo_retr(true, bl); + nullpo_retr(true, st); + nullpo_retr(true, sc); switch (type) { - case SC_BERSERK: - if (!(sce->val2)) { //don't heal if already set - status->heal(bl, st->max_hp, 0, 1); //Do not use percent_heal as this healing must override BERSERK's block. - status->set_sp(bl, 0, 0); //Damage all SP + case SC_BLESSING: + //TO-DO Blessing and Agi up should do 1 damage against players on Undead Status, even on PvM + //but cannot be plagiarized (this requires aegis investigation on packets and official behavior) [Brainstorm] + if ((!undead_flag && st->race != RC_DEMON) || bl->type == BL_PC) { + status_change_end(bl, SC_CURSE, INVALID_TIMER); + if (sc->data[SC_STONE] && sc->opt1 == OPT1_STONE) + status_change_end(bl, SC_STONE, INVALID_TIMER); } - sce->val2 = 5 * st->max_hp / 100; + if (sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_HIGH) + status_change_end(bl, SC_SOULLINK, INVALID_TIMER); break; - case SC_HLIF_CHANGE: - status_percent_heal(bl, 100, 100); + case SC_INC_AGI: + status_change_end(bl, SC_DEC_AGI, INVALID_TIMER); + if (sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_HIGH) + status_change_end(bl, SC_SOULLINK, INVALID_TIMER); break; - case SC_RUN: - { - struct unit_data *ud = unit->bl2ud(bl); - if( ud ) - ud->state.running = unit->run(bl, NULL, SC_RUN); - } + case SC_QUAGMIRE: + status_change_end(bl, SC_CONCENTRATION, INVALID_TIMER); + status_change_end(bl, SC_TRUESIGHT, INVALID_TIMER); + status_change_end(bl, SC_WINDWALK, INVALID_TIMER); + FALLTHROUGH + //Also blocks the ones below... + case SC_DEC_AGI: + case SC_ADORAMUS: + status_change_end(bl, SC_CARTBOOST, INVALID_TIMER); + //Also blocks the ones below... + FALLTHROUGH + case SC_DONTFORGETME: + status_change_end(bl, SC_INC_AGI, INVALID_TIMER); + status_change_end(bl, SC_ADRENALINE, INVALID_TIMER); + status_change_end(bl, SC_ADRENALINE2, INVALID_TIMER); + status_change_end(bl, SC_SPEARQUICKEN, INVALID_TIMER); + status_change_end(bl, SC_TWOHANDQUICKEN, INVALID_TIMER); + status_change_end(bl, SC_ONEHANDQUICKEN, INVALID_TIMER); + status_change_end(bl, SC_MER_QUICKEN, INVALID_TIMER); + status_change_end(bl, SC_ACCELERATION, INVALID_TIMER); break; - case SC_CASH_BOSS_ALARM: - if( sd ) - clif->bossmapinfo(sd->fd, map->id2boss(sce->val1), 0); // First Message + case SC_ONEHANDQUICKEN: + //Removes the Aspd potion effect, as reported by Vicious. [Skotlex] + status_change_end(bl, SC_ATTHASTE_POTION1, INVALID_TIMER); + status_change_end(bl, SC_ATTHASTE_POTION2, INVALID_TIMER); + status_change_end(bl, SC_ATTHASTE_POTION3, INVALID_TIMER); + status_change_end(bl, SC_ATTHASTE_INFINITY, INVALID_TIMER); break; - case SC_MER_HP: - status_percent_heal(bl, 100, 0); // Recover Full HP + case SC_OVERTHRUSTMAX: + //Cancels Normal Overthrust. [Skotlex] + status_change_end(bl, SC_OVERTHRUST, INVALID_TIMER); break; - case SC_MER_SP: - status_percent_heal(bl, 0, 100); // Recover Full SP + case SC_KYRIE: + //Cancels Assumptio + status_change_end(bl, SC_ASSUMPTIO, INVALID_TIMER); break; - case SC_PROMOTE_HEALTH_RESERCH: - status_percent_heal(bl, sce->val4, 0); + case SC_MAGNIFICAT: + //Cancels Offertorium + status_change_end(bl, SC_OFFERTORIUM, INVALID_TIMER); break; - case SC_ENERGY_DRINK_RESERCH: - status_percent_heal(bl, 0, sce->val4); + case SC_OFFERTORIUM: + //Cancels Magnificat + status_change_end(bl, SC_MAGNIFICAT, INVALID_TIMER); break; - /** - * Ranger - **/ - case SC_WUGDASH: - { - struct unit_data *ud = unit->bl2ud(bl); - if( ud ) - ud->state.running = unit->run(bl, sd, SC_WUGDASH); - } + case SC_DELUGE: + if (sc->data[SC_FOGWALL] && sc->data[SC_BLIND]) + status_change_end(bl, SC_BLIND, INVALID_TIMER); break; - case SC_COMBOATTACK: - switch (sce->val1) { - case TK_STORMKICK: - clif->skill_nodamage(bl,bl,TK_READYSTORM,1,1); - break; - case TK_DOWNKICK: - clif->skill_nodamage(bl,bl,TK_READYDOWN,1,1); - break; - case TK_TURNKICK: - clif->skill_nodamage(bl,bl,TK_READYTURN,1,1); - break; - case TK_COUNTER: - clif->skill_nodamage(bl,bl,TK_READYCOUNTER,1,1); - break; - case MO_COMBOFINISH: - case CH_TIGERFIST: - case CH_CHAINCRUSH: - if (sd) - clif->skillinfo(sd,MO_EXTREMITYFIST, INF_SELF_SKILL); - break; - case TK_JUMPKICK: - if (sd) - clif->skillinfo(sd,TK_JUMPKICK, INF_SELF_SKILL); - break; - case MO_TRIPLEATTACK: - if (sd && pc->checkskill(sd, SR_DRAGONCOMBO) > 0) - clif->skillinfo(sd,SR_DRAGONCOMBO, INF_SELF_SKILL); - break; - case SR_FALLENEMPIRE: - if (sd){ - clif->skillinfo(sd,SR_GATEOFHELL, INF_SELF_SKILL); - clif->skillinfo(sd,SR_TIGERCANNON, INF_SELF_SKILL); - } + case SC_SILENCE: + if (sc->data[SC_GOSPEL] && sc->data[SC_GOSPEL]->val4 == BCT_SELF) + status_change_end(bl, SC_GOSPEL, INVALID_TIMER); + break; + case SC_HIDING: + status_change_end(bl, SC_RG_CCONFINE_M, INVALID_TIMER); + status_change_end(bl, SC_RG_CCONFINE_S, INVALID_TIMER); + break; + case SC_BERSERK: + if (val3 == SC__BLOODYLUST) break; + if (battle_config.berserk_cancels_buffs) { + status_change_end(bl, SC_ONEHANDQUICKEN, INVALID_TIMER); + status_change_end(bl, SC_TWOHANDQUICKEN, INVALID_TIMER); + status_change_end(bl, SC_LKCONCENTRATION, INVALID_TIMER); + status_change_end(bl, SC_PARRYING, INVALID_TIMER); + status_change_end(bl, SC_AURABLADE, INVALID_TIMER); + status_change_end(bl, SC_MER_QUICKEN, INVALID_TIMER); + } + #ifdef RENEWAL + else { + status_change_end(bl, SC_TWOHANDQUICKEN, INVALID_TIMER); } + #endif break; - case SC_RAISINGDRAGON: - sce->val2 = st->max_hp / 100;// Officially tested its 1%hp drain. [Jobbie] + case SC_ASSUMPTIO: + status_change_end(bl, SC_KYRIE, INVALID_TIMER); + status_change_end(bl, SC_KAITE, INVALID_TIMER); + break; + case SC_KAITE: + status_change_end(bl, SC_ASSUMPTIO, INVALID_TIMER); + break; + case SC_CARTBOOST: + if (sc->data[SC_DEC_AGI] || sc->data[SC_ADORAMUS]) { + //Cancel Decrease Agi, but take no further effect [Skotlex] + status_change_end(bl, SC_DEC_AGI, INVALID_TIMER); + status_change_end(bl, SC_ADORAMUS, INVALID_TIMER); + return true; + } + break; + case SC_FUSION: + status_change_end(bl, SC_SOULLINK, INVALID_TIMER); + break; + case SC_GS_ADJUSTMENT: + status_change_end(bl, SC_GS_MADNESSCANCEL, INVALID_TIMER); + break; + case SC_GS_MADNESSCANCEL: + status_change_end(bl, SC_GS_ADJUSTMENT, INVALID_TIMER); + break; + //NPC_CHANGEUNDEAD will debuff Blessing and Agi Up + case SC_PROPERTYUNDEAD: + status_change_end(bl, SC_BLESSING, INVALID_TIMER); + status_change_end(bl, SC_INC_AGI, INVALID_TIMER); + break; + case SC_FOOD_STR: + status_change_end(bl, SC_FOOD_STR, INVALID_TIMER); + break; + case SC_FOOD_AGI: + status_change_end(bl, SC_FOOD_AGI, INVALID_TIMER); + break; + case SC_FOOD_VIT: + status_change_end(bl, SC_FOOD_VIT, INVALID_TIMER); + break; + case SC_FOOD_INT: + status_change_end(bl, SC_FOOD_INT, INVALID_TIMER); + break; + case SC_FOOD_DEX: + status_change_end(bl, SC_FOOD_DEX, INVALID_TIMER); + break; + case SC_FOOD_LUK: + status_change_end(bl, SC_FOOD_LUK, INVALID_TIMER); + break; + case SC_FOOD_STR_CASH: + status_change_end(bl, SC_FOOD_STR, INVALID_TIMER); + status_change_end(bl, SC_FOOD_STR_CASH, INVALID_TIMER); + break; + case SC_FOOD_AGI_CASH: + status_change_end(bl, SC_FOOD_AGI, INVALID_TIMER); + status_change_end(bl, SC_FOOD_AGI_CASH, INVALID_TIMER); + break; + case SC_FOOD_VIT_CASH: + status_change_end(bl, SC_FOOD_VIT, INVALID_TIMER); + status_change_end(bl, SC_FOOD_VIT_CASH, INVALID_TIMER); + break; + case SC_FOOD_INT_CASH: + status_change_end(bl, SC_FOOD_INT, INVALID_TIMER); + status_change_end(bl, SC_FOOD_INT_CASH, INVALID_TIMER); + break; + case SC_FOOD_DEX_CASH: + status_change_end(bl, SC_FOOD_DEX, INVALID_TIMER); + status_change_end(bl, SC_FOOD_DEX_CASH, INVALID_TIMER); + break; + case SC_FOOD_LUK_CASH: + status_change_end(bl, SC_FOOD_LUK, INVALID_TIMER); + status_change_end(bl, SC_FOOD_LUK_CASH, INVALID_TIMER); + break; + case SC_GM_BATTLE: + status_change_end(bl, SC_GM_BATTLE2, INVALID_TIMER); + break; + case SC_GM_BATTLE2: + status_change_end(bl, SC_GM_BATTLE, INVALID_TIMER); + break; + case SC_ENDURE: + if (val4 == 1) + status_change_end(bl, SC_LKCONCENTRATION, INVALID_TIMER); + break; + case SC_FIGHTINGSPIRIT: + case SC_OVERED_BOOST: + status_change_end(bl, type, INVALID_TIMER); // Remove previous one. + break; + case SC_MARSHOFABYSS: + status_change_end(bl, SC_INCAGI, INVALID_TIMER); + status_change_end(bl, SC_WINDWALK, INVALID_TIMER); + status_change_end(bl, SC_ATTHASTE_POTION1, INVALID_TIMER); + status_change_end(bl, SC_ATTHASTE_POTION2, INVALID_TIMER); + status_change_end(bl, SC_ATTHASTE_POTION3, INVALID_TIMER); + status_change_end(bl, SC_ATTHASTE_INFINITY, INVALID_TIMER); + break; + //Group A Status (doesn't overlap) + case SC_SWING: + case SC_SYMPHONY_LOVE: + case SC_MOONLIT_SERENADE: + case SC_RUSH_WINDMILL: + case SC_ECHOSONG: + case SC_HARMONIZE: + case SC_FRIGG_SONG: + if (type != SC_SWING) status_change_end(bl, SC_SWING, INVALID_TIMER); + if (type != SC_SYMPHONY_LOVE) status_change_end(bl, SC_SYMPHONY_LOVE, INVALID_TIMER); + if (type != SC_MOONLIT_SERENADE) status_change_end(bl, SC_MOONLIT_SERENADE, INVALID_TIMER); + if (type != SC_RUSH_WINDMILL) status_change_end(bl, SC_RUSH_WINDMILL, INVALID_TIMER); + if (type != SC_ECHOSONG) status_change_end(bl, SC_ECHOSONG, INVALID_TIMER); + if (type != SC_HARMONIZE) status_change_end(bl, SC_HARMONIZE, INVALID_TIMER); + if (type != SC_FRIGG_SONG) status_change_end(bl, SC_FRIGG_SONG, INVALID_TIMER); + break; + //Group B Status + case SC_SIREN: + case SC_DEEP_SLEEP: + case SC_SIRCLEOFNATURE: + case SC_LERADS_DEW: + case SC_MELODYOFSINK: + case SC_BEYOND_OF_WARCRY: + case SC_UNLIMITED_HUMMING_VOICE: + case SC_GLOOMYDAY: + case SC_SONG_OF_MANA: + case SC_DANCE_WITH_WUG: + if (type != SC_SIREN) status_change_end(bl, SC_SIREN, INVALID_TIMER); + if (type != SC_DEEP_SLEEP) status_change_end(bl, SC_DEEP_SLEEP, INVALID_TIMER); + if (type != SC_SIRCLEOFNATURE) status_change_end(bl, SC_SIRCLEOFNATURE, INVALID_TIMER); + if (type != SC_LERADS_DEW) status_change_end(bl, SC_LERADS_DEW, INVALID_TIMER); + if (type != SC_MELODYOFSINK) status_change_end(bl, SC_MELODYOFSINK, INVALID_TIMER); + if (type != SC_BEYOND_OF_WARCRY) status_change_end(bl, SC_BEYOND_OF_WARCRY, INVALID_TIMER); + if (type != SC_UNLIMITED_HUMMING_VOICE) status_change_end(bl, SC_UNLIMITED_HUMMING_VOICE, INVALID_TIMER); + if (type != SC_GLOOMYDAY) status_change_end(bl, SC_GLOOMYDAY, INVALID_TIMER); + if (type != SC_SONG_OF_MANA) status_change_end(bl, SC_SONG_OF_MANA, INVALID_TIMER); + if (type != SC_DANCE_WITH_WUG) status_change_end(bl, SC_DANCE_WITH_WUG, INVALID_TIMER); + break; + case SC_REFLECTSHIELD: + status_change_end(bl, SC_LG_REFLECTDAMAGE, INVALID_TIMER); + break; + case SC_LG_REFLECTDAMAGE: + status_change_end(bl, SC_REFLECTSHIELD, INVALID_TIMER); + break; + case SC_SHIELDSPELL_DEF: + case SC_SHIELDSPELL_MDEF: + case SC_SHIELDSPELL_REF: + status_change_end(bl, SC_MAGNIFICAT, INVALID_TIMER); + status_change_end(bl, SC_SHIELDSPELL_DEF, INVALID_TIMER); + status_change_end(bl, SC_SHIELDSPELL_MDEF, INVALID_TIMER); + status_change_end(bl, SC_SHIELDSPELL_REF, INVALID_TIMER); + break; + case SC_GENTLETOUCH_ENERGYGAIN: + case SC_GENTLETOUCH_CHANGE: + case SC_GENTLETOUCH_REVITALIZE: + if (type != SC_GENTLETOUCH_REVITALIZE) + status_change_end(bl, SC_GENTLETOUCH_REVITALIZE, INVALID_TIMER); + if (type != SC_GENTLETOUCH_ENERGYGAIN) + status_change_end(bl, SC_GENTLETOUCH_ENERGYGAIN, INVALID_TIMER); + if (type != SC_GENTLETOUCH_CHANGE) + status_change_end(bl, SC_GENTLETOUCH_CHANGE, INVALID_TIMER); + break; + case SC_INVINCIBLE: + status_change_end(bl, SC_INVINCIBLEOFF, INVALID_TIMER); + break; + case SC_INVINCIBLEOFF: + status_change_end(bl, SC_INVINCIBLE, INVALID_TIMER); + break; + case SC_MAGICPOWER: + status_change_end(bl, type, INVALID_TIMER); break; } - if( opt_flag&2 && sd && sd->touching_id ) - npc->touchnext_areanpc(sd,false); // run OnTouch_ on next char in range + return false; +} - return 1; +/** + * Check is boss resist to given sc. + * + * @param type Status change type. + * + * @retval true if boss resist. + * @retval false if boss not resist. + */ +bool status_is_boss_resist_sc(enum sc_type type) +{ + if (type >= SC_COMMON_MIN && type <= SC_COMMON_MAX) + return true; + switch (type) { + case SC_BLESSING: + case SC_DEC_AGI: + case SC_PROVOKE: + case SC_COMA: + case SC_GRAVITATION: + case SC_NJ_SUITON: + case SC_RICHMANKIM: + case SC_ROKISWEIL: + case SC_FOGWALL: + case SC_FROSTMISTY: + case SC_BURNING: + case SC_MARSHOFABYSS: + case SC_ADORAMUS: + case SC_NEEDLE_OF_PARALYZE: + case SC_DEEP_SLEEP: + case SC_COLD: + + // Exploit prevention - kRO Fix + case SC_PYREXIA: + case SC_DEATHHURT: + case SC_TOXIN: + case SC_PARALYSE: + case SC_VENOMBLEED: + case SC_MAGICMUSHROOM: + case SC_OBLIVIONCURSE: + case SC_LEECHESEND: + + // Ranger Effects + case SC_WUGBITE: + case SC_ELECTRICSHOCKER: + case SC_MAGNETICFIELD: + + // Masquerades + case SC__ENERVATION: + case SC__GROOMY: + case SC__LAZINESS: + case SC__UNLUCKY: + case SC__WEAKNESS: + case SC__IGNORANCE: + + // Other Effects + case SC_VACUUM_EXTREME: + case SC_NETHERWORLD: + case SC_FRESHSHRIMP: + case SC_SV_ROOTTWIST: + case SC_BITESCAR: + return true; + } + return false; +} + +/** + * Initial check for current statuses immune to given sc. + * + * @param sc Current statuses. + * @param type Status change type. + * + * @retval true if immune resist. + * @retval false if not immune resist. + */ +bool status_is_immune_to_status(struct status_change* sc, enum sc_type type) +{ + nullpo_retr(true, sc); + if (sc->data[SC_REFRESH]) { + if (type >= SC_COMMON_MIN && type <= SC_COMMON_MAX) // Confirmed. + return true; // Immune to status ailements + switch (type) { + case SC_DEEP_SLEEP: + case SC__CHAOS: + case SC_BURNING: + case SC_STUN: + case SC_SLEEP: + case SC_CURSE: + case SC_STONE: + case SC_POISON: + case SC_BLIND: + case SC_SILENCE: + case SC_BLOODING: + case SC_FREEZE: + case SC_FROSTMISTY: + case SC_COLD: + case SC_TOXIN: + case SC_PARALYSE: + case SC_VENOMBLEED: + case SC_MAGICMUSHROOM: + case SC_DEATHHURT: + case SC_PYREXIA: + case SC_OBLIVIONCURSE: + case SC_MARSHOFABYSS: + case SC_MANDRAGORA: + return true; + } + } else if (sc->data[SC_INSPIRATION]) { + if (type >= SC_COMMON_MIN && type <= SC_COMMON_MAX) + return true; // Immune to status ailements + switch (type) { + case SC_POISON: + case SC_BLIND: + case SC_STUN: + case SC_SILENCE: + case SC__CHAOS: + case SC_STONE: + case SC_SLEEP: + case SC_BLOODING: + case SC_CURSE: + case SC_BURNING: + case SC_FROSTMISTY: + case SC_FREEZE: + case SC_COLD: + case SC_FEAR: + case SC_TOXIN: + case SC_PARALYSE: + case SC_VENOMBLEED: + case SC_MAGICMUSHROOM: + case SC_DEATHHURT: + case SC_PYREXIA: + case SC_OBLIVIONCURSE: + case SC_LEECHESEND: + case SC_DEEP_SLEEP: + case SC_SATURDAY_NIGHT_FEVER: + case SC__BODYPAINT: + case SC__ENERVATION: + case SC__GROOMY: + case SC__IGNORANCE: + case SC__LAZINESS: + case SC__UNLUCKY: + case SC__WEAKNESS: + return true; + } + } + return false; } /*========================================== @@ -13289,7 +13416,7 @@ int status_readdb_refine_libconfig(const char *filename) char filepath[256]; int i = 0, count = 0; - sprintf(filepath, "%s/%s", map->db_path, filename); + safesnprintf(filepath, sizeof(filepath), "%s/%s", map->db_path, filename); if (!libconfig->load_file(&refine_db_conf, filepath)) return 0; @@ -13477,6 +13604,12 @@ void status_defaults(void) status->change_clear = status_change_clear; status->change_clear_buffs = status_change_clear_buffs; + status->is_immune_to_status = status_is_immune_to_status; + status->is_boss_resist_sc = status_is_boss_resist_sc; + status->end_sc_before_start = status_end_sc_before_start; + status->change_start_stop_action = status_change_start_stop_action; + status->change_start_set_option = status_change_start_set_option; + status->get_val_flag = status_get_val_flag; status->calc_bl_ = status_calc_bl_; status->calc_mob_ = status_calc_mob_; status->calc_pet_ = status_calc_pet_; @@ -13544,6 +13677,8 @@ void status_defaults(void) status->calc_ematk = status_calc_ematk; status->calc_bl_main = status_calc_bl_main; status->display_add = status_display_add; + status->change_start_display = status_change_start_display; + status->change_start_unknown_sc = status_change_start_unknown_sc; status->display_remove = status_display_remove; status->natural_heal = status_natural_heal; status->natural_heal_timer = status_natural_heal_timer; diff --git a/src/map/status.h b/src/map/status.h index de21fa16c..3c0a87175 100644 --- a/src/map/status.h +++ b/src/map/status.h @@ -2331,6 +2331,14 @@ struct status_interface { int (*get_sc_def) (struct block_list *src, struct block_list *bl, enum sc_type type, int rate, int tick, int flag); int (*change_start) (struct block_list *src, struct block_list *bl, enum sc_type type, int rate, int val1, int val2, int val3, int val4, int tick, int flag); int (*change_end_) (struct block_list* bl, enum sc_type type, int tid, const char* file, int line); + bool (*is_immune_to_status) (struct status_change* sc, enum sc_type type); + bool (*is_boss_resist_sc) (enum sc_type type); + bool (*end_sc_before_start) (struct block_list *bl, struct status_data *st, struct status_change* sc, enum sc_type type, int undead_flag, int val1, int val2, int val3, int val4); + void (*change_start_stop_action) (struct block_list *bl, enum sc_type type); + int (*change_start_set_option) (struct block_list *bl, struct status_change* sc, enum sc_type type, int val1, int val2, int val3, int val4); + int (*get_val_flag) (enum sc_type type); + void (*change_start_display) (struct map_session_data *sd, enum sc_type type, int val1, int val2, int val3, int val4); + bool (*change_start_unknown_sc) (struct block_list *src, struct block_list *bl, enum sc_type type, int calc_flag, int rate, int val1, int val2, int val3, int val4, int tick, int flag); int (*kaahi_heal_timer) (int tid, int64 tick, int id, intptr_t data); int (*change_timer) (int tid, int64 tick, int id, intptr_t data); int (*change_timer_sub) (struct block_list* bl, va_list ap); |