Index: scripts/globals/weaponskills.lua =================================================================== --- scripts/globals/weaponskills.lua (revision 2147) +++ scripts/globals/weaponskills.lua (working copy) @@ -34,12 +34,24 @@ ccmin = 0; ccmax = 0; hasMightyStrikes = attacker:hasStatusEffect(EFFECT_MIGHTY_STRIKES); + isSneakValid = attacker:hasStatusEffect(EFFECT_SNEAK_ATTACK); if(isSneakValid and not attacker:isBehind(target))then isSneakValid = false; end attacker:delStatusEffect(EFFECT_SNEAK_ATTACK); + --the check wether the TA user is or is not behind a party/alliance member is + --handled in ai_char_normal.cpp directly before OnUseWeaponSkill is executed + isTrickValid = attacker:hasStatusEffect(EFFECT_TRICK_ATTACK); + attacker:delStatusEffect(EFFECT_TRICK_ATTACK); + + --only important if THF main, level 60+ + isTrickAssassin = false; + if (isTrickValid and attacker:getMainJob() == 6 and attacker:getMainLvl() >=60) then + isTrickAssassin = true; + end + ccritratio = 0; critrate = 0; ccritratio = cCritRatio( ((attacker:getStat(MOD_ATT)*atkmulti)/target:getStat(MOD_DEF))+1,attacker:getMainLvl(),target:getMainLvl()); @@ -78,29 +90,40 @@ local tpHitsLanded = 0; local tpHits = 0; - if (firsthit <= hitrate or isSneakValid or math.random() < attacker:getMod(MOD_ZANSHIN)/100) then - if(canCrit or isSneakValid) then + local agiBonusDmg = 0; + + if (firsthit <= hitrate or isSneakValid or isTrickAssassin or math.random() < attacker:getMod(MOD_ZANSHIN)/100) then + if (isTrickValid and attacker:getMainJob() == 6) then --get bonus damage for AGI on THF main + agiBonusDmg = attacker:getStat(MOD_AGI) * ftp; + end + + if(canCrit or isSneakValid or isTrickAssassin) then local double critchance = math.random(); - if(critchance <= critrate or hasMightyStrikes or isSneakValid) then --crit hit! + if(critchance <= critrate or hasMightyStrikes or isSneakValid or isTrickAssassin) then --crit hit! local double cpdif = math.random((ccritratio[1]*1000),(ccritratio[2]*1000)); cpdif = cpdif/1000; - finaldmg = dmg * cpdif; - if(isSneakValid and attacker:getMainJob()==6) then --have to add on DEX bonus if on THF main - finaldmg = finaldmg + (attacker:getStat(MOD_DEX) * ftp * cpdif) + souleaterBonus(attacker); + finaldmg = (dmg + agiBonusDmg) * cpdif; + + if(isSneakValid and attacker:getMainJob() == 6) then --have to add on DEX bonus if on THF main + finaldmg = finaldmg + (attacker:getStat(MOD_DEX) * ftp * cpdif); --+ souleaterBonus(attacker); end else - finaldmg = dmg * pdif; + finaldmg = (dmg + agiBonusDmg) * pdif; end else - finaldmg = dmg * pdif + souleaterBonus(attacker); + finaldmg = (dmg + agiBonusDmg) * pdif; --+ souleaterBonus(attacker); end + + --if I understood the souleaterBonus wrong just delete the following line and un-outcomment the ones above again + finaldmg = finaldmg + souleaterBonus(attacker); tpHitsLanded = 1; end + tpHits = 1; if(attacker:getOffhandDmg() > 0 or attacker:getWeaponSkillType(0)==1) then local chance = math.random(); - if (chance<=hitrate or math.random() < attacker:getMod(MOD_ZANSHIN)/100 or isSneakValid) then --it hit + if (chance<=hitrate or math.random() < attacker:getMod(MOD_ZANSHIN)/100 or isSneakValid or isTrickAssassin) then --it hit pdif = math.random((cratio[1]*1000),(cratio[2]*1000)); --generate random PDIF pdif = pdif/1000; --multiplier set. if(canCrit) then Index: src/map/ai/ai_char_normal.cpp =================================================================== --- src/map/ai/ai_char_normal.cpp (revision 2147) +++ src/map/ai/ai_char_normal.cpp (working copy) @@ -835,7 +835,7 @@ { float pdif = battleutils::GetRangedPDIF(m_PChar,m_PBattleSubTarget); - if(rand()%100 < battleutils::GetCritHitRate(m_PChar,m_PBattleSubTarget, true)) + if(rand()%100 < battleutils::GetCritHitRate(m_PChar,m_PBattleSubTarget, true, true)) { pdif *= 1.25; //uncapped Action.speceffect = SPECEFFECT_CRITICAL_HIT; @@ -2069,6 +2069,17 @@ uint16 tpHitsLanded = 0; uint16 extraHitsLanded = 0; uint16 damage = 0; + + //in case TA party member is available + CBattleEntity* taChar = NULL; + + if (m_PChar->StatusEffectContainer->HasStatusEffect(EFFECT_TRICK_ATTACK)) { + taChar = battleutils::getAvailableTrickAttackChar(m_PChar, m_PBattleTarget); + + //in case no party/alliance member was found TA won't have any effect in weaponskills.lua + if (taChar == NULL) m_PChar->StatusEffectContainer->DelStatusEffect(EFFECT_TRICK_ATTACK); + } + damage = luautils::OnUseWeaponSkill(m_PChar, m_PBattleSubTarget, &tpHitsLanded, &extraHitsLanded); m_PChar->addTP(-bonusTp); @@ -2087,22 +2098,6 @@ m_PChar->health.tp = 0; } - - //incase a TA party member is available - CBattleEntity* taChar = NULL; - - //trick attack agi bonus for thf main job - if (m_PChar->GetMJob() == JOB_THF && m_PChar->StatusEffectContainer->HasStatusEffect(EFFECT_TRICK_ATTACK)) - { - taChar = battleutils::getAvailableTrickAttackChar(m_PChar,m_PBattleTarget); - if(taChar != NULL) damage += m_PChar->AGI(); - } - - //check if other jobs have trick attack active to change enmity lateron - if (taChar == NULL && m_PChar->StatusEffectContainer->HasStatusEffect(EFFECT_TRICK_ATTACK)) - taChar = battleutils::getAvailableTrickAttackChar(m_PChar,m_PBattleTarget); - - if (!battleutils::isValidSelfTargetWeaponskill(m_PWeaponSkill->getID())) { uint8 damslot = SLOT_MAIN; @@ -2476,6 +2471,12 @@ CBattleEntity* taChar = NULL; + if (m_PChar->StatusEffectContainer->HasStatusEffect(EFFECT_TRICK_ATTACK)) { + taChar = battleutils::getAvailableTrickAttackChar(m_PChar, m_PBattleTarget); + + if (taChar == NULL) m_PChar->StatusEffectContainer->DelStatusEffect(EFFECT_TRICK_ATTACK); + } + uint16 subType = m_PChar->m_Weapons[SLOT_SUB]->getDmgType(); if ((subType > 0 && subType < 4))//sub weapon is equipped! @@ -2559,7 +2560,7 @@ { 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); @@ -2587,20 +2588,10 @@ if(rand()%100 < 4) Monster->m_THLvl +=1; } - - //trick attack agi bonus for thf main job - if(m_PChar->GetMJob() == JOB_THF && (!ignoreTrickAttack) && m_PChar->StatusEffectContainer->HasStatusEffect(EFFECT_TRICK_ATTACK)) - { - taChar = battleutils::getAvailableTrickAttackChar(m_PChar,m_PBattleTarget); - if(taChar != NULL) bonusDMG += m_PChar->AGI(); - } + if(m_PChar->GetMJob() == JOB_THF && m_PChar->StatusEffectContainer->HasStatusEffect(EFFECT_TRICK_ATTACK) + && (!ignoreTrickAttack)) bonusDMG += m_PChar->AGI(); - //check if other jobs have trick attack active to change enmity lateron - if(taChar == NULL && m_PChar->StatusEffectContainer->HasStatusEffect(EFFECT_TRICK_ATTACK) && (!ignoreTrickAttack)) - taChar = battleutils::getAvailableTrickAttackChar(m_PChar,m_PBattleTarget); - - damage = (uint16)(((PWeapon->getDamage() + bonusDMG + battleutils::GetFSTR(m_PChar, m_PBattleTarget,fstrslot)) * DamageRatio)); Index: src/map/ai/ai_mob_dummy.cpp =================================================================== --- src/map/ai/ai_mob_dummy.cpp (revision 2147) +++ src/map/ai/ai_mob_dummy.cpp (working copy) @@ -1005,7 +1005,7 @@ Action.reaction = REACTION_NONE; Action.speceffect = SPECEFFECT_NONE; - bool isCritical = ( rand()%100 < battleutils::GetCritHitRate(m_PBattleTarget, m_PMob,false) ); + bool isCritical = ( rand()%100 < battleutils::GetCritHitRate(m_PBattleTarget, m_PMob, false, false) ); float DamageRatio = battleutils::GetDamageRatio(m_PBattleTarget, m_PMob,isCritical, 0); damage = (uint16)((m_PBattleTarget->m_Weapons[SLOT_MAIN]->getDamage() + battleutils::GetFSTR(m_PBattleTarget, m_PMob,SLOT_MAIN)) * DamageRatio); @@ -1014,7 +1014,7 @@ Action.flag = 2; } else{ - bool isCritical = ( rand()%100 < battleutils::GetCritHitRate(m_PMob, m_PBattleTarget,false) ); + bool isCritical = ( rand()%100 < battleutils::GetCritHitRate(m_PMob, m_PBattleTarget, false, false) ); if(m_PMob->StatusEffectContainer->HasStatusEffect(EFFECT_MIGHTY_STRIKES,0)){isCritical=true;} float DamageRatio = battleutils::GetDamageRatio(m_PMob, m_PBattleTarget,isCritical, 0); Index: src/map/ai/ai_pet_dummy.cpp =================================================================== --- src/map/ai/ai_pet_dummy.cpp (revision 2147) +++ src/map/ai/ai_pet_dummy.cpp (working copy) @@ -655,7 +655,7 @@ Action.speceffect = SPECEFFECT_HIT; Action.messageID = 1; - bool isCritical = ( rand()%100 < battleutils::GetCritHitRate(m_PPet, m_PBattleTarget, false) ); + bool isCritical = ( rand()%100 < battleutils::GetCritHitRate(m_PPet, m_PBattleTarget, false, false) ); float DamageRatio = battleutils::GetDamageRatio(m_PPet, m_PBattleTarget,isCritical, 0); if(isCritical) Index: src/map/battleutils.cpp =================================================================== --- src/map/battleutils.cpp (revision 2147) +++ src/map/battleutils.cpp (working copy) @@ -1447,16 +1447,16 @@ { int32 hitrate = 75; - if (PAttacker->objtype == TYPE_PC && PAttacker->StatusEffectContainer->HasStatusEffect(EFFECT_SNEAK_ATTACK)) - { - hitrate = 100; //attack with SA active cannot miss - } - else - { - hitrate = hitrate + (PAttacker->ACC() - PDefender->EVA()) / 2 + (PAttacker->GetMLevel() - PDefender->GetMLevel())*2; + //SA only has 100% hitrate when behind mob + if (PAttacker->objtype == TYPE_PC && PAttacker->StatusEffectContainer->HasStatusEffect(EFFECT_SNEAK_ATTACK) + && (abs(PDefender->loc.p.rotation - PAttacker->loc.p.rotation) < 23)) return 100; - hitrate = dsp_cap(hitrate, 20, 95); - } + if (PAttacker->objtype == TYPE_PC && PAttacker->StatusEffectContainer->HasStatusEffect(EFFECT_TRICK_ATTACK) + && PAttacker->GetMJob() == JOB_THF && PAttacker->GetMLevel() >= 60) return 100; + + hitrate = hitrate + (PAttacker->ACC() - PDefender->EVA()) / 2 + (PAttacker->GetMLevel() - PDefender->GetMLevel())*2; + hitrate = dsp_cap(hitrate, 20, 95); + return (uint8)hitrate; } @@ -1470,18 +1470,17 @@ { int32 hitrate = 75; - if (PAttacker->objtype == TYPE_PC && PAttacker->StatusEffectContainer->HasStatusEffect(EFFECT_SNEAK_ATTACK)) - { - hitrate = 100; //attack with SA active cannot miss - } - else - { - int32 attackeracc = ((PAttacker->getMod(MOD_ACC) + accuracy) * (100 + PAttacker->getMod(MOD_ACCP)))/100 + PAttacker->DEX()/2; - - hitrate = hitrate + (attackeracc - PDefender->EVA()) / 2 + (PAttacker->GetMLevel() - PDefender->GetMLevel())*2; + //SA only has 100% hitrate when behind mob + if (PAttacker->objtype == TYPE_PC && PAttacker->StatusEffectContainer->HasStatusEffect(EFFECT_SNEAK_ATTACK) + && (abs(PDefender->loc.p.rotation - PAttacker->loc.p.rotation) < 23)) return 100; - hitrate = dsp_cap(hitrate, 20, 95); - } + if (PAttacker->objtype == TYPE_PC && PAttacker->StatusEffectContainer->HasStatusEffect(EFFECT_TRICK_ATTACK) + && PAttacker->GetMJob() == JOB_THF && PAttacker->GetMLevel() >= 60) return 100; + + int32 attackeracc = ((PAttacker->getMod(MOD_ACC) + accuracy) * (100 + PAttacker->getMod(MOD_ACCP)))/100 + PAttacker->DEX()/2; + hitrate = hitrate + (attackeracc - PDefender->EVA()) / 2 + (PAttacker->GetMLevel() - PDefender->GetMLevel())*2; + hitrate = dsp_cap(hitrate, 20, 95); + return (uint8)hitrate; } @@ -1491,36 +1490,31 @@ * * ************************************************************************/ -uint8 GetCritHitRate(CBattleEntity* PAttacker, CBattleEntity* PDefender, bool ignoreSneakAttack) +uint8 GetCritHitRate(CBattleEntity* PAttacker, CBattleEntity* PDefender, bool ignoreSneakAttack, bool ignoreTrickAttack) { 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)) - { - // TODO: WRONG CALCULATION OF A POSITION OF THE CHARACTER + PAttacker->StatusEffectContainer->HasStatusEffect(EFFECT_MIGHTY_STRIKES)) return 100; + + // TODO: WRONG CALCULATION OF A POSITION OF THE CHARACTER + if (PAttacker->objtype == TYPE_PC && (!ignoreSneakAttack) && PAttacker->StatusEffectContainer->HasStatusEffect(EFFECT_SNEAK_ATTACK) + && (abs(PDefender->loc.p.rotation - PAttacker->loc.p.rotation) < 23)) return 100; + + if (PAttacker->objtype == TYPE_PC && (!ignoreTrickAttack) && PAttacker->StatusEffectContainer->HasStatusEffect(EFFECT_TRICK_ATTACK) + && PAttacker->GetMJob() == JOB_THF && PAttacker->GetMLevel() >= 60) return 100; - if(abs(PDefender->loc.p.rotation - PAttacker->loc.p.rotation) < 23) - { - crithitrate = 100; - } - } - 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()); + //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; } @@ -2491,8 +2485,7 @@ { for(uint8 i = 0; i < taUser->PParty->m_PAlliance->partyList.at(a)->members.size(); ++i) { - if (abs(taUser->PParty->m_PAlliance->partyList.at(a)->members.at(i)->loc.p.rotation - taUser->loc.p.rotation) < 23 && - abs(PMob->loc.p.rotation - taUser->PParty->m_PAlliance->partyList.at(a)->members.at(i)->loc.p.rotation) < 23) + if (abs(taUser->PParty->m_PAlliance->partyList.at(a)->members.at(i)->loc.p.rotation - taUser->loc.p.rotation) < 23) { float distancePartyChar = distance(taUser->PParty->m_PAlliance->partyList.at(a)->members.at(i)->loc.p,PMob->loc.p); @@ -2509,8 +2502,7 @@ }else{//no alliance for(uint8 i = 0; i < taUser->PParty->members.size(); ++i) { - if(abs(taUser->PParty->members.at(i)->loc.p.rotation - taUser->loc.p.rotation) < 23 && - abs(PMob->loc.p.rotation - taUser->PParty->members.at(i)->loc.p.rotation) < 23) + if(abs(taUser->PParty->members.at(i)->loc.p.rotation - taUser->loc.p.rotation) < 23) { float distancePartyChar = distance(taUser->PParty->members.at(i)->loc.p,PMob->loc.p); @@ -2525,8 +2517,9 @@ } } } -//no Trick attack party member available -return NULL; + + //no Trick attack party member available + return NULL; } /************************************************************************ Index: src/map/battleutils.h =================================================================== --- src/map/battleutils.h (revision 2147) +++ 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);