mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-19 08:11:30 +00:00
[Feature] Add Extra Kick Classes (#3613)
* [Feature] Add Extra Kick Classes # Notes - Allows operators to add extra classes to the "Kick" skill. - Without this only Warrior, Ranger, Monk, Beastlord, and Berserker could kick. * Remove gotos.
This commit is contained in:
parent
4fc3c27715
commit
833fa55fdf
@ -530,6 +530,7 @@ RULE_BOOL(Combat, BackstabIgnoresElemental, false, "Enable or disable Elemental
|
|||||||
RULE_BOOL(Combat, BackstabIgnoresBane, false, "Enable or disable Bane weapon damage affecting backstab damage, false by default.")
|
RULE_BOOL(Combat, BackstabIgnoresBane, false, "Enable or disable Bane weapon damage affecting backstab damage, false by default.")
|
||||||
RULE_BOOL(Combat, SummonMeleeRange, true, "Enable or disable summoning of a player when already in melee range of the summoner.")
|
RULE_BOOL(Combat, SummonMeleeRange, true, "Enable or disable summoning of a player when already in melee range of the summoner.")
|
||||||
RULE_BOOL(Combat, WaterMatchRequiredForAutoFireLoS, true, "Enable/Disable the requirement of both the attacker/victim being both in or out of water for AutoFire LoS to pass.")
|
RULE_BOOL(Combat, WaterMatchRequiredForAutoFireLoS, true, "Enable/Disable the requirement of both the attacker/victim being both in or out of water for AutoFire LoS to pass.")
|
||||||
|
RULE_INT(Combat, ExtraAllowedKickClassesBitmask, 0, "Bitmask for allowing extra classes beyond Warrior, Ranger, Beastlord, and Berserker to kick, No Extra Classes (0) by default")
|
||||||
RULE_CATEGORY_END()
|
RULE_CATEGORY_END()
|
||||||
|
|
||||||
RULE_CATEGORY(NPC)
|
RULE_CATEGORY(NPC)
|
||||||
|
|||||||
@ -281,41 +281,54 @@ void Mob::DoSpecialAttackDamage(Mob *who, EQ::skills::SkillType skill, int32 bas
|
|||||||
// 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 CombatAbility_Struct *ca_atk)
|
void Client::OPCombatAbility(const CombatAbility_Struct *ca_atk)
|
||||||
{
|
{
|
||||||
if (!GetTarget())
|
if (!GetTarget()) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// make sure were actually able to use such an attack. (Bards can throw while casting. ~Kayen confirmed on live 1/22)
|
// make sure were actually able to use such an attack. (Bards can throw while casting. ~Kayen confirmed on live 1/22)
|
||||||
if ((spellend_timer.Enabled() && GetClass() != BARD)|| IsFeared() || IsStunned() || IsMezzed() || DivineAura() || dead)
|
if (
|
||||||
|
(spellend_timer.Enabled() && GetClass() != BARD) ||
|
||||||
|
IsFeared() ||
|
||||||
|
IsStunned() ||
|
||||||
|
IsMezzed() ||
|
||||||
|
DivineAura() ||
|
||||||
|
dead
|
||||||
|
) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
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
|
||||||
if (ClientVersion() >= EQ::versions::ClientVersion::RoF2 && ca_atk->m_skill == EQ::skills::SkillTigerClaw)
|
if (ClientVersion() >= EQ::versions::ClientVersion::RoF2 && ca_atk->m_skill == EQ::skills::SkillTigerClaw) {
|
||||||
timer = pTimerCombatAbility2;
|
timer = pTimerCombatAbility2;
|
||||||
|
}
|
||||||
|
|
||||||
bool CanBypassSkillCheck = false;
|
bool bypass_skill_check = false;
|
||||||
|
|
||||||
if (ca_atk->m_skill == EQ::skills::SkillBash) { // SLAM - Bash without a shield equipped
|
if (ca_atk->m_skill == EQ::skills::SkillBash) { // SLAM - Bash without a shield equipped
|
||||||
switch (GetRace())
|
switch (GetRace()) {
|
||||||
{
|
case OGRE:
|
||||||
case OGRE:
|
case TROLL:
|
||||||
case TROLL:
|
case BARBARIAN:
|
||||||
case BARBARIAN:
|
bypass_skill_check = true;
|
||||||
CanBypassSkillCheck = true;
|
default:
|
||||||
default:
|
break;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check to see if actually have skill */
|
// Check to see if actually have skill
|
||||||
if (!MaxSkill(static_cast<EQ::skills::SkillType>(ca_atk->m_skill)) && !CanBypassSkillCheck)
|
if (!MaxSkill(static_cast<EQ::skills::SkillType>(ca_atk->m_skill)) && !bypass_skill_check) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (GetTarget()->GetID() != ca_atk->m_target)
|
if (GetTarget()->GetID() != ca_atk->m_target) { // invalid packet.
|
||||||
return; // invalid packet.
|
|
||||||
|
|
||||||
if (!IsAttackAllowed(GetTarget()))
|
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IsAttackAllowed(GetTarget())) {
|
||||||
|
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
|
||||||
@ -324,146 +337,194 @@ void Client::OPCombatAbility(const CombatAbility_Struct *ca_atk)
|
|||||||
if (ca_atk->m_skill == EQ::skills::SkillThrowing) {
|
if (ca_atk->m_skill == EQ::skills::SkillThrowing) {
|
||||||
SetAttackTimer();
|
SetAttackTimer();
|
||||||
ThrowingAttack(GetTarget());
|
ThrowingAttack(GetTarget());
|
||||||
if (CheckDoubleRangedAttack())
|
|
||||||
|
if (CheckDoubleRangedAttack()) {
|
||||||
ThrowingAttack(GetTarget(), true);
|
ThrowingAttack(GetTarget(), true);
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ranged attack (archery)
|
// ranged attack (archery)
|
||||||
if (ca_atk->m_skill == EQ::skills::SkillArchery) {
|
if (ca_atk->m_skill == EQ::skills::SkillArchery) {
|
||||||
SetAttackTimer();
|
SetAttackTimer();
|
||||||
RangedAttack(GetTarget());
|
RangedAttack(GetTarget());
|
||||||
if (CheckDoubleRangedAttack())
|
|
||||||
|
if (CheckDoubleRangedAttack()) {
|
||||||
RangedAttack(GetTarget(), true);
|
RangedAttack(GetTarget(), true);
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 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(Chat::Red, "Ability recovery time not yet met.");
|
Message(Chat::Red, "Ability recovery time not yet met.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ReuseTime = 0;
|
int reuse_time = 0;
|
||||||
int ClientHaste = GetHaste();
|
int haste = GetHaste();
|
||||||
int HasteMod = 0;
|
int haste_modifier = 0;
|
||||||
|
|
||||||
if (ClientHaste >= 0)
|
if (haste >= 0) {
|
||||||
HasteMod = (10000 / (100 + ClientHaste)); //+100% haste = 2x as many attacks
|
haste_modifier = (10000 / (100 + haste)); //+100% haste = 2x as many attacks
|
||||||
else
|
} else {
|
||||||
HasteMod = (100 - ClientHaste); //-100% haste = 1/2 as many attacks
|
haste_modifier = (100 - haste); //-100% haste = 1/2 as many attacks
|
||||||
|
}
|
||||||
|
|
||||||
int64 dmg = 0;
|
int64 damage = 0;
|
||||||
|
int16 skill_reduction = GetSkillReuseTime(ca_atk->m_skill);
|
||||||
|
|
||||||
int32 skill_reduction = 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'
|
||||||
|
if (
|
||||||
// not sure what the '100' indicates..if ->m_atk is not used as 'slot' reference, then change SlotRange above back to '11'
|
ca_atk->m_atk == 100 &&
|
||||||
if (ca_atk->m_atk == 100 &&
|
ca_atk->m_skill == EQ::skills::SkillBash
|
||||||
ca_atk->m_skill == EQ::skills::SkillBash) { // SLAM - Bash without a shield equipped
|
) { // SLAM - Bash without a shield equipped
|
||||||
if (GetTarget() != this) {
|
if (GetTarget() != this) {
|
||||||
|
|
||||||
CheckIncreaseSkill(EQ::skills::SkillBash, GetTarget(), 10);
|
CheckIncreaseSkill(EQ::skills::SkillBash, GetTarget(), 10);
|
||||||
DoAnim(animTailRake, 0, false);
|
DoAnim(animTailRake, 0, false);
|
||||||
|
|
||||||
int32 ht = 0;
|
int hate_override = 0;
|
||||||
if (GetWeaponDamage(GetTarget(), GetInv().GetItem(EQ::invslot::slotSecondary)) <= 0 &&
|
|
||||||
GetWeaponDamage(GetTarget(), GetInv().GetItem(EQ::invslot::slotShoulders)) <= 0)
|
|
||||||
dmg = -5;
|
|
||||||
else
|
|
||||||
ht = dmg = GetBaseSkillDamage(EQ::skills::SkillBash, GetTarget());
|
|
||||||
|
|
||||||
ReuseTime = BashReuseTime - 1 - skill_reduction;
|
if (
|
||||||
ReuseTime = (ReuseTime * HasteMod) / 100;
|
GetWeaponDamage(GetTarget(), GetInv().GetItem(EQ::invslot::slotSecondary)) <= 0 &&
|
||||||
DoSpecialAttackDamage(GetTarget(), EQ::skills::SkillBash, dmg, 0, ht, ReuseTime);
|
GetWeaponDamage(GetTarget(), GetInv().GetItem(EQ::invslot::slotShoulders)) <= 0
|
||||||
if (ReuseTime > 0)
|
) {
|
||||||
p_timers.Start(timer, ReuseTime);
|
damage = -5;
|
||||||
|
} else {
|
||||||
|
hate_override = damage = GetBaseSkillDamage(EQ::skills::SkillBash, GetTarget());
|
||||||
|
}
|
||||||
|
|
||||||
|
reuse_time = BashReuseTime - 1 - skill_reduction;
|
||||||
|
reuse_time = (reuse_time * haste_modifier) / 100;
|
||||||
|
DoSpecialAttackDamage(GetTarget(), EQ::skills::SkillBash, damage, 0, hate_override, reuse_time);
|
||||||
|
|
||||||
|
if (reuse_time) {
|
||||||
|
p_timers.Start(timer, reuse_time);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ca_atk->m_atk == 100 && ca_atk->m_skill == EQ::skills::SkillFrenzy) {
|
if (ca_atk->m_atk == 100 && ca_atk->m_skill == EQ::skills::SkillFrenzy) {
|
||||||
|
int attack_rounds = 1;
|
||||||
|
int max_dmg = GetBaseSkillDamage(EQ::skills::SkillFrenzy, GetTarget());
|
||||||
|
|
||||||
CheckIncreaseSkill(EQ::skills::SkillFrenzy, GetTarget(), 10);
|
CheckIncreaseSkill(EQ::skills::SkillFrenzy, GetTarget(), 10);
|
||||||
int AtkRounds = 1;
|
|
||||||
int32 max_dmg = GetBaseSkillDamage(EQ::skills::SkillFrenzy, GetTarget());
|
|
||||||
DoAnim(anim1HWeapon, 0, false);
|
DoAnim(anim1HWeapon, 0, false);
|
||||||
|
|
||||||
if (GetClass() == BERSERKER) {
|
if (GetClass() == BERSERKER) {
|
||||||
int chance = GetLevel() * 2 + GetSkill(EQ::skills::SkillFrenzy);
|
int chance = GetLevel() * 2 + GetSkill(EQ::skills::SkillFrenzy);
|
||||||
if (zone->random.Roll0(450) < chance)
|
|
||||||
AtkRounds++;
|
if (zone->random.Roll0(450) < chance) {
|
||||||
if (zone->random.Roll0(450) < chance)
|
attack_rounds++;
|
||||||
AtkRounds++;
|
}
|
||||||
|
|
||||||
|
if (zone->random.Roll0(450) < chance) {
|
||||||
|
attack_rounds++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ReuseTime = FrenzyReuseTime - 1 - skill_reduction;
|
reuse_time = FrenzyReuseTime - 1 - skill_reduction;
|
||||||
ReuseTime = (ReuseTime * HasteMod) / 100;
|
reuse_time = (reuse_time * haste_modifier) / 100;
|
||||||
|
|
||||||
auto primary_in_use = GetInv().GetItem(EQ::invslot::slotPrimary);
|
const EQ::ItemInstance* primary_in_use = GetInv().GetItem(EQ::invslot::slotPrimary);
|
||||||
if (primary_in_use && GetWeaponDamage(GetTarget(), primary_in_use) <= 0) {
|
if (primary_in_use && GetWeaponDamage(GetTarget(), primary_in_use) <= 0) {
|
||||||
max_dmg = DMG_INVULNERABLE;
|
max_dmg = DMG_INVULNERABLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (AtkRounds > 0) {
|
while (attack_rounds > 0) {
|
||||||
if (GetTarget())
|
if (GetTarget()) {
|
||||||
DoSpecialAttackDamage(GetTarget(), EQ::skills::SkillFrenzy, max_dmg, 0, max_dmg, ReuseTime);
|
DoSpecialAttackDamage(GetTarget(), EQ::skills::SkillFrenzy, max_dmg, 0, max_dmg, reuse_time);
|
||||||
AtkRounds--;
|
}
|
||||||
|
|
||||||
|
attack_rounds--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reuse_time) {
|
||||||
|
p_timers.Start(timer, reuse_time);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ReuseTime > 0)
|
|
||||||
p_timers.Start(timer, ReuseTime);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (GetClass()) {
|
const uint8 class_id = GetClass();
|
||||||
case BERSERKER:
|
|
||||||
case WARRIOR:
|
// Warrior, Ranger, Monk, Beastlord, and Berserker can kick always
|
||||||
case RANGER:
|
const uint32 allowed_kick_classes = RuleI(Combat, ExtraAllowedKickClassesBitmask);
|
||||||
case BEASTLORD:
|
|
||||||
if (ca_atk->m_atk != 100 || ca_atk->m_skill != EQ::skills::SkillKick)
|
const bool can_use_kick = (
|
||||||
break;
|
class_id == WARRIOR ||
|
||||||
|
class_id == RANGER ||
|
||||||
|
class_id == MONK ||
|
||||||
|
class_id == BEASTLORD ||
|
||||||
|
class_id == BERSERKER ||
|
||||||
|
allowed_kick_classes & GetPlayerClassBit(class_id)
|
||||||
|
);
|
||||||
|
|
||||||
|
bool found_skill = false;
|
||||||
|
|
||||||
|
if (
|
||||||
|
ca_atk->m_atk == 100 &&
|
||||||
|
ca_atk->m_skill == EQ::skills::SkillKick &&
|
||||||
|
can_use_kick
|
||||||
|
) {
|
||||||
if (GetTarget() != this) {
|
if (GetTarget() != this) {
|
||||||
CheckIncreaseSkill(EQ::skills::SkillKick, GetTarget(), 10);
|
CheckIncreaseSkill(EQ::skills::SkillKick, GetTarget(), 10);
|
||||||
DoAnim(animKick, 0, false);
|
DoAnim(animKick, 0, false);
|
||||||
|
|
||||||
int32 ht = 0;
|
int hate_override = 0;
|
||||||
if (GetWeaponDamage(GetTarget(), GetInv().GetItem(EQ::invslot::slotFeet)) <= 0)
|
if (GetWeaponDamage(GetTarget(), GetInv().GetItem(EQ::invslot::slotFeet)) <= 0) {
|
||||||
dmg = -5;
|
damage = -5;
|
||||||
else
|
} else {
|
||||||
ht = dmg = GetBaseSkillDamage(EQ::skills::SkillKick, GetTarget());
|
hate_override = damage = GetBaseSkillDamage(EQ::skills::SkillKick, GetTarget());
|
||||||
|
}
|
||||||
|
|
||||||
ReuseTime = KickReuseTime - 1 - skill_reduction;
|
reuse_time = KickReuseTime - 1 - skill_reduction;
|
||||||
DoSpecialAttackDamage(GetTarget(), EQ::skills::SkillKick, dmg, 0, ht, ReuseTime);
|
DoSpecialAttackDamage(GetTarget(), EQ::skills::SkillKick, damage, 0, hate_override, reuse_time);
|
||||||
|
|
||||||
|
found_skill = true;
|
||||||
}
|
}
|
||||||
break;
|
}
|
||||||
case MONK: {
|
|
||||||
ReuseTime = MonkSpecialAttack(GetTarget(), ca_atk->m_skill) - 1 - skill_reduction;
|
if (class_id == MONK) {
|
||||||
|
reuse_time = 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 wu_chance = (
|
||||||
|
itembonuses.DoubleSpecialAttack +
|
||||||
|
spellbonuses.DoubleSpecialAttack +
|
||||||
|
aabonuses.DoubleSpecialAttack
|
||||||
|
);
|
||||||
|
|
||||||
if (wuchance) {
|
if (wu_chance) {
|
||||||
const int MonkSPA[5] = {
|
const int monk_special_attacks[5] = {
|
||||||
EQ::skills::SkillFlyingKick,
|
EQ::skills::SkillFlyingKick,
|
||||||
EQ::skills::SkillDragonPunch,
|
EQ::skills::SkillDragonPunch,
|
||||||
EQ::skills::SkillEagleStrike,
|
EQ::skills::SkillEagleStrike,
|
||||||
EQ::skills::SkillTigerClaw,
|
EQ::skills::SkillTigerClaw,
|
||||||
EQ::skills::SkillRoundKick
|
EQ::skills::SkillRoundKick
|
||||||
};
|
};
|
||||||
|
|
||||||
int extra = 0;
|
int extra = 0;
|
||||||
// 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)
|
||||||
while (wuchance > 0) {
|
while (wu_chance > 0) {
|
||||||
if (zone->random.Roll(wuchance)) {
|
if (zone->random.Roll(wu_chance)) {
|
||||||
++extra;
|
++extra;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
wuchance /= 4;
|
|
||||||
|
wu_chance /= 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (extra) {
|
if (extra) {
|
||||||
SendColoredText(
|
SendColoredText(
|
||||||
400,
|
400,
|
||||||
@ -474,37 +535,47 @@ void Client::OPCombatAbility(const CombatAbility_Struct *ca_atk)
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
auto classic = RuleB(Combat, ClassicMasterWu);
|
|
||||||
|
const bool is_classic_master_wu = RuleB(Combat, ClassicMasterWu);
|
||||||
while (extra) {
|
while (extra) {
|
||||||
MonkSpecialAttack(GetTarget(), (classic ? MonkSPA[zone->random.Int(0, 4)] : ca_atk->m_skill));
|
MonkSpecialAttack(
|
||||||
|
GetTarget(),
|
||||||
|
(is_classic_master_wu ? monk_special_attacks[zone->random.Int(0, 4)] : ca_atk->m_skill)
|
||||||
|
);
|
||||||
--extra;
|
--extra;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ReuseTime < 100) {
|
if (reuse_time < 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((EQ::skills::SkillType)ca_atk->m_skill, GetTarget(), 10);
|
CheckIncreaseSkill((EQ::skills::SkillType) ca_atk->m_skill, GetTarget(), 10);
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
found_skill = true;
|
||||||
case ROGUE: {
|
|
||||||
if (ca_atk->m_atk != 100 || ca_atk->m_skill != EQ::skills::SkillBackstab)
|
|
||||||
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;
|
if (
|
||||||
if (ReuseTime > 0) {
|
ca_atk->m_atk == 100 &&
|
||||||
p_timers.Start(timer, ReuseTime);
|
ca_atk->m_skill == EQ::skills::SkillBackstab &&
|
||||||
|
class_id == ROGUE
|
||||||
|
) {
|
||||||
|
reuse_time = BackstabReuseTime - 1 - skill_reduction;
|
||||||
|
TryBackstab(GetTarget(), reuse_time);
|
||||||
|
found_skill = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found_skill) {
|
||||||
|
reuse_time = 9 - skill_reduction;
|
||||||
|
}
|
||||||
|
|
||||||
|
reuse_time = (reuse_time * haste_modifier) / 100;
|
||||||
|
|
||||||
|
reuse_time = EQ::Clamp(reuse_time, 0, reuse_time);
|
||||||
|
|
||||||
|
if (reuse_time) {
|
||||||
|
p_timers.Start(timer, reuse_time);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user