Rework OPCombatAbiltiy a bit

This is done to help remove some code duplication in the future
This commit is contained in:
Michael Cook (mackal) 2017-01-15 22:19:32 -05:00
parent 8c6fefa33e
commit b92d6c57a1
3 changed files with 106 additions and 121 deletions

View File

@ -1290,7 +1290,7 @@ private:
void OPGMEndTraining(const EQApplicationPacket *app); void OPGMEndTraining(const EQApplicationPacket *app);
void OPGMTrainSkill(const EQApplicationPacket *app); void OPGMTrainSkill(const EQApplicationPacket *app);
void OPGMSummon(const EQApplicationPacket *app); void OPGMSummon(const EQApplicationPacket *app);
void OPCombatAbility(const EQApplicationPacket *app); void OPCombatAbility(const CombatAbility_Struct *ca_atk);
// Bandolier Methods // Bandolier Methods
void CreateBandolier(const EQApplicationPacket *app); void CreateBandolier(const EQApplicationPacket *app);

View File

@ -4622,7 +4622,8 @@ void Client::Handle_OP_CombatAbility(const EQApplicationPacket *app)
std::cout << "Wrong size on OP_CombatAbility. Got: " << app->size << ", Expected: " << sizeof(CombatAbility_Struct) << std::endl; std::cout << "Wrong size on OP_CombatAbility. Got: " << app->size << ", Expected: " << sizeof(CombatAbility_Struct) << std::endl;
return; return;
} }
OPCombatAbility(app); auto ca_atk = (CombatAbility_Struct *)app->pBuffer;
OPCombatAbility(ca_atk);
return; return;
} }

View File

