From 0d77398385fef6dade61532f2456bb1b7367f0c7 Mon Sep 17 00:00:00 2001 From: Aleos Date: Tue, 18 Sep 2018 11:05:27 -0400 Subject: [PATCH] Cleaned up Banding behavior (#3486) * Fixes #3478. * Adjusted Banding to use proper party counting functions. * Corrected the DEF and HP Regen bonus for Banding. * Banding Defense will no longer stack on itself. Thanks to @admkakaroto and @exneval! --- db/pre-re/skill_db.txt | 2 +- db/re/skill_db.txt | 2 +- src/map/party.cpp | 29 +++++++++++++ src/map/party.hpp | 1 + src/map/pc.cpp | 94 ------------------------------------------ src/map/pc.hpp | 2 - src/map/skill.cpp | 34 ++++++++++++--- src/map/skill.hpp | 2 + src/map/status.cpp | 10 +++-- 9 files changed, 69 insertions(+), 107 deletions(-) diff --git a/db/pre-re/skill_db.txt b/db/pre-re/skill_db.txt index ced6ee610a..6b2096a245 100644 --- a/db/pre-re/skill_db.txt +++ b/db/pre-re/skill_db.txt @@ -1115,7 +1115,7 @@ 2316,0,6,4,0,0x1,0,5,1,yes,0,0,0,none,0,0x0, LG_EXEEDBREAK,Exceed Break 2317,2,6,2,-1,0x2,0,5,1,yes,0,0,0,weapon,0,0x0, LG_OVERBRAND,Over Brand 2318,0,6,4,0,0x1,0,5,1,yes,0,0,0,none,0,0x0, LG_PRESTIGE,Prestige -2319,0,6,4,0,0x3,3,5,1,no,0,0,0,weapon,0,0x0, LG_BANDING,Banding //CHECK Splash isnt needed right? Banding has its own UNIT ID. +2319,0,6,4,0,0x3,3,5,1,no,0,0,0,weapon,0,0x0, LG_BANDING,Banding 2320,0,6,4,-1,0x2,3,5,1,yes,0,0,0,weapon,0,0x1000, LG_MOONSLASHER,Moon Slasher 2321,1,8,2,6,0x2,5,5,-7,yes,0,0,0,weapon,0,0x0, LG_RAYOFGENESIS,Ray of Genesis 2322,0,6,16,0,0x3,1,5,1,yes,0,0,0,none,0,0x0, LG_PIETY,Piety diff --git a/db/re/skill_db.txt b/db/re/skill_db.txt index a722995800..10c2e5c835 100644 --- a/db/re/skill_db.txt +++ b/db/re/skill_db.txt @@ -1121,7 +1121,7 @@ 2316,0,6,4,0,0x1,0,5,1,yes,0,0,0,none,0,0x0, LG_EXEEDBREAK,Exceed Break 2317,2,6,2,-1,0x2,0,5,1,yes,0,0,0,weapon,0,0x0, LG_OVERBRAND,Over Brand 2318,0,6,4,0,0x1,0,5,1,yes,0,0,0,none,0,0x0, LG_PRESTIGE,Prestige -2319,0,6,4,0,0x3,3,5,1,no,0,0,0,weapon,0,0x0, LG_BANDING,Banding //CHECK Splash isnt needed right? Banding has its own UNIT ID. +2319,0,6,4,0,0x3,3,5,1,no,0,0,0,weapon,0,0x0, LG_BANDING,Banding 2320,0,6,4,-1,0x2,3,5,1,yes,0,0,0,weapon,0,0x1000, LG_MOONSLASHER,Moon Slasher 2321,1,8,2,6,0x2,5,5,-7,yes,0,0,0,weapon,0,0x0, LG_RAYOFGENESIS,Ray of Genesis 2322,0,6,16,0,0x3,1,5,1,yes,0,0,0,none,0,0x0, LG_PIETY,Piety diff --git a/src/map/party.cpp b/src/map/party.cpp index 8d3f384fdd..cd4ea9aa6c 100644 --- a/src/map/party.cpp +++ b/src/map/party.cpp @@ -1249,6 +1249,35 @@ int party_sub_count_class(struct block_list *bl, va_list ap) return 1; } +/** + * Special check for Royal Guard's Banding skill. + * @param bl: Object invoking the counter + * @param ap: List of parameters: Check Type + * @return 1 or total HP on success or 0 otherwise + */ +int party_sub_count_banding(struct block_list *bl, va_list ap) +{ + struct map_session_data *sd = (TBL_PC *)bl; + int type = va_arg(ap, int); // 0 = Banding Count, 1 = HP Check + + if (sd->state.autotrade) + return 0; + + if (battle_config.idle_no_share && pc_isidle(sd)) + return 0; + + if ((sd->class_&MAPID_THIRDMASK) != MAPID_ROYAL_GUARD) + return 0; + + if (!sd->sc.data[SC_BANDING]) + return 0; + + if (type == 1) + return status_get_hp(bl); + + return 1; +} + /// Executes 'func' for each party member on the same map and in range (0:whole map) int party_foreachsamemap(int (*func)(struct block_list*,va_list),struct map_session_data *sd,int range,...) { diff --git a/src/map/party.hpp b/src/map/party.hpp index d27633db7d..a6465285d5 100644 --- a/src/map/party.hpp +++ b/src/map/party.hpp @@ -89,6 +89,7 @@ int party_share_loot(struct party_data* p, struct map_session_data* sd, struct i int party_send_dot_remove(struct map_session_data *sd); int party_sub_count(struct block_list *bl, va_list ap); int party_sub_count_class(struct block_list *bl, va_list ap); +int party_sub_count_banding(struct block_list *bl, va_list ap); int party_foreachsamemap(int (*func)(struct block_list *,va_list),struct map_session_data *sd,int range,...); /*========================================== diff --git a/src/map/pc.cpp b/src/map/pc.cpp index ab1040ecad..ac5561063a 100755 --- a/src/map/pc.cpp +++ b/src/map/pc.cpp @@ -339,100 +339,6 @@ void pc_delspiritball(struct map_session_data *sd,int count,int type) } } -static int pc_check_banding( struct block_list *bl, va_list ap ) { - int *c, *b_sd; - struct block_list *src; - struct map_session_data *tsd; - struct status_change *sc; - - nullpo_ret(bl); - nullpo_ret(tsd = (struct map_session_data*)bl); - nullpo_ret(src = va_arg(ap,struct block_list *)); - c = va_arg(ap,int *); - b_sd = va_arg(ap, int *); - - if(pc_isdead(tsd)) - return 0; - - sc = status_get_sc(bl); - - if( sc && sc->data[SC_BANDING] ) - { - b_sd[(*c)++] = tsd->bl.id; - return 1; - } - - return 0; -} - -int pc_banding(struct map_session_data *sd, uint16 skill_lv) { - int c; - int b_sd[MAX_PARTY]; // In case of a full Royal Guard party. - int i, j, hp, extra_hp = 0, tmp_qty = 0; - int range = skill_get_splash(LG_BANDING,skill_lv); - - nullpo_ret(sd); - - c = 0; - memset(b_sd, 0, sizeof(b_sd)); - i = party_foreachsamemap(pc_check_banding,sd,range,&sd->bl,&c,&b_sd); - - if( c < 1 ) //just recalc status no need to recalc hp - { // No more Royal Guards in Banding found. - struct status_change *sc; - if( (sc = status_get_sc(&sd->bl)) != NULL && sc->data[SC_BANDING] ) - { - sc->data[SC_BANDING]->val2 = 0; // Reset the counter - status_calc_bl(&sd->bl, status_sc2scb_flag(SC_BANDING)); - } - return 0; - } - - //Add yourself - hp = status_get_hp(&sd->bl); - i++; - - // Get total HP of all Royal Guards in party. - for( j = 0; j < i; j++ ){ - struct map_session_data *bsd = map_id2sd(b_sd[j]); - if( bsd != NULL ) - hp += status_get_hp(&bsd->bl); - } - - // Set average HP. - hp = hp / i; - - // If a Royal Guard have full HP, give more HP to others that haven't full HP. - for( j = 0; j < i; j++ ) - { - int tmp_hp=0; - struct map_session_data *bsd = map_id2sd(b_sd[j]); - if( bsd != NULL && (tmp_hp = hp - status_get_max_hp(&bsd->bl)) > 0 ){ - extra_hp += tmp_hp; - tmp_qty++; - } - } - - if( extra_hp > 0 && tmp_qty > 0 ) - hp += extra_hp / tmp_qty; - - for( j = 0; j < i; j++ ){ - struct map_session_data *bsd = map_id2sd(b_sd[j]); - if( bsd != NULL ) - { - struct status_change *sc; - status_set_hp(&bsd->bl,hp,0); // Set hp - if( (sc = status_get_sc(&bsd->bl)) != NULL && sc->data[SC_BANDING] ) - { - sc->data[SC_BANDING]->val2 = c; // Set the counter. It doesn't count your self. - status_calc_bl(&bsd->bl, status_sc2scb_flag(SC_BANDING)); // Set atk and def. - } - } - } - - return c; -} - /** * Increases a player's fame points and displays a notice to him * @param sd Player diff --git a/src/map/pc.hpp b/src/map/pc.hpp index 05e861c648..3d3af17037 100644 --- a/src/map/pc.hpp +++ b/src/map/pc.hpp @@ -1290,8 +1290,6 @@ bool pc_isautolooting(struct map_session_data *sd, unsigned short nameid); void pc_overheat(struct map_session_data *sd, int16 heat); -int pc_banding(struct map_session_data *sd, uint16 skill_lv); - void pc_itemcd_do(struct map_session_data *sd, bool load); uint8 pc_itemcd_add(struct map_session_data *sd, struct item_data *id, unsigned int tick, unsigned short n); uint8 pc_itemcd_check(struct map_session_data *sd, struct item_data *id, unsigned int tick, unsigned short n); diff --git a/src/map/skill.cpp b/src/map/skill.cpp index 9dbe34afda..f9f91020f4 100755 --- a/src/map/skill.cpp +++ b/src/map/skill.cpp @@ -2366,8 +2366,7 @@ int skill_counter_additional_effect (struct block_list* src, struct block_list * { struct status_change *sc = status_get_sc(src); if( sc && sc->data[SC_FORCEOFVANGUARD] && sc->data[SC_BANDING] && sc->data[SC_BANDING]->val2 > 6 ) { - char i; - for( i = 0; i < sc->data[SC_FORCEOFVANGUARD]->val3; i++ ) + for(int i = 0; i < sc->data[SC_FORCEOFVANGUARD]->val3; i++ ) pc_addspiritball(sd, skill_get_time(LG_FORCEOFVANGUARD,1),sc->data[SC_FORCEOFVANGUARD]->val3); } } @@ -12247,10 +12246,8 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui case LG_BANDING: if( sc && sc->data[SC_BANDING] ) status_change_end(src,SC_BANDING,INVALID_TIMER); - else if( (sg = skill_unitsetting(src,skill_id,skill_lv,src->x,src->y,0)) != NULL ) { + else if( (sg = skill_unitsetting(src,skill_id,skill_lv,src->x,src->y,0)) != NULL ) sc_start4(src,src,SC_BANDING,100,skill_lv,0,0,sg->group_id,skill_get_time(skill_id,skill_lv)); - if( sd ) pc_banding(sd,skill_lv); - } clif_skill_nodamage(src,src,skill_id,skill_lv,1); break; @@ -17333,6 +17330,33 @@ int skill_detonator(struct block_list *bl, va_list ap) return 0; } +/** + * Calculate Royal Guard's Banding bonus + * @param sd: Player data + * @return Number of Royal Guard + */ +int skill_banding_count(struct map_session_data *sd) +{ + nullpo_ret(sd); + + int range = skill_get_splash(LG_BANDING, 1); + uint8 count = party_foreachsamemap(party_sub_count_banding, sd, range, 0); + unsigned int group_hp = party_foreachsamemap(party_sub_count_banding, sd, range, 1); + + // HP is set to the average HP of the Banding group + if (count > 1) + status_set_hp(&sd->bl, group_hp / count, 0); + + // Royal Guard count check for Banding + if (sd && sd->status.party_id) { + if (count > MAX_PARTY) + return MAX_PARTY; + else if (count > 1) + return count; // Effect bonus from additional Royal Guards if not above the max + } + return 0; +} + /** * Rebellion's Bind Trap explosion * @author [Cydh] diff --git a/src/map/skill.hpp b/src/map/skill.hpp index 8c927b237c..4984005a49 100644 --- a/src/map/skill.hpp +++ b/src/map/skill.hpp @@ -2205,6 +2205,8 @@ int skill_elementalanalysis(struct map_session_data *sd, int n, uint16 skill_lv, int skill_changematerial(struct map_session_data *sd, int n, unsigned short *item_list); // Genetic Change Material. int skill_get_elemental_type(uint16 skill_id, uint16 skill_lv); +int skill_banding_count(struct map_session_data *sd); + int skill_is_combo(uint16 skill_id); void skill_combo_toggle_inf(struct block_list* bl, uint16 skill_id, int inf); void skill_combo(struct block_list* src,struct block_list *dsrc, struct block_list *bl, uint16 skill_id, uint16 skill_lv, int tick); diff --git a/src/map/status.cpp b/src/map/status.cpp index d08be8e812..fdfe92a40b 100644 --- a/src/map/status.cpp +++ b/src/map/status.cpp @@ -715,7 +715,7 @@ void initChangeTables(void) set_sc( LG_FORCEOFVANGUARD , SC_FORCEOFVANGUARD , EFST_FORCEOFVANGUARD , SCB_MAXHP ); set_sc( LG_EXEEDBREAK , SC_EXEEDBREAK , EFST_EXEEDBREAK , SCB_NONE ); set_sc( LG_PRESTIGE , SC_PRESTIGE , EFST_PRESTIGE , SCB_DEF ); - set_sc( LG_BANDING , SC_BANDING , EFST_BANDING , SCB_DEF2|SCB_WATK ); + set_sc( LG_BANDING , SC_BANDING , EFST_BANDING , SCB_DEF|SCB_WATK|SCB_REGEN ); set_sc( LG_PIETY , SC_BENEDICTIO , EFST_BENEDICTIO , SCB_DEF_ELE ); set_sc( LG_EARTHDRIVE , SC_EARTHDRIVE , EFST_EARTHDRIVE , SCB_DEF|SCB_ASPD ); set_sc( LG_INSPIRATION , SC_INSPIRATION , EFST_INSPIRATION , SCB_WATK|SCB_STR|SCB_AGI|SCB_VIT|SCB_INT|SCB_DEX|SCB_LUK|SCB_HIT|SCB_MAXHP); @@ -4657,6 +4657,8 @@ void status_calc_regen_rate(struct block_list *bl, struct regen_data *regen, str } else regen->flag &= ~sce->val4; // Remove regen as specified by val4 } + if (sc->data[SC_BANDING] && sc->data[SC_BANDING]->val2 > 1) + regen->hp += cap_value(regen->hp * 50 / 100, 1, SHRT_MAX); if(sc->data[SC_GT_REVITALIZE]) { regen->hp += cap_value(regen->hp * sc->data[SC_GT_REVITALIZE]->val3/100, 1, SHRT_MAX); regen->state.walk = 1; @@ -6522,8 +6524,6 @@ static signed short status_calc_def2(struct block_list *bl, struct status_change if(sc->data[SC_SUN_COMFORT]) def2 += sc->data[SC_SUN_COMFORT]->val2; - if( sc->data[SC_BANDING] && sc->data[SC_BANDING]->val2 > 1 ) - def2 += (5 + sc->data[SC_BANDING]->val1) * sc->data[SC_BANDING]->val2; #ifdef RENEWAL if (sc->data[SC_SKA]) def2 += 80; @@ -9333,6 +9333,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty case SC_OBLIVIONCURSE: case SC_LEECHESEND: case SC_CURSEDCIRCLE_TARGET: + case SC_BANDING_DEFENCE: case SC__ENERVATION: case SC__GROOMY: case SC__IGNORANCE: @@ -10631,6 +10632,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty val3 = ((val1 * 15) + (10 * (sd?pc_checkskill(sd,CR_DEFENDER):skill_get_max(CR_DEFENDER)))) * status_get_lv(bl) / 100; // Defence added break; case SC_BANDING: + val2 = (sd ? skill_banding_count(sd) : 1); tick_time = 5000; // [GodLesZ] tick time break; case SC_MAGNETICFIELD: @@ -13351,7 +13353,7 @@ TIMER_FUNC(status_change_timer){ case SC_BANDING: if( status_charge(bl, 0, 7 - sce->val1) ) { - if( sd ) pc_banding(sd, sce->val1); + sce->val2 = (sd ? skill_banding_count(sd) : 1); sc_timer_next(5000 + tick); return 0; }