mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-12 05:21:29 +00:00
Rework OPCombatAbiltiy a bit
This is done to help remove some code duplication in the future
This commit is contained in:
parent
8c6fefa33e
commit
b92d6c57a1
@ -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);
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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{
|
ht = dmg = GetBaseSkillDamage(EQEmu::skills::SkillBash, GetTarget());
|
||||||
if (!GetTarget()->CheckHitChance(this, EQEmu::skills::SkillBash, 0)) {
|
|
||||||
dmg = 0;
|
|
||||||
ht = GetBaseSkillDamage(EQEmu::skills::SkillBash, GetTarget());
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
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,102 +317,96 @@ 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;
|
|
||||||
}
|
|
||||||
if (GetTarget() != this) {
|
|
||||||
CheckIncreaseSkill(EQEmu::skills::SkillKick, GetTarget(), 10);
|
|
||||||
DoAnim(animKick);
|
|
||||||
|
|
||||||
int32 ht = 0;
|
|
||||||
if (GetWeaponDamage(GetTarget(), GetInv().GetItem(EQEmu::inventory::slotFeet)) <= 0){
|
|
||||||
dmg = -5;
|
|
||||||
}
|
|
||||||
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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ReuseTime = KickReuseTime-1-skill_reduction;
|
|
||||||
DoSpecialAttackDamage(GetTarget(), EQEmu::skills::SkillKick, dmg, 0, ht, ReuseTime);
|
|
||||||
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case MONK: {
|
if (GetTarget() != this) {
|
||||||
ReuseTime = MonkSpecialAttack(GetTarget(), ca_atk->m_skill) - 1 - skill_reduction;
|
CheckIncreaseSkill(EQEmu::skills::SkillKick, GetTarget(), 10);
|
||||||
|
DoAnim(animKick);
|
||||||
|
|
||||||
//Live AA - Technique of Master Wu
|
int32 ht = 0;
|
||||||
int wuchance = itembonuses.DoubleSpecialAttack + spellbonuses.DoubleSpecialAttack + aabonuses.DoubleSpecialAttack;
|
if (GetWeaponDamage(GetTarget(), GetInv().GetItem(EQEmu::inventory::slotFeet)) <= 0)
|
||||||
if (wuchance) {
|
dmg = -5;
|
||||||
if (wuchance >= 100 || zone->random.Roll(wuchance)) {
|
else
|
||||||
const int MonkSPA[5] = { EQEmu::skills::SkillFlyingKick, EQEmu::skills::SkillDragonPunch, EQEmu::skills::SkillEagleStrike, EQEmu::skills::SkillTigerClaw, EQEmu::skills::SkillRoundKick };
|
ht = dmg = GetBaseSkillDamage(EQEmu::skills::SkillKick, GetTarget());
|
||||||
int extra = 1;
|
|
||||||
// always 1/4 of the double attack chance, 25% at rank 5 (100/4)
|
|
||||||
if (zone->random.Roll(wuchance / 4))
|
|
||||||
extra++;
|
|
||||||
// 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);
|
|
||||||
// live uses 400 here -- not sure if it's the best for all clients though
|
|
||||||
SendColoredText(400, msg);
|
|
||||||
auto classic = RuleB(Combat, ClassicMasterWu);
|
|
||||||
while (extra) {
|
|
||||||
MonkSpecialAttack(GetTarget(), classic ? MonkSPA[zone->random.Int(0, 4)] : ca_atk->m_skill);
|
|
||||||
extra--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(ReuseTime < 100) {
|
ReuseTime = KickReuseTime - 1 - skill_reduction;
|
||||||
//hackish... but we return a huge reuse time if this is an
|
DoSpecialAttackDamage(GetTarget(), EQEmu::skills::SkillKick, dmg, 0, ht, ReuseTime, true);
|
||||||
// invalid skill, otherwise, we can safely assume it is a
|
|
||||||
// valid monk skill and just cast it to a SkillType
|
|
||||||
CheckIncreaseSkill((EQEmu::skills::SkillType) ca_atk->m_skill, GetTarget(), 10);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
case ROGUE: {
|
break;
|
||||||
if (ca_atk->m_atk != 100 || ca_atk->m_skill != EQEmu::skills::SkillBackstab) {
|
case MONK: {
|
||||||
break;
|
ReuseTime = MonkSpecialAttack(GetTarget(), ca_atk->m_skill) - 1 - skill_reduction;
|
||||||
|
|
||||||
|
// Live AA - Technique of Master Wu
|
||||||
|
int wuchance =
|
||||||
|
itembonuses.DoubleSpecialAttack + spellbonuses.DoubleSpecialAttack + aabonuses.DoubleSpecialAttack;
|
||||||
|
if (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};
|
||||||
|
int extra = 1;
|
||||||
|
// always 1/4 of the double attack chance, 25% at rank 5 (100/4)
|
||||||
|
if (zone->random.Roll(wuchance / 4))
|
||||||
|
extra++;
|
||||||
|
// 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);
|
||||||
|
// live uses 400 here -- not sure if it's the best for all clients though
|
||||||
|
SendColoredText(400, msg);
|
||||||
|
auto classic = RuleB(Combat, ClassicMasterWu);
|
||||||
|
while (extra) {
|
||||||
|
MonkSpecialAttack(GetTarget(),
|
||||||
|
classic ? MonkSPA[zone->random.Int(0, 4)] : ca_atk->m_skill);
|
||||||
|
extra--;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ReuseTime = BackstabReuseTime-1 - skill_reduction;
|
|
||||||
TryBackstab(GetTarget(), ReuseTime);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
default:
|
|
||||||
//they have no abilities... wtf? make em wait a bit
|
if (ReuseTime < 100) {
|
||||||
ReuseTime = 9 - skill_reduction;
|
// hackish... but we return a huge reuse time if this is an
|
||||||
|
// invalid skill, otherwise, we can safely assume it is a
|
||||||
|
// valid monk skill and just cast it to a SkillType
|
||||||
|
CheckIncreaseSkill((EQEmu::skills::SkillType)ca_atk->m_skill, GetTarget(), 10);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ROGUE: {
|
||||||
|
if (ca_atk->m_atk != 100 || ca_atk->m_skill != EQEmu::skills::SkillBackstab)
|
||||||
break;
|
break;
|
||||||
|
ReuseTime = BackstabReuseTime-1 - skill_reduction;
|
||||||
|
TryBackstab(GetTarget(), ReuseTime);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
//they have no abilities... wtf? make em wait a bit
|
||||||
|
ReuseTime = 9 - skill_reduction;
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user