@ -217,14 +217,14 @@ void Mob::DoSpecialAttackDamage(Mob *who, EQEmu::skills::SkillType skill, int32
} }
// We should probably refactor this to take the struct not the packet // We should probably refactor this to take the struct not the packet
void Client::OPCombatAbility(const EQApplicationPacket *app) { void Client::OPCombatAbility(const CombatAbility_Struct *ca_atk)
if(!GetTarget()) {
if (!GetTarget())
return; return;
//make sure were actually able to use such an attack. // make sure were actually able to use such an attack.
if(spellend_timer.Enabled() || IsFeared() || IsStunned() || IsMezzed() || DivineAura() || dead) if (spellend_timer.Enabled() || IsFeared() || IsStunned() || IsMezzed() || DivineAura() || dead)
return; return;
CombatAbility_Struct* ca_atk = (CombatAbility_Struct*) app->pBuffer;
pTimerType timer = pTimerCombatAbility; pTimerType timer = pTimerCombatAbility;
// RoF2+ Tiger Claw is unlinked from other monk skills, if they ever do that for other classes there will need // 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 // to be more checks here
@ -235,15 +235,15 @@ void Client::OPCombatAbility(const EQApplicationPacket *app) {
if (!MaxSkill(static_cast<EQEmu::skills::SkillType>(ca_atk->m_skill))) if (!MaxSkill(static_cast<EQEmu::skills::SkillType>(ca_atk->m_skill)))
return; return;
if(GetTarget()->GetID() != ca_atk->m_target) if (GetTarget()->GetID() != ca_atk->m_target)
return; //invalid packet. return; // invalid packet.
if(!IsAttackAllowed(GetTarget())) if (!IsAttackAllowed(GetTarget()))
return; return;
//These two are not subject to the combat ability timer, as they // These two are not subject to the combat ability timer, as they
//allready do their checking in conjunction with the attack timer // allready do their checking in conjunction with the attack timer
//throwing weapons // throwing weapons
if (ca_atk->m_atk == EQEmu::inventory::slotRange) { if (ca_atk->m_atk == EQEmu::inventory::slotRange) {
if (ca_atk->m_skill == EQEmu::skills::SkillThrowing) { if (ca_atk->m_skill == EQEmu::skills::SkillThrowing) {
SetAttackTimer(); SetAttackTimer();
@ -252,7 +252,7 @@ void Client::OPCombatAbility(const EQApplicationPacket *app) {
ThrowingAttack(GetTarget(), true); ThrowingAttack(GetTarget(), true);
return; return;
} }
//ranged attack (archery) // ranged attack (archery)
if (ca_atk->m_skill == EQEmu::skills::SkillArchery) { if (ca_atk->m_skill == EQEmu::skills::SkillArchery) {
SetAttackTimer(); SetAttackTimer();
RangedAttack(GetTarget()); RangedAttack(GetTarget());
@ -260,15 +260,15 @@ void Client::OPCombatAbility(const EQApplicationPacket *app) {
RangedAttack(GetTarget(), true); RangedAttack(GetTarget(), true);
return; return;
} }
//could we return here? Im not sure is m_atk 11 is used for real specials // could we return here? Im not sure is m_atk 11 is used for real specials
} }
//check range for all these abilities, they are all close combat stuff // check range for all these abilities, they are all close combat stuff
if(!CombatRange(GetTarget())) if (!CombatRange(GetTarget()))
return; return;
if(!p_timers.Expired(&database, timer, false)) { if (!p_timers.Expired(&database, timer, false)) {
Message(13,"Ability recovery time not yet met."); Message(13, "Ability recovery time not yet met.");
return; return;
} }
@ -276,18 +276,18 @@ void Client::OPCombatAbility(const EQApplicationPacket *app) {
int ClientHaste = GetHaste(); int ClientHaste = GetHaste();
int HasteMod = 0; int HasteMod = 0;
if(ClientHaste >= 0){ if (ClientHaste >= 0)
HasteMod = (10000/(100+ClientHaste)); //+100% haste = 2x as many attacks HasteMod = (10000 / (100 + ClientHaste)); //+100% haste = 2x as many attacks
} else
else{ HasteMod = (100 - ClientHaste); //-100% haste = 1/2 as many attacks
HasteMod = (100-ClientHaste); //-100% haste = 1/2 as many attacks
}
int32 dmg = 0; int32 dmg = 0;
int32 skill_reduction = this->GetSkillReuseTime(ca_atk->m_skill); int32 skill_reduction = this->GetSkillReuseTime(ca_atk->m_skill);
// not sure what the '100' indicates..if ->m_atk is not used as 'slot' reference, then change SlotRange above back to '11' // not sure what the '100' indicates..if ->m_atk is not used as 'slot' reference, then change SlotRange above back to '11'
if ((ca_atk->m_atk == 100) && (ca_atk->m_skill == EQEmu::skills::SkillBash)) { // SLAM - Bash without a shield equipped if (ca_atk->m_atk == 100 &&
ca_atk->m_skill == EQEmu::skills::SkillBash) { // SLAM - Bash without a shield equipped
if (GetTarget() != this) { if (GetTarget() != this) {
CheckIncreaseSkill(EQEmu::skills::SkillBash, GetTarget(), 10); CheckIncreaseSkill(EQEmu::skills::SkillBash, GetTarget(), 10);
@ -295,31 +295,21 @@ void Client::OPCombatAbility(const EQApplicationPacket *app) {
int32 ht = 0; int32 ht = 0;
if (GetWeaponDamage(GetTarget(), GetInv().GetItem(EQEmu::inventory::slotSecondary)) <= 0 && if (GetWeaponDamage(GetTarget(), GetInv().GetItem(EQEmu::inventory::slotSecondary)) <= 0 &&
GetWeaponDamage(GetTarget(), GetInv().GetItem(EQEmu::inventory::slotShoulders)) <= 0){ GetWeaponDamage(GetTarget(), GetInv().GetItem(EQEmu::inventory::slotShoulders)) <= 0)
dmg = -5; dmg = -5;
} else
else{
if (!GetTarget()->CheckHitChance(this, EQEmu::skills::SkillBash, 0)) {
dmg = 0;
ht = GetBaseSkillDamage(EQEmu::skills::SkillBash, GetTarget());
}
else{
ht = dmg = GetBaseSkillDamage(EQEmu::skills::SkillBash, GetTarget()); ht = dmg = GetBaseSkillDamage(EQEmu::skills::SkillBash, GetTarget());
}
}
ReuseTime = BashReuseTime-1-skill_reduction; ReuseTime = BashReuseTime - 1 - skill_reduction;
ReuseTime = (ReuseTime*HasteMod)/100; ReuseTime = (ReuseTime * HasteMod) / 100;
DoSpecialAttackDamage(GetTarget(), EQEmu::skills::SkillBash, dmg, 0, ht, ReuseTime); DoSpecialAttackDamage(GetTarget(), EQEmu::skills::SkillBash, dmg, 0, ht, ReuseTime, true);
if(ReuseTime > 0) if (ReuseTime > 0)
{
p_timers.Start(timer, ReuseTime); p_timers.Start(timer, ReuseTime);
} }
}
return; return;
} }
if ((ca_atk->m_atk == 100) && (ca_atk->m_skill == EQEmu::skills::SkillFrenzy)){ if (ca_atk->m_atk == 100 && ca_atk->m_skill == EQEmu::skills::SkillFrenzy) {
CheckIncreaseSkill(EQEmu::skills::SkillFrenzy, GetTarget(), 10); CheckIncreaseSkill(EQEmu::skills::SkillFrenzy, GetTarget(), 10);
int AtkRounds = 3; int AtkRounds = 3;
int32 max_dmg = GetBaseSkillDamage(EQEmu::skills::SkillFrenzy, GetTarget()); int32 max_dmg = GetBaseSkillDamage(EQEmu::skills::SkillFrenzy, GetTarget());
@ -327,90 +317,84 @@ void Client::OPCombatAbility(const EQApplicationPacket *app) {
max_dmg = mod_frenzy_damage(max_dmg); max_dmg = mod_frenzy_damage(max_dmg);
ReuseTime = FrenzyReuseTime-1-skill_reduction; ReuseTime = FrenzyReuseTime - 1 - skill_reduction;
ReuseTime = (ReuseTime*HasteMod)/100; ReuseTime = (ReuseTime * HasteMod) / 100;
//Live parses show around 55% Triple 35% Double 10% Single, you will always get first hit. // Live parses show around 55% Triple 35% Double 10% Single, you will always get first hit.
while(AtkRounds > 0) { while (AtkRounds > 0) {
if (GetTarget() && (AtkRounds == 1 || zone->random.Roll(75))) { if (GetTarget() && (AtkRounds == 1 || zone->random.Roll(75))) {
DoSpecialAttackDamage(GetTarget(), EQEmu::skills::SkillFrenzy, max_dmg, 0, max_dmg, ReuseTime, true); DoSpecialAttackDamage(GetTarget(), EQEmu::skills::SkillFrenzy, max_dmg, 0, max_dmg,
ReuseTime, true);
} }
AtkRounds--; AtkRounds--;
} }
if(ReuseTime > 0) { if (ReuseTime > 0)
p_timers.Start(timer, ReuseTime); p_timers.Start(timer, ReuseTime);
}
return; return;
} }
switch(GetClass()){ switch (GetClass()) {
case BERSERKER: case BERSERKER:
case WARRIOR: case WARRIOR:
case RANGER: case RANGER:
case BEASTLORD: case BEASTLORD:
if (ca_atk->m_atk != 100 || ca_atk->m_skill != EQEmu::skills::SkillKick) { if (ca_atk->m_atk != 100 || ca_atk->m_skill != EQEmu::skills::SkillKick)
break; break;
}
if (GetTarget() != this) { if (GetTarget() != this) {
CheckIncreaseSkill(EQEmu::skills::SkillKick, GetTarget(), 10); CheckIncreaseSkill(EQEmu::skills::SkillKick, GetTarget(), 10);
DoAnim(animKick); DoAnim(animKick);
int32 ht = 0; int32 ht = 0;
if (GetWeaponDamage(GetTarget(), GetInv().GetItem(EQEmu::inventory::slotFeet)) <= 0){ if (GetWeaponDamage(GetTarget(), GetInv().GetItem(EQEmu::inventory::slotFeet)) <= 0)
dmg = -5; dmg = -5;
} else
else{
if (!GetTarget()->CheckHitChance(this, EQEmu::skills::SkillKick, 0)) {
dmg = 0;
ht = GetBaseSkillDamage(EQEmu::skills::SkillKick, GetTarget());
}
else{
ht = dmg = GetBaseSkillDamage(EQEmu::skills::SkillKick, GetTarget()); ht = dmg = GetBaseSkillDamage(EQEmu::skills::SkillKick, GetTarget());
}
}
ReuseTime = KickReuseTime-1-skill_reduction;
DoSpecialAttackDamage(GetTarget(), EQEmu::skills::SkillKick, dmg, 0, ht, ReuseTime);
ReuseTime = KickReuseTime - 1 - skill_reduction;
DoSpecialAttackDamage(GetTarget(), EQEmu::skills::SkillKick, dmg, 0, ht, ReuseTime, true);
} }
break; break;
case MONK: { case MONK: {
ReuseTime = MonkSpecialAttack(GetTarget(), ca_atk->m_skill) - 1 - skill_reduction; ReuseTime = MonkSpecialAttack(GetTarget(), ca_atk->m_skill) - 1 - skill_reduction;
//Live AA - Technique of Master Wu // Live AA - Technique of Master Wu
int wuchance = itembonuses.DoubleSpecialAttack + spellbonuses.DoubleSpecialAttack + aabonuses.DoubleSpecialAttack; int wuchance =
itembonuses.DoubleSpecialAttack + spellbonuses.DoubleSpecialAttack + aabonuses.DoubleSpecialAttack;
if (wuchance) { if (wuchance) {
if (wuchance >= 100 || zone->random.Roll(wuchance)) { if (wuchance >= 100 || zone->random.Roll(wuchance)) {
const int MonkSPA[5] = { EQEmu::skills::SkillFlyingKick, EQEmu::skills::SkillDragonPunch, EQEmu::skills::SkillEagleStrike, EQEmu::skills::SkillTigerClaw, EQEmu::skills::SkillRoundKick }; const int MonkSPA[5] = {EQEmu::skills::SkillFlyingKick, EQEmu::skills::SkillDragonPunch,
EQEmu::skills::SkillEagleStrike, EQEmu::skills::SkillTigerClaw,
EQEmu::skills::SkillRoundKick};
int extra = 1; int extra = 1;
// always 1/4 of the double attack chance, 25% at rank 5 (100/4) // always 1/4 of the double attack chance, 25% at rank 5 (100/4)
if (zone->random.Roll(wuchance / 4)) if (zone->random.Roll(wuchance / 4))
extra++; extra++;
// They didn't add a string ID for this. // They didn't add a string ID for this.
std::string msg = StringFormat("The spirit of Master Wu fills you! You gain %d additional attack(s).", extra); std::string msg = StringFormat(
"The spirit of Master Wu fills you! You gain %d additional attack(s).", extra);
// live uses 400 here -- not sure if it's the best for all clients though // live uses 400 here -- not sure if it's the best for all clients though
SendColoredText(400, msg); SendColoredText(400, msg);
auto classic = RuleB(Combat, ClassicMasterWu); auto classic = RuleB(Combat, ClassicMasterWu);
while (extra) { while (extra) {
MonkSpecialAttack(GetTarget(), classic ? MonkSPA[zone->random.Int(0, 4)] : ca_atk->m_skill); MonkSpecialAttack(GetTarget(),
classic ? MonkSPA[zone->random.Int(0, 4)] : ca_atk->m_skill);
extra--; extra--;
} }
} }
} }
if(ReuseTime < 100) { if (ReuseTime < 100) {
//hackish... but we return a huge reuse time if this is an // hackish... but we return a huge reuse time if this is an
// invalid skill, otherwise, we can safely assume it is a // invalid skill, otherwise, we can safely assume it is a
// valid monk skill and just cast it to a SkillType // valid monk skill and just cast it to a SkillType
CheckIncreaseSkill((EQEmu::skills::SkillType) ca_atk->m_skill, GetTarget(), 10); CheckIncreaseSkill((EQEmu::skills::SkillType)ca_atk->m_skill, GetTarget(), 10);
} }
break; break;
} }
case ROGUE: { case ROGUE: {
if (ca_atk->m_atk != 100 || ca_atk->m_skill != EQEmu::skills::SkillBackstab) { if (ca_atk->m_atk != 100 || ca_atk->m_skill != EQEmu::skills::SkillBackstab)
break; break;
}
ReuseTime = BackstabReuseTime-1 - skill_reduction; ReuseTime = BackstabReuseTime-1 - skill_reduction;
TryBackstab(GetTarget(), ReuseTime); TryBackstab(GetTarget(), ReuseTime);
break; break;
@ -421,8 +405,8 @@ void Client::OPCombatAbility(const EQApplicationPacket *app) {
break; break;
} }
ReuseTime = (ReuseTime*HasteMod)/100; ReuseTime = (ReuseTime * HasteMod) / 100;
if(ReuseTime > 0){ if (ReuseTime > 0) {
p_timers.Start(timer, ReuseTime); p_timers.Start(timer, ReuseTime);
} }
} }