diff --git a/common/ptimer.h b/common/ptimer.h index d12b6779d..8a559a148 100644 --- a/common/ptimer.h +++ b/common/ptimer.h @@ -39,7 +39,8 @@ enum { //values for pTimerType pTimerDisciplineReuseStart = 14, pTimerDisciplineReuseEnd = 24, pTimerCombatAbility = 25, - pTimerBeggingPickPocket = 26, + pTimerCombatAbility2 = 26, // RoF2+ Tiger Claw is unlinked from other monk skills, generic in case other classes ever need it + pTimerBeggingPickPocket = 27, pTimerLayHands = 87, //these IDs are used by client too pTimerHarmTouch = 89, //so dont change them diff --git a/zone/special_attacks.cpp b/zone/special_attacks.cpp index faae0e3b1..0f0a110cd 100644 --- a/zone/special_attacks.cpp +++ b/zone/special_attacks.cpp @@ -95,7 +95,7 @@ void Mob::ApplySpecialAttackMod(SkillUseTypes skill, int32 &dmg, int32 &mindmg) } } -void Mob::DoSpecialAttackDamage(Mob *who, SkillUseTypes skill, int32 max_damage, int32 min_damage, int32 hate_override,int ReuseTime, +void Mob::DoSpecialAttackDamage(Mob *who, SkillUseTypes skill, int32 max_damage, int32 min_damage, int32 hate_override,int ReuseTime, bool HitChance, bool CanAvoid) { //this really should go through the same code as normal melee damage to //pick up all the special behavior there @@ -181,6 +181,11 @@ void Client::OPCombatAbility(const EQApplicationPacket *app) { return; CombatAbility_Struct* ca_atk = (CombatAbility_Struct*) app->pBuffer; + pTimerType timer = pTimerCombatAbility; + // RoF2+ Tiger Claw is unlinked from other monk skills, if they ever do that for other classes there will need + // to be more checks here + if (GetClientVersion() >= ClientVersion::RoF2 && ca_atk->m_skill == SkillTigerClaw) + timer = pTimerCombatAbility2; /* Check to see if actually have skill */ if (!MaxSkill(static_cast(ca_atk->m_skill))) @@ -218,7 +223,7 @@ void Client::OPCombatAbility(const EQApplicationPacket *app) { if(!CombatRange(GetTarget())) return; - if(!p_timers.Expired(&database, pTimerCombatAbility, false)) { + if(!p_timers.Expired(&database, timer, false)) { Message(13,"Ability recovery time not yet met."); return; } @@ -268,7 +273,7 @@ void Client::OPCombatAbility(const EQApplicationPacket *app) { DoSpecialAttackDamage(GetTarget(), SkillBash, dmg, 1, ht, ReuseTime); if(ReuseTime > 0) { - p_timers.Start(pTimerCombatAbility, ReuseTime); + p_timers.Start(timer, ReuseTime); } } return; @@ -304,7 +309,7 @@ void Client::OPCombatAbility(const EQApplicationPacket *app) { } if(ReuseTime > 0) { - p_timers.Start(pTimerCombatAbility, ReuseTime); + p_timers.Start(timer, ReuseTime); } return; } @@ -390,7 +395,7 @@ void Client::OPCombatAbility(const EQApplicationPacket *app) { ReuseTime = (ReuseTime*HasteMod)/100; if(ReuseTime > 0){ - p_timers.Start(pTimerCombatAbility, ReuseTime); + p_timers.Start(timer, ReuseTime); } } @@ -558,7 +563,7 @@ void Mob::TryBackstab(Mob *other, int ReuseTime) { if (level > 54) { // Check for double attack with main hand assuming maxed DA Skill (MS) - if(IsClient() && CastToClient()->CheckDoubleAttack(false)) + if(IsClient() && CastToClient()->CheckDoubleAttack(false)) if(other->GetHP() > 0) RogueBackstab(other,true, ReuseTime); @@ -650,10 +655,10 @@ void Mob::RogueBackstab(Mob* other, bool min_damage, int ReuseTime) } ndamage = mod_backstab_damage(ndamage); - + uint32 Assassinate_Dmg = 0; Assassinate_Dmg = TryAssassinate(other, SkillBackstab, ReuseTime); - + if (Assassinate_Dmg) { ndamage = Assassinate_Dmg; entity_list.MessageClose_StringID(this, false, 200, MT_CritMelee, ASSASSINATES, GetName()); @@ -797,26 +802,26 @@ void Client::RangedAttack(Mob* other, bool CanDoubleAttack) { //EndlessQuiver AA base1 = 100% Chance to avoid consumption arrow. int ChanceAvoidConsume = aabonuses.ConsumeProjectile + itembonuses.ConsumeProjectile + spellbonuses.ConsumeProjectile; - if (!ChanceAvoidConsume || (ChanceAvoidConsume < 100 && zone->random.Int(0,99) > ChanceAvoidConsume)){ + if (!ChanceAvoidConsume || (ChanceAvoidConsume < 100 && zone->random.Int(0,99) > ChanceAvoidConsume)){ DeleteItemInInventory(ammo_slot, 1, true); Log.Out(Logs::Detail, Logs::Combat, "Consumed one arrow from slot %d", ammo_slot); } else { Log.Out(Logs::Detail, Logs::Combat, "Endless Quiver prevented ammo consumption."); } - CheckIncreaseSkill(SkillArchery, GetTarget(), -15); + CheckIncreaseSkill(SkillArchery, GetTarget(), -15); CommonBreakInvisible(); } -void Mob::DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon, const ItemInst* Ammo, uint16 weapon_damage, int16 chance_mod, int16 focus, int ReuseTime, +void Mob::DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon, const ItemInst* Ammo, uint16 weapon_damage, int16 chance_mod, int16 focus, int ReuseTime, uint32 range_id, uint32 ammo_id, const Item_Struct *AmmoItem, int AmmoSlot, float speed) { - - if ((other == nullptr || - ((IsClient() && CastToClient()->dead) || - (other->IsClient() && other->CastToClient()->dead)) || - HasDied() || + + if ((other == nullptr || + ((IsClient() && CastToClient()->dead) || + (other->IsClient() && other->CastToClient()->dead)) || + HasDied() || (!IsAttackAllowed(other)) || - (other->GetInvul() || + (other->GetInvul() || other->GetSpecialAbility(IMMUNE_MELEE)))) { return; @@ -841,12 +846,12 @@ void Mob::DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Ite LaunchProjectile = true; else{ /* - Item sync check on projectile landing. + Item sync check on projectile landing. Weapon damage is already calculated so this only affects procs! Ammo proc check will use database to find proc if you used up your last ammo. If you change range item mid projectile flight, you loose your chance to proc from bow (Deal with it!). */ - + if (!RangeWeapon && !Ammo && range_id && ammo_id){ ProjectileImpact = true; @@ -858,8 +863,8 @@ void Mob::DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Ite _RangeWeapon = CastToClient()->m_inv[MainRange]; if (_RangeWeapon && _RangeWeapon->GetItem() && _RangeWeapon->GetItem()->ID == range_id) - RangeWeapon = _RangeWeapon; - + RangeWeapon = _RangeWeapon; + _Ammo = CastToClient()->m_inv[AmmoSlot]; if (_Ammo && _Ammo->GetItem() && _Ammo->GetItem()->ID == ammo_id) Ammo = _Ammo; @@ -985,7 +990,7 @@ void Mob::DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Ite other->AddToHateList(this, hate, 0, false); other->Damage(this, TotalDmg, SPELL_UNKNOWN, SkillArchery); - + //Skill Proc Success if (TotalDmg > 0 && HasSkillProcSuccess() && other && !other->HasDied()){ if (ReuseTime) @@ -1047,10 +1052,10 @@ bool Mob::TryProjectileAttack(Mob* other, const Item_Struct *item, SkillUseTypes ProjectileAtk[slot].origin_x = GetX(); ProjectileAtk[slot].origin_y = GetY(); ProjectileAtk[slot].origin_z = GetZ(); - + if (RangeWeapon && RangeWeapon->GetItem()) ProjectileAtk[slot].ranged_id = RangeWeapon->GetItem()->ID; - + if (Ammo && Ammo->GetItem()) ProjectileAtk[slot].ammo_id = Ammo->GetItem()->ID; @@ -1085,7 +1090,7 @@ void Mob::ProjectileAttack() disable = false; Mob* target = entity_list.GetMobID(ProjectileAtk[i].target_id); - + if (target && target->IsMoving()){ //Only recalculate hit increment if target moving //Due to frequency that we need to check increment the targets position variables may not be updated even if moving. Do a simple check before calculating distance. if (ProjectileAtk[i].tlast_x != target->GetX() || ProjectileAtk[i].tlast_y != target->GetY()){ @@ -1109,7 +1114,7 @@ void Mob::ProjectileAttack() else CastToNPC()->DoRangedAttackDmg(target, false, ProjectileAtk[i].wpn_dmg,0, static_cast(ProjectileAtk[i].skill)); } - + else { if (ProjectileAtk[i].skill == SkillArchery) @@ -1120,7 +1125,7 @@ void Mob::ProjectileAttack() SpellOnTarget(ProjectileAtk[i].wpn_dmg, target, false, true, spells[ProjectileAtk[i].wpn_dmg].ResistDiff, true); } } - + ProjectileAtk[i].increment = 0; ProjectileAtk[i].target_id = 0; ProjectileAtk[i].wpn_dmg = 0; @@ -1180,7 +1185,7 @@ float Mob::GetRangeDistTargetSizeMod(Mob* other) mod = 42.0f + (5.8f * (tsize - 15.0f)); else mod = 75.0f; - + return (mod + 2.0f); //Add 2.0f as buffer to prevent any chance of failures, client enforce range check regardless. } @@ -1210,7 +1215,7 @@ void NPC::RangedAttack(Mob* other) float min_range = static_cast(RuleI(Combat, MinRangedAttackDist)); float max_range = 250; // needs to be longer than 200(most spells) - + if (sa_max_range) max_range = static_cast(sa_max_range); @@ -1242,12 +1247,12 @@ void NPC::RangedAttack(Mob* other) } void NPC::DoRangedAttackDmg(Mob* other, bool Launch, int16 damage_mod, int16 chance_mod, SkillUseTypes skill, float speed, const char *IDFile) { - - if ((other == nullptr || - (other->HasDied())) || - HasDied() || + + if ((other == nullptr || + (other->HasDied())) || + HasDied() || (!IsAttackAllowed(other)) || - (other->GetInvul() || + (other->GetInvul() || other->GetSpecialAbility(IMMUNE_MELEE))) { return; @@ -1268,7 +1273,7 @@ void NPC::DoRangedAttackDmg(Mob* other, bool Launch, int16 damage_mod, int16 cha ammo = GetAmmoIDfile(); ProjectileAnimation(other, 0,false,speed,0,0,0,ammo,skillInUse); - + if (RuleB(Combat, ProjectileDmgOnImpact)) { TryProjectileAttack(other, nullptr, skillInUse, damage_mod, nullptr, nullptr, 0, speed); @@ -1276,7 +1281,7 @@ void NPC::DoRangedAttackDmg(Mob* other, bool Launch, int16 damage_mod, int16 cha } } - if (!chance_mod) + if (!chance_mod) chance_mod = GetSpecialAbilityParam(SPECATK_RANGED_ATK, 2); if (!other->CheckHitChance(this, skillInUse, MainRange, chance_mod)) @@ -1298,11 +1303,11 @@ void NPC::DoRangedAttackDmg(Mob* other, bool Launch, int16 damage_mod, int16 cha if (!damage_mod) damage_mod = GetSpecialAbilityParam(SPECATK_RANGED_ATK, 3);//Damage modifier - TotalDmg += TotalDmg * damage_mod / 100; + TotalDmg += TotalDmg * damage_mod / 100; other->AvoidDamage(this, TotalDmg, false); other->MeleeMitigation(this, TotalDmg, MinDmg); - + if (TotalDmg > 0) CommonOutgoingHitSuccess(other, TotalDmg, skillInUse); else if (TotalDmg < -4) @@ -1432,18 +1437,18 @@ void Client::ThrowingAttack(Mob* other, bool CanDoubleAttack) { //old was 51 //consume ammo DeleteItemInInventory(ammo_slot, 1, true); - CheckIncreaseSkill(SkillThrowing, GetTarget()); + CheckIncreaseSkill(SkillThrowing, GetTarget()); CommonBreakInvisible(); } void Mob::DoThrowingAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Item_Struct* AmmoItem, uint16 weapon_damage, int16 chance_mod,int16 focus, int ReuseTime, uint32 range_id, int AmmoSlot, float speed) { - if ((other == nullptr || - ((IsClient() && CastToClient()->dead) || - (other->IsClient() && other->CastToClient()->dead)) || - HasDied() || + if ((other == nullptr || + ((IsClient() && CastToClient()->dead) || + (other->IsClient() && other->CastToClient()->dead)) || + HasDied() || (!IsAttackAllowed(other)) || - (other->GetInvul() || + (other->GetInvul() || other->GetSpecialAbility(IMMUNE_MELEE)))) { return; @@ -1511,7 +1516,7 @@ void Mob::DoThrowingAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Ite return; } } - else + else WDmg = weapon_damage; if (focus) //From FcBaseEffects @@ -1535,7 +1540,7 @@ void Mob::DoThrowingAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Ite Log.Out(Logs::Detail, Logs::Combat, "Item DMG %d. Max Damage %d. Hit for damage %d", WDmg, MaxDmg, TotalDmg); if (!Assassinate_Dmg) other->AvoidDamage(this, TotalDmg, false); //CanRiposte=false - Can not riposte throw attacks. - + other->MeleeMitigation(this, TotalDmg, minDmg); if(TotalDmg > 0) CommonOutgoingHitSuccess(other, TotalDmg, SkillThrowing); @@ -1620,7 +1625,7 @@ void Mob::SendItemAnimation(Mob *to, const Item_Struct *item, SkillUseTypes skil safe_delete(outapp); } -void Mob::ProjectileAnimation(Mob* to, int item_id, bool IsArrow, float speed, float angle, float tilt, float arc, const char *IDFile, SkillUseTypes skillInUse) { +void Mob::ProjectileAnimation(Mob* to, int item_id, bool IsArrow, float speed, float angle, float tilt, float arc, const char *IDFile, SkillUseTypes skillInUse) { if (!to) return; @@ -2092,7 +2097,7 @@ void Client::DoClassAttacks(Mob *ca_target, uint16 skill, bool IsRiposte) } ReuseTime = ReuseTime / HasteMod; - if(ReuseTime > 0 && !IsRiposte){ + if(ReuseTime > 0 && !IsRiposte){ p_timers.Start(pTimerCombatAbility, ReuseTime); } } @@ -2270,7 +2275,7 @@ float Mob::GetSpecialProcChances(uint16 hand) if (RuleB(Combat, AdjustSpecialProcPerMinute)) { ProcChance = (static_cast(weapon_speed) * - RuleR(Combat, AvgSpecialProcsPerMinute) / 60000.0f); + RuleR(Combat, AvgSpecialProcsPerMinute) / 60000.0f); ProcBonus += static_cast(mydex/35) + static_cast(itembonuses.HeroicDEX / 25); ProcChance += ProcChance * ProcBonus / 100.0f; } else { @@ -2363,7 +2368,7 @@ void Mob::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes int Hand = MainPrimary; if (hate == 0 && weapon_damage > 1) hate = weapon_damage; - if(weapon_damage > 0){ + if(weapon_damage > 0){ if (focus) //From FcBaseEffects weapon_damage += weapon_damage*focus/100; @@ -2376,7 +2381,7 @@ void Mob::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes int32 max_hit = (2 * weapon_damage*GetDamageTable(skillinuse)) / 100; if(GetLevel() >= 28 && IsWarriorClass() ) { - int ucDamageBonus = GetWeaponDamageBonus((const Item_Struct*) nullptr ); + int ucDamageBonus = GetWeaponDamageBonus((const Item_Struct*) nullptr ); min_hit += (int) ucDamageBonus; max_hit += (int) ucDamageBonus; hate += ucDamageBonus; @@ -2411,7 +2416,7 @@ void Mob::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes } else { other->AvoidDamage(this, damage, CanRiposte); other->MeleeMitigation(this, damage, min_hit); - if(damage > 0) + if(damage > 0) CommonOutgoingHitSuccess(other, damage, skillinuse); } @@ -2449,7 +2454,7 @@ void Mob::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes if (CanSkillProc && HasSkillProcs()) TrySkillProc(other, skillinuse, ReuseTime); - + if (CanSkillProc && (damage > 0) && HasSkillProcSuccess()) TrySkillProc(other, skillinuse, ReuseTime, true); }