From ae13db97ea770e37450e4e2c1a7919ce98d705a8 Mon Sep 17 00:00:00 2001 From: shennetsind Date: Thu, 28 Nov 2013 13:20:02 -0200 Subject: Follow up fdb6de1aa34086fd4d22ae127437727f556cea3c Modified reflect code so that each reflection source can judge whether to apply or not, necessary for mechanics such as item-bonus reflect triggers even on autoguard while reflect shield does not. Re-added that "reflect shield" overhead display which I mistakenly removed in fdb6de1aa34086fd4d22ae127437727f556cea3c. Added code to refrain damage numbers from overlapping in the client, which would render them illegible. Special Thanks to kyeme, Yommy. http://hercules.ws/board/tracker/issue-7792-safety-wall-reflect-bug-body-relocation-error/ Signed-off-by: shennetsind --- src/map/atcommand.c | 4 +- src/map/battle.c | 246 +++++++++++++++++++++++++++-------------------- src/map/battle.h | 4 +- src/map/clif.c | 197 ++++++++++++++++++++++++++----------- src/map/clif.h | 14 ++- src/map/packets_struct.h | 26 +++++ src/map/skill.c | 20 ++-- src/map/status.c | 14 +-- src/map/unit.c | 4 +- src/map/unit.h | 2 +- 10 files changed, 346 insertions(+), 185 deletions(-) diff --git a/src/map/atcommand.c b/src/map/atcommand.c index 01711f21b..c355f6bbd 100644 --- a/src/map/atcommand.c +++ b/src/map/atcommand.c @@ -1052,7 +1052,7 @@ ACMD(heal) if ( hp < 0 && sp <= 0 ) { status->damage(NULL, &sd->bl, -hp, -sp, 0, 0); - clif->damage(&sd->bl,&sd->bl, timer->gettick(), 0, 0, -hp, 0, 4, 0); + clif->damage(&sd->bl,&sd->bl, 0, 0, -hp, 0, 4, 0); clif->message(fd, msg_txt(156)); // HP or/and SP modified. return true; } @@ -1063,7 +1063,7 @@ ACMD(heal) status->heal(&sd->bl, hp, 0, 0); else { status->damage(NULL, &sd->bl, -hp, 0, 0, 0); - clif->damage(&sd->bl,&sd->bl, timer->gettick(), 0, 0, -hp, 0, 4, 0); + clif->damage(&sd->bl,&sd->bl, 0, 0, -hp, 0, 4, 0); } } diff --git a/src/map/battle.c b/src/map/battle.c index 5666e37fa..d65bb910f 100644 --- a/src/map/battle.c +++ b/src/map/battle.c @@ -2602,16 +2602,15 @@ int64 battle_calc_damage(struct block_list *src,struct block_list *bl,struct Dam struct skill_unit_group* group = skill->id2group(sc->data[SC_SAFETYWALL]->val3); uint16 skill_id = sc->data[SC_SAFETYWALL]->val2; if (group) { + d->dmg_lv = ATK_BLOCK; if(skill_id == MH_STEINWAND){ if (--group->val2<=0) skill->del_unitgroup(group,ALC_MARK); - d->dmg_lv = ATK_BLOCK; return 0; } /** * in RE, SW possesses a lifetime equal to 3 times the caster's health **/ - d->dmg_lv = ATK_BLOCK; #ifdef RENEWAL if ( ( group->val2 - damage) > 0 ) { group->val2 -= (int)cap_value(damage,INT_MIN,INT_MAX); @@ -4994,11 +4993,7 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list } if( wd.damage + wd.damage2 ) { //There is a total damage value - int64 rdamage = 0; - - if( src != target ) { // Don't reflect your own damage (Grand Cross) - rdamage = battle->calc_return_damage(target, src, wd.damage + wd.damage2, wd.flag, skill_id); - } + int64 damage = wd.damage + wd.damage2; if(!wd.damage2) { wd.damage = battle->calc_damage(src,target,&wd,wd.damage,skill_id,skill_lv); @@ -5031,35 +5026,22 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list #endif } - if( rdamage && wd.dmg_lv >= ATK_BLOCK ) {/* yes block still applies, somehow gravity thinks it makes sense. */ - - if( tsc && tsc->data[SC_DEATHBOUND] ) { - wd.damage = wd.damage + wd.damage2; + if( src != target ) { // Don't reflect your own damage (Grand Cross) + + if( wd.dmg_lv == ATK_MISS || wd.dmg_lv == ATK_BLOCK ) { + int64 prev1 = wd.damage, prev2 = wd.damage2; + + wd.damage = damage; wd.damage2 = 0; - status_change_end(target,SC_DEATHBOUND,INVALID_TIMER); - } - - if( tsc && tsc->data[SC_LG_REFLECTDAMAGE] ) { - bool change = false; - if( sd && !sd->state.autocast ) - change = true; - if( change ) - sd->state.autocast = 1; - map->foreachinshootrange(battle->damage_area,target,skill->get_splash(LG_REFLECTDAMAGE,1),BL_CHAR,timer->gettick(),target,wd.amotion,sstatus->dmotion,rdamage,tstatus->race); - if( change ) - sd->state.autocast = 0; - } else { - int rdelay; - - rdelay = clif->damage(src, src, timer->gettick(), status_get_amotion(src), status_get_dmotion(src), rdamage, 1, 4, 0); - - //Use Reflect Shield to signal this kind of skill trigger. [Skotlex] - if( tsd ) - battle->drain(tsd, src, rdamage, rdamage, sstatus->race, is_boss(src)); - battle->delay_damage(timer->gettick(), wd.amotion,target,src,0,CR_REFLECTSHIELD,0,rdamage,ATK_DEF,rdelay,true); - skill->additional_effect(target, src, CR_REFLECTSHIELD, 1, BF_WEAPON|BF_SHORT|BF_NORMAL,ATK_DEF,timer->gettick()); - } - + + battle->reflect_damage(target, src, &wd, skill_id); + + wd.damage = prev1; + wd.damage2 = prev2; + + } else + battle->reflect_damage(target, src, &wd, skill_id); + } } @@ -5073,7 +5055,7 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list rnd()%100 < tsc->data[SC_SWORDREJECT]->val2 ) { ATK_RATER(50); - status_fix_damage(target,src,wd.damage,clif->damage(target,src,timer->gettick(),0,0,wd.damage,0,0,0)); + status_fix_damage(target,src,wd.damage,clif->damage(target,src,0,0,wd.damage,0,0,0)); clif->skill_nodamage(target,target,ST_REJECTSWORD,tsc->data[SC_SWORDREJECT]->val1,1); if( --(tsc->data[SC_SWORDREJECT]->val3) <= 0 ) status_change_end(target, SC_SWORDREJECT, INVALID_TIMER); @@ -5134,20 +5116,24 @@ struct Damage battle_calc_attack(int attack_type,struct block_list *bl,struct bl d.dmg_lv = ATK_DEF; return d; } - -//Calculates BF_WEAPON returned damage. -int64 battle_calc_return_damage(struct block_list *target, struct block_list *src, int64 damage, int flag, uint16 skill_id){ - int64 rdamage = 0, trdamage = 0; - struct map_session_data* sd; - struct status_change* sc; +//Performs reflect damage (magic (maya) is performed over skill.c). +void battle_reflect_damage(struct block_list *target, struct block_list *src, struct Damage *wd,uint16 skill_id) { + int64 damage = wd->damage + wd->damage2, rdamage = 0, trdamage = 0; + struct map_session_data *sd, *tsd; + struct status_change *sc; + int64 tick = timer->gettick(); + int delay = 50, rdelay = 0; #ifdef RENEWAL int max_reflect_damage; - + max_reflect_damage = max(status_get_max_hp(target), status_get_max_hp(target) * status->get_lv(target) / 100); #endif - sd = BL_CAST(BL_PC, target); + + sd = BL_CAST(BL_PC, src); + + tsd = BL_CAST(BL_PC, target); sc = status->get_sc(target); - + #ifdef RENEWAL #define NORMALIZE_RDAMAGE(d) ( trdamage += rdamage = max(1, min(max_reflect_damage, (d))) ) #else @@ -5158,82 +5144,138 @@ int64 battle_calc_return_damage(struct block_list *target, struct block_list *sr sc = NULL; if( sc ) { - + if( sc->data[SC_CRESCENTELBOW] && !is_boss(src) && rnd()%100 < sc->data[SC_CRESCENTELBOW]->val2 ){ //ATK [{(Target HP / 100) x Skill Level} x Caster Base Level / 125] % + [Received damage x {1 + (Skill Level x 0.2)}] int ratio = (status_get_hp(src) / 100) * sc->data[SC_CRESCENTELBOW]->val1 * status->get_lv(target) / 125; if (ratio > 5000) ratio = 5000; // Maximum of 5000% ATK rdamage = rdamage * ratio / 100 + (damage) * (10 + sc->data[SC_CRESCENTELBOW]->val1 * 20 / 10) / 10; skill->blown(target, src, skill->get_blewcount(SR_CRESCENTELBOW_AUTOSPELL, sc->data[SC_CRESCENTELBOW]->val1), unit->getdir(src), 0); - clif->skill_damage(target, src, timer->gettick(), status_get_amotion(src), 0, rdamage, - 1, SR_CRESCENTELBOW_AUTOSPELL, sc->data[SC_CRESCENTELBOW]->val1, 6); // This is how official does - clif->damage(src, target, timer->gettick(), status_get_amotion(src)+1000, 0, rdamage/10, 1, 0, 0); + clif->skill_damage(target, src, tick, status_get_amotion(src), 0, rdamage, + 1, SR_CRESCENTELBOW_AUTOSPELL, sc->data[SC_CRESCENTELBOW]->val1, 6); // This is how official does + clif->delay_damage(tick + delay, src, target,status_get_amotion(src)+1000,0, rdamage/10, 1, 0); status->damage(src, target, status->damage(target, src, rdamage, 0, 0, 1)/10, 0, 0, 1); status_change_end(target, SC_CRESCENTELBOW, INVALID_TIMER); - return 0; // Just put here to minimize redundancy + /* shouldn't this trigger skill->additional_effect? */ + return; // Just put here to minimize redundancy } - - if( sc->data[SC_KYOMU] && !sc->data[SC_DEATHBOUND] ){ - // Nullify reflecting ability - return 0; - } - - } - - if( flag & BF_SHORT) {//Bounces back part of the damage. - if ( sd && sd->bonus.short_weapon_damage_return ) { - NORMALIZE_RDAMAGE(damage * sd->bonus.short_weapon_damage_return / 100); - } - if( sc ) { - if( sc->data[SC_REFLECTSHIELD] && skill_id != WS_CARTTERMINATION ){ - int64 t = damage * sc->data[SC_REFLECTSHIELD]->val2 / 100; - - if (flag & BF_SKILL) { - if (flag&BF_WEAPON) - t = t * map->list[src->m].weapon_damage_rate / 100; - if (flag&BF_MISC) - t = t * map->list[src->m].misc_damage_rate / 100; - } else { - if (flag & BF_SHORT) - t = t * map->list[src->m].short_damage_rate / 100; - } - - NORMALIZE_RDAMAGE(t); - } - if( sc->data[SC_LG_REFLECTDAMAGE] && rand()%100 < (30 + 10*sc->data[SC_LG_REFLECTDAMAGE]->val1) ) { - NORMALIZE_RDAMAGE(damage * sc->data[SC_LG_REFLECTDAMAGE]->val2 / 100); - } - + + if( wd->flag & BF_SHORT ) { if( !is_boss(src) ) { - if( sc->data[SC_DEATHBOUND] && skill_id != WS_CARTTERMINATION ) { uint8 dir = map->calc_dir(target,src->x,src->y), - t_dir = unit->getdir(target); - + t_dir = unit->getdir(target); + if( !map->check_dir(dir,t_dir) ) { int64 rd1 = damage * sc->data[SC_DEATHBOUND]->val2 / 100; // Amplify damage. + trdamage += rdamage = rd1 - (damage = rd1 * 30 / 100); // not normalized as intended. - clif->skill_damage(src, target, timer->gettick(), status_get_amotion(src), 0, -3000, 1, RK_DEATHBOUND, sc->data[SC_DEATHBOUND]->val1, 6); + rdelay = clif->skill_damage(src, target, tick, status_get_amotion(src), status_get_dmotion(src), -3000, 1, RK_DEATHBOUND, sc->data[SC_DEATHBOUND]->val1, 6); skill->blown(target, src, skill->get_blewcount(RK_DEATHBOUND, sc->data[SC_DEATHBOUND]->val1), unit->getdir(src), 0); + + if( tsd ) /* is this right? rdamage as both left and right? */ + battle->drain(tsd, src, rdamage, rdamage, status_get_race(src), 0); + battle->delay_damage(tick, wd->amotion,target,src,0,CR_REFLECTSHIELD,0,rdamage,ATK_DEF,rdelay,true); + + delay += 100;/* gradual increase so the numbers don't clip in the client */ } + wd->damage = wd->damage + wd->damage2; + wd->damage2 = 0; + status_change_end(target,SC_DEATHBOUND,INVALID_TIMER); } + } + } + + if( sc->data[SC_KYOMU] ){ + // Nullify reflecting ability of the conditions onwards + return; + } + + } + + if( wd->flag & BF_SHORT ) { + if ( tsd && tsd->bonus.short_weapon_damage_return ) { + NORMALIZE_RDAMAGE(damage * tsd->bonus.short_weapon_damage_return / 100); + + rdelay = clif->delay_damage(tick+delay,src, src, status_get_amotion(src), status_get_dmotion(src), rdamage, 1, 4); + + /* is this right? rdamage as both left and right? */ + battle->drain(tsd, src, rdamage, rdamage, status_get_race(src), 0); + battle->delay_damage(tick, wd->amotion,target,src,0,CR_REFLECTSHIELD,0,rdamage,ATK_DEF,rdelay,true); + + delay += 100;/* gradual increase so the numbers don't clip in the client */ + } + + if( sc && wd->dmg_lv >= ATK_BLOCK ) {/* yes block still applies, somehow gravity thinks it makes sense. */ + if( sc->data[SC_REFLECTSHIELD] && skill_id != WS_CARTTERMINATION ) { + NORMALIZE_RDAMAGE(damage * sc->data[SC_REFLECTSHIELD]->val2 / 100); + +#ifndef RENEWAL + rdelay = clif->delay_damage(tick+delay,src, src, status_get_amotion(src), status_get_dmotion(src), rdamage, 1, 4); +#else + rdelay = clif->skill_damage(src, src, tick, delay, status_get_dmotion(src), rdamage, 1, CR_REFLECTSHIELD, 1, 4); +#endif + /* is this right? rdamage as both left and right? */ + if( tsd ) + battle->drain(tsd, src, rdamage, rdamage, status_get_race(src), 0); + battle->delay_damage(tick, wd->amotion,target,src,0,CR_REFLECTSHIELD,0,rdamage,ATK_DEF,rdelay,true); + + delay += 100;/* gradual increase so the numbers don't clip in the client */ + } + if( sc->data[SC_LG_REFLECTDAMAGE] && rand()%100 < (30 + 10*sc->data[SC_LG_REFLECTDAMAGE]->val1) ) { + bool change = false; + + NORMALIZE_RDAMAGE(damage * sc->data[SC_LG_REFLECTDAMAGE]->val2 / 100); - if( sc->data[SC_SHIELDSPELL_DEF] && sc->data[SC_SHIELDSPELL_DEF]->val1 == 2 ){ - NORMALIZE_RDAMAGE(damage * sc->data[SC_SHIELDSPELL_DEF]->val2 / 100); + trdamage -= rdamage;/* wont count towards total */ + + if( sd && !sd->state.autocast ) { + change = true; + sd->state.autocast = 1; } + map->foreachinshootrange(battle->damage_area,target,skill->get_splash(LG_REFLECTDAMAGE,1),BL_CHAR,tick,target,delay,wd->dmotion,rdamage,status_get_race(target)); + + if( change ) + sd->state.autocast = 0; + + delay += 150;/* gradual increase so the numbers don't clip in the client */ + } + if( sc->data[SC_SHIELDSPELL_DEF] && sc->data[SC_SHIELDSPELL_DEF]->val1 == 2 ){ + NORMALIZE_RDAMAGE(damage * sc->data[SC_SHIELDSPELL_DEF]->val2 / 100); + + rdelay = clif->delay_damage(tick+delay,src, src, status_get_amotion(src), status_get_dmotion(src), rdamage, 1, 4); + + /* is this right? rdamage as both left and right? */ + if( tsd ) + battle->drain(tsd, src, rdamage, rdamage, status_get_race(src), 0); + battle->delay_damage(tick, wd->amotion,target,src,0,CR_REFLECTSHIELD,0,rdamage,ATK_DEF,rdelay,true); + + delay += 100;/* gradual increase so the numbers don't clip in the client */ } } - } else { - if (sd && sd->bonus.long_weapon_damage_return){ - NORMALIZE_RDAMAGE(damage * sd->bonus.long_weapon_damage_return / 100); + } else {/* long */ + if ( tsd && tsd->bonus.long_weapon_damage_return ) { + NORMALIZE_RDAMAGE(damage * tsd->bonus.long_weapon_damage_return / 100); + + rdelay = clif->delay_damage(tick+delay,src, src, status_get_amotion(src), status_get_dmotion(src), rdamage, 1, 4); + + /* is this right? rdamage as both left and right? */ + battle->drain(tsd, src, rdamage, rdamage, status_get_race(src), 0); + battle->delay_damage(tick, wd->amotion,target,src,0,CR_REFLECTSHIELD,0,rdamage,ATK_DEF,rdelay,true); + + delay += 100;/* gradual increase so the numbers don't clip in the client */ } } - - return max(0, trdamage); + + /* something caused reflect */ + if( trdamage ) { + skill->additional_effect(target, src, CR_REFLECTSHIELD, 1, BF_WEAPON|BF_SHORT|BF_NORMAL,ATK_DEF,tick); + } + + return; #undef NORMALIZE_RDAMAGE } - void battle_drain(TBL_PC *sd, struct block_list *tbl, int64 rdamage, int64 ldamage, int race, int boss) { struct weapon_data *wd; @@ -5308,7 +5350,7 @@ int battle_damage_area(struct block_list *bl, va_list ap) { battle->delay_damage(tick, amotion,src,bl,0,CR_REFLECTSHIELD,0,damage,ATK_DEF,0,true); else status_fix_damage(src,bl,damage,0); - clif->damage(bl,bl,tick,amotion,dmotion,damage,1,ATK_BLOCK,0); + clif->damage(bl,bl,amotion,dmotion,damage,1,ATK_BLOCK,0); if( !(src && src->type == BL_PC && ((TBL_PC*)src)->state.autocast) ) skill->additional_effect(src, bl, CR_REFLECTSHIELD, 1, BF_WEAPON|BF_SHORT|BF_NORMAL,ATK_DEF,tick); map->freeblock_unlock(); @@ -5397,7 +5439,7 @@ enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* t if(dist <= 0 || (!map->check_dir(dir,t_dir) && dist <= tstatus->rhw.range+1)) { uint16 skill_lv = tsc->data[SC_AUTOCOUNTER]->val1; clif->skillcastcancel(target); //Remove the casting bar. [Skotlex] - clif->damage(src, target, tick, sstatus->amotion, 1, 0, 1, 0, 0); //Display MISS. + clif->damage(src, target, sstatus->amotion, 1, 0, 1, 0, 0); //Display MISS. status_change_end(target, SC_AUTOCOUNTER, INVALID_TIMER); skill->attack(BF_WEAPON,target,target,src,KN_AUTOCOUNTER,skill_lv,tick,0); return ATK_BLOCK; @@ -5411,7 +5453,7 @@ enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* t status_change_end(target, SC_BLADESTOP_WAIT, INVALID_TIMER); if(sc_start4(src, SC_BLADESTOP, 100, sd?pc->checkskill(sd, MO_BLADESTOP):5, 0, 0, target->id, duration)) { //Target locked. - clif->damage(src, target, tick, sstatus->amotion, 1, 0, 1, 0, 0); //Display MISS. + clif->damage(src, target, sstatus->amotion, 1, 0, 1, 0, 0); //Display MISS. clif->bladestop(target, src->id, 1); sc_start4(target, SC_BLADESTOP, 100, skill_lv, 0, 0, src->id, duration); return ATK_BLOCK; @@ -5518,7 +5560,7 @@ enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* t } } - wd.dmotion = clif->damage(src, target, tick, wd.amotion, wd.dmotion, wd.damage, wd.div_ , wd.type, wd.damage2); + wd.dmotion = clif->damage(src, target, wd.amotion, wd.dmotion, wd.damage, wd.div_ , wd.type, wd.damage2); if (sd && sd->bonus.splash_range > 0 && damage > 0) skill->castend_damage_id(src, target, 0, 1, tick, 0); @@ -5546,7 +5588,7 @@ enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* t (d_bl->type == BL_PC && ((TBL_PC*)d_bl)->devotion[sce->val2] == target->id) ) && check_distance_bl(target, d_bl, sce->val3) ) { - clif->damage(d_bl, d_bl, timer->gettick(), 0, 0, damage, 0, 0, 0); + clif->damage(d_bl, d_bl, 0, 0, damage, 0, 0, 0); status_fix_damage(NULL, d_bl, damage, 0); } else @@ -5560,10 +5602,10 @@ enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* t } else if( tsc->data[SC_WATER_SCREEN_OPTION] && tsc->data[SC_WATER_SCREEN_OPTION]->val1 ) { struct block_list *e_bl = map->id2bl(tsc->data[SC_WATER_SCREEN_OPTION]->val1); if( e_bl && !status->isdead(e_bl) ) { - clif->damage(e_bl,e_bl,tick,wd.amotion,wd.dmotion,damage,wd.div_,wd.type,wd.damage2); + clif->damage(e_bl,e_bl,wd.amotion,wd.dmotion,damage,wd.div_,wd.type,wd.damage2); status->damage(target,e_bl,damage,0,0,0); // Just show damage in target. - clif->damage(src, target, tick, wd.amotion, wd.dmotion, damage, wd.div_, wd.type, wd.damage2 ); + clif->damage(src, target, wd.amotion, wd.dmotion, damage, wd.div_, wd.type, wd.damage2 ); map->freeblock_unlock(); return ATK_NONE; } @@ -6825,7 +6867,7 @@ void battle_defaults(void) { battle->calc_weapon_attack = battle_calc_weapon_attack; battle->delay_damage = battle_delay_damage; battle->drain = battle_drain; - battle->calc_return_damage = battle_calc_return_damage; + battle->reflect_damage = battle_reflect_damage; battle->attr_ratio = battle_attr_ratio; battle->attr_fix = battle_attr_fix; battle->calc_cardfix = battle_calc_cardfix; diff --git a/src/map/battle.h b/src/map/battle.h index 645b1761f..4d4508742 100644 --- a/src/map/battle.h +++ b/src/map/battle.h @@ -526,8 +526,8 @@ struct battle_interface { int (*delay_damage) (int64 tick, int amotion, struct block_list *src, struct block_list *target, int attack_type, uint16 skill_id, uint16 skill_lv, int64 damage, enum damage_lv dmg_lv, int ddelay, bool additional_effects); /* drain damage */ void (*drain) (struct map_session_data *sd, struct block_list *tbl, int64 rdamage, int64 ldamage, int race, int boss); - /* damage return/reflect */ - int64 (*calc_return_damage) (struct block_list *target, struct block_list *src, int64 damage, int flag, uint16 skill_id); + /* damage reflect */ + void (*reflect_damage) (struct block_list *target, struct block_list *src, struct Damage *wd,uint16 skill_id); /* attribute rate */ int (*attr_ratio) (int atk_elem, int def_type, int def_lv); /* applies attribute modifiers */ diff --git a/src/map/clif.c b/src/map/clif.c index 6550af5b9..a383617b5 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -45,7 +45,6 @@ #include "clif.h" #include "mail.h" #include "quest.h" -#include "packets_struct.h" #include "irc-bot.h" #include @@ -4363,78 +4362,68 @@ int clif_calc_walkdelay(struct block_list *bl,int delay, int type, int damage, i /// 10 = critical hit /// 11 = lucky dodge /// 12 = (touch skill?) -int clif_damage(struct block_list* src, struct block_list* dst, int64 tick, int sdelay, int ddelay, int64 in_damage, int div, int type, int64 in_damage2) { - unsigned char buf[33]; +int clif_damage(struct block_list* src, struct block_list* dst, int sdelay, int ddelay, int64 in_damage, short div, unsigned char type, int64 in_damage2) { + struct packet_damage p; struct status_change *sc; - int damage,damage2; #if PACKETVER < 20071113 - const int cmd = 0x8a; + short damage,damage2; #else - const int cmd = 0x2e1; + int damage,damage2; #endif nullpo_ret(src); nullpo_ret(dst); - - damage = (int)cap_value(in_damage,INT_MIN,INT_MAX); - damage2 = (int)cap_value(in_damage2,INT_MIN,INT_MAX); - - type = clif_calc_delay(type,div,damage+damage2,ddelay); + sc = status->get_sc(dst); - if(sc && sc->count) { - if(sc->data[SC_ILLUSION]) { - if(damage) damage = damage*(sc->data[SC_ILLUSION]->val2) + rnd()%100; - if(damage2) damage2 = damage2*(sc->data[SC_ILLUSION]->val2) + rnd()%100; - } + + if(sc && sc->count && sc->data[SC_ILLUSION]) { + if(in_damage) in_damage = in_damage*(sc->data[SC_ILLUSION]->val2) + rnd()%100; + if(in_damage2) in_damage2 = in_damage2*(sc->data[SC_ILLUSION]->val2) + rnd()%100; } - - WBUFW(buf,0)=cmd; - WBUFL(buf,2)=src->id; - WBUFL(buf,6)=dst->id; - WBUFL(buf,10)=(uint32)tick; - WBUFL(buf,14)=sdelay; - WBUFL(buf,18)=ddelay; + #if PACKETVER < 20071113 - if (battle_config.hide_woe_damage && map_flag_gvg2(src->m)) { - WBUFW(buf,22)=damage?div:0; - WBUFW(buf,27)=damage2?div:0; - } else { - WBUFW(buf,22)=min(damage, INT16_MAX); - WBUFW(buf,27)=damage2; - } - WBUFW(buf,24)=div; - WBUFB(buf,26)=type; + damage = (short)min(in_damage,INT16_MAX); + damage2 = (short)min(in_damage2,INT16_MAX); #else - if (battle_config.hide_woe_damage && map_flag_gvg2(src->m)) { - WBUFL(buf,22)=damage?div:0; - WBUFL(buf,29)=damage2?div:0; - } else { - WBUFL(buf,22)=damage; - WBUFL(buf,29)=damage2; - } - WBUFW(buf,26)=div; - WBUFB(buf,28)=type; + damage = (int)min(in_damage,INT_MAX); + damage2 = (int)min(in_damage2,INT_MAX); #endif + type = clif_calc_delay(type,div,damage+damage2,ddelay); + + p.PacketType = damageType; + p.GID = src->id; + p.targetGID = dst->id; + p.startTime = (uint32)timer->gettick(); + p.attackMT = sdelay; + p.attackedMT = ddelay; + p.count = div; + p.action = type; + + if( battle_config.hide_woe_damage && map_flag_gvg2(src->m) ) { + p.damage = damage?div:0; + p.leftDamage = damage2?div:0; + } else { + p.damage = damage; + p.leftDamage = damage2; + } + if(disguised(dst)) { - clif->send(buf,packet_len(cmd),dst,AREA_WOS); - WBUFL(buf,6) = -dst->id; - clif->send(buf,packet_len(cmd),dst,SELF); + clif->send(&p,sizeof(p),dst,AREA_WOS); + p.targetGID = -dst->id; + clif->send(&p,sizeof(p),dst,SELF); } else - clif->send(buf,packet_len(cmd),dst,AREA); + clif->send(&p,sizeof(p),dst,AREA); if(disguised(src)) { - WBUFL(buf,2) = -src->id; + p.GID = -src->id; if (disguised(dst)) - WBUFL(buf,6) = dst->id; -#if PACKETVER < 20071113 - if(damage > 0) WBUFW(buf,22) = -1; - if(damage2 > 0) WBUFW(buf,27) = -1; -#else - if(damage > 0) WBUFL(buf,22) = -1; - if(damage2 > 0) WBUFL(buf,29) = -1; -#endif - clif->send(buf,packet_len(cmd),src,SELF); + p.targetGID = dst->id; + + if(damage > 0) p.damage = -1; + if(damage2 > 0) p.leftDamage = -1; + + clif->send(&p,sizeof(p),src,SELF); } if(src == dst) { @@ -4450,7 +4439,7 @@ int clif_damage(struct block_list* src, struct block_list* dst, int64 tick, int *------------------------------------------*/ void clif_takeitem(struct block_list* src, struct block_list* dst) { - //clif->damage(src,dst,0,0,0,0,0,1,0); + //clif->damage(src,dst,0,0,0,0,1,0); unsigned char buf[32]; nullpo_retv(src); @@ -17932,7 +17921,9 @@ void clif_notify_bounditem(struct map_session_data *sd, unsigned short index) { clif->send(&p,sizeof(p), &sd->bl, SELF); } -/* (GM) right click -> 'remove all equipment' */ +/** + * Parses the (GM) right click option 'remove all equipment' + **/ void clif_parse_GMFullStrip(int fd, struct map_session_data *sd) { struct map_session_data *tsd = map->id2sd(RFIFOL(fd,2)); int i; @@ -17946,6 +17937,90 @@ void clif_parse_GMFullStrip(int fd, struct map_session_data *sd) { pc->unequipitem( tsd , tsd->equip_index[ i ] , 2 ); } } +/** + * clif_delay_damage timer, sends the stored data and clears the memory afterwards + **/ +int clif_delay_damage_sub(int tid, int64 tick, int id, intptr_t data) { + struct cdelayed_damage *dd = (struct cdelayed_damage *)data; + + clif->send(&dd->p,sizeof(struct packet_damage),&dd->bl,AREA_WOS); + + ers_free(clif->delayed_damage_ers,dd); + + return 0; +} +/** + * Delays sending a damage packet in order to avoid the visual display to overlap + * + * @param tick when to trigger the timer (e.g. timer->gettick() + 500) + * @param src block_list pointer of the src + * @param dst block_list pointer of the damage source + * @param sdelay attack motion usually status_get_amotion() + * @param ddelay damage motion usually status_get_dmotion() + * @param in_damage total damage to be sent + * @param div amount of hits + * @param type action type + * + * @return clif->calc_walkdelay used in further processing + **/ +int clif_delay_damage(int64 tick, struct block_list *src, struct block_list *dst, int sdelay, int ddelay, int64 in_damage, short div, unsigned char type) { + struct cdelayed_damage *dd; + struct status_change *sc; +#if PACKETVER < 20071113 + short damage; +#else + int damage; +#endif + + nullpo_ret(src); + nullpo_ret(dst); + + sc = status->get_sc(dst); + + if(sc && sc->count && sc->data[SC_ILLUSION]) { + if(in_damage) in_damage = in_damage*(sc->data[SC_ILLUSION]->val2) + rnd()%100; + } + +#if PACKETVER < 20071113 + damage = (short)min(in_damage,INT16_MAX); +#else + damage = (int)min(in_damage,INT_MAX); +#endif + + type = clif_calc_delay(type,div,damage,ddelay); + + dd = ers_alloc(clif->delayed_damage_ers, struct cdelayed_damage); + + dd->p.PacketType = damageType; + dd->p.GID = src->id; + dd->p.targetGID = dst->id; + dd->p.startTime = (uint32)timer->gettick(); + dd->p.attackMT = sdelay; + dd->p.attackedMT = ddelay; + dd->p.count = div; + dd->p.action = type; + dd->p.leftDamage = 0; + + if( battle_config.hide_woe_damage && map_flag_gvg2(src->m) ) + dd->p.damage = damage?div:0; + else + dd->p.damage = damage; + + dd->bl.m = dst->m; + dd->bl.x = dst->x; + dd->bl.y = dst->y; + dd->bl.type = BL_NUL; + + if( tick > timer->gettick() ) + timer->add(tick,clif->delay_damage_sub,0,(intptr_t)dd); + else { + clif->send(&dd->p,sizeof(struct packet_damage),&dd->bl,AREA_WOS); + + ers_free(clif->delayed_damage_ers,dd); + } + + return clif->calc_walkdelay(dst,ddelay,type,damage,div); +} /* */ unsigned short clif_decrypt_cmd( int cmd, struct map_session_data *sd ) { @@ -18221,7 +18296,8 @@ int do_init_clif(bool minimal) { timer->add_func_list(clif->delayquit, "clif_delayquit"); clif->delay_clearunit_ers = ers_new(sizeof(struct block_list),"clif.c::delay_clearunit_ers",ERS_OPT_CLEAR); - + clif->delayed_damage_ers = ers_new(sizeof(struct cdelayed_damage),"clif.c::delayed_damage_ers",ERS_OPT_CLEAR); + clif->channel_db = stridb_alloc(DB_OPT_DUP_KEY|DB_OPT_RELEASE_DATA, HCHSYS_NAME_LENGTH); hChSys.ally = hChSys.local = hChSys.irc = hChSys.ally_autojoin = hChSys.local_autojoin = false; clif->chann_config_read(); @@ -18251,6 +18327,7 @@ void do_final_clif(void) { db_destroy(clif->channel_db); ers_destroy(clif->delay_clearunit_ers); + ers_destroy(clif->delayed_damage_ers); for(i = 0; i < CASHSHOP_TAB_MAX; i++) { int k; @@ -18267,6 +18344,7 @@ void clif_defaults(void) { clif->bind_ip = INADDR_ANY; clif->map_port = 5121; clif->ally_only = false; + clif->delayed_damage_ers = NULL; /* core */ clif->init = do_init_clif; clif->final = do_final_clif; @@ -18754,6 +18832,9 @@ void clif_defaults(void) { clif->show_modifiers = clif_show_modifiers; /* */ clif->notify_bounditem = clif_notify_bounditem; + /* */ + clif->delay_damage = clif_delay_damage; + clif->delay_damage_sub = clif_delay_damage_sub; /*------------------------ *- Parse Incoming Packet *------------------------*/ diff --git a/src/map/clif.h b/src/map/clif.h index 890f2d4c2..8b78f27e9 100644 --- a/src/map/clif.h +++ b/src/map/clif.h @@ -9,6 +9,8 @@ #include "../common/db.h" #include "../common/mmo.h" #include "../common/socket.h" +#include "../map/map.h" +#include "../map/packets_struct.h" #include /** @@ -505,6 +507,11 @@ struct hCSData { unsigned int price; }; +struct cdelayed_damage { + struct packet_damage p; + struct block_list bl; +}; + /** * Vars **/ @@ -533,6 +540,8 @@ struct clif_interface { unsigned int cryptKey[3]; /* */ bool ally_only; + /* */ + struct eri *delayed_damage_ers; /* core */ int (*init) (bool minimal); void (*final) (void); @@ -634,7 +643,7 @@ struct clif_interface { void (*scriptclear) (struct map_session_data *sd, int npcid); /* client-user-interface-related */ void (*viewpoint) (struct map_session_data *sd, int npc_id, int type, int x, int y, int id, int color); - int (*damage) (struct block_list* src, struct block_list* dst, int64 tick, int sdelay, int ddelay, int64 damage, int div, int type, int64 damage2); + int (*damage) (struct block_list* src, struct block_list* dst, int sdelay, int ddelay, int64 damage, short div, unsigned char type, int64 damage2); void (*sitting) (struct block_list* bl); void (*standing) (struct block_list* bl); void (*arrow_create_list) (struct map_session_data *sd); @@ -1021,6 +1030,9 @@ struct clif_interface { void (*show_modifiers) (struct map_session_data *sd); /* */ void (*notify_bounditem) (struct map_session_data *sd, unsigned short index); + /* */ + int (*delay_damage) (int64 tick, struct block_list *src, struct block_list *dst, int sdelay, int ddelay, int64 in_damage, short div, unsigned char type); + int (*delay_damage_sub) (int tid, int64 tick, int id, intptr_t data); /*------------------------ *- Parse Incoming Packet *------------------------*/ diff --git a/src/map/packets_struct.h b/src/map/packets_struct.h index 7e7f8bd87..df90b35a4 100644 --- a/src/map/packets_struct.h +++ b/src/map/packets_struct.h @@ -54,6 +54,11 @@ enum packet_headers { spawn_unit2Type = 0x7c, idle_unit2Type = 0x78, #endif +#if PACKETVER < 20071113 + damageType = 0x8a, +#else + damageType = 0x2e1, +#endif #if PACKETVER < 4 spawn_unitType = 0x79, #elif PACKETVER < 7 @@ -869,6 +874,27 @@ struct packet_graffiti_entry { char msg[80]; } __attribute__((packed)); +struct packet_damage { + short PacketType; + unsigned int GID; + unsigned int targetGID; + unsigned int startTime; + int attackMT; + int attackedMT; +#if PACKETVER < 20071113 + short damage; +#else + int damage; +#endif + short count; + unsigned char action; +#if PACKETVER < 20071113 + short leftDamage; +#else + int leftDamage; +#endif +} __attribute__((packed)); + #pragma pack(pop) #endif /* _PACKETS_STRUCT_H_ */ diff --git a/src/map/skill.c b/src/map/skill.c index 84c45e8a6..45d06c97a 100644 --- a/src/map/skill.c +++ b/src/map/skill.c @@ -2380,7 +2380,7 @@ int skill_attack(int attack_type, struct block_list* src, struct block_list *dsr case NPC_CRITICALSLASH: case TF_DOUBLE: case GS_CHAINACTION: - dmg.dmotion = clif->damage(src,bl,tick,dmg.amotion,dmg.dmotion,damage,dmg.div_,dmg.type,dmg.damage2); + dmg.dmotion = clif->damage(src,bl,dmg.amotion,dmg.dmotion,damage,dmg.div_,dmg.type,dmg.damage2); break; case AS_SPLASHER: @@ -2680,12 +2680,12 @@ int skill_attack(int attack_type, struct block_list* src, struct block_list *dsr ) && check_distance_bl(bl, d_bl, sce->val3) ) { if(!rmdamage){ - clif->damage(d_bl,d_bl, timer->gettick(), 0, 0, damage, 0, 0, 0); + clif->damage(d_bl,d_bl, 0, 0, damage, 0, 0, 0); status_fix_damage(NULL,d_bl, damage, 0); } else{ //Reflected magics are done directly on the target not on paladin //This check is only for magical skill. //For BF_WEAPON skills types track var rdamage and function battle_calc_return_damage - clif->damage(bl,bl, timer->gettick(), 0, 0, damage, 0, 0, 0); + clif->damage(bl,bl, 0, 0, damage, 0, 0, 0); status_fix_damage(bl,bl, damage, 0); } } @@ -3866,7 +3866,7 @@ int skill_castend_damage_id(struct block_list* src, struct block_list *bl, uint1 break; case CH_PALMSTRIKE: // Palm Strike takes effect 1sec after casting. [Skotlex] // clif->skill_nodamage(src,bl,skill_id,skill_lv,0); //Can't make this one display the correct attack animation delay :/ - clif->damage(src,bl,tick,status_get_amotion(src),0,-1,1,4,0); //Display an absorbed damage attack. + clif->damage(src,bl,status_get_amotion(src),0,-1,1,4,0); //Display an absorbed damage attack. skill->addtimerskill(src, tick + (1000+status_get_amotion(src)), bl->id, 0, 0, skill_id, skill_lv, BF_WEAPON, flag); break; @@ -7307,7 +7307,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin case 3: // 1000 damage, random armor destroyed { status_fix_damage(src, bl, 1000, 0); - clif->damage(src,bl,tick,0,0,1000,0,0,0); + clif->damage(src,bl,0,0,1000,0,0,0); if( !status->isdead(bl) ) { int where[] = { EQP_ARMOR, EQP_SHIELD, EQP_HELM, EQP_SHOES, EQP_GARMENT }; skill->break_equip(bl, where[rnd()%5], 10000, BCT_ENEMY); @@ -7344,14 +7344,14 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin break; case 10: // 6666 damage, atk matk halved, cursed status_fix_damage(src, bl, 6666, 0); - clif->damage(src,bl,tick,0,0,6666,0,0,0); + clif->damage(src,bl,0,0,6666,0,0,0); sc_start(bl,SC_INCATKRATE,100,-50,skill->get_time2(skill_id,skill_lv)); sc_start(bl,SC_INCMATKRATE,100,-50,skill->get_time2(skill_id,skill_lv)); sc_start(bl,SC_CURSE,skill_lv,100,skill->get_time2(skill_id,skill_lv)); break; case 11: // 4444 damage status_fix_damage(src, bl, 4444, 0); - clif->damage(src,bl,tick,0,0,4444,0,0,0); + clif->damage(src,bl,0,0,4444,0,0,0); break; case 12: // stun sc_start(bl,SC_STUN,100,skill_lv,5000); @@ -8690,7 +8690,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin sc_start(bl, type, 100, skill_lv,skill->get_time(skill_id, skill_lv)); } else if( flag&2 ) { if( src->id != bl->id && battle->check_target(src,bl,BCT_ENEMY) > 0 ) - status_fix_damage(src,bl,9999,clif->damage(src,bl,tick,0,0,9999,0,0,0)); + status_fix_damage(src,bl,9999,clif->damage(src,bl,0,0,9999,0,0,0)); } else if( sd ) { short chance = sstatus->int_/6 + sd->status.job_level/5 + skill_lv*4; if( !sd->status.party_id || (rnd()%100 > chance)) { @@ -8706,7 +8706,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin clif->skill_nodamage(src, bl, skill_id, skill_lv, sc_start(src,SC_STOP,100,skill_lv,skill->get_time2(skill_id,skill_lv))); if( flag&2 ) // Dealed here to prevent conflicts - status_fix_damage(src,bl,9999,clif->damage(src,bl,tick,0,0,9999,0,0,0)); + status_fix_damage(src,bl,9999,clif->damage(src,bl,0,0,9999,0,0,0)); } break; @@ -15114,7 +15114,7 @@ bool skill_check_shadowform(struct block_list *bl, int64 damage, int hit){ return false; } - status->damage(bl, src, damage, 0, clif->damage(src, src, timer->gettick(), 500, 500, damage, hit, (hit > 1 ? 8 : 0), 0), 0); + status->damage(bl, src, damage, 0, clif->damage(src, src, 500, 500, damage, hit, (hit > 1 ? 8 : 0), 0), 0); if( (--sc->data[SC__SHADOWFORM]->val3) <= 0 ) { status_change_end(bl, SC__SHADOWFORM, INVALID_TIMER); if( src->type == BL_PC ) diff --git a/src/map/status.c b/src/map/status.c index 132724bef..29a1689a1 100644 --- a/src/map/status.c +++ b/src/map/status.c @@ -9629,7 +9629,7 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const struct block_list* src = map->id2bl(sce->val2); if( tid == -1 || !src) break; // Terminated by Damage - status_fix_damage(src,bl,400*sce->val1,clif->damage(bl,bl,timer->gettick(),0,0,400*sce->val1,0,0,0)); + status_fix_damage(src,bl,400*sce->val1,clif->damage(bl,bl,0,0,400*sce->val1,0,0,0)); } break; case SC_WUGDASH: @@ -10325,7 +10325,7 @@ int status_change_timer(int tid, int64 tick, int id, intptr_t data) { case SC_PYREXIA: if( --(sce->val4) > 0 ) { map->freeblock_lock(); - clif->damage(bl,bl,tick,status_get_amotion(bl),status_get_dmotion(bl)+500,100,0,0,0); + clif->damage(bl,bl,status_get_amotion(bl),status_get_dmotion(bl)+500,100,0,0,0); status_fix_damage(NULL,bl,100,0); if( sc->data[type] ) { sc_timer_next(3000+tick,status->change_timer,bl->id,data); @@ -10341,7 +10341,7 @@ int status_change_timer(int tid, int64 tick, int id, intptr_t data) { damage += st->vit * (sce->val1 - 3); unit->skillcastcancel(bl,2); map->freeblock_lock(); - status->damage(bl, bl, damage, 0, clif->damage(bl,bl,tick,status_get_amotion(bl),status_get_dmotion(bl)+500,damage,1,0,0), 1); + status->damage(bl, bl, damage, 0, clif->damage(bl,bl,status_get_amotion(bl),status_get_dmotion(bl)+500,damage,1,0,0), 1); if( sc->data[type] ) { sc_timer_next(1000 + tick, status->change_timer, bl->id, data ); } @@ -10399,7 +10399,7 @@ int status_change_timer(int tid, int64 tick, int id, intptr_t data) { if( --(sce->val4) > 0 ) { //Damage is every 10 seconds including 3%sp drain. map->freeblock_lock(); - clif->damage(bl,bl,tick,status_get_amotion(bl),1,1,0,0,0); + clif->damage(bl,bl,status_get_amotion(bl),1,1,0,0,0); status->damage(NULL, bl, 1, st->max_sp * 3 / 100, 0, 0); //cancel dmg only if cancelable if( sc->data[type] ) { sc_timer_next(10000 + tick, status->change_timer, bl->id, data ); @@ -10449,7 +10449,7 @@ int status_change_timer(int tid, int64 tick, int id, intptr_t data) { int damage = 1000 + 3 * status_get_max_hp(bl) / 100; // Deals fixed (1000 + 3%*MaxHP) map->freeblock_lock(); - clif->damage(bl,bl,tick,0,0,damage,1,9,0); //damage is like endure effect with no walk delay + clif->damage(bl,bl,0,0,damage,1,9,0); //damage is like endure effect with no walk delay status->damage(src, bl, damage, 0, 0, 1); if( sc->data[type]){ // Target still lives. [LimitLine] @@ -10554,7 +10554,7 @@ int status_change_timer(int tid, int64 tick, int id, intptr_t data) { break; map->freeblock_lock(); damage = sce->val3; - status->damage(src, bl, damage, 0, clif->damage(bl,bl,tick,st->amotion,st->dmotion+200,damage,1,0,0), 1); + status->damage(src, bl, damage, 0, clif->damage(bl,bl,st->amotion,st->dmotion+200,damage,1,0,0), 1); unit->skillcastcancel(bl,1); if ( sc->data[type] ) { sc_timer_next(1000 + tick, status->change_timer, bl->id, data); @@ -10657,7 +10657,7 @@ int status_change_timer(int tid, int64 tick, int id, intptr_t data) { int damage = st->max_hp / 100; // Suggestion 1% each second if( damage >= st->hp ) damage = st->hp - 1; // Do not kill, just keep you with 1 hp minimum map->freeblock_lock(); - status_fix_damage(NULL,bl,damage,clif->damage(bl,bl,tick,0,0,damage,0,0,0)); + status_fix_damage(NULL,bl,damage,clif->damage(bl,bl,0,0,damage,0,0,0)); if( sc->data[type] ) { sc_timer_next(1000 + tick, status->change_timer, bl->id, data); } diff --git a/src/map/unit.c b/src/map/unit.c index 04af6c117..872ad1f8b 100644 --- a/src/map/unit.c +++ b/src/map/unit.c @@ -2021,13 +2021,13 @@ int unit_counttargeted(struct block_list* bl) /*========================================== * *------------------------------------------*/ -int unit_fixdamage(struct block_list *src, struct block_list *target, int64 tick, int sdelay, int ddelay, int64 damage, int div, int type, int64 damage2) { +int unit_fixdamage(struct block_list *src, struct block_list *target, int sdelay, int ddelay, int64 damage, short div, unsigned char type, int64 damage2) { nullpo_ret(target); if(damage+damage2 <= 0) return 0; - return status_fix_damage(src,target,damage+damage2,clif->damage(target,target,tick,sdelay,ddelay,damage,div,type,damage2)); + return status_fix_damage(src,target,damage+damage2,clif->damage(target,target,sdelay,ddelay,damage,div,type,damage2)); } /*========================================== diff --git a/src/map/unit.h b/src/map/unit.h index 8220b7e8f..a2d743875 100644 --- a/src/map/unit.h +++ b/src/map/unit.h @@ -113,7 +113,7 @@ struct unit_interface { int (*skillcastcancel) (struct block_list *bl, int type); void (*dataset) (struct block_list *bl); int (*counttargeted) (struct block_list *bl); - int (*fixdamage) (struct block_list *src, struct block_list *target, int64 tick, int sdelay, int ddelay, int64 damage, int div, int type, int64 damage2); + int (*fixdamage) (struct block_list *src, struct block_list *target, int sdelay, int ddelay, int64 damage, short div, unsigned char type, int64 damage2); int (*changeviewsize) (struct block_list *bl, short size); int (*remove_map) (struct block_list *bl, clr_type clrtype, const char *file, int line, const char *func); void (*remove_map_pc) (struct map_session_data *sd, clr_type clrtype); -- cgit v1.2.3-60-g2f50