From eb0a79f1bf6fe36ead95371b591f226d0cf1aeb1 Mon Sep 17 00:00:00 2001 From: aleos89 Date: Fri, 28 Aug 2015 15:05:24 -0400 Subject: [PATCH] Bug Fixes * Fixes #587 - Corrected Amistr Defence to properly calculate VIT for renewal and DEF for pre-renewal. * Fixes #588 - Fixed skills not being properly removed when being copied by Plagiarism or Reproduce. * Fixes #589 - Blessing no longer gives stat bonuses when Curse is active. * Fixes #599 - Fixed a possible crash by Praefatio. * Fixes #601 - Exceed Break now cancels when switching weapons and is properly removed on misses. --- src/map/battle.c | 8 +++--- src/map/pc.c | 67 ++++++++++++++++++++++++++---------------------- src/map/skill.c | 31 ++++++++++------------ src/map/status.c | 31 ++++++++++++++-------- 4 files changed, 74 insertions(+), 63 deletions(-) diff --git a/src/map/battle.c b/src/map/battle.c index ef0b6035aa..f791f2c40e 100644 --- a/src/map/battle.c +++ b/src/map/battle.c @@ -3300,10 +3300,6 @@ static int battle_calc_attack_skill_ratio(struct Damage wd, struct block_list *s status_change_end(src,SC_CRUSHSTRIKE,INVALID_TIMER); skill_break_equip(src,src,EQP_WEAPON,2000,BCT_SELF); } - if (sc->data[SC_EXEEDBREAK] && !skill_id) { - skillratio += -100 + sc->data[SC_EXEEDBREAK]->val1; - status_change_end(src,SC_EXEEDBREAK,INVALID_TIMER); - } //!TODO: Verify this placement & skills that affected by these effects [Cydh] if (sc->data[SC_HEAT_BARREL]) skillratio += 200; @@ -7060,6 +7056,10 @@ enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* t wd = battle_calc_attack(BF_WEAPON, src, target, 0, 0, flag); if( sc && sc->count ) { + if (sc->data[SC_EXEEDBREAK]) { + wd.damage *= sc->data[SC_EXEEDBREAK]->val1 / 100; + status_change_end(src, SC_EXEEDBREAK, INVALID_TIMER); + } if( sc->data[SC_SPELLFIST] ) { if( --(sc->data[SC_SPELLFIST]->val1) >= 0 ){ struct Damage ad = battle_calc_attack(BF_MAGIC,src,target,sc->data[SC_SPELLFIST]->val3,sc->data[SC_SPELLFIST]->val4,flag|BF_SHORT); diff --git a/src/map/pc.c b/src/map/pc.c index 6b6cffd198..0e2ced305d 100755 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -5480,7 +5480,7 @@ uint8 pc_checkskill(struct map_session_data *sd, uint16 skill_id) } /** - * Chk if we still have the correct weapon to continue the skill (actually status) + * Check if we still have the correct weapon to continue the skill (actually status) * If not ending it * @param sd * @return 0:error, 1:check done @@ -5497,7 +5497,6 @@ static void pc_checkallowskill(struct map_session_data *sd) SC_ADRENALINE2, SC_DANCING, SC_GATLINGFEVER, - SC_FEARBREEZE }; uint8 i; nullpo_retv(sd); @@ -9468,45 +9467,38 @@ bool pc_equipitem(struct map_session_data *sd,short n,int req_pos) * 2 - force unequip * return: false - fail; true - success *------------------------------------------*/ -bool pc_unequipitem(struct map_session_data *sd,int n,int flag) { - int i,iflag; +bool pc_unequipitem(struct map_session_data *sd, int n, int flag) { + int i, iflag; bool status_cacl = false; + nullpo_retr(false,sd); - if( n < 0 || n >= MAX_INVENTORY ) { + if (n < 0 || n >= MAX_INVENTORY) { clif_unequipitemack(sd,0,0,0); return false; } - + if (!sd->status.inventory[n].equip) { + clif_unequipitemack(sd,n,0,0); + return false; //Nothing to unequip + } // status change that makes player cannot unequip equipment - if( !(flag&2) && sd->sc.count && ( - sd->sc.data[SC_BERSERK] || + if (!(flag&2) && sd->sc.count && + (sd->sc.data[SC_BERSERK] || sd->sc.data[SC_SATURDAYNIGHTFEVER] || sd->sc.data[SC__BLOODYLUST] || sd->sc.data[SC_KYOUGAKU] || - (sd->sc.data[SC_PYROCLASTIC] && sd->inventory_data[n]->type == IT_WEAPON)) ) // can't switch weapon + (sd->sc.data[SC_PYROCLASTIC] && + sd->inventory_data[n]->type == IT_WEAPON))) // can't switch weapon { clif_unequipitemack(sd,n,0,0); return false; } - if (&sd->sc) { - if (sd->sc.data[SC_HOVERING] && sd->inventory_data[n]->type == IT_ARMOR && sd->inventory_data[n]->nameid == ITEMID_HOVERING_BOOSTER) - status_change_end(&sd->bl, SC_HOVERING, INVALID_TIMER); - if (sd->sc.data[SC_HEAT_BARREL]) - status_change_end(&sd->bl,SC_HEAT_BARREL,INVALID_TIMER); - if (sd->sc.data[SC_P_ALTER] && (sd->inventory_data[n]->type == IT_WEAPON || sd->inventory_data[n]->type == IT_AMMO)) - status_change_end(&sd->bl,SC_P_ALTER,INVALID_TIMER); - } - if(battle_config.battle_log) + if (battle_config.battle_log) ShowInfo("unequip %d %x:%x\n",n,pc_equippoint(sd,n),sd->status.inventory[n].equip); - if(!sd->status.inventory[n].equip){ //Nothing to unequip - clif_unequipitemack(sd,n,0,0); - return false; - } - for(i=0;istatus.inventory[n].equip & equip_pos[i]) + for(i = 0; i < EQI_MAX; i++) { + if (sd->status.inventory[n].equip & equip_pos[i]) sd->equip_index[i] = -1; } @@ -9566,20 +9558,32 @@ bool pc_unequipitem(struct map_session_data *sd,int n,int flag) { clif_unequipitemack(sd,n,sd->status.inventory[n].equip,1); - if((sd->status.inventory[n].equip & EQP_ARMS) && sd->inventory_data[n]->type == IT_WEAPON && //On weapon change (right and left hand) - (!sd->sc.data[SC_SEVENWIND] || sd->sc.data[SC_ASPERSIO])) //Check for seven wind (but not level seven!) - skill_enchant_elemental_end(&sd->bl,SC_NONE); + status_change_end(&sd->bl,SC_HEAT_BARREL,INVALID_TIMER); + // On weapon change (right and left hand) + if ((sd->status.inventory[n].equip & EQP_ARMS) && sd->inventory_data[n]->type == IT_WEAPON) { + if (!sd->sc.data[SC_SEVENWIND] || sd->sc.data[SC_ASPERSIO]) //Check for seven wind (but not level seven!) + skill_enchant_elemental_end(&sd->bl, SC_NONE); + status_change_end(&sd->bl, SC_FEARBREEZE, INVALID_TIMER); + status_change_end(&sd->bl, SC_EXEEDBREAK, INVALID_TIMER); + status_change_end(&sd->bl, SC_P_ALTER, INVALID_TIMER); + } - if(sd->status.inventory[n].equip & EQP_ARMOR) { - // On Armor Change... - status_change_end(&sd->bl, SC_BENEDICTIO, INVALID_TIMER); + // On armor change + if (sd->status.inventory[n].equip & EQP_ARMOR) { + if (sd->sc.data[SC_HOVERING] && sd->inventory_data[n]->nameid == ITEMID_HOVERING_BOOSTER) + status_change_end(&sd->bl, SC_HOVERING, INVALID_TIMER); + //status_change_end(&sd->bl, SC_BENEDICTIO, INVALID_TIMER); // No longer is removed? Need confirmation status_change_end(&sd->bl, SC_ARMOR_RESIST, INVALID_TIMER); } + // On ammo change + if (sd->inventory_data[n]->type == IT_AMMO) + status_change_end(&sd->bl, SC_P_ALTER, INVALID_TIMER); + if( sd->state.autobonus&sd->status.inventory[n].equip ) sd->state.autobonus &= ~sd->status.inventory[n].equip; //Check for activated autobonus [Inkfish] - sd->status.inventory[n].equip=0; + sd->status.inventory[n].equip = 0; iflag = sd->npc_item_flag; /* check for combos (MUST be before status_calc_pc) */ @@ -9592,6 +9596,7 @@ bool pc_unequipitem(struct map_session_data *sd,int n,int flag) { else { for( i = 0; i < sd->inventory_data[n]->slot; i++ ) { struct item_data *data; + if (!sd->status.inventory[n].card[i]) continue; if ( ( data = itemdb_exists(sd->status.inventory[n].card[i]) ) != NULL ) { diff --git a/src/map/skill.c b/src/map/skill.c index 6eb9293d67..ef3fd4e19e 100755 --- a/src/map/skill.c +++ b/src/map/skill.c @@ -2766,10 +2766,10 @@ static void skill_do_copy(struct block_list* src,struct block_list *bl, uint16 s case 1: //Copied by Plagiarism { if (tsd->cloneskill_idx > 0 && tsd->status.skill[tsd->cloneskill_idx].flag == SKILL_FLAG_PLAGIARIZED) { - clif_deleteskill(tsd,tsd->status.skill[tsd->cloneskill_idx].id); tsd->status.skill[tsd->cloneskill_idx].id = 0; tsd->status.skill[tsd->cloneskill_idx].lv = 0; tsd->status.skill[tsd->cloneskill_idx].flag = SKILL_FLAG_PERMANENT; + clif_deleteskill(tsd,tsd->status.skill[tsd->cloneskill_idx].id); } lv = min(skill_lv,pc_checkskill(tsd,RG_PLAGIARISM)); //Copied level never be > player's RG_PLAGIARISM level @@ -2786,10 +2786,10 @@ static void skill_do_copy(struct block_list* src,struct block_list *bl, uint16 s //Skill level copied depends on Reproduce skill that used lv = (tsc) ? tsc->data[SC__REPRODUCE]->val1 : 1; if( tsd->reproduceskill_idx > 0 && tsd->status.skill[tsd->reproduceskill_idx].flag == SKILL_FLAG_PLAGIARIZED ) { - clif_deleteskill(tsd,tsd->status.skill[tsd->reproduceskill_idx].id); tsd->status.skill[tsd->reproduceskill_idx].id = 0; tsd->status.skill[tsd->reproduceskill_idx].lv = 0; tsd->status.skill[tsd->reproduceskill_idx].flag = SKILL_FLAG_PERMANENT; + clif_deleteskill(tsd,tsd->status.skill[tsd->reproduceskill_idx].id); } //Level dependent and limitation. @@ -8779,7 +8779,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui break; case AB_ANCILLA: - if( sd ) { + if( sd ) { clif_skill_nodamage(src,bl,skill_id,skill_lv,1); skill_produce_mix(sd, skill_id, ITEMID_ANCILLA, 0, 0, 0, 1, -1); } @@ -8799,16 +8799,16 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui break; case AB_PRAEFATIO: - if( sd == NULL || sd->status.party_id == 0 || flag&1 ) - clif_skill_nodamage(bl, bl, skill_id, skill_lv, sc_start4(src, bl, type, 100, skill_lv, 0, 0, ( sd->status.party_id ? party_foreachsamemap(party_sub_count, sd, 0) : 1 ), skill_get_time(skill_id, skill_lv))); + if( !sd || sd->status.party_id == 0 || flag&1 ) + clif_skill_nodamage(bl, bl, skill_id, skill_lv, sc_start4(src, bl, type, 100, skill_lv, 0, 0, (sd && sd->status.party_id ? party_foreachsamemap(party_sub_count, sd, 0) : 1 ), skill_get_time(skill_id, skill_lv))); else if( sd ) party_foreachsamemap(skill_area_sub, sd, skill_get_splash(skill_id, skill_lv), src, skill_id, skill_lv, tick, flag|BCT_PARTY|1, skill_castend_nodamage_id); break; case AB_CHEAL: - if( sd == NULL || sd->status.party_id == 0 || flag&1 ) { + if( !sd || sd->status.party_id == 0 || flag&1 ) { if( sd && tstatus && !battle_check_undead(tstatus->race, tstatus->def_ele) && !tsc->data[SC_BERSERK] ) { - int partycount = ( sd->status.party_id ? party_foreachsamemap(party_sub_count, sd, 0) : 0 ); + int partycount = (sd->status.party_id ? party_foreachsamemap(party_sub_count, sd, 0) : 0); i = skill_calc_heal(src, bl, AL_HEAL, pc_checkskill(sd, AL_HEAL), true); @@ -8822,16 +8822,14 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui i = ~i + 1; status_heal(bl, i, 0, 0); } - } - else if( sd ) + } else if( sd ) party_foreachsamemap(skill_area_sub, sd, skill_get_splash(skill_id, skill_lv), src, skill_id, skill_lv, tick, flag|BCT_PARTY|1, skill_castend_nodamage_id); break; case AB_ORATIO: if( flag&1 ) sc_start(src,bl, type, 40 + 5 * skill_lv, skill_lv, skill_get_time(skill_id, skill_lv)); - else - { + else { map_foreachinrange(skill_area_sub, src, skill_get_splash(skill_id, skill_lv), BL_CHAR, src, skill_id, skill_lv, tick, flag|BCT_ENEMY|1, skill_castend_nodamage_id); clif_skill_nodamage(src, bl, skill_id, skill_lv, 1); @@ -8839,7 +8837,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui break; case AB_LAUDAAGNUS: - if( flag&1 || sd == NULL || !sd->status.party_id ) { + if( flag&1 || !sd || !sd->status.party_id ) { if( tsc && (tsc->data[SC_FREEZE] || tsc->data[SC_STONE] || tsc->data[SC_BLIND] || tsc->data[SC_BURNING] || tsc->data[SC_FREEZING] || tsc->data[SC_CRYSTALIZE])) { // Success Chance: (40 + 10 * Skill Level) % @@ -8850,7 +8848,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui status_change_end(bl, SC_BURNING, INVALID_TIMER); status_change_end(bl, SC_FREEZING, INVALID_TIMER); status_change_end(bl, SC_CRYSTALIZE, INVALID_TIMER); - }else //Success rate only applies to the curing effect and not stat bonus. Bonus status only applies to non infected targets + } else //Success rate only applies to the curing effect and not stat bonus. Bonus status only applies to non infected targets clif_skill_nodamage(bl, bl, skill_id, skill_lv, sc_start(src,bl, type, 100, skill_lv, skill_get_time(skill_id, skill_lv))); } else if( sd ) @@ -8859,7 +8857,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui break; case AB_LAUDARAMUS: - if( flag&1 || sd == NULL || !sd->status.party_id ) { + if( flag&1 || !sd || !sd->status.party_id ) { if( tsc && (tsc->data[SC_SLEEP] || tsc->data[SC_STUN] || tsc->data[SC_MANDRAGORA] || tsc->data[SC_SILENCE] || tsc->data[SC_DEEPSLEEP]) ){ // Success Chance: (40 + 10 * Skill Level) % if( rnd()%100 > 40+10*skill_lv ) break; @@ -8868,7 +8866,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui status_change_end(bl, SC_MANDRAGORA, INVALID_TIMER); status_change_end(bl, SC_SILENCE, INVALID_TIMER); status_change_end(bl, SC_DEEPSLEEP, INVALID_TIMER); - }else // Success rate only applies to the curing effect and not stat bonus. Bonus status only applies to non infected targets + } else // Success rate only applies to the curing effect and not stat bonus. Bonus status only applies to non infected targets clif_skill_nodamage(bl, bl, skill_id, skill_lv, sc_start(src,bl, type, 100, skill_lv, skill_get_time(skill_id, skill_lv))); } else if( sd ) @@ -8877,8 +8875,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui break; case AB_CLEARANCE: - if( flag&1 || (i = skill_get_splash(skill_id, skill_lv)) < 1 ) - { //As of the behavior in official server Clearance is just a super version of Dispell skill. [Jobbie] + if( flag&1 || (i = skill_get_splash(skill_id, skill_lv)) < 1 ) { // As of the behavior in official server Clearance is just a super version of Dispell skill. [Jobbie] if( bl->type != BL_MOB && battle_check_target(src,bl,BCT_PARTY) <= 0 ) // Only affect mob or party. break; diff --git a/src/map/status.c b/src/map/status.c index 34f1311172..b7074aa8cf 100644 --- a/src/map/status.c +++ b/src/map/status.c @@ -536,7 +536,12 @@ void initChangeTables(void) set_sc( HLIF_CHANGE , SC_CHANGE , SI_BLANK , SCB_VIT|SCB_INT ); set_sc( HFLI_FLEET , SC_FLEET , SI_BLANK , SCB_ASPD|SCB_BATK|SCB_WATK ); set_sc( HFLI_SPEED , SC_SPEED , SI_BLANK , SCB_FLEE ); - set_sc( HAMI_DEFENCE , SC_DEFENCE , SI_BLANK , SCB_DEF ); + set_sc( HAMI_DEFENCE , SC_DEFENCE , SI_BLANK , +#ifndef RENEWAL + SCB_DEF ); +#else + SCB_VIT ); +#endif set_sc( HAMI_BLOODLUST , SC_BLOODLUST , SI_BLANK , SCB_BATK|SCB_WATK ); /* Homunculus S */ @@ -5853,7 +5858,7 @@ static defType status_calc_def(struct block_list *bl, struct status_change *sc, def += sc->data[SC_DRUMBATTLE]->val3; #ifndef RENEWAL if(sc->data[SC_DEFENCE]) - def += sc->data[SC_DEFENCE]->val2 ; + def += sc->data[SC_DEFENCE]->val2; #endif if(sc->data[SC_INCDEFRATE]) def += def * sc->data[SC_INCDEFRATE]->val1/100; @@ -8194,10 +8199,14 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty case SC_BLESSING: // !TODO: 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 && status->race!=RC_DEMON) || bl->type == BL_PC) { + if ((!undead_flag && status->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_CURSE]) { + status_change_end(bl, SC_CURSE, INVALID_TIMER); + return 1; // End Curse and do not give stat boost + } } if(sc->data[SC_SPIRIT] && sc->data[SC_SPIRIT]->val2 == SL_HIGH) status_change_end(bl, SC_SPIRIT, INVALID_TIMER); @@ -9815,14 +9824,14 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty tick_time = 10000; // [GodLesZ] tick time break; case SC_EXEEDBREAK: - { - short idx = -1; - val1 *= 100; // 100 * skill_lv - if( sd && (idx = sd->equip_index[EQI_HAND_R]) >= 0 && sd->inventory_data[idx] ) { - val1 += (sd->inventory_data[idx]->weight/10 * sd->inventory_data[idx]->wlv * status_get_lv(bl) / 100); - val1 += 10 * sd->status.job_level; - } - } + val1 = 100 * val1; + if (sd) { // Players + short index = sd->equip_index[EQI_HAND_R]; + + if (index >= 0 && sd->inventory_data[index] && sd->inventory_data[index]->type == IT_WEAPON) + val1 += 10 * sd->status.job_level + sd->inventory_data[index]->weight / 10 * sd->inventory_data[index]->wlv * status_get_lv(bl) / 100; + } else // Monster + val1 += 500; break; case SC_PRESTIGE: val2 = (status->int_ + status->luk) * val1 / 20 * status_get_lv(bl) / 200 + val1; // Chance to evade magic damage.