Index: src/map/ai/ai_char_normal.cpp =================================================================== --- src/map/ai/ai_char_normal.cpp (revision 2104) +++ src/map/ai/ai_char_normal.cpp (working copy) @@ -2430,9 +2430,9 @@ } else if ( rand()%100 < hitRate) { - bool ignoreSneakAttack = (i != 0); // Sneak attack critical effect should only be given on the first swing. + bool ignoreSneakAttack = (i != 0); // Sneak attack critical effect should only be given on the first swing. bool ignoreTrickAttack = (i != 0); - bool isCritical = (rand()%100 < battleutils::GetCritHitRate(m_PChar, m_PBattleTarget, ignoreSneakAttack)); + bool isCritical = (rand()%100 < battleutils::GetCritHitRate(m_PChar, m_PBattleTarget, ignoreSneakAttack, ignoreTrickAttack)); float DamageRatio = battleutils::GetDamageRatio(m_PChar, m_PBattleTarget, isCritical, 0); Index: src/map/battleutils.cpp =================================================================== --- src/map/battleutils.cpp (revision 2104) +++ src/map/battleutils.cpp (working copy) @@ -1454,20 +1454,37 @@ { int32 hitrate = 75; - if (PAttacker->objtype == TYPE_PC && PAttacker->StatusEffectContainer->HasStatusEffect(EFFECT_SNEAK_ATTACK)) - { - hitrate = 100; //attack with SA active cannot miss + if (PAttacker->objtype == TYPE_PC && PAttacker->StatusEffectContainer->HasStatusEffect(EFFECT_SNEAK_ATTACK)) { + //SA only gives 100% accuracy when positioned behind a mob + if (abs(PDefender->loc.p.rotation - PAttacker->loc.p.rotation) < 23) { + hitrate = 100; + + return (uint8)hitrate; + } } - else - { - int32 defendereva = (PDefender->getMod(MOD_EVA) * (100 + PDefender->getMod(MOD_EVAP)))/100 + PDefender->AGI()/2; - int32 attackeracc = (PAttacker->getMod(MOD_ACC) * (100 + PAttacker->getMod(MOD_ACCP)))/100 + PAttacker->DEX()/2; + + if (PAttacker->objtype == TYPE_PC && PAttacker->StatusEffectContainer->HasStatusEffect(EFFECT_TRICK_ATTACK) + && PAttacker->GetMJob() == JOB_THF && PAttacker->GetMLevel() >= 60) { + //TA only gives 100% accuracy when positioned behind a player + CBattleEntity* taChar = NULL; + + taChar = getAvailableTrickAttackChar(PAttacker, PDefender); + if (taChar != NULL) { + hitrate = 100; - hitrate = hitrate + (attackeracc - defendereva) / 2 + (PAttacker->GetMLevel() - PDefender->GetMLevel())*2; + return (uint8)hitrate; + } + } - hitrate = dsp_cap(hitrate, 20, 95); - } - return (uint8)hitrate; + + int32 defendereva = (PDefender->getMod(MOD_EVA) * (100 + PDefender->getMod(MOD_EVAP)))/100 + PDefender->AGI()/2; + int32 attackeracc = (PAttacker->getMod(MOD_ACC) * (100 + PAttacker->getMod(MOD_ACCP)))/100 + PAttacker->DEX()/2; + + hitrate = hitrate + (attackeracc - defendereva) / 2 + (PAttacker->GetMLevel() - PDefender->GetMLevel())*2; + + hitrate = dsp_cap(hitrate, 20, 95); + + return (uint8)hitrate; } /************************************************************************ @@ -1480,20 +1497,37 @@ { int32 hitrate = 75; - if (PAttacker->objtype == TYPE_PC && PAttacker->StatusEffectContainer->HasStatusEffect(EFFECT_SNEAK_ATTACK)) - { - hitrate = 100; //attack with SA active cannot miss - } - else - { - int32 defendereva = (PDefender->getMod(MOD_EVA) * (100 + PDefender->getMod(MOD_EVAP)))/100 + PDefender->AGI()/2; - int32 attackeracc = ((PAttacker->getMod(MOD_ACC) + accuracy) * (100 + PAttacker->getMod(MOD_ACCP)))/100 + PAttacker->DEX()/2; + if (PAttacker->objtype == TYPE_PC && PAttacker->StatusEffectContainer->HasStatusEffect(EFFECT_SNEAK_ATTACK)) { + //SA only gives 100% accuracy when positioned behind a mob + if (abs(PDefender->loc.p.rotation - PAttacker->loc.p.rotation) < 23) { + hitrate = 100; - hitrate = hitrate + (attackeracc - defendereva) / 2 + (PAttacker->GetMLevel() - PDefender->GetMLevel())*2; + return (uint8)hitrate; + } + } - hitrate = dsp_cap(hitrate, 20, 95); + if (PAttacker->objtype == TYPE_PC && PAttacker->StatusEffectContainer->HasStatusEffect(EFFECT_TRICK_ATTACK) + && PAttacker->GetMJob() == JOB_THF && PAttacker->GetMLevel() >= 60) { + //TA only gives 100% accuracy when positioned behind a player + CBattleEntity* taChar = NULL; + + taChar = getAvailableTrickAttackChar(PAttacker, PDefender); + if (taChar != NULL) { + hitrate = 100; + + return (uint8)hitrate; + } } - return (uint8)hitrate; + + + int32 defendereva = (PDefender->getMod(MOD_EVA) * (100 + PDefender->getMod(MOD_EVAP)))/100 + PDefender->AGI()/2; + int32 attackeracc = ((PAttacker->getMod(MOD_ACC) + accuracy) * (100 + PAttacker->getMod(MOD_ACCP)))/100 + PAttacker->DEX()/2; + + hitrate = hitrate + (attackeracc - defendereva) / 2 + (PAttacker->GetMLevel() - PDefender->GetMLevel())*2; + + hitrate = dsp_cap(hitrate, 20, 95); + + return (uint8)hitrate; } /************************************************************************ @@ -1505,33 +1539,48 @@ uint8 GetCritHitRate(CBattleEntity* PAttacker, CBattleEntity* PDefender, bool ignoreSneakAttack) { int32 crithitrate = 5; + if(PAttacker->StatusEffectContainer->HasStatusEffect(EFFECT_MIGHTY_STRIKES,0) || PAttacker->StatusEffectContainer->HasStatusEffect(EFFECT_MIGHTY_STRIKES)){ return 100; } - else if (PAttacker->objtype == TYPE_PC && (!ignoreSneakAttack) && PAttacker->StatusEffectContainer->HasStatusEffect(EFFECT_SNEAK_ATTACK)) + + if (PAttacker->objtype == TYPE_PC && (!ignoreSneakAttack) && PAttacker->StatusEffectContainer->HasStatusEffect(EFFECT_SNEAK_ATTACK)) { // TODO: WRONG CALCULATION OF A POSITION OF THE CHARACTER if(abs(PDefender->loc.p.rotation - PAttacker->loc.p.rotation) < 23) { crithitrate = 100; + + return (uint8)crithitrate; } } - else - { - //apply merit mods - if (PAttacker->objtype == TYPE_PC) crithitrate += ((CCharEntity*)PAttacker)->PMeritPoints->GetMeritValue(MERIT_CRIT_HIT_RATE,PAttacker->GetMLevel()); - if (PDefender->objtype == TYPE_PC) crithitrate -= ((CCharEntity*)PDefender)->PMeritPoints->GetMeritValue(MERIT_ENEMY_CRIT_RATE,PDefender->GetMLevel()); + + if (PAttacker->objtype == TYPE_PC && (!ignoreTrickAttack) && PAttacker->StatusEffectContainer->HasStatusEffect(EFFECT_TRICK_ATTACK) + && PAttacker->GetMJob() == JOB_THF && PAttacker->GetMLevel() >= 60) { + CBattleEntity* taChar = NULL; + + taChar = getAvailableTrickAttackChar(PAttacker, PDefender); + if (taChar != NULL) { + crithitrate = 100; + + return (uint8)crithitrate; + } + } + + //apply merit mods + if (PAttacker->objtype == TYPE_PC) crithitrate += ((CCharEntity*)PAttacker)->PMeritPoints->GetMeritValue(MERIT_CRIT_HIT_RATE,PAttacker->GetMLevel()); + if (PDefender->objtype == TYPE_PC) crithitrate -= ((CCharEntity*)PDefender)->PMeritPoints->GetMeritValue(MERIT_ENEMY_CRIT_RATE,PDefender->GetMLevel()); - int32 attackerdex = PAttacker->DEX(); - int32 defenderagi = PDefender->AGI(); + int32 attackerdex = PAttacker->DEX(); + int32 defenderagi = PDefender->AGI(); - int32 dDEX = dsp_cap(attackerdex - defenderagi,0,50); + int32 dDEX = dsp_cap(attackerdex - defenderagi,0,50); - crithitrate += (dDEX * 30) / 100 + PAttacker->getMod(MOD_CRITHITRATE) + PDefender->getMod(MOD_ENEMYCRITRATE); - crithitrate = dsp_cap(crithitrate,0,100); - } + crithitrate += (dDEX * 30) / 100 + PAttacker->getMod(MOD_CRITHITRATE) + PDefender->getMod(MOD_ENEMYCRITRATE); + crithitrate = dsp_cap(crithitrate,0,100); + return (uint8)crithitrate; } Index: src/map/battleutils.h =================================================================== --- src/map/battleutils.h (revision 2104) +++ src/map/battleutils.h (working copy) @@ -96,7 +96,7 @@ int32 GetFSTR(CBattleEntity* PAttacker, CBattleEntity* PDefender, uint8 SlotID); uint8 GetHitRate(CBattleEntity* PAttacker, CBattleEntity* PDefender); uint8 GetHitRateAccOffset(CBattleEntity* PAttacker, CBattleEntity* PDefender, uint32 accuracy); - uint8 GetCritHitRate(CBattleEntity* PAttacker, CBattleEntity* PDefender, bool ignoreSneakAttack); + uint8 GetCritHitRate(CBattleEntity* PAttacker, CBattleEntity* PDefender, bool ignoreSneakAttack, bool ignoreTrickAttack); uint8 CheckMultiHits(CBattleEntity* PEntity, CItemWeapon* PWeapon); uint8 GetBlockRate(CBattleEntity* PAttacker, CBattleEntity* PDefender); uint8 GetParryRate(CBattleEntity* PAttacker, CBattleEntity* PDefender);