Implement Triple Attack as a skill

See change log for more details
Optional SQL will max toons triple attack skills
This commit is contained in:
Michael Cook (mackal) 2015-07-06 16:11:00 -04:00
parent 5a73d26d12
commit 1e75b4ba77
9 changed files with 157 additions and 107 deletions

View File

@ -1,5 +1,12 @@
EQEMu Changelog (Started on Sept 24, 2003 15:50)
-------------------------------------------------------
== 07/06/2015 ==
mackal: Implement Triple Attack Skill
Parses showed about rand(1000) for the chance, may need more investigating
Corrected Double Attack chances as well
Running optional 2015_07_06_TripleAttack.sql will set current toons to their max skill
This is optional because the admins might want to go a different route.
== 07/05/2015 ==
mackal: Rewrite NPC combat attack round logic
An NPC "quading" is really just an NPC with innate dual wield that doubles on both hands

View File

@ -108,16 +108,17 @@ enum SkillUseTypes
/*13869*/ SkillBerserking,
/*13902*/ SkillTaunt,
/*05837*/ SkillFrenzy, // This appears to be the only listed one not grouped with the others
/*00000*/ _EmuSkillCount // move to last position of active enumeration labels
// SoF+ specific skills
// /*03670*/ SkillRemoveTraps,
// /*13049*/ SkillTripleAttack,
/*03670*/ SkillRemoveTraps,
/*13049*/ SkillTripleAttack,
// RoF2+ specific skills
// /*00789*/ Skill2HPiercing,
// /*01216*/ SkillNone, // This needs to move down as new skills are added
/*00000*/ _EmuSkillCount // move to last position of active enumeration labels
// Skill Counts
// /*-----*/ _SkillCount_62 = 75, // use for Ti and earlier max skill checks
// /*-----*/ _SkillCount_SoF = 77, // use for SoF thru RoF1 max skill checks
@ -170,7 +171,7 @@ enum SkillUseTypes
};
// temporary until it can be sorted out...
#define HIGHEST_SKILL SkillFrenzy
#define HIGHEST_SKILL SkillTripleAttack
// Spell Effects use this value to determine if an effect applies to all skills.
#define ALL_SKILLS -1

View File

@ -0,0 +1,27 @@
DELIMITER $$
DROP PROCEDURE IF EXISTS GrantTripleAttack$$
CREATE PROCEDURE GrantTripleAttack()
BEGIN
DECLARE finished INT;
DECLARE char_id INT;
DECLARE skill_max INT;
DECLARE cur CURSOR FOR SELECT character_data.id, skill_caps.cap FROM `character_data` LEFT JOIN `skill_caps` ON character_data.`level` = skill_caps.`level` AND character_data.class = skill_caps.class AND skill_caps.skillID = 76;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET finished = 1;
OPEN cur;
SET finished = 0;
REPEAT
FETCH cur INTO char_id, skill_max;
IF skill_max IS NOT NULL AND skill_max > 0 THEN
REPLACE INTO `character_skills` (`id`, `skill_id`, `value`) VALUES(char_id, 76, skill_max);
END IF;
UNTIL finished END REPEAT;
CLOSE cur;
END$$
DELIMITER ;
CALL GrantTripleAttack();
DROP PROCEDURE GrantTripleAttack;

View File

@ -3406,41 +3406,39 @@ bool Mob::HasRangedProcs() const
return false;
}
bool Client::CheckDoubleAttack(bool tripleAttack) {
bool Client::CheckDoubleAttack()
{
int chance = 0;
int skill = GetSkill(SkillDoubleAttack);
//Check for bonuses that give you a double attack chance regardless of skill (ie Bestial Frenzy/Harmonious Attack AA)
uint32 bonusGiveDA = aabonuses.GiveDoubleAttack + spellbonuses.GiveDoubleAttack + itembonuses.GiveDoubleAttack;
if(!HasSkill(SkillDoubleAttack) && !bonusGiveDA)
int bonusGiveDA = aabonuses.GiveDoubleAttack + spellbonuses.GiveDoubleAttack + itembonuses.GiveDoubleAttack;
if (skill > 0)
chance = skill + GetLevel();
else if (!bonusGiveDA)
return false;
float chance = 0.0f;
if (bonusGiveDA)
chance += bonusGiveDA / 100.0f * 500; // convert to skill value
int per_inc = aabonuses.DoubleAttackChance + spellbonuses.DoubleAttackChance + itembonuses.DoubleAttackChance;
if (per_inc)
chance += chance * per_inc / 100;
uint16 skill = GetSkill(SkillDoubleAttack);
int32 bonusDA = aabonuses.DoubleAttackChance + spellbonuses.DoubleAttackChance + itembonuses.DoubleAttackChance;
//Use skill calculations otherwise, if you only have AA applied GiveDoubleAttack chance then use that value as the base.
if (skill)
chance = (float(skill+GetLevel()) * (float(100.0f+bonusDA+bonusGiveDA) /100.0f)) /500.0f;
else
chance = (float(bonusGiveDA) * (float(100.0f+bonusDA)/100.0f) ) /100.0f;
//Live now uses a static Triple Attack skill (lv 46 = 2% lv 60 = 20%) - We do not have this skill on EMU ATM.
//A reasonable forumla would then be TA = 20% * chance
//AA's can also give triple attack skill over cap. (ie Burst of Power) NOTE: Skill ID in spell data is 76 (Triple Attack)
//Kayen: Need to decide if we can implement triple attack skill before working in over the cap effect.
if(tripleAttack) {
// Only some Double Attack classes get Triple Attack [This is already checked in client_processes.cpp]
int32 triple_bonus = spellbonuses.TripleAttackChance + itembonuses.TripleAttackChance;
chance *= 0.2f; //Baseline chance is 20% of your double attack chance.
chance *= float(100.0f+triple_bonus)/100.0f; //Apply modifiers.
return zone->random.Int(1, 500) <= chance;
}
if(zone->random.Roll(chance))
return true;
// Admittedly these parses were short, but this check worked for 3 toons across multiple levels
// with varying triple attack skill (1-3% error at least)
bool Client::CheckTripleAttack()
{
int chance = GetSkill(SkillTripleAttack);
if (chance < 1)
return false;
int per_inc = aabonuses.TripleAttackChance + spellbonuses.TripleAttackChance + itembonuses.TripleAttackChance;
if (per_inc)
chance += chance * per_inc / 100;
return zone->random.Int(1, 1000) <= chance;
}
bool Client::CheckDoubleRangedAttack() {
@ -3452,7 +3450,7 @@ bool Client::CheckDoubleRangedAttack() {
return false;
}
bool Mob::CheckDoubleAttack(bool tripleAttack)
bool Mob::CheckDoubleAttack()
{
// Not 100% certain pets follow this or if it's just from pets not always
// having the same skills as most mobs
@ -5054,21 +5052,28 @@ void Client::DoAttackRounds(Mob *target, int hand, bool IsFromSpell)
if (candouble) {
CheckIncreaseSkill(SkillDoubleAttack, target, -10);
if (CheckDoubleAttack())
if (CheckDoubleAttack()) {
Attack(target, hand, false, false, IsFromSpell);
if (hand == MainPrimary && GetLevel() >= 60 &&
(GetClass() == MONK || GetClass() == WARRIOR || GetClass() == RANGER || GetClass() == BERSERKER) &&
CheckDoubleAttack(true))
// you can only triple from the main hand
if (hand == MainPrimary && CanThisClassTripleAttack()) {
CheckIncreaseSkill(SkillTripleAttack, target, -10);
if (CheckTripleAttack())
Attack(target, hand, false, false, IsFromSpell);
}
}
}
if (hand == MainPrimary) {
// According to http://www.monkly-business.net/forums/showpost.php?p=312095&postcount=168 a dev told them flurry isn't dependant on triple attack
// the parses kind of back that up and all of my parses seemed to be 4 or 5 attacks in the round which would work out to be
// doubles or triples with 2 from flurries or triple with 1 or 2 flurries ... Going with the "dev quote" I guess like we've always had it
auto flurrychance = aabonuses.FlurryChance + spellbonuses.FlurryChance + itembonuses.FlurryChance;
if (flurrychance && zone->random.Roll(flurrychance)) {
Attack(target, hand, false, false, IsFromSpell);
Attack(target, hand, false, false, IsFromSpell);
Message_StringID(MT_NPCFlurry, YOU_FLURRY);
}
// I haven't parsed where this guy happens, but it's not part of the normal chain above so this is fine
auto extraattackchance = aabonuses.ExtraAttackChance + spellbonuses.ExtraAttackChance + itembonuses.ExtraAttackChance;
if (extraattackchance && HasTwoHanderEquipped() && zone->random.Roll(extraattackchance))
Attack(target, hand, false, false, IsFromSpell);

View File

@ -888,7 +888,8 @@ public:
bool CheckTradeLoreConflict(Client* other);
void LinkDead();
void Insight(uint32 t_id);
bool CheckDoubleAttack(bool tripleAttack = false);
bool CheckDoubleAttack();
bool CheckTripleAttack();
bool CheckDoubleRangedAttack();
bool CheckDualWield();

View File

@ -2302,7 +2302,7 @@ void command_setskill(Client *c, const Seperator *sep)
Log.Out(Logs::General, Logs::Normal, "Set skill request from %s, target:%s skill_id:%i value:%i", c->GetName(), c->GetTarget()->GetName(), atoi(sep->arg[1]), atoi(sep->arg[2]) );
int skill_num = atoi(sep->arg[1]);
uint16 skill_value = atoi(sep->arg[2]);
if(skill_num < HIGHEST_SKILL)
if(skill_num <= HIGHEST_SKILL)
c->GetTarget()->CastToClient()->SetSkill((SkillUseTypes)skill_num, skill_value);
}
}

View File

@ -2409,6 +2409,14 @@ bool Mob::CanThisClassDoubleAttack(void) const
}
}
bool Mob::CanThisClassTripleAttack() const
{
if (!IsClient())
return false; // When they added the real triple attack skill, mobs lost the ability to triple
else
return CastToClient()->HasSkill(SkillTripleAttack);
}
bool Mob::IsWarriorClass(void) const
{
switch(GetClass())

View File

@ -169,7 +169,7 @@ public:
virtual bool CheckDualWield();
void DoMainHandAttackRounds(Mob *target, ExtraAttackOptions *opts = nullptr);
void DoOffHandAttackRounds(Mob *target, ExtraAttackOptions *opts = nullptr);
virtual bool CheckDoubleAttack(bool tripleAttack = false); // mob version doesn't use this flag
virtual bool CheckDoubleAttack();
// inline process for places where we need to do them outside of the AI_Process
void ProcessAttackRounds(Mob *target, ExtraAttackOptions *opts = nullptr)
{
@ -750,6 +750,7 @@ public:
virtual int GetMonkHandToHandDamage(void);
bool CanThisClassDoubleAttack(void) const;
bool CanThisClassTripleAttack() const;
bool CanThisClassDualWield(void) const;
bool CanThisClassRiposte(void) const;
bool CanThisClassDodge(void) const;

View File

@ -536,7 +536,7 @@ void Mob::TryBackstab(Mob *other, int ReuseTime) {
RogueBackstab(other,false,ReuseTime);
if (level > 54) {
if(IsClient() && CastToClient()->CheckDoubleAttack(false))
if(IsClient() && CastToClient()->CheckDoubleAttack())
{
if(other->GetHP() > 0)
RogueBackstab(other,false,ReuseTime);
@ -558,7 +558,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())
if(other->GetHP() > 0)
RogueBackstab(other,true, ReuseTime);