mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-11 21:01:29 +00:00
* Clean up for fear related bonus variables SPA 181 FearResistChance (% chance to outright resist fear) and SPA 102 Fearless (on live used only on pets for full fear immunity if presents) The way were calculating the bonuses was mixing the variables we used for each together in a way that could cause conflicts when combined with negate spell effect. While doing some live testing was able to confirm SPA102 when cast on pets will terminate the fear on the next tick which is consistent with how we have the mechanic coded. * Update spells.cpp --------- Co-authored-by: Akkadius <akkadius1@gmail.com>
5914 lines
183 KiB
C++
5914 lines
183 KiB
C++
/* EQEMu: Everquest Server Emulator
|
|
Copyright (C) 2001-2004 EQEMu Development Team (http://eqemu.org)
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; version 2 of the License.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
|
are required to give you total support for your newly bought product;
|
|
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
|
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
#include "../common/classes.h"
|
|
#include "../common/data_verification.h"
|
|
#include "../common/global_define.h"
|
|
#include "../common/item_instance.h"
|
|
#include "../common/rulesys.h"
|
|
#include "../common/spdat.h"
|
|
|
|
#include "client.h"
|
|
#include "entity.h"
|
|
#include "mob.h"
|
|
|
|
#include "bot.h"
|
|
|
|
#include "quest_parser_collection.h"
|
|
|
|
|
|
#ifndef WIN32
|
|
#include <stdlib.h>
|
|
#include "../common/unix.h"
|
|
#endif
|
|
|
|
|
|
void Mob::CalcBonuses()
|
|
{
|
|
CalcSpellBonuses(&spellbonuses);
|
|
CalcAABonuses(&aabonuses);
|
|
CalcMaxHP();
|
|
CalcMaxMana();
|
|
SetAttackTimer();
|
|
CalcAC();
|
|
CalcSeeInvisibleLevel();
|
|
CalcInvisibleLevel();
|
|
|
|
/* Fast walking NPC's are prone to disappear into walls/hills
|
|
We set this here because NPC's can cast spells to change walkspeed/runspeed
|
|
*/
|
|
float get_walk_speed = static_cast<float>(0.025f * GetWalkspeed());
|
|
rooted = FindType(SE_Root);
|
|
}
|
|
|
|
void NPC::CalcBonuses()
|
|
{
|
|
memset(&itembonuses, 0, sizeof(StatBonuses));
|
|
|
|
if (GetOwner() || RuleB(NPC, UseItemBonusesForNonPets)) {
|
|
CalcItemBonuses(&itembonuses);
|
|
}
|
|
|
|
// This has to happen last, so we actually take the item bonuses into account.
|
|
Mob::CalcBonuses();
|
|
}
|
|
|
|
void Client::CalcBonuses()
|
|
{
|
|
memset(&itembonuses, 0, sizeof(StatBonuses));
|
|
CalcItemBonuses(&itembonuses);
|
|
CalcHeroicBonuses(&itembonuses);
|
|
CalcEdibleBonuses(&itembonuses);
|
|
CalcSpellBonuses(&spellbonuses);
|
|
CalcAABonuses(&aabonuses);
|
|
|
|
CalcSeeInvisibleLevel();
|
|
CalcInvisibleLevel();
|
|
|
|
ProcessItemCaps(); // caps that depend on spell/aa bonuses
|
|
|
|
RecalcWeight();
|
|
|
|
CalcAC();
|
|
CalcATK();
|
|
CalcHaste();
|
|
|
|
CalcSTR();
|
|
CalcSTA();
|
|
CalcDEX();
|
|
CalcAGI();
|
|
CalcINT();
|
|
CalcWIS();
|
|
CalcCHA();
|
|
|
|
CalcMR();
|
|
CalcFR();
|
|
CalcDR();
|
|
CalcPR();
|
|
CalcCR();
|
|
CalcCorrup();
|
|
|
|
CalcMaxHP();
|
|
CalcMaxMana();
|
|
CalcMaxEndurance();
|
|
|
|
SetAttackTimer();
|
|
|
|
rooted = FindType(SE_Root);
|
|
|
|
XPRate = 100 + spellbonuses.XPRateMod;
|
|
|
|
if (GetMaxXTargets() != 5 + aabonuses.extra_xtargets)
|
|
SetMaxXTargets(5 + aabonuses.extra_xtargets);
|
|
|
|
// hmm maybe a better way to do this
|
|
int metabolism = spellbonuses.Metabolism + itembonuses.Metabolism + aabonuses.Metabolism;
|
|
int timer = GetClass() == Class::Monk ? CONSUMPTION_MNK_TIMER : CONSUMPTION_TIMER;
|
|
timer = timer * (100 + metabolism) / 100;
|
|
if (timer != consume_food_timer.GetTimerTime())
|
|
consume_food_timer.SetTimer(timer);
|
|
}
|
|
|
|
int Mob::CalcRecommendedLevelBonus(uint8 current_level, uint8 recommended_level, int base_stat)
|
|
{
|
|
if (recommended_level && current_level < recommended_level) {
|
|
int32 stat_modifier = (current_level * 10000 / recommended_level) * base_stat;
|
|
|
|
stat_modifier += stat_modifier < 0 ? -5000 : 5000;
|
|
|
|
return (stat_modifier / 10000);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void Mob::CalcItemBonuses(StatBonuses* b) {
|
|
ClearItemFactionBonuses();
|
|
SetShieldEquipped(false);
|
|
SetTwoHandBluntEquipped(false);
|
|
SetTwoHanderEquipped(false);
|
|
SetDualWeaponsEquipped(false);
|
|
|
|
int16 i;
|
|
|
|
for (i = EQ::invslot::BONUS_BEGIN; i <= EQ::invslot::BONUS_SKILL_END; i++) {
|
|
const auto* inst = GetInv().GetItem(i);
|
|
|
|
if (!inst) {
|
|
continue;
|
|
}
|
|
|
|
AddItemBonuses(inst, b, false, false, 0, (i == EQ::invslot::slotAmmo));
|
|
|
|
//These are given special flags due to how often they are checked for various spell effects.
|
|
const auto* item = inst->GetItem();
|
|
if (
|
|
item &&
|
|
item->ItemType == EQ::item::ItemTypeShield &&
|
|
i == EQ::invslot::slotSecondary
|
|
) {
|
|
SetShieldEquipped(true);
|
|
} else if (
|
|
item &&
|
|
item->ItemType == EQ::item::ItemType2HBlunt &&
|
|
i == EQ::invslot::slotPrimary
|
|
) {
|
|
SetTwoHandBluntEquipped(true);
|
|
SetTwoHanderEquipped(true);
|
|
} else if (
|
|
item &&
|
|
(item->ItemType == EQ::item::ItemType2HSlash || item->ItemType == EQ::item::ItemType2HPiercing) &&
|
|
i == EQ::invslot::slotPrimary
|
|
) {
|
|
SetTwoHanderEquipped(true);
|
|
}
|
|
}
|
|
|
|
if (CanThisClassDualWield()) {
|
|
SetDualWeaponsEquipped(true);
|
|
}
|
|
|
|
if (IsClient()) {
|
|
if (CastToClient()->GetPP().tribute_active) {
|
|
for (auto const &t: CastToClient()->GetPP().tributes) {
|
|
auto item_id = CastToClient()->LookupTributeItemID(t.tribute, t.tier);
|
|
if (item_id) {
|
|
const EQ::ItemInstance *inst = database.CreateItem(item_id);
|
|
if (!inst) {
|
|
continue;
|
|
}
|
|
|
|
AddItemBonuses(inst, b, false, true);
|
|
safe_delete(inst);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (IsOfClientBot()) {
|
|
for (i = EQ::invslot::GUILD_TRIBUTE_BEGIN; i <= EQ::invslot::GUILD_TRIBUTE_END; i++) {
|
|
const auto* inst = GetInv().GetItem(i);
|
|
if (!inst) {
|
|
continue;
|
|
}
|
|
|
|
AddItemBonuses(inst, b, false, true);
|
|
}
|
|
}
|
|
|
|
if (
|
|
RuleI(Spells, AdditiveBonusWornType) &&
|
|
RuleI(Spells, AdditiveBonusWornType) != EQ::item::ItemEffectWorn
|
|
) {
|
|
for (i = EQ::invslot::BONUS_BEGIN; i <= EQ::invslot::BONUS_STAT_END; i++) {
|
|
const EQ::ItemInstance* inst = m_inv[i];
|
|
if (!inst) {
|
|
continue;
|
|
}
|
|
|
|
AdditiveWornBonuses(inst, b);
|
|
}
|
|
}
|
|
|
|
if (IsMerc()) {
|
|
SetAttackTimer();
|
|
}
|
|
}
|
|
|
|
// These item stat caps depend on spells/AAs so we process them after those are processed
|
|
void Mob::ProcessItemCaps()
|
|
{
|
|
itembonuses.HPRegen = std::min(itembonuses.HPRegen, CalcHPRegenCap());
|
|
itembonuses.ManaRegen = std::min(itembonuses.ManaRegen, CalcManaRegenCap());
|
|
itembonuses.EnduranceRegen = std::min(itembonuses.EnduranceRegen, CalcEnduranceRegenCap());
|
|
|
|
// The Sleeper Tomb Avatar proc counts towards item ATK
|
|
// The client uses a 100 here, so using a 100 here the client and server will agree
|
|
// For example, if you set the effect to be 200 it will get 100 item ATK and 100 spell ATK
|
|
if (IsValidSpell(SPELL_AVATAR_ST_PROC) && FindBuff(SPELL_AVATAR_ST_PROC)) {
|
|
itembonuses.ATK += 100;
|
|
spellbonuses.ATK -= 100;
|
|
}
|
|
|
|
itembonuses.ATK = std::min(itembonuses.ATK, CalcItemATKCap());
|
|
|
|
if (IsOfClientBotMerc() && itembonuses.SpellDmg > RuleI(Character, ItemSpellDmgCap)) {
|
|
itembonuses.SpellDmg = RuleI(Character, ItemSpellDmgCap);
|
|
}
|
|
|
|
if (IsOfClientBotMerc() && itembonuses.HealAmt > RuleI(Character, ItemHealAmtCap)) {
|
|
itembonuses.HealAmt = RuleI(Character, ItemHealAmtCap);
|
|
}
|
|
}
|
|
|
|
void Mob::AddItemBonuses(const EQ::ItemInstance* inst, StatBonuses* b, bool is_augment, bool is_tribute, int recommended_level_override, bool is_ammo_item) {
|
|
if (!inst || !inst->IsClassCommon()) {
|
|
return;
|
|
}
|
|
|
|
if (inst->GetAugmentType() == 0 && is_augment) {
|
|
return;
|
|
}
|
|
|
|
const auto* item = inst->GetItem();
|
|
if (!item) {
|
|
return;
|
|
}
|
|
|
|
if (IsClient() && !is_tribute && !inst->IsEquipable(GetBaseRace(), GetClass())) {
|
|
if (item->ItemType != EQ::item::ItemTypeFood && item->ItemType != EQ::item::ItemTypeDrink) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
const auto current_level = GetLevel();
|
|
|
|
if (IsClient() && current_level < inst->GetItemRequiredLevel(true)) {
|
|
return;
|
|
}
|
|
|
|
if (is_ammo_item) {
|
|
return;
|
|
}
|
|
|
|
const auto recommended_level = is_augment ? recommended_level_override : inst->GetItemRecommendedLevel(true);
|
|
const bool meets_recommended = (IsNPC() && !RuleB(Items, NPCUseRecommendedLevels)) || current_level >= recommended_level;
|
|
|
|
auto CalcItemBonus = [&](int statValue) -> int {
|
|
return meets_recommended ? statValue : CalcRecommendedLevelBonus(current_level, recommended_level, statValue);
|
|
};
|
|
|
|
auto CalcCappedItemBonus = [&](int currentStat, int bonus, int cap) -> int {
|
|
int calc_stat = currentStat + CalcItemBonus(bonus);
|
|
return IsOfClientBotMerc() ? std::min(cap, calc_stat) : calc_stat;
|
|
};
|
|
|
|
b->HP += CalcItemBonus(item->HP);
|
|
b->Mana += CalcItemBonus(item->Mana);
|
|
b->Endurance += CalcItemBonus(item->Endur);
|
|
b->AC += CalcItemBonus(item->AC);
|
|
|
|
b->STR += CalcItemBonus(item->AStr + item->HeroicStr);
|
|
b->STA += CalcItemBonus(item->ASta + item->HeroicSta);
|
|
b->DEX += CalcItemBonus(item->ADex + item->HeroicDex);
|
|
b->AGI += CalcItemBonus(item->AAgi + item->HeroicAgi);
|
|
b->INT += CalcItemBonus(item->AInt + item->HeroicInt);
|
|
b->WIS += CalcItemBonus(item->AWis + item->HeroicWis);
|
|
b->CHA += CalcItemBonus(item->ACha + item->HeroicCha);
|
|
|
|
b->HeroicSTR += CalcItemBonus(item->HeroicStr);
|
|
b->HeroicSTA += CalcItemBonus(item->HeroicSta);
|
|
b->HeroicDEX += CalcItemBonus(item->HeroicDex);
|
|
b->HeroicAGI += CalcItemBonus(item->HeroicAgi);
|
|
b->HeroicINT += CalcItemBonus(item->HeroicInt);
|
|
b->HeroicWIS += CalcItemBonus(item->HeroicWis);
|
|
b->HeroicCHA += CalcItemBonus(item->HeroicCha);
|
|
|
|
b->STRCapMod += item->HeroicStr;
|
|
b->STACapMod += item->HeroicSta;
|
|
b->DEXCapMod += item->HeroicDex;
|
|
b->AGICapMod += item->HeroicAgi;
|
|
b->INTCapMod += item->HeroicInt;
|
|
b->WISCapMod += item->HeroicWis;
|
|
b->CHACapMod += item->HeroicCha;
|
|
|
|
b->MR += CalcItemBonus(item->MR + item->HeroicMR);
|
|
b->FR += CalcItemBonus(item->FR + item->HeroicFR);
|
|
b->CR += CalcItemBonus(item->CR + item->HeroicCR);
|
|
b->PR += CalcItemBonus(item->PR + item->HeroicPR);
|
|
b->DR += CalcItemBonus(item->DR + item->HeroicDR);
|
|
b->Corrup += CalcItemBonus(item->SVCorruption + item->HeroicSVCorrup);
|
|
|
|
b->HeroicMR += CalcItemBonus(item->HeroicMR);
|
|
b->HeroicFR += CalcItemBonus(item->HeroicFR);
|
|
b->HeroicCR += CalcItemBonus(item->HeroicCR);
|
|
b->HeroicPR += CalcItemBonus(item->HeroicPR);
|
|
b->HeroicDR += CalcItemBonus(item->HeroicDR);
|
|
b->HeroicCorrup += CalcItemBonus(item->HeroicSVCorrup);
|
|
|
|
b->MRCapMod += item->HeroicMR;
|
|
b->FRCapMod += item->HeroicFR;
|
|
b->CRCapMod += item->HeroicCR;
|
|
b->PRCapMod += item->HeroicPR;
|
|
b->DRCapMod += item->HeroicDR;
|
|
b->CorrupCapMod += item->HeroicSVCorrup;
|
|
|
|
b->HPRegen += CalcItemBonus(item->Regen);
|
|
b->ManaRegen += CalcItemBonus(item->ManaRegen);
|
|
b->EnduranceRegen += CalcItemBonus(item->EnduranceRegen);
|
|
|
|
// These have rule-configured caps.
|
|
b->ATK = CalcCappedItemBonus(b->ATK, item->Attack, RuleI(Character, ItemATKCap) + itembonuses.ItemATKCap + spellbonuses.ItemATKCap + aabonuses.ItemATKCap);
|
|
b->DamageShield = CalcCappedItemBonus(b->DamageShield, item->DamageShield, RuleI(Character, ItemDamageShieldCap));
|
|
b->SpellShield = CalcCappedItemBonus(b->SpellShield, item->SpellShield, RuleI(Character, ItemSpellShieldingCap));
|
|
b->MeleeMitigation = CalcCappedItemBonus(b->MeleeMitigation, item->Shielding, RuleI(Character, ItemShieldingCap));
|
|
b->StunResist = CalcCappedItemBonus(b->StunResist, item->StunResist, RuleI(Character, ItemStunResistCap));
|
|
b->StrikeThrough = CalcCappedItemBonus(b->StrikeThrough, item->StrikeThrough, RuleI(Character, ItemStrikethroughCap));
|
|
b->AvoidMeleeChance = CalcCappedItemBonus(b->AvoidMeleeChance, item->Avoidance, RuleI(Character, ItemAvoidanceCap));
|
|
b->HitChance = CalcCappedItemBonus(b->HitChance, item->Accuracy, RuleI(Character, ItemAccuracyCap));
|
|
b->ProcChance = CalcCappedItemBonus(b->ProcChance, item->CombatEffects, RuleI(Character, ItemCombatEffectsCap));
|
|
b->DoTShielding = CalcCappedItemBonus(b->DoTShielding, item->DotShielding, RuleI(Character, ItemDoTShieldingCap));
|
|
b->HealAmt = CalcCappedItemBonus(b->HealAmt, item->HealAmt, RuleI(Character, ItemHealAmtCap));
|
|
b->SpellDmg = CalcCappedItemBonus(b->SpellDmg, item->SpellDmg, RuleI(Character, ItemSpellDmgCap));
|
|
b->Clairvoyance = CalcCappedItemBonus(b->Clairvoyance, item->Clairvoyance, RuleI(Character, ItemClairvoyanceCap));
|
|
b->DSMitigation = CalcCappedItemBonus(b->DSMitigation, item->DSMitigation, RuleI(Character, ItemDSMitigationCap));
|
|
|
|
if (b->haste < item->Haste) {
|
|
b->haste = item->Haste;
|
|
}
|
|
|
|
if (item->ExtraDmgAmt != 0 && item->ExtraDmgSkill <= EQ::skills::HIGHEST_SKILL) {
|
|
if (item->ExtraDmgSkill == ALL_SKILLS) {
|
|
for (const auto &skill_id: EQ::skills::GetExtraDamageSkills()) {
|
|
b->SkillDamageAmount[skill_id] = CalcCappedItemBonus(b->SkillDamageAmount[skill_id], item->ExtraDmgAmt, RuleI(Character, ItemExtraDmgCap));
|
|
}
|
|
} else {
|
|
b->SkillDamageAmount[item->ExtraDmgSkill] = CalcCappedItemBonus(b->SkillDamageAmount[item->ExtraDmgSkill], item->ExtraDmgAmt, RuleI(Character, ItemExtraDmgCap));
|
|
}
|
|
}
|
|
|
|
if (item->Worn.Effect > 0 && item->Worn.Type == EQ::item::ItemEffectWorn) {
|
|
ApplySpellsBonuses(item->Worn.Effect, item->Worn.Level, b, 0, item->Worn.Type);
|
|
}
|
|
|
|
if (item->Focus.Effect > 0 && item->Focus.Type == EQ::item::ItemEffectFocus) {
|
|
if (
|
|
IsOfClientBotMerc() ||
|
|
(IsNPC() && RuleB(Spells, NPC_UseFocusFromItems))
|
|
) {
|
|
ApplySpellsBonuses(item->Focus.Effect, item->Focus.Level, b, 0);
|
|
}
|
|
}
|
|
|
|
switch (item->BardType) {
|
|
case EQ::item::ItemTypeAllInstrumentTypes: { // (e.g. Singing Short Sword)
|
|
if (item->BardValue > b->singingMod) {
|
|
b->singingMod = item->BardValue;
|
|
}
|
|
|
|
if (item->BardValue > b->brassMod) {
|
|
b->brassMod = item->BardValue;
|
|
}
|
|
|
|
if (item->BardValue > b->stringedMod) {
|
|
b->stringedMod = item->BardValue;
|
|
}
|
|
|
|
if (item->BardValue > b->percussionMod) {
|
|
b->percussionMod = item->BardValue;
|
|
}
|
|
|
|
if (item->BardValue > b->windMod) {
|
|
b->windMod = item->BardValue;
|
|
}
|
|
|
|
break;
|
|
}
|
|
case EQ::item::ItemTypeSinging: {
|
|
if (item->BardValue > b->singingMod) {
|
|
b->singingMod = item->BardValue;
|
|
}
|
|
|
|
break;
|
|
}
|
|
case EQ::item::ItemTypeWindInstrument: {
|
|
if (item->BardValue > b->windMod) {
|
|
b->windMod = item->BardValue;
|
|
}
|
|
|
|
break;
|
|
}
|
|
case EQ::item::ItemTypeStringedInstrument: {
|
|
if (item->BardValue > b->stringedMod) {
|
|
b->stringedMod = item->BardValue;
|
|
}
|
|
|
|
break;
|
|
}
|
|
case EQ::item::ItemTypeBrassInstrument: {
|
|
if (item->BardValue > b->brassMod) {
|
|
b->brassMod = item->BardValue;
|
|
}
|
|
|
|
break;
|
|
}
|
|
case EQ::item::ItemTypePercussionInstrument: {
|
|
if (item->BardValue > b->percussionMod) {
|
|
b->percussionMod = item->BardValue;
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (item->SkillModValue != 0 && item->SkillModType <= EQ::skills::HIGHEST_SKILL) {
|
|
if (
|
|
(item->SkillModValue > 0 && b->skillmod[item->SkillModType] < item->SkillModValue) ||
|
|
(item->SkillModValue < 0 && b->skillmod[item->SkillModType] > item->SkillModValue)
|
|
) {
|
|
b->skillmod[item->SkillModType] = item->SkillModValue;
|
|
}
|
|
}
|
|
|
|
if (item->FactionMod1) {
|
|
if (item->FactionAmt1 > 0 && item->FactionAmt1 > GetItemFactionBonus(item->FactionMod1)) {
|
|
AddItemFactionBonus(item->FactionMod1, item->FactionAmt1);
|
|
} else if (item->FactionAmt1 < 0 && item->FactionAmt1 < GetItemFactionBonus(item->FactionMod1)) {
|
|
AddItemFactionBonus(item->FactionMod1, item->FactionAmt1);
|
|
}
|
|
}
|
|
|
|
if (item->FactionMod2) {
|
|
if (item->FactionAmt2 > 0 && item->FactionAmt2 > GetItemFactionBonus(item->FactionMod2)) {
|
|
AddItemFactionBonus(item->FactionMod2, item->FactionAmt2);
|
|
} else if (item->FactionAmt2 < 0 && item->FactionAmt2 < GetItemFactionBonus(item->FactionMod2)) {
|
|
AddItemFactionBonus(item->FactionMod2, item->FactionAmt2);
|
|
}
|
|
}
|
|
|
|
if (item->FactionMod3) {
|
|
if (item->FactionAmt3 > 0 && item->FactionAmt3 > GetItemFactionBonus(item->FactionMod3)) {
|
|
AddItemFactionBonus(item->FactionMod3, item->FactionAmt3);
|
|
} else if (item->FactionAmt3 < 0 && item->FactionAmt3 < GetItemFactionBonus(item->FactionMod3)) {
|
|
AddItemFactionBonus(item->FactionMod3, item->FactionAmt3);
|
|
}
|
|
}
|
|
|
|
if (item->FactionMod4) {
|
|
if (item->FactionAmt4 > 0 && item->FactionAmt4 > GetItemFactionBonus(item->FactionMod4)) {
|
|
AddItemFactionBonus(item->FactionMod4, item->FactionAmt4);
|
|
} else if (item->FactionAmt4 < 0 && item->FactionAmt4 < GetItemFactionBonus(item->FactionMod4)) {
|
|
AddItemFactionBonus(item->FactionMod4, item->FactionAmt4);
|
|
}
|
|
}
|
|
|
|
if (!is_augment) {
|
|
for (int i = EQ::invaug::SOCKET_BEGIN; i <= EQ::invaug::SOCKET_END; i++) {
|
|
const auto* augment = inst->GetAugment(i);
|
|
if (!augment) {
|
|
continue;
|
|
}
|
|
|
|
AddItemBonuses(augment, b, true, false, recommended_level);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Mob::AdditiveWornBonuses(const EQ::ItemInstance* inst, StatBonuses* b, bool is_augment) {
|
|
/*
|
|
Powerful Non-live like option allows developers to add worn effects on items that
|
|
can stack with other worn effects of the same spell effect type, instead of only taking the highest value.
|
|
Ie Cleave I = 40 pct cleave - So if you equip 3 cleave I items you will have a 120% cleave bonus.
|
|
To enable use RuleI(Spells, AdditiveBonusWornType)
|
|
Setting value = 2 Will force all live items to automatically be calculated additively
|
|
Setting value to anything else will indicate the item 'worntype' that if set to the same, will cause the bonuses to use this calculation
|
|
which will also stack with regular (worntype 2) effects. [Ie set rule = 3 and item worntype = 3]
|
|
*/
|
|
|
|
if (!inst || !inst->IsClassCommon()) {
|
|
return;
|
|
}
|
|
|
|
if (inst->GetAugmentType() == 0 && is_augment) {
|
|
return;
|
|
}
|
|
|
|
const auto* item = inst->GetItem();
|
|
|
|
if (!inst->IsEquipable(GetBaseRace(), GetClass())) {
|
|
return;
|
|
}
|
|
|
|
if (GetLevel() < item->ReqLevel) {
|
|
return;
|
|
}
|
|
|
|
if (item->Worn.Effect > 0 && item->Worn.Type == RuleI(Spells, AdditiveBonusWornType)) {
|
|
ApplySpellsBonuses(
|
|
item->Worn.Effect,
|
|
item->Worn.Level,
|
|
b,
|
|
0,
|
|
item->Worn.Type
|
|
);
|
|
}
|
|
|
|
if (!is_augment) {
|
|
int i;
|
|
for (i = EQ::invaug::SOCKET_BEGIN; i <= EQ::invaug::SOCKET_END; i++) {
|
|
AdditiveWornBonuses(inst->GetAugment(i), b, true);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Client::CalcEdibleBonuses(StatBonuses* newbon) {
|
|
uint32 i;
|
|
|
|
bool food = false;
|
|
bool drink = false;
|
|
for (i = EQ::invslot::GENERAL_BEGIN; i <= EQ::invslot::GENERAL_END; i++)
|
|
{
|
|
if (food && drink)
|
|
break;
|
|
const EQ::ItemInstance* inst = GetInv().GetItem(i);
|
|
if (inst && inst->GetItem() && inst->IsClassCommon()) {
|
|
const EQ::ItemData *item = inst->GetItem();
|
|
if (!food && item->ItemType == EQ::item::ItemTypeFood)
|
|
food = true;
|
|
else if (!drink && item->ItemType == EQ::item::ItemTypeDrink)
|
|
drink = true;
|
|
else
|
|
continue;
|
|
AddItemBonuses(inst, newbon);
|
|
}
|
|
}
|
|
for (i = EQ::invbag::GENERAL_BAGS_BEGIN; i <= EQ::invbag::GENERAL_BAGS_END; i++)
|
|
{
|
|
if (food && drink)
|
|
break;
|
|
const EQ::ItemInstance* inst = GetInv().GetItem(i);
|
|
if (inst && inst->GetItem() && inst->IsClassCommon()) {
|
|
const EQ::ItemData *item = inst->GetItem();
|
|
if (!food && item->ItemType == EQ::item::ItemTypeFood)
|
|
food = true;
|
|
else if (!drink && item->ItemType == EQ::item::ItemTypeDrink)
|
|
drink = true;
|
|
else
|
|
continue;
|
|
AddItemBonuses(inst, newbon);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Mob::CalcAABonuses(StatBonuses *newbon)
|
|
{
|
|
memset(newbon, 0, sizeof(StatBonuses)); // start fresh
|
|
|
|
for (const auto &aa : aa_ranks) {
|
|
auto ability_rank = zone->GetAlternateAdvancementAbilityAndRank(aa.first, aa.second.first);
|
|
auto ability = ability_rank.first;
|
|
auto rank = ability_rank.second;
|
|
|
|
if(!ability) {
|
|
continue;
|
|
}
|
|
|
|
// bad data or no effects
|
|
if (rank->effects.empty())
|
|
continue;
|
|
|
|
ApplyAABonuses(*rank, newbon);
|
|
}
|
|
}
|
|
|
|
//A lot of the normal spell functions (IsBlankSpellEffect, etc) are set for just spells (in common/spdat.h).
|
|
//For now, we'll just put them directly into the code and comment with the corresponding normal function
|
|
//Maybe we'll fix it later? :-D
|
|
void Mob::ApplyAABonuses(const AA::Rank &rank, StatBonuses *newbon)
|
|
{
|
|
if (rank.effects.empty()) // sanity check. why bother if no slots to fill?
|
|
return;
|
|
|
|
uint32 effect = 0;
|
|
int32 base_value = 0;
|
|
int32 limit_value = 0; // only really used for SE_RaiseStatCap & SE_ReduceSkillTimer in aa_effects table
|
|
uint32 slot = 0;
|
|
|
|
for (const auto &e : rank.effects) {
|
|
effect = e.effect_id;
|
|
base_value = e.base_value;
|
|
limit_value = e.limit_value;
|
|
slot = e.slot;
|
|
|
|
// we default to 0 (SE_CurrentHP) for the effect, so if there aren't any base1/2 values, we'll just skip it
|
|
if (effect == 0 && base_value == 0 && limit_value == 0)
|
|
continue;
|
|
|
|
// IsBlankSpellEffect()
|
|
if (effect == SE_Blank || (effect == SE_CHA && base_value == 0) || effect == SE_StackingCommand_Block ||
|
|
effect == SE_StackingCommand_Overwrite)
|
|
continue;
|
|
|
|
LogAA("Applying Effect [{}] from AA [{}] in slot [{}] (base1: [{}], base2: [{}]) on [{}]",
|
|
effect, rank.id, slot, base_value, limit_value, GetCleanName());
|
|
|
|
uint8 focus = IsFocusEffect(0, 0, true, effect);
|
|
if (focus) {
|
|
newbon->FocusEffects[focus] = effect;
|
|
continue;
|
|
}
|
|
|
|
switch (effect) {
|
|
case SE_ACv2:
|
|
case SE_ArmorClass:
|
|
newbon->AC += base_value;
|
|
break;
|
|
// Note: AA effects that use accuracy are skill limited, while spell effect is not.
|
|
case SE_Accuracy:
|
|
// Bad data or unsupported new skill
|
|
if (limit_value > EQ::skills::HIGHEST_SKILL)
|
|
break;
|
|
if ((limit_value == ALL_SKILLS) && (newbon->Accuracy[EQ::skills::HIGHEST_SKILL + 1] < base_value))
|
|
newbon->Accuracy[EQ::skills::HIGHEST_SKILL + 1] = base_value;
|
|
else if (newbon->Accuracy[limit_value] < base_value)
|
|
newbon->Accuracy[limit_value] += base_value;
|
|
break;
|
|
case SE_CurrentHP: // regens
|
|
newbon->HPRegen += base_value;
|
|
break;
|
|
case SE_CurrentEndurance:
|
|
newbon->EnduranceRegen += base_value;
|
|
break;
|
|
case SE_MovementSpeed:
|
|
newbon->movementspeed += base_value; // should we let these stack?
|
|
/*if (base1 > newbon->movementspeed) //or should we use a total value?
|
|
newbon->movementspeed = base1;*/
|
|
break;
|
|
case SE_STR:
|
|
newbon->STR += base_value;
|
|
break;
|
|
case SE_DEX:
|
|
newbon->DEX += base_value;
|
|
break;
|
|
case SE_AGI:
|
|
newbon->AGI += base_value;
|
|
break;
|
|
case SE_STA:
|
|
newbon->STA += base_value;
|
|
break;
|
|
case SE_INT:
|
|
newbon->INT += base_value;
|
|
break;
|
|
case SE_WIS:
|
|
newbon->WIS += base_value;
|
|
break;
|
|
case SE_CHA:
|
|
newbon->CHA += base_value;
|
|
break;
|
|
case SE_WaterBreathing:
|
|
// handled by client
|
|
break;
|
|
case SE_CurrentMana:
|
|
newbon->ManaRegen += base_value;
|
|
break;
|
|
case SE_ManaPool:
|
|
newbon->Mana += base_value;
|
|
break;
|
|
case SE_ItemManaRegenCapIncrease:
|
|
newbon->ItemManaRegenCap += base_value;
|
|
break;
|
|
case SE_ResistFire:
|
|
newbon->FR += base_value;
|
|
break;
|
|
case SE_ResistCold:
|
|
newbon->CR += base_value;
|
|
break;
|
|
case SE_ResistPoison:
|
|
newbon->PR += base_value;
|
|
break;
|
|
case SE_ResistDisease:
|
|
newbon->DR += base_value;
|
|
break;
|
|
case SE_ResistMagic:
|
|
newbon->MR += base_value;
|
|
break;
|
|
case SE_ResistCorruption:
|
|
newbon->Corrup += base_value;
|
|
break;
|
|
case SE_IncreaseSpellHaste:
|
|
break;
|
|
case SE_IncreaseRange:
|
|
break;
|
|
case SE_MaxHPChange:
|
|
newbon->PercentMaxHPChange += base_value;
|
|
break;
|
|
case SE_Packrat:
|
|
newbon->Packrat += base_value;
|
|
break;
|
|
case SE_TwoHandBash:
|
|
break;
|
|
case SE_SetBreathLevel:
|
|
break;
|
|
case SE_RaiseStatCap:
|
|
switch (limit_value) {
|
|
// are these #define'd somewhere?
|
|
case 0: // str
|
|
newbon->STRCapMod += base_value;
|
|
break;
|
|
case 1: // sta
|
|
newbon->STACapMod += base_value;
|
|
break;
|
|
case 2: // agi
|
|
newbon->AGICapMod += base_value;
|
|
break;
|
|
case 3: // dex
|
|
newbon->DEXCapMod += base_value;
|
|
break;
|
|
case 4: // wis
|
|
newbon->WISCapMod += base_value;
|
|
break;
|
|
case 5: // int
|
|
newbon->INTCapMod += base_value;
|
|
break;
|
|
case 6: // cha
|
|
newbon->CHACapMod += base_value;
|
|
break;
|
|
case 7: // mr
|
|
newbon->MRCapMod += base_value;
|
|
break;
|
|
case 8: // cr
|
|
newbon->CRCapMod += base_value;
|
|
break;
|
|
case 9: // fr
|
|
newbon->FRCapMod += base_value;
|
|
break;
|
|
case 10: // pr
|
|
newbon->PRCapMod += base_value;
|
|
break;
|
|
case 11: // dr
|
|
newbon->DRCapMod += base_value;
|
|
break;
|
|
case 12: // corruption
|
|
newbon->CorrupCapMod += base_value;
|
|
break;
|
|
}
|
|
break;
|
|
case SE_SpellSlotIncrease:
|
|
break;
|
|
case SE_MysticalAttune:
|
|
newbon->BuffSlotIncrease += base_value;
|
|
break;
|
|
case SE_TotalHP:
|
|
newbon->FlatMaxHPChange += base_value;
|
|
break;
|
|
case SE_StunResist:
|
|
newbon->StunResist += base_value;
|
|
break;
|
|
case SE_SpellCritChance:
|
|
newbon->CriticalSpellChance += base_value;
|
|
break;
|
|
case SE_SpellCritDmgIncrease:
|
|
newbon->SpellCritDmgIncrease += base_value;
|
|
break;
|
|
case SE_DotCritDmgIncrease:
|
|
newbon->DotCritDmgIncrease += base_value;
|
|
break;
|
|
case SE_ResistSpellChance:
|
|
newbon->ResistSpellChance += base_value;
|
|
break;
|
|
case SE_CriticalHealChance:
|
|
newbon->CriticalHealChance += base_value;
|
|
break;
|
|
case SE_CriticalHealOverTime:
|
|
newbon->CriticalHealOverTime += base_value;
|
|
break;
|
|
case SE_CriticalDoTChance:
|
|
newbon->CriticalDoTChance += base_value;
|
|
break;
|
|
case SE_ReduceSkillTimer:
|
|
newbon->SkillReuseTime[limit_value] += base_value;
|
|
break;
|
|
case SE_Fearless:
|
|
newbon->Fearless = true;
|
|
break;
|
|
case SE_PersistantCasting:
|
|
newbon->PersistantCasting += base_value;
|
|
break;
|
|
case SE_DelayDeath:
|
|
newbon->DelayDeath += base_value;
|
|
break;
|
|
case SE_FrontalStunResist:
|
|
newbon->FrontalStunResist += base_value;
|
|
break;
|
|
case SE_ImprovedBindWound:
|
|
newbon->BindWound += base_value;
|
|
break;
|
|
case SE_MaxBindWound:
|
|
newbon->MaxBindWound += base_value;
|
|
break;
|
|
case SE_SeeInvis:
|
|
base_value = std::min({ base_value, MAX_INVISIBILTY_LEVEL });
|
|
if (newbon->SeeInvis < base_value) {
|
|
newbon->SeeInvis = base_value;
|
|
}
|
|
break;
|
|
case SE_BaseMovementSpeed:
|
|
newbon->BaseMovementSpeed += base_value;
|
|
break;
|
|
case SE_IncreaseRunSpeedCap:
|
|
newbon->IncreaseRunSpeedCap += base_value;
|
|
break;
|
|
case SE_ConsumeProjectile:
|
|
newbon->ConsumeProjectile += base_value;
|
|
break;
|
|
case SE_ForageAdditionalItems:
|
|
newbon->ForageAdditionalItems += base_value;
|
|
break;
|
|
case SE_Salvage:
|
|
newbon->SalvageChance += base_value;
|
|
break;
|
|
case SE_ArcheryDamageModifier:
|
|
newbon->ArcheryDamageModifier += base_value;
|
|
break;
|
|
case SE_DoubleRangedAttack:
|
|
newbon->DoubleRangedAttack += base_value;
|
|
break;
|
|
case SE_DamageShield:
|
|
newbon->DamageShield += base_value;
|
|
break;
|
|
case SE_CharmBreakChance:
|
|
newbon->CharmBreakChance += base_value;
|
|
break;
|
|
case SE_OffhandRiposteFail:
|
|
newbon->OffhandRiposteFail += base_value;
|
|
break;
|
|
case SE_ItemAttackCapIncrease:
|
|
newbon->ItemATKCap += base_value;
|
|
break;
|
|
case SE_GivePetGroupTarget:
|
|
newbon->GivePetGroupTarget = true;
|
|
break;
|
|
case SE_ItemHPRegenCapIncrease:
|
|
newbon->ItemHPRegenCap += base_value;
|
|
break;
|
|
case SE_Ambidexterity:
|
|
newbon->Ambidexterity += base_value;
|
|
break;
|
|
case SE_PetMaxHP:
|
|
newbon->PetMaxHP += base_value;
|
|
break;
|
|
case SE_AvoidMeleeChance:
|
|
newbon->AvoidMeleeChanceEffect += base_value;
|
|
break;
|
|
case SE_CombatStability:
|
|
newbon->CombatStability += base_value;
|
|
break;
|
|
case SE_AddSingingMod:
|
|
switch (limit_value) {
|
|
case EQ::item::ItemTypeWindInstrument:
|
|
newbon->windMod += base_value;
|
|
break;
|
|
case EQ::item::ItemTypeStringedInstrument:
|
|
newbon->stringedMod += base_value;
|
|
break;
|
|
case EQ::item::ItemTypeBrassInstrument:
|
|
newbon->brassMod += base_value;
|
|
break;
|
|
case EQ::item::ItemTypePercussionInstrument:
|
|
newbon->percussionMod += base_value;
|
|
break;
|
|
case EQ::item::ItemTypeSinging:
|
|
newbon->singingMod += base_value;
|
|
break;
|
|
}
|
|
break;
|
|
case SE_SongModCap:
|
|
newbon->songModCap += base_value;
|
|
break;
|
|
case SE_PetCriticalHit:
|
|
newbon->PetCriticalHit += base_value;
|
|
break;
|
|
case SE_PetAvoidance:
|
|
newbon->PetAvoidance += base_value;
|
|
break;
|
|
case SE_ShieldBlock:
|
|
newbon->ShieldBlock += base_value;
|
|
break;
|
|
case SE_ShieldEquipDmgMod:
|
|
newbon->ShieldEquipDmgMod += base_value;
|
|
break;
|
|
case SE_SecondaryDmgInc:
|
|
newbon->SecondaryDmgInc = true;
|
|
break;
|
|
case SE_ChangeAggro:
|
|
newbon->hatemod += base_value;
|
|
break;
|
|
case SE_EndurancePool:
|
|
newbon->Endurance += base_value;
|
|
break;
|
|
case SE_ChannelChanceItems:
|
|
newbon->ChannelChanceItems += base_value;
|
|
break;
|
|
case SE_ChannelChanceSpells:
|
|
newbon->ChannelChanceSpells += base_value;
|
|
break;
|
|
case SE_DoubleSpecialAttack:
|
|
newbon->DoubleSpecialAttack += base_value;
|
|
break;
|
|
case SE_TripleBackstab:
|
|
newbon->TripleBackstab += base_value;
|
|
break;
|
|
case SE_FrontalBackstabMinDmg:
|
|
newbon->FrontalBackstabMinDmg = true;
|
|
break;
|
|
case SE_FrontalBackstabChance:
|
|
newbon->FrontalBackstabChance += base_value;
|
|
break;
|
|
case SE_Double_Backstab_Front:
|
|
newbon->Double_Backstab_Front += base_value;
|
|
break;
|
|
case SE_BlockBehind:
|
|
newbon->BlockBehind += base_value;
|
|
break;
|
|
case SE_StrikeThrough:
|
|
case SE_StrikeThrough2:
|
|
newbon->StrikeThrough += base_value;
|
|
break;
|
|
case SE_DoubleAttackChance:
|
|
newbon->DoubleAttackChance += base_value;
|
|
break;
|
|
case SE_GiveDoubleAttack:
|
|
newbon->GiveDoubleAttack += base_value;
|
|
break;
|
|
case SE_ProcChance:
|
|
newbon->ProcChanceSPA += base_value;
|
|
break;
|
|
case SE_RiposteChance:
|
|
newbon->RiposteChance += base_value;
|
|
break;
|
|
case SE_DodgeChance:
|
|
newbon->DodgeChance += base_value;
|
|
break;
|
|
case SE_ParryChance:
|
|
newbon->ParryChance += base_value;
|
|
break;
|
|
case SE_IncreaseBlockChance:
|
|
newbon->IncreaseBlockChance += base_value;
|
|
break;
|
|
case SE_Flurry:
|
|
newbon->FlurryChance += base_value;
|
|
break;
|
|
case SE_PetFlurry:
|
|
newbon->PetFlurry += base_value;
|
|
break;
|
|
case SE_BardSongRange:
|
|
newbon->SongRange += base_value;
|
|
break;
|
|
case SE_RootBreakChance:
|
|
newbon->RootBreakChance += base_value;
|
|
break;
|
|
case SE_UnfailingDivinity:
|
|
newbon->UnfailingDivinity += base_value;
|
|
break;
|
|
case SE_CrippBlowChance:
|
|
newbon->CrippBlowChance += base_value;
|
|
break;
|
|
|
|
case SE_HitChance: {
|
|
// Bad data or unsupported new skill
|
|
if (limit_value > EQ::skills::HIGHEST_SKILL)
|
|
break;
|
|
if (limit_value == ALL_SKILLS)
|
|
newbon->HitChanceEffect[EQ::skills::HIGHEST_SKILL + 1] += base_value;
|
|
else
|
|
newbon->HitChanceEffect[limit_value] += base_value;
|
|
break;
|
|
}
|
|
|
|
case SE_ProcOnKillShot:
|
|
for (int i = 0; i < MAX_SPELL_TRIGGER * 3; i += 3) {
|
|
if (!newbon->SpellOnKill[i] ||
|
|
((newbon->SpellOnKill[i] == limit_value) && (newbon->SpellOnKill[i + 1] < base_value))) {
|
|
// base1 = chance, base2 = SpellID to be triggered, base3 = min npc level
|
|
newbon->SpellOnKill[i] = limit_value;
|
|
newbon->SpellOnKill[i + 1] = base_value;
|
|
|
|
if (GetLevel() > 15)
|
|
newbon->SpellOnKill[i + 2] =
|
|
GetLevel() - 15; // AA specifiy "non-trivial"
|
|
else
|
|
newbon->SpellOnKill[i + 2] = 0;
|
|
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SE_SpellOnDeath:
|
|
for (int i = 0; i < MAX_SPELL_TRIGGER * 2; i += 2) {
|
|
if (!newbon->SpellOnDeath[i]) {
|
|
// base1 = SpellID to be triggered, base2 = chance to fire
|
|
newbon->SpellOnDeath[i] = base_value;
|
|
newbon->SpellOnDeath[i + 1] = limit_value;
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SE_WeaponProc:
|
|
case SE_AddMeleeProc:
|
|
for (int i = 0; i < MAX_AA_PROCS; i += 4) {
|
|
if (!newbon->SpellProc[i + SBIndex::COMBAT_PROC_ORIGIN_ID]) {
|
|
newbon->SpellProc[i + SBIndex::COMBAT_PROC_ORIGIN_ID] = rank.id; //aa rank id
|
|
newbon->SpellProc[i + SBIndex::COMBAT_PROC_SPELL_ID] = base_value; //proc spell id
|
|
newbon->SpellProc[i + SBIndex::COMBAT_PROC_RATE_MOD] = limit_value; //proc rate modifer
|
|
newbon->SpellProc[i + SBIndex::COMBAT_PROC_REUSE_TIMER] = 0; //Lock out Timer
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SE_RangedProc:
|
|
for (int i = 0; i < MAX_AA_PROCS; i += 4) {
|
|
if (!newbon->RangedProc[i + SBIndex::COMBAT_PROC_ORIGIN_ID]) {
|
|
newbon->RangedProc[i + SBIndex::COMBAT_PROC_ORIGIN_ID] = rank.id; //aa rank id
|
|
newbon->RangedProc[i + SBIndex::COMBAT_PROC_SPELL_ID] = base_value; //proc spell id
|
|
newbon->RangedProc[i + SBIndex::COMBAT_PROC_RATE_MOD] = limit_value; //proc rate modifer
|
|
newbon->RangedProc[i + SBIndex::COMBAT_PROC_REUSE_TIMER] = 0; //Lock out Timer
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SE_DefensiveProc:
|
|
for (int i = 0; i < MAX_AA_PROCS; i += 4) {
|
|
if (!newbon->DefensiveProc[i + SBIndex::COMBAT_PROC_ORIGIN_ID]) {
|
|
newbon->DefensiveProc[i + SBIndex::COMBAT_PROC_ORIGIN_ID] = rank.id; //aa rank id
|
|
newbon->DefensiveProc[i + SBIndex::COMBAT_PROC_SPELL_ID] = base_value; //proc spell id
|
|
newbon->DefensiveProc[i + SBIndex::COMBAT_PROC_RATE_MOD] = limit_value; //proc rate modifer
|
|
newbon->DefensiveProc[i + SBIndex::COMBAT_PROC_REUSE_TIMER] = 0; //Lock out Timer
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SE_Proc_Timer_Modifier: {
|
|
/*
|
|
AA can multiples of this in a single effect, proc should use the timer
|
|
that comes after the respective proc spell effect, thus rank.id will be already set
|
|
when this is checked.
|
|
*/
|
|
|
|
newbon->Proc_Timer_Modifier = true;
|
|
|
|
for (int i = 0; i < MAX_AA_PROCS; i += 4) {
|
|
if (newbon->SpellProc[i + SBIndex::COMBAT_PROC_ORIGIN_ID] == rank.id) {
|
|
if (!newbon->SpellProc[i + SBIndex::COMBAT_PROC_REUSE_TIMER]) {
|
|
newbon->SpellProc[i + SBIndex::COMBAT_PROC_REUSE_TIMER] = limit_value;//Lock out Timer
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (newbon->RangedProc[i + SBIndex::COMBAT_PROC_ORIGIN_ID] == rank.id) {
|
|
if (!newbon->RangedProc[i + SBIndex::COMBAT_PROC_REUSE_TIMER]) {
|
|
newbon->RangedProc[i + SBIndex::COMBAT_PROC_REUSE_TIMER] = limit_value;//Lock out Timer
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (newbon->DefensiveProc[i + SBIndex::COMBAT_PROC_ORIGIN_ID] == rank.id) {
|
|
if (!newbon->DefensiveProc[i + SBIndex::COMBAT_PROC_REUSE_TIMER]) {
|
|
newbon->DefensiveProc[i + SBIndex::COMBAT_PROC_REUSE_TIMER] = limit_value;//Lock out Timer
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_CriticalHitChance: {
|
|
// Bad data or unsupported new skill
|
|
if (limit_value > EQ::skills::HIGHEST_SKILL)
|
|
break;
|
|
if (limit_value == ALL_SKILLS)
|
|
newbon->CriticalHitChance[EQ::skills::HIGHEST_SKILL + 1] += base_value;
|
|
else
|
|
newbon->CriticalHitChance[limit_value] += base_value;
|
|
} break;
|
|
|
|
case SE_CriticalDamageMob: {
|
|
// Bad data or unsupported new skill
|
|
if (limit_value > EQ::skills::HIGHEST_SKILL)
|
|
break;
|
|
// base1 = effect value, base2 = skill restrictions(-1 for all)
|
|
if (limit_value == ALL_SKILLS)
|
|
newbon->CritDmgMod[EQ::skills::HIGHEST_SKILL + 1] += base_value;
|
|
else
|
|
newbon->CritDmgMod[limit_value] += base_value;
|
|
break;
|
|
}
|
|
|
|
case SE_Critical_Melee_Damage_Mod_Max:
|
|
{
|
|
// Bad data or unsupported new skill
|
|
if (limit_value > EQ::skills::HIGHEST_SKILL)
|
|
break;
|
|
int skill = limit_value == ALL_SKILLS ? EQ::skills::HIGHEST_SKILL + 1 : limit_value;
|
|
if (base_value < 0 && newbon->CritDmgModNoStack[skill] > base_value)
|
|
newbon->CritDmgModNoStack[skill] = base_value;
|
|
else if (base_value > 0 && newbon->CritDmgModNoStack[skill] < base_value)
|
|
newbon->CritDmgModNoStack[skill] = base_value;
|
|
break;
|
|
}
|
|
|
|
case SE_CriticalSpellChance: {
|
|
newbon->CriticalSpellChance += base_value;
|
|
|
|
if (limit_value > newbon->SpellCritDmgIncNoStack)
|
|
newbon->SpellCritDmgIncNoStack = limit_value;
|
|
|
|
break;
|
|
}
|
|
|
|
case SE_ResistFearChance: {
|
|
newbon->ResistFearChance += base_value; // these should stack
|
|
break;
|
|
}
|
|
|
|
case SE_SkillDamageAmount: {
|
|
// Bad data or unsupported new skill
|
|
if (limit_value > EQ::skills::HIGHEST_SKILL)
|
|
break;
|
|
if (limit_value == ALL_SKILLS)
|
|
newbon->SkillDamageAmount[EQ::skills::HIGHEST_SKILL + 1] += base_value;
|
|
else
|
|
newbon->SkillDamageAmount[limit_value] += base_value;
|
|
break;
|
|
}
|
|
|
|
case SE_SkillAttackProc: {
|
|
for (int i = 0; i < MAX_CAST_ON_SKILL_USE; i += 3) {
|
|
if (!newbon->SkillAttackProc[i + SBIndex::SKILLATK_PROC_SPELL_ID]) { // spell id
|
|
newbon->SkillAttackProc[i + SBIndex::SKILLATK_PROC_SPELL_ID] = rank.spell; // spell to proc
|
|
newbon->SkillAttackProc[i + SBIndex::SKILLATK_PROC_CHANCE] = base_value; // Chance base 1000 = 100% proc rate
|
|
newbon->SkillAttackProc[i + SBIndex::SKILLATK_PROC_SKILL] = limit_value; // Skill to Proc Offr
|
|
|
|
if (limit_value <= EQ::skills::HIGHEST_SKILL) {
|
|
newbon->HasSkillAttackProc[limit_value] = true; //check first before looking for any effects.
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_DamageModifier: {
|
|
// Bad data or unsupported new skill
|
|
if (limit_value > EQ::skills::HIGHEST_SKILL)
|
|
break;
|
|
if (limit_value == ALL_SKILLS)
|
|
newbon->DamageModifier[EQ::skills::HIGHEST_SKILL + 1] += base_value;
|
|
else
|
|
newbon->DamageModifier[limit_value] += base_value;
|
|
break;
|
|
}
|
|
|
|
case SE_DamageModifier2: {
|
|
// Bad data or unsupported new skill
|
|
if (limit_value > EQ::skills::HIGHEST_SKILL)
|
|
break;
|
|
if (limit_value == ALL_SKILLS)
|
|
newbon->DamageModifier2[EQ::skills::HIGHEST_SKILL + 1] += base_value;
|
|
else
|
|
newbon->DamageModifier2[limit_value] += base_value;
|
|
break;
|
|
}
|
|
|
|
case SE_Skill_Base_Damage_Mod: {
|
|
// Bad data or unsupported new skill
|
|
if (limit_value > EQ::skills::HIGHEST_SKILL)
|
|
break;
|
|
if (limit_value == ALL_SKILLS)
|
|
newbon->DamageModifier3[EQ::skills::HIGHEST_SKILL + 1] += base_value;
|
|
else
|
|
newbon->DamageModifier3[limit_value] += base_value;
|
|
break;
|
|
}
|
|
|
|
case SE_SlayUndead: {
|
|
if (newbon->SlayUndead[SBIndex::SLAYUNDEAD_DMG_MOD] < base_value) {
|
|
newbon->SlayUndead[SBIndex::SLAYUNDEAD_DMG_MOD] = base_value; // Rate
|
|
newbon->SlayUndead[SBIndex::SLAYUNDEAD_RATE_MOD] = limit_value; // Damage Modifier
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_DoubleRiposte: {
|
|
newbon->DoubleRiposte += base_value;
|
|
break;
|
|
}
|
|
|
|
case SE_GiveDoubleRiposte: {
|
|
// 0=Regular Riposte 1=Skill Attack Riposte 2=Skill
|
|
if (limit_value == 0) {
|
|
if (newbon->GiveDoubleRiposte[SBIndex::DOUBLE_RIPOSTE_CHANCE] < base_value)
|
|
newbon->GiveDoubleRiposte[SBIndex::DOUBLE_RIPOSTE_CHANCE] = base_value;
|
|
}
|
|
// Only for special attacks.
|
|
else if (limit_value > 0 && (newbon->GiveDoubleRiposte[SBIndex::DOUBLE_RIPOSTE_SKILL_ATK_CHANCE] < base_value)) {
|
|
newbon->GiveDoubleRiposte[SBIndex::DOUBLE_RIPOSTE_SKILL_ATK_CHANCE] = base_value;
|
|
newbon->GiveDoubleRiposte[SBIndex::DOUBLE_RIPOSTE_SKILL] = limit_value;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
// Physically raises skill cap ie if 55/55 it will raise to 55/60
|
|
case SE_RaiseSkillCap: {
|
|
|
|
if (limit_value > EQ::skills::HIGHEST_SKILL)
|
|
break;
|
|
|
|
if (newbon->RaiseSkillCap[limit_value] < base_value)
|
|
newbon->RaiseSkillCap[limit_value] = base_value;
|
|
break;
|
|
}
|
|
|
|
case SE_MasteryofPast: {
|
|
if (newbon->MasteryofPast < base_value)
|
|
newbon->MasteryofPast = base_value;
|
|
break;
|
|
}
|
|
|
|
case SE_CastingLevel: {
|
|
newbon->adjusted_casting_skill += base_value;
|
|
break;
|
|
}
|
|
|
|
case SE_CastingLevel2: {
|
|
newbon->effective_casting_level += base_value;
|
|
break;
|
|
}
|
|
|
|
case SE_DivineSave: {
|
|
if (newbon->DivineSaveChance[SBIndex::DIVINE_SAVE_CHANCE] < base_value) {
|
|
newbon->DivineSaveChance[SBIndex::DIVINE_SAVE_CHANCE] = base_value;
|
|
newbon->DivineSaveChance[SBIndex::DIVINE_SAVE_SPELL_TRIGGER_ID] = limit_value;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_SpellEffectResistChance: {
|
|
for (int e = 0; e < MAX_RESISTABLE_EFFECTS * 2; e += 2) {
|
|
if (
|
|
!newbon->SEResist[e + 1] ||
|
|
(
|
|
newbon->SEResist[e + 1] &&
|
|
newbon->SEResist[e] == limit_value &&
|
|
newbon->SEResist[e + 1] < base_value
|
|
)
|
|
) {
|
|
newbon->SEResist[e] = limit_value; // Spell Effect ID
|
|
newbon->SEResist[e + 1] = base_value; // Resist Chance
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_MitigateDamageShield: {
|
|
|
|
//AA that increase mitigation are set to negative.
|
|
if (base_value < 0) {
|
|
base_value = base_value * (-1);
|
|
}
|
|
|
|
newbon->DSMitigationOffHand += base_value;
|
|
break;
|
|
}
|
|
|
|
case SE_FinishingBlow: {
|
|
// base1 = chance, base2 = damage
|
|
if (newbon->FinishingBlow[SBIndex::FINISHING_EFFECT_DMG] < limit_value) {
|
|
newbon->FinishingBlow[SBIndex::FINISHING_EFFECT_PROC_CHANCE] = base_value;
|
|
newbon->FinishingBlow[SBIndex::FINISHING_EFFECT_DMG] = limit_value;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_FinishingBlowLvl: {
|
|
// base1 = level, base2 = ??? (Set to 200 in AA data, possible proc rate mod?)
|
|
if (newbon->FinishingBlowLvl[SBIndex::FINISHING_EFFECT_LEVEL_MAX] < base_value) {
|
|
newbon->FinishingBlowLvl[SBIndex::FINISHING_EFFECT_LEVEL_MAX] = base_value;
|
|
newbon->FinishingBlowLvl[SBIndex::FINISHING_BLOW_LEVEL_HP_RATIO] = limit_value;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_StunBashChance:
|
|
newbon->StunBashChance += base_value;
|
|
break;
|
|
|
|
case SE_IncreaseChanceMemwipe:
|
|
newbon->IncreaseChanceMemwipe += base_value;
|
|
break;
|
|
|
|
case SE_CriticalMend:
|
|
newbon->CriticalMend += base_value;
|
|
break;
|
|
|
|
case SE_HealRate:
|
|
newbon->HealRate += base_value;
|
|
break;
|
|
|
|
case SE_MeleeLifetap: {
|
|
|
|
if ((base_value < 0) && (newbon->MeleeLifetap > base_value))
|
|
newbon->MeleeLifetap = base_value;
|
|
|
|
else if (newbon->MeleeLifetap < base_value)
|
|
newbon->MeleeLifetap = base_value;
|
|
break;
|
|
}
|
|
|
|
case SE_Vampirism:
|
|
newbon->Vampirism += base_value;
|
|
break;
|
|
|
|
case SE_FrenziedDevastation:
|
|
newbon->FrenziedDevastation += limit_value;
|
|
break;
|
|
|
|
case SE_SpellProcChance:
|
|
newbon->SpellProcChance += base_value;
|
|
break;
|
|
|
|
case SE_Berserk:
|
|
newbon->BerserkSPA = true;
|
|
break;
|
|
|
|
case SE_Metabolism:
|
|
newbon->Metabolism += base_value;
|
|
break;
|
|
|
|
case SE_ImprovedReclaimEnergy: {
|
|
if ((base_value < 0) && (newbon->ImprovedReclaimEnergy > base_value))
|
|
newbon->ImprovedReclaimEnergy = base_value;
|
|
|
|
else if (newbon->ImprovedReclaimEnergy < base_value)
|
|
newbon->ImprovedReclaimEnergy = base_value;
|
|
break;
|
|
}
|
|
|
|
case SE_HeadShot: {
|
|
if (newbon->HeadShot[SBIndex::FINISHING_EFFECT_DMG] < limit_value) {
|
|
newbon->HeadShot[SBIndex::FINISHING_EFFECT_PROC_CHANCE] = base_value;
|
|
newbon->HeadShot[SBIndex::FINISHING_EFFECT_DMG] = limit_value;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_HeadShotLevel: {
|
|
if (newbon->HSLevel[SBIndex::FINISHING_EFFECT_LEVEL_MAX] < base_value) {
|
|
newbon->HSLevel[SBIndex::FINISHING_EFFECT_LEVEL_MAX] = base_value;
|
|
newbon->HSLevel[SBIndex::FINISHING_EFFECT_LEVEL_CHANCE_BONUS] = limit_value;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_Assassinate: {
|
|
if (newbon->Assassinate[SBIndex::FINISHING_EFFECT_DMG] < limit_value) {
|
|
newbon->Assassinate[SBIndex::FINISHING_EFFECT_PROC_CHANCE] = base_value;
|
|
newbon->Assassinate[SBIndex::FINISHING_EFFECT_DMG] = limit_value;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_AssassinateLevel: {
|
|
if (newbon->AssassinateLevel[SBIndex::FINISHING_EFFECT_LEVEL_MAX] < base_value) {
|
|
newbon->AssassinateLevel[SBIndex::FINISHING_EFFECT_LEVEL_MAX] = base_value;
|
|
newbon->AssassinateLevel[SBIndex::FINISHING_EFFECT_LEVEL_CHANCE_BONUS] = limit_value;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_PetMeleeMitigation:
|
|
newbon->PetMeleeMitigation += base_value;
|
|
break;
|
|
|
|
case SE_FactionModPct: {
|
|
if ((base_value < 0) && (newbon->FactionModPct > base_value))
|
|
newbon->FactionModPct = base_value;
|
|
|
|
else if (newbon->FactionModPct < base_value)
|
|
newbon->FactionModPct = base_value;
|
|
break;
|
|
}
|
|
|
|
case SE_Illusion:
|
|
newbon->Illusion = rank.spell;
|
|
break;
|
|
|
|
case SE_IllusionPersistence:
|
|
newbon->IllusionPersistence = base_value;
|
|
break;
|
|
|
|
case SE_LimitToSkill: {
|
|
|
|
// Bad data or unsupported new skill
|
|
if (base_value > EQ::skills::HIGHEST_SKILL) {
|
|
break;
|
|
}
|
|
if (base_value <= EQ::skills::HIGHEST_SKILL) {
|
|
newbon->LimitToSkill[base_value] = true;
|
|
newbon->LimitToSkill[EQ::skills::HIGHEST_SKILL + 2] = true; //Used as a general exists check
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_SkillProcAttempt: {
|
|
for (int e = 0; e < MAX_SKILL_PROCS; e++) {
|
|
if (newbon->SkillProc[e] && newbon->SkillProc[e] == rank.id)
|
|
break; // Do not use the same aa id more than once.
|
|
|
|
else if (!newbon->SkillProc[e]) {
|
|
newbon->SkillProc[e] = rank.id;
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_SkillProcSuccess: {
|
|
|
|
for (int e = 0; e < MAX_SKILL_PROCS; e++) {
|
|
if (newbon->SkillProcSuccess[e] && newbon->SkillProcSuccess[e] == rank.id)
|
|
break; // Do not use the same spell id more than once.
|
|
|
|
else if (!newbon->SkillProcSuccess[e]) {
|
|
newbon->SkillProcSuccess[e] = rank.id;
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_MeleeMitigation:
|
|
newbon->MeleeMitigationEffect += base_value;
|
|
break;
|
|
|
|
case SE_ATK:
|
|
newbon->ATK += base_value;
|
|
break;
|
|
case SE_IncreaseExtTargetWindow:
|
|
newbon->extra_xtargets += base_value;
|
|
break;
|
|
|
|
case SE_PC_Pet_Rampage: {
|
|
newbon->PC_Pet_Rampage[SBIndex::PET_RAMPAGE_CHANCE] += base_value; //Chance to rampage
|
|
if (newbon->PC_Pet_Rampage[SBIndex::PET_RAMPAGE_DMG_MOD] < limit_value)
|
|
newbon->PC_Pet_Rampage[SBIndex::PET_RAMPAGE_DMG_MOD] = limit_value; //Damage modifer - take highest
|
|
break;
|
|
}
|
|
|
|
case SE_PC_Pet_AE_Rampage: {
|
|
newbon->PC_Pet_AE_Rampage[SBIndex::PET_RAMPAGE_CHANCE] += base_value; //Chance to rampage
|
|
if (newbon->PC_Pet_AE_Rampage[SBIndex::PET_RAMPAGE_DMG_MOD] < limit_value)
|
|
newbon->PC_Pet_AE_Rampage[SBIndex::PET_RAMPAGE_DMG_MOD] = limit_value; //Damage modifer - take highest
|
|
break;
|
|
}
|
|
|
|
case SE_PC_Pet_Flurry_Chance:
|
|
newbon->PC_Pet_Flurry += base_value; //Chance to Flurry
|
|
break;
|
|
|
|
case SE_ShroudofStealth:
|
|
newbon->ShroudofStealth = true;
|
|
break;
|
|
|
|
case SE_ReduceFallDamage:
|
|
newbon->ReduceFallDamage += base_value;
|
|
break;
|
|
|
|
case SE_ReduceTradeskillFail:{
|
|
|
|
if (limit_value > EQ::skills::HIGHEST_SKILL)
|
|
break;
|
|
|
|
newbon->ReduceTradeskillFail[limit_value] += base_value;
|
|
break;
|
|
}
|
|
|
|
case SE_TradeSkillMastery:
|
|
if (newbon->TradeSkillMastery < base_value)
|
|
newbon->TradeSkillMastery = base_value;
|
|
break;
|
|
|
|
case SE_NoBreakAESneak:
|
|
if (newbon->NoBreakAESneak < base_value)
|
|
newbon->NoBreakAESneak = base_value;
|
|
break;
|
|
|
|
case SE_FeignedCastOnChance:
|
|
if (newbon->FeignedCastOnChance < base_value)
|
|
newbon->FeignedCastOnChance = base_value;
|
|
break;
|
|
|
|
case SE_AddPetCommand:
|
|
if (base_value && limit_value < PET_MAXCOMMANDS)
|
|
newbon->PetCommands[limit_value] = true;
|
|
break;
|
|
|
|
case SE_FeignedMinion:
|
|
if (newbon->FeignedMinionChance < base_value) {
|
|
newbon->FeignedMinionChance = base_value;
|
|
}
|
|
newbon->PetCommands[PET_FEIGN] = true;
|
|
break;
|
|
|
|
case SE_AdditionalAura:
|
|
newbon->aura_slots += base_value;
|
|
break;
|
|
|
|
case SE_IncreaseTrapCount:
|
|
newbon->trap_slots += base_value;
|
|
break;
|
|
|
|
case SE_ForageSkill:
|
|
newbon->GrantForage += base_value;
|
|
// we need to grant a skill point here
|
|
// I'd rather not do this here, but whatever, probably fine
|
|
if (IsClient()) {
|
|
auto client = CastToClient();
|
|
if (client->GetRawSkill(EQ::skills::SkillType::SkillForage) == 0)
|
|
client->SetSkill(EQ::skills::SkillType::SkillForage, 1);
|
|
}
|
|
break;
|
|
|
|
case SE_Attack_Accuracy_Max_Percent:
|
|
newbon->Attack_Accuracy_Max_Percent += base_value;
|
|
break;
|
|
|
|
case SE_AC_Mitigation_Max_Percent:
|
|
newbon->AC_Mitigation_Max_Percent += base_value;
|
|
break;
|
|
|
|
case SE_AC_Avoidance_Max_Percent:
|
|
newbon->AC_Avoidance_Max_Percent += base_value;
|
|
break;
|
|
|
|
case SE_Damage_Taken_Position_Mod:
|
|
{
|
|
//Mitigate if damage taken from behind base2 = 0, from front base2 = 1
|
|
if (limit_value < 0 || limit_value >= 2) {
|
|
break;
|
|
}
|
|
else if (base_value < 0 && newbon->Damage_Taken_Position_Mod[limit_value] > base_value)
|
|
newbon->Damage_Taken_Position_Mod[limit_value] = base_value;
|
|
else if (base_value > 0 && newbon->Damage_Taken_Position_Mod[limit_value] < base_value)
|
|
newbon->Damage_Taken_Position_Mod[limit_value] = base_value;
|
|
break;
|
|
}
|
|
|
|
case SE_Melee_Damage_Position_Mod:
|
|
{
|
|
if (limit_value < 0 || limit_value >= 2) {
|
|
break;
|
|
}
|
|
else if (base_value < 0 && newbon->Melee_Damage_Position_Mod[limit_value] > base_value)
|
|
newbon->Melee_Damage_Position_Mod[limit_value] = base_value;
|
|
else if (base_value > 0 && newbon->Melee_Damage_Position_Mod[limit_value] < base_value)
|
|
newbon->Melee_Damage_Position_Mod[limit_value] = base_value;
|
|
break;
|
|
}
|
|
|
|
case SE_Damage_Taken_Position_Amt:
|
|
{
|
|
//Mitigate if damage taken from behind base2 = 0, from front base2 = 1
|
|
if (limit_value < 0 || limit_value >= 2) {
|
|
break;
|
|
}
|
|
newbon->Damage_Taken_Position_Amt[limit_value] += base_value;
|
|
break;
|
|
}
|
|
|
|
case SE_Melee_Damage_Position_Amt:
|
|
{
|
|
//Mitigate if damage taken from behind base2 = 0, from front base2 = 1
|
|
if (limit_value < 0 || limit_value >= 2) {
|
|
break;
|
|
}
|
|
|
|
newbon->Melee_Damage_Position_Amt[limit_value] += base_value;
|
|
break;
|
|
}
|
|
|
|
case SE_DS_Mitigation_Amount:
|
|
newbon->DS_Mitigation_Amount += base_value;
|
|
break;
|
|
|
|
case SE_DS_Mitigation_Percentage:
|
|
newbon->DS_Mitigation_Percentage += base_value;
|
|
break;
|
|
|
|
case SE_Pet_Crit_Melee_Damage_Pct_Owner:
|
|
newbon->Pet_Crit_Melee_Damage_Pct_Owner += base_value;
|
|
break;
|
|
|
|
case SE_Pet_Add_Atk:
|
|
newbon->Pet_Add_Atk += base_value;
|
|
break;
|
|
|
|
case SE_Weapon_Stance:
|
|
{
|
|
if (IsValidSpell(base_value)) { //base1 is the spell_id of buff
|
|
if (limit_value <= WEAPON_STANCE_TYPE_MAX) { //0=2H, 1=Shield, 2=DW
|
|
if (IsValidSpell(newbon->WeaponStance[limit_value])) { //Check if we already a spell_id saved for this effect
|
|
if (spells[newbon->WeaponStance[limit_value]].rank < spells[base_value].rank) { //If so, check if any new spellids with higher rank exist (live spells for this are ranked).
|
|
newbon->WeaponStance[limit_value] = base_value; //Overwrite with new effect
|
|
SetWeaponStanceEnabled(true);
|
|
}
|
|
}
|
|
else {
|
|
newbon->WeaponStance[limit_value] = base_value; //If no prior effect exists, then apply
|
|
SetWeaponStanceEnabled(true);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_ExtraAttackChance:
|
|
{
|
|
if (newbon->ExtraAttackChance[SBIndex::EXTRA_ATTACK_CHANCE] < base_value) {
|
|
newbon->ExtraAttackChance[SBIndex::EXTRA_ATTACK_CHANCE] = base_value;
|
|
newbon->ExtraAttackChance[SBIndex::EXTRA_ATTACK_NUM_ATKS] = limit_value ? limit_value : 1;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_AddExtraAttackPct_1h_Primary:
|
|
{
|
|
if (newbon->ExtraAttackChancePrimary[SBIndex::EXTRA_ATTACK_CHANCE] < base_value) {
|
|
newbon->ExtraAttackChancePrimary[SBIndex::EXTRA_ATTACK_CHANCE] = base_value;
|
|
newbon->ExtraAttackChancePrimary[SBIndex::EXTRA_ATTACK_NUM_ATKS] = limit_value ? limit_value : 1;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_AddExtraAttackPct_1h_Secondary:
|
|
{
|
|
|
|
if (newbon->ExtraAttackChanceSecondary[SBIndex::EXTRA_ATTACK_CHANCE] < base_value) {
|
|
newbon->ExtraAttackChanceSecondary[SBIndex::EXTRA_ATTACK_CHANCE] = base_value;
|
|
newbon->ExtraAttackChanceSecondary[SBIndex::EXTRA_ATTACK_NUM_ATKS] = limit_value ? limit_value : 1;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_Double_Melee_Round:
|
|
{
|
|
if (newbon->DoubleMeleeRound[SBIndex::DOUBLE_MELEE_ROUND_CHANCE] < base_value) {
|
|
newbon->DoubleMeleeRound[SBIndex::DOUBLE_MELEE_ROUND_CHANCE] = base_value;
|
|
newbon->DoubleMeleeRound[SBIndex::DOUBLE_MELEE_ROUND_DMG_BONUS] = limit_value;
|
|
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_ExtendedShielding:
|
|
{
|
|
if (newbon->ExtendedShielding < base_value) {
|
|
newbon->ExtendedShielding = base_value;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_ShieldDuration:
|
|
{
|
|
if (newbon->ShieldDuration < base_value) {
|
|
newbon->ShieldDuration = base_value;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_Worn_Endurance_Regen_Cap:
|
|
newbon->ItemEnduranceRegenCap += base_value;
|
|
break;
|
|
|
|
|
|
case SE_SecondaryForte:
|
|
if (newbon->SecondaryForte < base_value) {
|
|
newbon->SecondaryForte = base_value;
|
|
}
|
|
break;
|
|
|
|
case SE_ZoneSuspendMinion:
|
|
newbon->ZoneSuspendMinion = base_value;
|
|
break;
|
|
|
|
|
|
case SE_Reflect:
|
|
|
|
if (newbon->reflect[SBIndex::REFLECT_CHANCE] < base_value) {
|
|
newbon->reflect[SBIndex::REFLECT_CHANCE] = base_value;
|
|
}
|
|
if (newbon->reflect[SBIndex::REFLECT_RESISTANCE_MOD] < limit_value) {
|
|
newbon->reflect[SBIndex::REFLECT_RESISTANCE_MOD] = limit_value;
|
|
}
|
|
break;
|
|
|
|
case SE_SpellDamageShield:
|
|
newbon->SpellDamageShield += base_value;
|
|
break;
|
|
|
|
case SE_Amplification:
|
|
newbon->Amplification += base_value;
|
|
break;
|
|
|
|
case SE_MitigateSpellDamage:
|
|
{
|
|
newbon->MitigateSpellRune[SBIndex::MITIGATION_RUNE_PERCENT] += base_value;
|
|
break;
|
|
}
|
|
|
|
case SE_MitigateDotDamage:
|
|
{
|
|
newbon->MitigateDotRune[SBIndex::MITIGATION_RUNE_PERCENT] += base_value;
|
|
break;
|
|
}
|
|
|
|
case SE_TrapCircumvention:
|
|
newbon->TrapCircumvention += base_value;
|
|
break;
|
|
|
|
// to do
|
|
case SE_PetDiscipline:
|
|
break;
|
|
case SE_PotionBeltSlots:
|
|
break;
|
|
case SE_BandolierSlots:
|
|
break;
|
|
case SE_ReduceApplyPoisonTime:
|
|
break;
|
|
case SE_NimbleEvasion:
|
|
break;
|
|
|
|
// not handled here
|
|
case SE_HastenedAASkill:
|
|
// not handled here but don't want to clutter debug log -- these may need to be verified to ignore
|
|
case SE_LimitMaxLevel:
|
|
case SE_LimitResist:
|
|
case SE_LimitTarget:
|
|
case SE_LimitEffect:
|
|
case SE_LimitSpellType:
|
|
case SE_LimitMinDur:
|
|
case SE_LimitInstant:
|
|
case SE_LimitMinLevel:
|
|
case SE_LimitCastTimeMin:
|
|
case SE_LimitCastTimeMax:
|
|
case SE_LimitSpell:
|
|
case SE_LimitCombatSkills:
|
|
case SE_LimitManaMin:
|
|
case SE_LimitSpellGroup:
|
|
case SE_LimitSpellClass:
|
|
case SE_LimitSpellSubclass:
|
|
case SE_LimitHPPercent:
|
|
case SE_LimitManaPercent:
|
|
case SE_LimitEndPercent:
|
|
case SE_LimitClass:
|
|
case SE_LimitRace:
|
|
case SE_LimitCastingSkill:
|
|
case SE_LimitUseMin:
|
|
case SE_LimitUseType:
|
|
break;
|
|
|
|
default:
|
|
LogAA("SPA [{}] not accounted for in AA [{}] ([{}])", effect, rank.base_ability->name.c_str(), rank.id);
|
|
break;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
void Mob::CalcSpellBonuses(StatBonuses* newbon)
|
|
{
|
|
int i;
|
|
|
|
memset(newbon, 0, sizeof(StatBonuses));
|
|
newbon->AggroRange = -1;
|
|
newbon->AssistRange = -1;
|
|
|
|
int buff_count = GetMaxTotalSlots();
|
|
for (i = 0; i < buff_count; i++) {
|
|
if (IsValidSpell(buffs[i].spellid)) {
|
|
ApplySpellsBonuses(buffs[i].spellid, buffs[i].casterlevel, newbon, buffs[i].casterid, 0, buffs[i].ticsremaining, i, buffs[i].instrument_mod);
|
|
|
|
if (buffs[i].hit_number > 0) {
|
|
Numhits(true);
|
|
}
|
|
}
|
|
}
|
|
|
|
//Applies any perma NPC spell bonuses from npc_spells_effects table.
|
|
if (IsNPC())
|
|
CastToNPC()->ApplyAISpellEffects(newbon);
|
|
|
|
//Disables a specific spell effect bonus completely, can also be limited to negate only item, AA or spell bonuses.
|
|
if (spellbonuses.NegateEffects){
|
|
for(i = 0; i < buff_count; i++) {
|
|
if(IsValidSpell(buffs[i].spellid) && (IsEffectInSpell(buffs[i].spellid, SE_NegateSpellEffect)) )
|
|
NegateSpellEffectBonuses(buffs[i].spellid);
|
|
}
|
|
}
|
|
|
|
if (GetClass() == Class::Bard)
|
|
newbon->ManaRegen = 0; // Bards do not get mana regen from spells.
|
|
}
|
|
|
|
void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *new_bonus, uint16 casterId,
|
|
uint8 WornType, int32 ticsremaining, int buffslot, int instrument_mod,
|
|
bool IsAISpellEffect, uint16 effect_id, int32 se_base, int32 se_limit, int32 se_max)
|
|
{
|
|
int i, effect_value, limit_value, max_value, spell_effect_id;
|
|
bool AdditiveWornBonus = false;
|
|
|
|
if(!IsAISpellEffect && !IsValidSpell(spell_id))
|
|
return;
|
|
|
|
for (i = 0; i < EFFECT_COUNT; i++)
|
|
{
|
|
//Buffs/Item effects
|
|
if (!IsAISpellEffect) {
|
|
|
|
if(IsBlankSpellEffect(spell_id, i))
|
|
continue;
|
|
|
|
uint8 focus = IsFocusEffect(spell_id, i);
|
|
if (focus)
|
|
{
|
|
if (WornType){
|
|
if (RuleB(Spells, UseAdditiveFocusFromWornSlotWithLimits)) {
|
|
new_bonus->FocusEffectsWornWithLimits[focus] = spells[spell_id].effect_id[i];
|
|
}
|
|
else if (RuleB(Spells, UseAdditiveFocusFromWornSlot)) {
|
|
new_bonus->FocusEffectsWorn[focus] += spells[spell_id].base_value[i];
|
|
}
|
|
}
|
|
else {
|
|
new_bonus->FocusEffects[focus] = spells[spell_id].effect_id[i];
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (WornType && (RuleI(Spells, AdditiveBonusWornType) == WornType)) {
|
|
AdditiveWornBonus = true;
|
|
}
|
|
|
|
spell_effect_id = spells[spell_id].effect_id[i];
|
|
effect_value = CalcSpellEffectValue(spell_id, i, casterlevel, instrument_mod, nullptr, ticsremaining, casterId);
|
|
limit_value = spells[spell_id].limit_value[i];
|
|
max_value = spells[spell_id].max_value[i];
|
|
}
|
|
//Use AISpellEffects
|
|
else {
|
|
spell_effect_id = effect_id;
|
|
effect_value = se_base;
|
|
limit_value = se_limit;
|
|
max_value = se_max;
|
|
|
|
//Special custom cases for loading effects on to NPC from 'npc_spels_effects' table
|
|
//Non-Focused Effect to modify incoming spell damage by resist type.
|
|
if (spell_effect_id == SE_FcSpellVulnerability) {
|
|
ModVulnerability(limit_value, effect_value);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
switch (spell_effect_id)
|
|
{
|
|
case SE_CurrentHP: //regens
|
|
if(effect_value > 0) {
|
|
new_bonus->HPRegen += effect_value;
|
|
}
|
|
break;
|
|
|
|
case SE_CurrentEndurance:
|
|
new_bonus->EnduranceRegen += effect_value;
|
|
break;
|
|
|
|
case SE_ChangeFrenzyRad:
|
|
{
|
|
if (max_value != 0 && GetLevel() > max_value)
|
|
break;
|
|
|
|
if(new_bonus->AggroRange == -1 || effect_value < new_bonus->AggroRange)
|
|
{
|
|
new_bonus->AggroRange = static_cast<float>(effect_value);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_Harmony:
|
|
{
|
|
if (max_value != 0 && GetLevel() > max_value)
|
|
break;
|
|
// Harmony effect as buff - kinda tricky
|
|
// harmony could stack with a lull spell, which has better aggro range
|
|
// take the one with less range in any case
|
|
if(new_bonus->AssistRange == -1 || effect_value < new_bonus->AssistRange)
|
|
{
|
|
new_bonus->AssistRange = static_cast<float>(effect_value);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_AttackSpeed:
|
|
{
|
|
if ((effect_value - 100) > 0) { // Haste
|
|
if (new_bonus->haste < 0) break; // Slowed - Don't apply haste
|
|
if ((effect_value - 100) > new_bonus->haste) {
|
|
new_bonus->haste = effect_value - 100;
|
|
}
|
|
}
|
|
else if ((effect_value - 100) < 0) { // Slow
|
|
int real_slow_value = (100 - effect_value) * -1;
|
|
real_slow_value -= (real_slow_value * GetSlowMitigation()/100);
|
|
if (real_slow_value < new_bonus->haste)
|
|
new_bonus->haste = real_slow_value;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_AttackSpeed2:
|
|
{
|
|
if ((effect_value - 100) > 0) { // Haste V2 - Stacks with V1 but does not Overcap
|
|
if (new_bonus->hastetype2 < 0) break; //Slowed - Don't apply haste2
|
|
if ((effect_value - 100) > new_bonus->hastetype2) {
|
|
new_bonus->hastetype2 = effect_value - 100;
|
|
}
|
|
}
|
|
else if ((effect_value - 100) < 0) { // Slow
|
|
int real_slow_value = (100 - effect_value) * -1;
|
|
real_slow_value -= (real_slow_value * GetSlowMitigation()/100);
|
|
if (real_slow_value < new_bonus->hastetype2)
|
|
new_bonus->hastetype2 = real_slow_value;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_AttackSpeed3:
|
|
{
|
|
if (effect_value < 0){ //Slow
|
|
effect_value -= (effect_value * GetSlowMitigation()/100);
|
|
if (effect_value < new_bonus->hastetype3)
|
|
new_bonus->hastetype3 = effect_value;
|
|
}
|
|
|
|
else if (effect_value > 0) { // Haste V3 - Stacks and Overcaps
|
|
if (effect_value > new_bonus->hastetype3) {
|
|
new_bonus->hastetype3 = effect_value;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_AttackSpeed4:
|
|
{
|
|
// These don't generate the IMMUNE_ATKSPEED message and the icon shows up
|
|
// but have no effect on the mobs attack speed
|
|
if (GetSpecialAbility(SpecialAbility::SlowImmunity))
|
|
break;
|
|
|
|
if (effect_value < 0) //A few spells use negative values(Descriptions all indicate it should be a slow)
|
|
effect_value = effect_value * -1;
|
|
|
|
if (effect_value > 0 && effect_value > new_bonus->inhibitmelee) {
|
|
effect_value -= (effect_value * GetSlowMitigation()/100);
|
|
if (effect_value > new_bonus->inhibitmelee)
|
|
new_bonus->inhibitmelee = effect_value;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case SE_IncreaseArchery:
|
|
{
|
|
new_bonus->increase_archery += effect_value;
|
|
break;
|
|
}
|
|
|
|
case SE_TotalHP:
|
|
{
|
|
new_bonus->FlatMaxHPChange += effect_value;
|
|
break;
|
|
}
|
|
|
|
case SE_ManaRegen_v2:
|
|
case SE_CurrentMana:
|
|
{
|
|
new_bonus->ManaRegen += effect_value;
|
|
break;
|
|
}
|
|
|
|
case SE_ManaPool:
|
|
{
|
|
new_bonus->Mana += effect_value;
|
|
break;
|
|
}
|
|
|
|
case SE_Stamina:
|
|
{
|
|
new_bonus->EnduranceReduction += effect_value;
|
|
break;
|
|
}
|
|
|
|
case SE_ACv2:
|
|
case SE_ArmorClass:
|
|
{
|
|
new_bonus->AC += effect_value;
|
|
break;
|
|
}
|
|
|
|
case SE_ATK:
|
|
{
|
|
new_bonus->ATK += effect_value;
|
|
break;
|
|
}
|
|
|
|
case SE_STR:
|
|
{
|
|
new_bonus->STR += effect_value;
|
|
break;
|
|
}
|
|
|
|
case SE_DEX:
|
|
{
|
|
new_bonus->DEX += effect_value;
|
|
break;
|
|
}
|
|
|
|
case SE_AGI:
|
|
{
|
|
new_bonus->AGI += effect_value;
|
|
break;
|
|
}
|
|
|
|
case SE_STA:
|
|
{
|
|
new_bonus->STA += effect_value;
|
|
break;
|
|
}
|
|
|
|
case SE_INT:
|
|
{
|
|
new_bonus->INT += effect_value;
|
|
break;
|
|
}
|
|
|
|
case SE_WIS:
|
|
{
|
|
new_bonus->WIS += effect_value;
|
|
break;
|
|
}
|
|
|
|
case SE_CHA:
|
|
{
|
|
if (spells[spell_id].base_value[i] != 0) {
|
|
new_bonus->CHA += effect_value;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_AllStats:
|
|
{
|
|
new_bonus->STR += effect_value;
|
|
new_bonus->DEX += effect_value;
|
|
new_bonus->AGI += effect_value;
|
|
new_bonus->STA += effect_value;
|
|
new_bonus->INT += effect_value;
|
|
new_bonus->WIS += effect_value;
|
|
new_bonus->CHA += effect_value;
|
|
break;
|
|
}
|
|
|
|
case SE_ResistFire:
|
|
{
|
|
new_bonus->FR += effect_value;
|
|
break;
|
|
}
|
|
|
|
case SE_ResistCold:
|
|
{
|
|
new_bonus->CR += effect_value;
|
|
break;
|
|
}
|
|
|
|
case SE_ResistPoison:
|
|
{
|
|
new_bonus->PR += effect_value;
|
|
break;
|
|
}
|
|
|
|
case SE_ResistDisease:
|
|
{
|
|
new_bonus->DR += effect_value;
|
|
break;
|
|
}
|
|
|
|
case SE_ResistMagic:
|
|
{
|
|
new_bonus->MR += effect_value;
|
|
break;
|
|
}
|
|
|
|
case SE_ResistAll:
|
|
{
|
|
new_bonus->MR += effect_value;
|
|
new_bonus->DR += effect_value;
|
|
new_bonus->PR += effect_value;
|
|
new_bonus->CR += effect_value;
|
|
new_bonus->FR += effect_value;
|
|
break;
|
|
}
|
|
|
|
case SE_ResistCorruption:
|
|
{
|
|
new_bonus->Corrup += effect_value;
|
|
break;
|
|
}
|
|
|
|
case SE_RaiseStatCap:
|
|
{
|
|
switch(spells[spell_id].limit_value[i])
|
|
{
|
|
//are these #define'd somewhere?
|
|
case 0: //str
|
|
new_bonus->STRCapMod += effect_value;
|
|
break;
|
|
case 1: //sta
|
|
new_bonus->STACapMod += effect_value;
|
|
break;
|
|
case 2: //agi
|
|
new_bonus->AGICapMod += effect_value;
|
|
break;
|
|
case 3: //dex
|
|
new_bonus->DEXCapMod += effect_value;
|
|
break;
|
|
case 4: //wis
|
|
new_bonus->WISCapMod += effect_value;
|
|
break;
|
|
case 5: //int
|
|
new_bonus->INTCapMod += effect_value;
|
|
break;
|
|
case 6: //cha
|
|
new_bonus->CHACapMod += effect_value;
|
|
break;
|
|
case 7: //mr
|
|
new_bonus->MRCapMod += effect_value;
|
|
break;
|
|
case 8: //cr
|
|
new_bonus->CRCapMod += effect_value;
|
|
break;
|
|
case 9: //fr
|
|
new_bonus->FRCapMod += effect_value;
|
|
break;
|
|
case 10: //pr
|
|
new_bonus->PRCapMod += effect_value;
|
|
break;
|
|
case 11: //dr
|
|
new_bonus->DRCapMod += effect_value;
|
|
break;
|
|
case 12: // corruption
|
|
new_bonus->CorrupCapMod += effect_value;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_CastingLevel: // Brilliance of Ro
|
|
{
|
|
new_bonus->adjusted_casting_skill += effect_value;
|
|
break;
|
|
}
|
|
|
|
case SE_CastingLevel2:
|
|
{
|
|
new_bonus->effective_casting_level += effect_value;
|
|
|
|
if (RuleB(Spells, SnareOverridesSpeedBonuses) && effect_value < 0) {
|
|
new_bonus->movementspeed = effect_value;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_MovementSpeed:
|
|
new_bonus->movementspeed += effect_value;
|
|
break;
|
|
|
|
case SE_SpellDamageShield:
|
|
new_bonus->SpellDamageShield += effect_value;
|
|
break;
|
|
|
|
case SE_DamageShield:
|
|
{
|
|
new_bonus->DamageShield += effect_value;
|
|
new_bonus->DamageShieldSpellID = spell_id;
|
|
//When using npc_spells_effects MAX value can be set to determine DS Type
|
|
if (IsAISpellEffect && max_value)
|
|
new_bonus->DamageShieldType = GetDamageShieldType(spell_id, max_value);
|
|
else
|
|
new_bonus->DamageShieldType = GetDamageShieldType(spell_id);
|
|
|
|
break;
|
|
}
|
|
|
|
case SE_ReverseDS:
|
|
{
|
|
new_bonus->ReverseDamageShield += effect_value;
|
|
new_bonus->ReverseDamageShieldSpellID = spell_id;
|
|
|
|
if (IsAISpellEffect && max_value)
|
|
new_bonus->ReverseDamageShieldType = GetDamageShieldType(spell_id, max_value);
|
|
else
|
|
new_bonus->ReverseDamageShieldType = GetDamageShieldType(spell_id);
|
|
break;
|
|
}
|
|
|
|
case SE_Reflect:
|
|
|
|
if (AdditiveWornBonus) {
|
|
new_bonus->reflect[SBIndex::REFLECT_CHANCE] += effect_value;
|
|
}
|
|
|
|
else if (new_bonus->reflect[SBIndex::REFLECT_CHANCE] < effect_value) {
|
|
new_bonus->reflect[SBIndex::REFLECT_CHANCE] = effect_value;
|
|
new_bonus->reflect[SBIndex::REFLECT_RESISTANCE_MOD] = limit_value;
|
|
new_bonus->reflect[SBIndex::REFLECT_DMG_EFFECTIVENESS] = max_value;
|
|
}
|
|
break;
|
|
|
|
case SE_Amplification:
|
|
new_bonus->Amplification += effect_value;
|
|
break;
|
|
|
|
case SE_ChangeAggro:
|
|
new_bonus->hatemod += effect_value;
|
|
break;
|
|
|
|
case SE_MeleeMitigation:
|
|
// This value is negative because it counteracts another SPA :P
|
|
new_bonus->MeleeMitigationEffect += effect_value;
|
|
break;
|
|
|
|
case SE_CriticalHitChance:
|
|
{
|
|
// Bad data or unsupported new skill
|
|
if (limit_value > EQ::skills::HIGHEST_SKILL)
|
|
break;
|
|
if (AdditiveWornBonus) {
|
|
if(limit_value == ALL_SKILLS)
|
|
new_bonus->CriticalHitChance[EQ::skills::HIGHEST_SKILL + 1] += effect_value;
|
|
else
|
|
new_bonus->CriticalHitChance[limit_value] += effect_value;
|
|
}
|
|
|
|
else if(effect_value < 0) {
|
|
|
|
if (limit_value == ALL_SKILLS && new_bonus->CriticalHitChance[EQ::skills::HIGHEST_SKILL + 1] > effect_value)
|
|
new_bonus->CriticalHitChance[EQ::skills::HIGHEST_SKILL + 1] = effect_value;
|
|
else if(limit_value != ALL_SKILLS && new_bonus->CriticalHitChance[limit_value] > effect_value)
|
|
new_bonus->CriticalHitChance[limit_value] = effect_value;
|
|
}
|
|
|
|
|
|
else if (limit_value == ALL_SKILLS && new_bonus->CriticalHitChance[EQ::skills::HIGHEST_SKILL + 1] < effect_value)
|
|
new_bonus->CriticalHitChance[EQ::skills::HIGHEST_SKILL + 1] = effect_value;
|
|
else if(limit_value != ALL_SKILLS && new_bonus->CriticalHitChance[limit_value] < effect_value)
|
|
new_bonus->CriticalHitChance[limit_value] = effect_value;
|
|
|
|
break;
|
|
}
|
|
|
|
case SE_CrippBlowChance:
|
|
{
|
|
if (AdditiveWornBonus)
|
|
new_bonus->CrippBlowChance += effect_value;
|
|
|
|
else if((effect_value < 0) && (new_bonus->CrippBlowChance > effect_value))
|
|
new_bonus->CrippBlowChance = effect_value;
|
|
|
|
else if(new_bonus->CrippBlowChance < effect_value)
|
|
new_bonus->CrippBlowChance = effect_value;
|
|
|
|
break;
|
|
}
|
|
|
|
case SE_AvoidMeleeChance:
|
|
{
|
|
if (AdditiveWornBonus)
|
|
new_bonus->AvoidMeleeChanceEffect += effect_value;
|
|
|
|
else if((effect_value < 0) && (new_bonus->AvoidMeleeChanceEffect > effect_value))
|
|
new_bonus->AvoidMeleeChanceEffect = effect_value;
|
|
|
|
else if(new_bonus->AvoidMeleeChanceEffect < effect_value)
|
|
new_bonus->AvoidMeleeChanceEffect = effect_value;
|
|
break;
|
|
}
|
|
|
|
case SE_RiposteChance:
|
|
{
|
|
if (AdditiveWornBonus)
|
|
new_bonus->RiposteChance += effect_value;
|
|
|
|
else if((effect_value < 0) && (new_bonus->RiposteChance > effect_value))
|
|
new_bonus->RiposteChance = effect_value;
|
|
|
|
else if(new_bonus->RiposteChance < effect_value)
|
|
new_bonus->RiposteChance = effect_value;
|
|
break;
|
|
}
|
|
|
|
case SE_DodgeChance:
|
|
{
|
|
if (AdditiveWornBonus)
|
|
new_bonus->DodgeChance += effect_value;
|
|
|
|
else if((effect_value < 0) && (new_bonus->DodgeChance > effect_value))
|
|
new_bonus->DodgeChance = effect_value;
|
|
|
|
if(new_bonus->DodgeChance < effect_value)
|
|
new_bonus->DodgeChance = effect_value;
|
|
break;
|
|
}
|
|
|
|
case SE_ParryChance:
|
|
{
|
|
if (AdditiveWornBonus)
|
|
new_bonus->ParryChance += effect_value;
|
|
|
|
else if((effect_value < 0) && (new_bonus->ParryChance > effect_value))
|
|
new_bonus->ParryChance = effect_value;
|
|
|
|
if(new_bonus->ParryChance < effect_value)
|
|
new_bonus->ParryChance = effect_value;
|
|
break;
|
|
}
|
|
|
|
case SE_DualWieldChance:
|
|
{
|
|
if (AdditiveWornBonus)
|
|
new_bonus->DualWieldChance += effect_value;
|
|
|
|
else if((effect_value < 0) && (new_bonus->DualWieldChance > effect_value))
|
|
new_bonus->DualWieldChance = effect_value;
|
|
|
|
if(new_bonus->DualWieldChance < effect_value)
|
|
new_bonus->DualWieldChance = effect_value;
|
|
break;
|
|
}
|
|
|
|
case SE_DoubleAttackChance:
|
|
{
|
|
|
|
if (AdditiveWornBonus)
|
|
new_bonus->DoubleAttackChance += effect_value;
|
|
|
|
else if((effect_value < 0) && (new_bonus->DoubleAttackChance > effect_value))
|
|
new_bonus->DoubleAttackChance = effect_value;
|
|
|
|
if(new_bonus->DoubleAttackChance < effect_value)
|
|
new_bonus->DoubleAttackChance = effect_value;
|
|
break;
|
|
}
|
|
|
|
case SE_TripleAttackChance:
|
|
{
|
|
|
|
if (AdditiveWornBonus)
|
|
new_bonus->TripleAttackChance += effect_value;
|
|
|
|
else if((effect_value < 0) && (new_bonus->TripleAttackChance > effect_value))
|
|
new_bonus->TripleAttackChance = effect_value;
|
|
|
|
if(new_bonus->TripleAttackChance < effect_value)
|
|
new_bonus->TripleAttackChance = effect_value;
|
|
break;
|
|
}
|
|
|
|
case SE_MeleeLifetap:
|
|
{
|
|
if (AdditiveWornBonus)
|
|
new_bonus->MeleeLifetap += spells[spell_id].base_value[i];
|
|
|
|
else if((effect_value < 0) && (new_bonus->MeleeLifetap > effect_value))
|
|
new_bonus->MeleeLifetap = effect_value;
|
|
|
|
else if(new_bonus->MeleeLifetap < effect_value)
|
|
new_bonus->MeleeLifetap = effect_value;
|
|
break;
|
|
}
|
|
|
|
case SE_Vampirism:
|
|
new_bonus->Vampirism += effect_value;
|
|
break;
|
|
|
|
case SE_AllInstrumentMod:
|
|
{
|
|
if(effect_value > new_bonus->singingMod)
|
|
new_bonus->singingMod = effect_value;
|
|
if(effect_value > new_bonus->brassMod)
|
|
new_bonus->brassMod = effect_value;
|
|
if(effect_value > new_bonus->percussionMod)
|
|
new_bonus->percussionMod = effect_value;
|
|
if(effect_value > new_bonus->windMod)
|
|
new_bonus->windMod = effect_value;
|
|
if(effect_value > new_bonus->stringedMod)
|
|
new_bonus->stringedMod = effect_value;
|
|
break;
|
|
}
|
|
|
|
case SE_ResistSpellChance:
|
|
new_bonus->ResistSpellChance += effect_value;
|
|
break;
|
|
|
|
case SE_ResistFearChance:
|
|
{
|
|
new_bonus->ResistFearChance += effect_value; // these should stack
|
|
break;
|
|
}
|
|
|
|
case SE_Fearless:
|
|
new_bonus->Fearless = true;
|
|
break;
|
|
|
|
case SE_HundredHands:
|
|
{
|
|
if (AdditiveWornBonus)
|
|
new_bonus->HundredHands += effect_value;
|
|
|
|
if (effect_value > 0 && effect_value > new_bonus->HundredHands)
|
|
new_bonus->HundredHands = effect_value; //Increase Weapon Delay
|
|
else if (effect_value < 0 && effect_value < new_bonus->HundredHands)
|
|
new_bonus->HundredHands = effect_value; //Decrease Weapon Delay
|
|
break;
|
|
}
|
|
|
|
case SE_MeleeSkillCheck:
|
|
{
|
|
if(new_bonus->MeleeSkillCheck < effect_value) {
|
|
new_bonus->MeleeSkillCheck = effect_value;
|
|
new_bonus->MeleeSkillCheckSkill = limit_value==ALL_SKILLS?255:limit_value;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_HitChance:
|
|
{
|
|
// Bad data or unsupported new skill
|
|
if (limit_value > EQ::skills::HIGHEST_SKILL)
|
|
break;
|
|
|
|
if (AdditiveWornBonus){
|
|
if(limit_value == ALL_SKILLS)
|
|
new_bonus->HitChanceEffect[EQ::skills::HIGHEST_SKILL + 1] += effect_value;
|
|
else
|
|
new_bonus->HitChanceEffect[limit_value] += effect_value;
|
|
}
|
|
|
|
else if(limit_value == ALL_SKILLS){
|
|
|
|
if ((effect_value < 0) && (new_bonus->HitChanceEffect[EQ::skills::HIGHEST_SKILL + 1] > effect_value))
|
|
new_bonus->HitChanceEffect[EQ::skills::HIGHEST_SKILL + 1] = effect_value;
|
|
|
|
else if (!new_bonus->HitChanceEffect[EQ::skills::HIGHEST_SKILL + 1] ||
|
|
((new_bonus->HitChanceEffect[EQ::skills::HIGHEST_SKILL + 1] > 0) && (new_bonus->HitChanceEffect[EQ::skills::HIGHEST_SKILL + 1] < effect_value)))
|
|
new_bonus->HitChanceEffect[EQ::skills::HIGHEST_SKILL + 1] = effect_value;
|
|
}
|
|
|
|
else {
|
|
|
|
if ((effect_value < 0) && (new_bonus->HitChanceEffect[limit_value] > effect_value))
|
|
new_bonus->HitChanceEffect[limit_value] = effect_value;
|
|
|
|
else if (!new_bonus->HitChanceEffect[limit_value] ||
|
|
((new_bonus->HitChanceEffect[limit_value] > 0) && (new_bonus->HitChanceEffect[limit_value] < effect_value)))
|
|
new_bonus->HitChanceEffect[limit_value] = effect_value;
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case SE_DamageModifier:
|
|
{
|
|
// Bad data or unsupported new skill
|
|
if (limit_value > EQ::skills::HIGHEST_SKILL)
|
|
break;
|
|
int skill = limit_value == ALL_SKILLS ? EQ::skills::HIGHEST_SKILL + 1 : limit_value;
|
|
if (effect_value < 0 && new_bonus->DamageModifier[skill] > effect_value)
|
|
new_bonus->DamageModifier[skill] = effect_value;
|
|
else if (effect_value > 0 && new_bonus->DamageModifier[skill] < effect_value)
|
|
new_bonus->DamageModifier[skill] = effect_value;
|
|
break;
|
|
}
|
|
|
|
case SE_DamageModifier2:
|
|
{
|
|
// Bad data or unsupported new skill
|
|
if (limit_value > EQ::skills::HIGHEST_SKILL)
|
|
break;
|
|
int skill = limit_value == ALL_SKILLS ? EQ::skills::HIGHEST_SKILL + 1 : limit_value;
|
|
if (effect_value < 0 && new_bonus->DamageModifier2[skill] > effect_value)
|
|
new_bonus->DamageModifier2[skill] = effect_value;
|
|
else if (effect_value > 0 && new_bonus->DamageModifier2[skill] < effect_value)
|
|
new_bonus->DamageModifier2[skill] = effect_value;
|
|
break;
|
|
}
|
|
|
|
case SE_Skill_Base_Damage_Mod:
|
|
{
|
|
// Bad data or unsupported new skill
|
|
if (limit_value > EQ::skills::HIGHEST_SKILL)
|
|
break;
|
|
int skill = limit_value == ALL_SKILLS ? EQ::skills::HIGHEST_SKILL + 1 : limit_value;
|
|
if (effect_value < 0 && new_bonus->DamageModifier3[skill] > effect_value)
|
|
new_bonus->DamageModifier3[skill] = effect_value;
|
|
else if (effect_value > 0 && new_bonus->DamageModifier3[skill] < effect_value)
|
|
new_bonus->DamageModifier3[skill] = effect_value;
|
|
break;
|
|
}
|
|
|
|
case SE_MinDamageModifier:
|
|
{
|
|
// Bad data or unsupported new skill
|
|
if (limit_value > EQ::skills::HIGHEST_SKILL)
|
|
break;
|
|
int skill = limit_value == ALL_SKILLS ? EQ::skills::HIGHEST_SKILL + 1 : limit_value;
|
|
if (effect_value < 0 && new_bonus->MinDamageModifier[skill] > effect_value)
|
|
new_bonus->MinDamageModifier[skill] = effect_value;
|
|
else if (effect_value > 0 && new_bonus->MinDamageModifier[skill] < effect_value)
|
|
new_bonus->MinDamageModifier[skill] = effect_value;
|
|
break;
|
|
}
|
|
|
|
case SE_ReduceSkill: {
|
|
// Bad data or unsupported new skill
|
|
if (spells[spell_id].base_value[i] > EQ::skills::HIGHEST_SKILL) {
|
|
break;
|
|
}
|
|
//cap skill reducation at 100%
|
|
uint32 skill_reducation_percent = spells[spell_id].formula[i];
|
|
if (spells[spell_id].formula[i] > 100) {
|
|
skill_reducation_percent = 100;
|
|
}
|
|
|
|
if (spells[spell_id].base_value[i] <= EQ::skills::HIGHEST_SKILL) {
|
|
if (new_bonus->ReduceSkill[spells[spell_id].base_value[i]] < skill_reducation_percent) {
|
|
new_bonus->ReduceSkill[spells[spell_id].base_value[i]] = skill_reducation_percent;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_StunResist:
|
|
{
|
|
if(new_bonus->StunResist < effect_value)
|
|
new_bonus->StunResist = effect_value;
|
|
break;
|
|
}
|
|
|
|
case SE_ProcChance:
|
|
{
|
|
if (AdditiveWornBonus)
|
|
new_bonus->ProcChanceSPA += effect_value;
|
|
|
|
else if((effect_value < 0) && (new_bonus->ProcChanceSPA > effect_value))
|
|
new_bonus->ProcChanceSPA = effect_value;
|
|
|
|
if(new_bonus->ProcChanceSPA < effect_value)
|
|
new_bonus->ProcChanceSPA = effect_value;
|
|
|
|
break;
|
|
}
|
|
|
|
case SE_ExtraAttackChance:
|
|
{
|
|
if (AdditiveWornBonus) {
|
|
new_bonus->ExtraAttackChance[SBIndex::EXTRA_ATTACK_CHANCE] += effect_value;
|
|
new_bonus->ExtraAttackChance[SBIndex::EXTRA_ATTACK_NUM_ATKS] = limit_value ? limit_value : 1;
|
|
}
|
|
if (new_bonus->ExtraAttackChance[SBIndex::EXTRA_ATTACK_CHANCE] < effect_value) {
|
|
new_bonus->ExtraAttackChance[SBIndex::EXTRA_ATTACK_CHANCE] = effect_value;
|
|
new_bonus->ExtraAttackChance[SBIndex::EXTRA_ATTACK_NUM_ATKS] = limit_value ? limit_value : 1;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_AddExtraAttackPct_1h_Primary:
|
|
{
|
|
if (AdditiveWornBonus) {
|
|
new_bonus->ExtraAttackChancePrimary[SBIndex::EXTRA_ATTACK_CHANCE] += effect_value;
|
|
new_bonus->ExtraAttackChancePrimary[SBIndex::EXTRA_ATTACK_NUM_ATKS] = limit_value ? limit_value : 1;
|
|
}
|
|
|
|
if (new_bonus->ExtraAttackChancePrimary[SBIndex::EXTRA_ATTACK_CHANCE] < effect_value) {
|
|
new_bonus->ExtraAttackChancePrimary[SBIndex::EXTRA_ATTACK_CHANCE] = effect_value;
|
|
new_bonus->ExtraAttackChancePrimary[SBIndex::EXTRA_ATTACK_NUM_ATKS] = limit_value ? limit_value : 1;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_AddExtraAttackPct_1h_Secondary:
|
|
{
|
|
if (AdditiveWornBonus) {
|
|
new_bonus->ExtraAttackChanceSecondary[SBIndex::EXTRA_ATTACK_CHANCE] += effect_value;
|
|
new_bonus->ExtraAttackChanceSecondary[SBIndex::EXTRA_ATTACK_NUM_ATKS] = limit_value ? limit_value : 1;
|
|
}
|
|
|
|
if (new_bonus->ExtraAttackChanceSecondary[SBIndex::EXTRA_ATTACK_CHANCE] < effect_value) {
|
|
new_bonus->ExtraAttackChanceSecondary[SBIndex::EXTRA_ATTACK_CHANCE] = effect_value;
|
|
new_bonus->ExtraAttackChanceSecondary[SBIndex::EXTRA_ATTACK_NUM_ATKS] = limit_value ? limit_value : 1;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_Double_Melee_Round:
|
|
{
|
|
if (AdditiveWornBonus) {
|
|
new_bonus->DoubleMeleeRound[SBIndex::DOUBLE_MELEE_ROUND_CHANCE] += effect_value;
|
|
new_bonus->DoubleMeleeRound[SBIndex::DOUBLE_MELEE_ROUND_DMG_BONUS] += limit_value;
|
|
}
|
|
|
|
if (new_bonus->DoubleMeleeRound[SBIndex::DOUBLE_MELEE_ROUND_CHANCE] < effect_value) {
|
|
new_bonus->DoubleMeleeRound[SBIndex::DOUBLE_MELEE_ROUND_CHANCE] = effect_value;
|
|
new_bonus->DoubleMeleeRound[SBIndex::DOUBLE_MELEE_ROUND_DMG_BONUS] = limit_value;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_PercentXPIncrease:
|
|
{
|
|
if(new_bonus->XPRateMod < effect_value)
|
|
new_bonus->XPRateMod = effect_value;
|
|
break;
|
|
}
|
|
|
|
case SE_DeathSave:
|
|
{
|
|
if(new_bonus->DeathSave[SBIndex::DEATH_SAVE_TYPE] < effect_value)
|
|
{
|
|
new_bonus->DeathSave[SBIndex::DEATH_SAVE_TYPE] = effect_value; //1='Partial' 2='Full'
|
|
new_bonus->DeathSave[SBIndex::DEATH_SAVE_BUFFSLOT] = buffslot;
|
|
//These are used in later expansion spell effects.
|
|
new_bonus->DeathSave[SBIndex::DEATH_SAVE_MIN_LEVEL_FOR_HEAL] = limit_value;//Min level for HealAmt
|
|
new_bonus->DeathSave[SBIndex::DEATH_SAVE_HEAL_AMT] = max_value;//HealAmt
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_DivineSave:
|
|
{
|
|
if (AdditiveWornBonus) {
|
|
new_bonus->DivineSaveChance[SBIndex::DIVINE_SAVE_CHANCE] += effect_value;
|
|
new_bonus->DivineSaveChance[SBIndex::DIVINE_SAVE_SPELL_TRIGGER_ID] = 0;
|
|
}
|
|
|
|
else if(new_bonus->DivineSaveChance[SBIndex::DIVINE_SAVE_CHANCE] < effect_value)
|
|
{
|
|
new_bonus->DivineSaveChance[SBIndex::DIVINE_SAVE_CHANCE] = effect_value;
|
|
new_bonus->DivineSaveChance[SBIndex::DIVINE_SAVE_SPELL_TRIGGER_ID] = limit_value;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_Flurry:
|
|
new_bonus->FlurryChance += effect_value;
|
|
break;
|
|
|
|
case SE_Accuracy:
|
|
{
|
|
// Bad data or unsupported new skill
|
|
if (limit_value > EQ::skills::HIGHEST_SKILL)
|
|
break;
|
|
if ((effect_value < 0) && (new_bonus->Accuracy[EQ::skills::HIGHEST_SKILL + 1] > effect_value))
|
|
new_bonus->Accuracy[EQ::skills::HIGHEST_SKILL + 1] = effect_value;
|
|
|
|
else if (!new_bonus->Accuracy[EQ::skills::HIGHEST_SKILL + 1] ||
|
|
((new_bonus->Accuracy[EQ::skills::HIGHEST_SKILL + 1] > 0) && (new_bonus->Accuracy[EQ::skills::HIGHEST_SKILL + 1] < effect_value)))
|
|
new_bonus->Accuracy[EQ::skills::HIGHEST_SKILL + 1] = effect_value;
|
|
break;
|
|
}
|
|
|
|
case SE_MaxHPChange:
|
|
new_bonus->PercentMaxHPChange += effect_value;
|
|
break;
|
|
|
|
case SE_EndurancePool:
|
|
new_bonus->Endurance += effect_value;
|
|
break;
|
|
|
|
case SE_HealRate:
|
|
new_bonus->HealRate += effect_value;
|
|
break;
|
|
|
|
case SE_SkillDamageTaken:
|
|
{
|
|
// Bad data or unsupported new skill
|
|
if (limit_value > EQ::skills::HIGHEST_SKILL)
|
|
break;
|
|
//When using npc_spells_effects if MAX value set, use stackable quest based modifier.
|
|
if (IsAISpellEffect && max_value){
|
|
if(limit_value == ALL_SKILLS)
|
|
SkillDmgTaken_Mod[EQ::skills::HIGHEST_SKILL + 1] = effect_value;
|
|
else
|
|
SkillDmgTaken_Mod[limit_value] = effect_value;
|
|
}
|
|
else {
|
|
|
|
if(limit_value == ALL_SKILLS)
|
|
new_bonus->SkillDmgTaken[EQ::skills::HIGHEST_SKILL + 1] += effect_value;
|
|
else
|
|
new_bonus->SkillDmgTaken[limit_value] += effect_value;
|
|
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_SpellCritChance:
|
|
new_bonus->CriticalSpellChance += effect_value;
|
|
break;
|
|
|
|
case SE_CriticalSpellChance:
|
|
{
|
|
new_bonus->CriticalSpellChance += effect_value;
|
|
|
|
if (limit_value > new_bonus->SpellCritDmgIncNoStack)
|
|
new_bonus->SpellCritDmgIncNoStack = limit_value;
|
|
break;
|
|
}
|
|
|
|
case SE_SpellCritDmgIncrease:
|
|
new_bonus->SpellCritDmgIncrease += effect_value;
|
|
break;
|
|
|
|
case SE_DotCritDmgIncrease:
|
|
new_bonus->DotCritDmgIncrease += effect_value;
|
|
break;
|
|
|
|
case SE_CriticalHealChance:
|
|
new_bonus->CriticalHealChance += effect_value;
|
|
break;
|
|
|
|
case SE_CriticalHealOverTime:
|
|
new_bonus->CriticalHealOverTime += effect_value;
|
|
break;
|
|
|
|
case SE_CriticalHealDecay:
|
|
new_bonus->CriticalHealDecay = true;
|
|
break;
|
|
|
|
case SE_CriticalRegenDecay:
|
|
new_bonus->CriticalRegenDecay = true;
|
|
break;
|
|
|
|
case SE_CriticalDotDecay:
|
|
new_bonus->CriticalDotDecay = true;
|
|
break;
|
|
|
|
case SE_MitigateDamageShield:
|
|
{
|
|
/*
|
|
Bard songs have identical negative base value and positive max
|
|
The effect for the songs should increase mitigation. There are
|
|
spells that do decrease the mitigation with just negative base values.
|
|
To be consistent all values that increase mitigation will be set to positives
|
|
*/
|
|
if (max_value > 0 && effect_value < 0) {
|
|
effect_value = max_value;
|
|
}
|
|
|
|
new_bonus->DSMitigationOffHand += effect_value;
|
|
break;
|
|
}
|
|
|
|
case SE_CriticalDoTChance:
|
|
new_bonus->CriticalDoTChance += effect_value;
|
|
break;
|
|
|
|
case SE_ProcOnKillShot:
|
|
{
|
|
for(int e = 0; e < MAX_SPELL_TRIGGER*3; e+=3)
|
|
{
|
|
if(!new_bonus->SpellOnKill[e])
|
|
{
|
|
// Base2 = Spell to fire | Base1 = % chance | Base3 = min level
|
|
new_bonus->SpellOnKill[e] = limit_value;
|
|
new_bonus->SpellOnKill[e+1] = effect_value;
|
|
new_bonus->SpellOnKill[e+2] = max_value;
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_SpellOnDeath:
|
|
{
|
|
for(int e = 0; e < MAX_SPELL_TRIGGER; e+=2)
|
|
{
|
|
if(!new_bonus->SpellOnDeath[e])
|
|
{
|
|
// Base2 = Spell to fire | Base1 = % chance
|
|
new_bonus->SpellOnDeath[e] = limit_value;
|
|
new_bonus->SpellOnDeath[e+1] = effect_value;
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_CriticalDamageMob:
|
|
{
|
|
// Bad data or unsupported new skill
|
|
if (limit_value > EQ::skills::HIGHEST_SKILL)
|
|
break;
|
|
if(limit_value == ALL_SKILLS)
|
|
new_bonus->CritDmgMod[EQ::skills::HIGHEST_SKILL + 1] += effect_value;
|
|
else
|
|
new_bonus->CritDmgMod[limit_value] += effect_value;
|
|
break;
|
|
}
|
|
|
|
case SE_Critical_Melee_Damage_Mod_Max:
|
|
{
|
|
// Bad data or unsupported new skill
|
|
if (limit_value > EQ::skills::HIGHEST_SKILL)
|
|
break;
|
|
int skill = limit_value == ALL_SKILLS ? EQ::skills::HIGHEST_SKILL + 1 : limit_value;
|
|
if (effect_value < 0 && new_bonus->CritDmgModNoStack[skill] > effect_value)
|
|
new_bonus->CritDmgModNoStack[skill] = effect_value;
|
|
else if (effect_value > 0 && new_bonus->CritDmgModNoStack[skill] < effect_value) {
|
|
new_bonus->CritDmgModNoStack[skill] = effect_value;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_ReduceSkillTimer:
|
|
{
|
|
if(new_bonus->SkillReuseTime[limit_value] < effect_value)
|
|
new_bonus->SkillReuseTime[limit_value] = effect_value;
|
|
break;
|
|
}
|
|
|
|
case SE_SkillDamageAmount:
|
|
{
|
|
// Bad data or unsupported new skill
|
|
if (limit_value > EQ::skills::HIGHEST_SKILL)
|
|
break;
|
|
if(limit_value == ALL_SKILLS)
|
|
new_bonus->SkillDamageAmount[EQ::skills::HIGHEST_SKILL + 1] += effect_value;
|
|
else
|
|
new_bonus->SkillDamageAmount[limit_value] += effect_value;
|
|
break;
|
|
}
|
|
|
|
case SE_GravityEffect:
|
|
new_bonus->GravityEffect = 1;
|
|
break;
|
|
|
|
case SE_AntiGate:
|
|
new_bonus->AntiGate = true;
|
|
break;
|
|
|
|
case SE_MagicWeapon:
|
|
new_bonus->MagicWeapon = true;
|
|
break;
|
|
|
|
case SE_Hunger:
|
|
new_bonus->hunger = true;
|
|
break;
|
|
|
|
case SE_IncreaseBlockChance:
|
|
if (AdditiveWornBonus)
|
|
new_bonus->IncreaseBlockChance += effect_value;
|
|
else if (effect_value < 0 && new_bonus->IncreaseBlockChance > effect_value)
|
|
new_bonus->IncreaseBlockChance = effect_value;
|
|
else if (new_bonus->IncreaseBlockChance < effect_value)
|
|
new_bonus->IncreaseBlockChance = effect_value;
|
|
break;
|
|
|
|
case SE_PersistantCasting:
|
|
new_bonus->PersistantCasting += effect_value;
|
|
break;
|
|
|
|
case SE_LimitHPPercent:
|
|
{
|
|
if(new_bonus->HPPercCap[SBIndex::RESOURCE_PERCENT_CAP] != 0 && new_bonus->HPPercCap[SBIndex::RESOURCE_PERCENT_CAP] > effect_value){
|
|
new_bonus->HPPercCap[SBIndex::RESOURCE_PERCENT_CAP] = effect_value;
|
|
new_bonus->HPPercCap[SBIndex::RESOURCE_AMOUNT_CAP] = limit_value;
|
|
}
|
|
else if(new_bonus->HPPercCap[SBIndex::RESOURCE_PERCENT_CAP] == 0){
|
|
new_bonus->HPPercCap[SBIndex::RESOURCE_PERCENT_CAP] = effect_value;
|
|
new_bonus->HPPercCap[SBIndex::RESOURCE_AMOUNT_CAP] = limit_value;
|
|
}
|
|
break;
|
|
}
|
|
case SE_LimitManaPercent:
|
|
{
|
|
if(new_bonus->ManaPercCap[SBIndex::RESOURCE_PERCENT_CAP] != 0 && new_bonus->ManaPercCap[SBIndex::RESOURCE_PERCENT_CAP] > effect_value){
|
|
new_bonus->ManaPercCap[SBIndex::RESOURCE_PERCENT_CAP] = effect_value;
|
|
new_bonus->ManaPercCap[SBIndex::RESOURCE_AMOUNT_CAP] = limit_value;
|
|
}
|
|
else if(new_bonus->ManaPercCap[SBIndex::RESOURCE_PERCENT_CAP] == 0) {
|
|
new_bonus->ManaPercCap[SBIndex::RESOURCE_PERCENT_CAP] = effect_value;
|
|
new_bonus->ManaPercCap[SBIndex::RESOURCE_AMOUNT_CAP] = limit_value;
|
|
}
|
|
|
|
break;
|
|
}
|
|
case SE_LimitEndPercent:
|
|
{
|
|
if(new_bonus->EndPercCap[SBIndex::RESOURCE_PERCENT_CAP] != 0 && new_bonus->EndPercCap[SBIndex::RESOURCE_PERCENT_CAP] > effect_value) {
|
|
new_bonus->EndPercCap[SBIndex::RESOURCE_PERCENT_CAP] = effect_value;
|
|
new_bonus->EndPercCap[SBIndex::RESOURCE_AMOUNT_CAP] = limit_value;
|
|
}
|
|
|
|
else if(new_bonus->EndPercCap[SBIndex::RESOURCE_PERCENT_CAP] == 0){
|
|
new_bonus->EndPercCap[SBIndex::RESOURCE_PERCENT_CAP] = effect_value;
|
|
new_bonus->EndPercCap[SBIndex::RESOURCE_AMOUNT_CAP] = limit_value;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case SE_NegateSpellEffect:
|
|
new_bonus->NegateEffects = true;
|
|
break;
|
|
|
|
case SE_ImmuneFleeing:
|
|
new_bonus->ImmuneToFlee = true;
|
|
if (currently_fleeing) // lets update shit now instead of next tick
|
|
ProcessFlee();
|
|
break;
|
|
|
|
case SE_DelayDeath:
|
|
new_bonus->DelayDeath += effect_value;
|
|
break;
|
|
|
|
case SE_SpellProcChance:
|
|
new_bonus->SpellProcChance += effect_value;
|
|
break;
|
|
|
|
case SE_CharmBreakChance:
|
|
new_bonus->CharmBreakChance += effect_value;
|
|
break;
|
|
|
|
case SE_BardSongRange:
|
|
new_bonus->SongRange += effect_value;
|
|
break;
|
|
|
|
case SE_HPToMana:
|
|
{
|
|
//Lower the ratio the more favorable
|
|
if ((!new_bonus->HPToManaConvert) || (new_bonus->HPToManaConvert >= effect_value)) {
|
|
new_bonus->HPToManaConvert = spells[spell_id].base_value[i];
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_SkillDamageAmount2:
|
|
{
|
|
// Bad data or unsupported new skill
|
|
if (limit_value > EQ::skills::HIGHEST_SKILL)
|
|
break;
|
|
if(limit_value == ALL_SKILLS)
|
|
new_bonus->SkillDamageAmount2[EQ::skills::HIGHEST_SKILL + 1] += effect_value;
|
|
else
|
|
new_bonus->SkillDamageAmount2[limit_value] += effect_value;
|
|
break;
|
|
}
|
|
|
|
case SE_NegateAttacks:
|
|
{
|
|
if (
|
|
!new_bonus->NegateAttacks[SBIndex::NEGATE_ATK_EXISTS] ||
|
|
(
|
|
new_bonus->NegateAttacks[SBIndex::NEGATE_ATK_MAX_DMG_ABSORB_PER_HIT] &&
|
|
new_bonus->NegateAttacks[SBIndex::NEGATE_ATK_MAX_DMG_ABSORB_PER_HIT] < max_value
|
|
)
|
|
) {
|
|
new_bonus->NegateAttacks[SBIndex::NEGATE_ATK_EXISTS] = 1;
|
|
new_bonus->NegateAttacks[SBIndex::NEGATE_ATK_BUFFSLOT] = buffslot;
|
|
new_bonus->NegateAttacks[SBIndex::NEGATE_ATK_MAX_DMG_ABSORB_PER_HIT] = max_value;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_MitigateMeleeDamage:
|
|
{
|
|
if (new_bonus->MitigateMeleeRune[SBIndex::MITIGATION_RUNE_PERCENT] < effect_value){
|
|
new_bonus->MitigateMeleeRune[SBIndex::MITIGATION_RUNE_PERCENT] = effect_value;
|
|
new_bonus->MitigateMeleeRune[SBIndex::MITIGATION_RUNE_BUFFSLOT] = buffslot;
|
|
new_bonus->MitigateMeleeRune[SBIndex::MITIGATION_RUNE_MAX_DMG_ABSORB_PER_HIT] = limit_value;
|
|
new_bonus->MitigateMeleeRune[SBIndex::MITIGATION_RUNE_MAX_HP_AMT] = max_value;
|
|
}
|
|
break;
|
|
}
|
|
|
|
|
|
case SE_MeleeThresholdGuard:
|
|
{
|
|
if (new_bonus->MeleeThresholdGuard[SBIndex::THRESHOLDGUARD_MITIGATION_PERCENT] < effect_value){
|
|
new_bonus->MeleeThresholdGuard[SBIndex::THRESHOLDGUARD_MITIGATION_PERCENT] = effect_value;
|
|
new_bonus->MeleeThresholdGuard[SBIndex::THRESHOLDGUARD_BUFFSLOT] = buffslot;
|
|
new_bonus->MeleeThresholdGuard[SBIndex::THRESHOLDGUARD_MIN_DMG_TO_TRIGGER] = limit_value;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_SpellThresholdGuard:
|
|
{
|
|
if (new_bonus->SpellThresholdGuard[SBIndex::THRESHOLDGUARD_MITIGATION_PERCENT] < effect_value){
|
|
new_bonus->SpellThresholdGuard[SBIndex::THRESHOLDGUARD_MITIGATION_PERCENT] = effect_value;
|
|
new_bonus->SpellThresholdGuard[SBIndex::THRESHOLDGUARD_BUFFSLOT] = buffslot;
|
|
new_bonus->SpellThresholdGuard[SBIndex::THRESHOLDGUARD_MIN_DMG_TO_TRIGGER] = limit_value;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_MitigateSpellDamage:
|
|
{
|
|
if (WornType) {
|
|
new_bonus->MitigateSpellRune[SBIndex::MITIGATION_RUNE_PERCENT] += effect_value;
|
|
}
|
|
|
|
if (new_bonus->MitigateSpellRune[SBIndex::MITIGATION_RUNE_PERCENT] < effect_value){
|
|
new_bonus->MitigateSpellRune[SBIndex::MITIGATION_RUNE_PERCENT] = effect_value;
|
|
new_bonus->MitigateSpellRune[SBIndex::MITIGATION_RUNE_BUFFSLOT] = buffslot;
|
|
new_bonus->MitigateSpellRune[SBIndex::MITIGATION_RUNE_MAX_DMG_ABSORB_PER_HIT] = limit_value;
|
|
new_bonus->MitigateSpellRune[SBIndex::MITIGATION_RUNE_MAX_HP_AMT] = max_value;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_MitigateDotDamage:
|
|
{
|
|
if (WornType) {
|
|
new_bonus->MitigateDotRune[SBIndex::MITIGATION_RUNE_PERCENT] += effect_value;
|
|
}
|
|
|
|
if (new_bonus->MitigateDotRune[SBIndex::MITIGATION_RUNE_PERCENT] < effect_value){
|
|
new_bonus->MitigateDotRune[SBIndex::MITIGATION_RUNE_PERCENT] = effect_value;
|
|
new_bonus->MitigateDotRune[SBIndex::MITIGATION_RUNE_BUFFSLOT] = buffslot;
|
|
new_bonus->MitigateDotRune[SBIndex::MITIGATION_RUNE_MAX_DMG_ABSORB_PER_HIT] = limit_value;
|
|
new_bonus->MitigateDotRune[SBIndex::MITIGATION_RUNE_MAX_HP_AMT] = max_value;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_ManaAbsorbPercentDamage:
|
|
{
|
|
if (new_bonus->ManaAbsorbPercentDamage < effect_value){
|
|
new_bonus->ManaAbsorbPercentDamage = effect_value;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_Endurance_Absorb_Pct_Damage:
|
|
{
|
|
if (new_bonus->EnduranceAbsorbPercentDamage[SBIndex::ENDURANCE_ABSORD_MITIGIATION] < effect_value) {
|
|
new_bonus->EnduranceAbsorbPercentDamage[SBIndex::ENDURANCE_ABSORD_MITIGIATION] = effect_value;
|
|
new_bonus->EnduranceAbsorbPercentDamage[SBIndex::ENDURANCE_ABSORD_DRAIN_PER_HP] = limit_value;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_Shield_Target:
|
|
{
|
|
if (new_bonus->ShieldTargetSpa[SBIndex::SHIELD_TARGET_MITIGATION_PERCENT] < effect_value) {
|
|
new_bonus->ShieldTargetSpa[SBIndex::SHIELD_TARGET_MITIGATION_PERCENT] = effect_value;
|
|
new_bonus->ShieldTargetSpa[SBIndex::SHIELD_TARGET_BUFFSLOT] = buffslot;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_TriggerMeleeThreshold:
|
|
new_bonus->TriggerMeleeThreshold = true;
|
|
break;
|
|
|
|
case SE_TriggerSpellThreshold:
|
|
new_bonus->TriggerSpellThreshold = true;
|
|
break;
|
|
|
|
case SE_ShieldBlock:
|
|
new_bonus->ShieldBlock += effect_value;
|
|
break;
|
|
|
|
case SE_ShieldEquipDmgMod:
|
|
new_bonus->ShieldEquipDmgMod += effect_value;
|
|
break;
|
|
|
|
case SE_BlockBehind:
|
|
new_bonus->BlockBehind += effect_value;
|
|
break;
|
|
|
|
case SE_Blind:
|
|
if (!RuleB(Combat, AllowRaidTargetBlind) && IsRaidTarget()) { // do not blind raid targets
|
|
break;
|
|
}
|
|
|
|
new_bonus->IsBlind = true;
|
|
break;
|
|
|
|
case SE_Fear:
|
|
new_bonus->IsFeared = true;
|
|
break;
|
|
|
|
//AA bonuses - implemented broadly into spell/item effects
|
|
case SE_FrontalStunResist:
|
|
new_bonus->FrontalStunResist += effect_value;
|
|
break;
|
|
|
|
case SE_ImprovedBindWound:
|
|
new_bonus->BindWound += effect_value;
|
|
break;
|
|
|
|
case SE_MaxBindWound:
|
|
new_bonus->MaxBindWound += effect_value;
|
|
break;
|
|
|
|
case SE_BaseMovementSpeed:
|
|
new_bonus->BaseMovementSpeed += effect_value;
|
|
break;
|
|
|
|
case SE_IncreaseRunSpeedCap:
|
|
new_bonus->IncreaseRunSpeedCap += effect_value;
|
|
break;
|
|
|
|
case SE_DoubleSpecialAttack:
|
|
new_bonus->DoubleSpecialAttack += effect_value;
|
|
break;
|
|
|
|
case SE_TripleBackstab:
|
|
new_bonus->TripleBackstab += effect_value;
|
|
break;
|
|
|
|
case SE_FrontalBackstabMinDmg:
|
|
new_bonus->FrontalBackstabMinDmg = true;
|
|
break;
|
|
|
|
case SE_FrontalBackstabChance:
|
|
new_bonus->FrontalBackstabChance += effect_value;
|
|
break;
|
|
|
|
case SE_Double_Backstab_Front:
|
|
new_bonus->Double_Backstab_Front += effect_value;
|
|
break;
|
|
|
|
case SE_ConsumeProjectile:
|
|
new_bonus->ConsumeProjectile += effect_value;
|
|
break;
|
|
|
|
case SE_ForageAdditionalItems:
|
|
new_bonus->ForageAdditionalItems += effect_value;
|
|
break;
|
|
|
|
case SE_Salvage:
|
|
new_bonus->SalvageChance += effect_value;
|
|
break;
|
|
|
|
case SE_ArcheryDamageModifier:
|
|
new_bonus->ArcheryDamageModifier += effect_value;
|
|
break;
|
|
|
|
case SE_DoubleRangedAttack:
|
|
new_bonus->DoubleRangedAttack += effect_value;
|
|
break;
|
|
|
|
case SE_SecondaryDmgInc:
|
|
new_bonus->SecondaryDmgInc = true;
|
|
break;
|
|
|
|
case SE_StrikeThrough:
|
|
case SE_StrikeThrough2:
|
|
new_bonus->StrikeThrough += effect_value;
|
|
break;
|
|
|
|
case SE_GiveDoubleAttack:
|
|
new_bonus->GiveDoubleAttack += effect_value;
|
|
break;
|
|
|
|
case SE_PetCriticalHit:
|
|
new_bonus->PetCriticalHit += effect_value;
|
|
break;
|
|
|
|
case SE_CombatStability:
|
|
new_bonus->CombatStability += effect_value;
|
|
break;
|
|
|
|
case SE_AddSingingMod:
|
|
switch (limit_value) {
|
|
case EQ::item::ItemTypeWindInstrument:
|
|
new_bonus->windMod += effect_value;
|
|
break;
|
|
case EQ::item::ItemTypeStringedInstrument:
|
|
new_bonus->stringedMod += effect_value;
|
|
break;
|
|
case EQ::item::ItemTypeBrassInstrument:
|
|
new_bonus->brassMod += effect_value;
|
|
break;
|
|
case EQ::item::ItemTypePercussionInstrument:
|
|
new_bonus->percussionMod += effect_value;
|
|
break;
|
|
case EQ::item::ItemTypeSinging:
|
|
new_bonus->singingMod += effect_value;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case SE_SongModCap:
|
|
new_bonus->songModCap += effect_value;
|
|
break;
|
|
|
|
case SE_PetAvoidance:
|
|
new_bonus->PetAvoidance += effect_value;
|
|
break;
|
|
|
|
case SE_Ambidexterity:
|
|
new_bonus->Ambidexterity += effect_value;
|
|
break;
|
|
|
|
case SE_PetMaxHP:
|
|
new_bonus->PetMaxHP += effect_value;
|
|
break;
|
|
|
|
case SE_PetFlurry:
|
|
new_bonus->PetFlurry += effect_value;
|
|
break;
|
|
|
|
case SE_GivePetGroupTarget:
|
|
new_bonus->GivePetGroupTarget = true;
|
|
break;
|
|
|
|
case SE_RootBreakChance:
|
|
new_bonus->RootBreakChance += effect_value;
|
|
break;
|
|
|
|
case SE_ChannelChanceItems:
|
|
new_bonus->ChannelChanceItems += effect_value;
|
|
break;
|
|
|
|
case SE_ChannelChanceSpells:
|
|
new_bonus->ChannelChanceSpells += effect_value;
|
|
break;
|
|
|
|
case SE_UnfailingDivinity:
|
|
new_bonus->UnfailingDivinity += effect_value;
|
|
break;
|
|
|
|
|
|
case SE_ItemHPRegenCapIncrease:
|
|
new_bonus->ItemHPRegenCap += effect_value;
|
|
break;
|
|
|
|
case SE_OffhandRiposteFail:
|
|
new_bonus->OffhandRiposteFail += effect_value;
|
|
break;
|
|
|
|
case SE_ItemAttackCapIncrease:
|
|
new_bonus->ItemATKCap += effect_value;
|
|
break;
|
|
|
|
case SE_TwoHandBluntBlock:
|
|
new_bonus->TwoHandBluntBlock += effect_value;
|
|
break;
|
|
|
|
case SE_StunBashChance:
|
|
new_bonus->StunBashChance += effect_value;
|
|
break;
|
|
|
|
case SE_IncreaseChanceMemwipe:
|
|
new_bonus->IncreaseChanceMemwipe += effect_value;
|
|
break;
|
|
|
|
case SE_CriticalMend:
|
|
new_bonus->CriticalMend += effect_value;
|
|
break;
|
|
|
|
case SE_SpellEffectResistChance:
|
|
{
|
|
for(int e = 0; e < MAX_RESISTABLE_EFFECTS*2; e+=2)
|
|
{
|
|
if (
|
|
!new_bonus->SEResist[e + 1] ||
|
|
(
|
|
new_bonus->SEResist[e + 1] &&
|
|
new_bonus->SEResist[e] == limit_value &&
|
|
new_bonus->SEResist[e + 1] < effect_value
|
|
)
|
|
) {
|
|
new_bonus->SEResist[e] = limit_value; //Spell Effect ID
|
|
new_bonus->SEResist[e + 1] = effect_value; //Resist Chance
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_MasteryofPast:
|
|
{
|
|
if(new_bonus->MasteryofPast < effect_value)
|
|
new_bonus->MasteryofPast = effect_value;
|
|
break;
|
|
}
|
|
|
|
case SE_DoubleRiposte:
|
|
{
|
|
new_bonus->DoubleRiposte += effect_value;
|
|
break;
|
|
}
|
|
|
|
case SE_GiveDoubleRiposte:
|
|
{
|
|
//Only allow for regular double riposte chance.
|
|
if(new_bonus->GiveDoubleRiposte[limit_value] == 0){
|
|
if(new_bonus->GiveDoubleRiposte[SBIndex::DOUBLE_RIPOSTE_CHANCE] < effect_value)
|
|
new_bonus->GiveDoubleRiposte[SBIndex::DOUBLE_RIPOSTE_CHANCE] = effect_value;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_SlayUndead: {
|
|
if (new_bonus->SlayUndead[SBIndex::SLAYUNDEAD_DMG_MOD] < effect_value) {
|
|
new_bonus->SlayUndead[SBIndex::SLAYUNDEAD_RATE_MOD] = limit_value; // Rate
|
|
new_bonus->SlayUndead[SBIndex::SLAYUNDEAD_DMG_MOD] = effect_value; // Damage Modifier
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_TriggerOnReqTarget:
|
|
case SE_TriggerOnReqCaster:
|
|
new_bonus->TriggerOnCastRequirement = true;
|
|
break;
|
|
|
|
case SE_DivineAura:
|
|
new_bonus->DivineAura = true;
|
|
break;
|
|
|
|
case SE_ImprovedTaunt:
|
|
if (new_bonus->ImprovedTaunt[SBIndex::IMPROVED_TAUNT_MAX_LVL] < effect_value) {
|
|
new_bonus->ImprovedTaunt[SBIndex::IMPROVED_TAUNT_MAX_LVL] = effect_value;
|
|
new_bonus->ImprovedTaunt[SBIndex::IMPROVED_TAUNT_AGGRO_MOD] = limit_value;
|
|
new_bonus->ImprovedTaunt[SBIndex::IMPROVED_TAUNT_BUFFSLOT] = buffslot;
|
|
}
|
|
break;
|
|
|
|
|
|
case SE_DistanceRemoval:
|
|
new_bonus->DistanceRemoval = true;
|
|
break;
|
|
|
|
case SE_FrenziedDevastation:
|
|
new_bonus->FrenziedDevastation += limit_value;
|
|
break;
|
|
|
|
case SE_Root:
|
|
if (new_bonus->Root[SBIndex::ROOT_EXISTS] && (new_bonus->Root[SBIndex::ROOT_BUFFSLOT] > buffslot)){
|
|
new_bonus->Root[SBIndex::ROOT_EXISTS] = 1;
|
|
new_bonus->Root[SBIndex::ROOT_BUFFSLOT] = buffslot;
|
|
}
|
|
else if (!new_bonus->Root[SBIndex::ROOT_EXISTS]){
|
|
new_bonus->Root[SBIndex::ROOT_EXISTS] = 1;
|
|
new_bonus->Root[SBIndex::ROOT_BUFFSLOT] = buffslot;
|
|
}
|
|
break;
|
|
|
|
case SE_Rune:
|
|
|
|
if (new_bonus->MeleeRune[SBIndex::RUNE_AMOUNT] && (new_bonus->MeleeRune[SBIndex::RUNE_BUFFSLOT] > buffslot)){
|
|
|
|
new_bonus->MeleeRune[SBIndex::RUNE_AMOUNT] = effect_value;
|
|
new_bonus->MeleeRune[SBIndex::RUNE_BUFFSLOT] = buffslot;
|
|
}
|
|
else if (!new_bonus->MeleeRune[SBIndex::RUNE_AMOUNT]){
|
|
new_bonus->MeleeRune[SBIndex::RUNE_AMOUNT] = effect_value;
|
|
new_bonus->MeleeRune[SBIndex::RUNE_BUFFSLOT] = buffslot;
|
|
}
|
|
|
|
break;
|
|
|
|
case SE_AbsorbMagicAtt:
|
|
if (new_bonus->AbsorbMagicAtt[SBIndex::RUNE_AMOUNT] && (new_bonus->AbsorbMagicAtt[SBIndex::RUNE_BUFFSLOT] > buffslot)){
|
|
new_bonus->AbsorbMagicAtt[SBIndex::RUNE_AMOUNT] = effect_value;
|
|
new_bonus->AbsorbMagicAtt[SBIndex::RUNE_BUFFSLOT] = buffslot;
|
|
}
|
|
else if (!new_bonus->AbsorbMagicAtt[SBIndex::RUNE_AMOUNT]){
|
|
new_bonus->AbsorbMagicAtt[SBIndex::RUNE_AMOUNT] = effect_value;
|
|
new_bonus->AbsorbMagicAtt[SBIndex::RUNE_BUFFSLOT] = buffslot;
|
|
}
|
|
break;
|
|
|
|
case SE_NegateIfCombat:
|
|
new_bonus->NegateIfCombat = true;
|
|
break;
|
|
|
|
case SE_Screech:
|
|
new_bonus->Screech = effect_value;
|
|
break;
|
|
|
|
case SE_AlterNPCLevel:
|
|
|
|
if (IsNPC()){
|
|
if (!new_bonus->AlterNPCLevel
|
|
|| ((effect_value < 0) && (new_bonus->AlterNPCLevel > effect_value))
|
|
|| ((effect_value > 0) && (new_bonus->AlterNPCLevel < effect_value))) {
|
|
|
|
int tmp_lv = GetOrigLevel() + effect_value;
|
|
if (tmp_lv < 1)
|
|
tmp_lv = 1;
|
|
else if (tmp_lv > 255)
|
|
tmp_lv = 255;
|
|
if ((GetLevel() != tmp_lv)){
|
|
new_bonus->AlterNPCLevel = effect_value;
|
|
SetLevel(tmp_lv);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SE_AStacker:
|
|
new_bonus->AStacker[SBIndex::BUFFSTACKER_EXISTS] = 1;
|
|
new_bonus->AStacker[SBIndex::BUFFSTACKER_VALUE] = effect_value;
|
|
break;
|
|
|
|
case SE_BStacker:
|
|
new_bonus->BStacker[SBIndex::BUFFSTACKER_EXISTS] = 1;
|
|
new_bonus->BStacker[SBIndex::BUFFSTACKER_VALUE] = effect_value;
|
|
break;
|
|
|
|
case SE_CStacker:
|
|
new_bonus->CStacker[SBIndex::BUFFSTACKER_EXISTS] = 1;
|
|
new_bonus->CStacker[SBIndex::BUFFSTACKER_VALUE] = effect_value;
|
|
break;
|
|
|
|
case SE_DStacker:
|
|
new_bonus->DStacker[SBIndex::BUFFSTACKER_EXISTS] = 1;
|
|
new_bonus->DStacker[SBIndex::BUFFSTACKER_VALUE] = effect_value;
|
|
break;
|
|
|
|
case SE_Berserk:
|
|
new_bonus->BerserkSPA = true;
|
|
break;
|
|
|
|
|
|
case SE_Metabolism:
|
|
new_bonus->Metabolism += effect_value;
|
|
break;
|
|
|
|
case SE_ImprovedReclaimEnergy:
|
|
{
|
|
if((effect_value < 0) && (new_bonus->ImprovedReclaimEnergy > effect_value))
|
|
new_bonus->ImprovedReclaimEnergy = effect_value;
|
|
|
|
else if(new_bonus->ImprovedReclaimEnergy < effect_value)
|
|
new_bonus->ImprovedReclaimEnergy = effect_value;
|
|
break;
|
|
}
|
|
|
|
case SE_HeadShot:
|
|
{
|
|
if(new_bonus->HeadShot[SBIndex::FINISHING_EFFECT_DMG] < limit_value){
|
|
new_bonus->HeadShot[SBIndex::FINISHING_EFFECT_PROC_CHANCE] = effect_value;
|
|
new_bonus->HeadShot[SBIndex::FINISHING_EFFECT_DMG] = limit_value;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_HeadShotLevel: {
|
|
if (new_bonus->HSLevel[SBIndex::FINISHING_EFFECT_LEVEL_MAX] < effect_value) {
|
|
new_bonus->HSLevel[SBIndex::FINISHING_EFFECT_LEVEL_MAX] = effect_value;
|
|
new_bonus->HSLevel[SBIndex::FINISHING_EFFECT_LEVEL_CHANCE_BONUS] = limit_value;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_Assassinate:
|
|
{
|
|
if(new_bonus->Assassinate[SBIndex::FINISHING_EFFECT_DMG] < limit_value){
|
|
new_bonus->Assassinate[SBIndex::FINISHING_EFFECT_PROC_CHANCE] = effect_value;
|
|
new_bonus->Assassinate[SBIndex::FINISHING_EFFECT_DMG] = limit_value;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_AssassinateLevel:
|
|
{
|
|
if(new_bonus->AssassinateLevel[SBIndex::FINISHING_EFFECT_LEVEL_MAX] < effect_value) {
|
|
new_bonus->AssassinateLevel[SBIndex::FINISHING_EFFECT_LEVEL_MAX] = effect_value;
|
|
new_bonus->AssassinateLevel[SBIndex::FINISHING_EFFECT_LEVEL_CHANCE_BONUS] = limit_value;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_FinishingBlow:
|
|
{
|
|
//base1 = chance, base2 = damage
|
|
if (new_bonus->FinishingBlow[SBIndex::FINISHING_EFFECT_DMG] < limit_value){
|
|
new_bonus->FinishingBlow[SBIndex::FINISHING_EFFECT_PROC_CHANCE] = effect_value;
|
|
new_bonus->FinishingBlow[SBIndex::FINISHING_EFFECT_DMG] = limit_value;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_FinishingBlowLvl:
|
|
{
|
|
if (new_bonus->FinishingBlowLvl[SBIndex::FINISHING_EFFECT_LEVEL_MAX] < effect_value){
|
|
new_bonus->FinishingBlowLvl[SBIndex::FINISHING_EFFECT_LEVEL_MAX] = effect_value;
|
|
new_bonus->FinishingBlowLvl[SBIndex::FINISHING_BLOW_LEVEL_HP_RATIO] = limit_value;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_PetMeleeMitigation:
|
|
new_bonus->PetMeleeMitigation += effect_value;
|
|
break;
|
|
|
|
case SE_Sanctuary:
|
|
new_bonus->Sanctuary = true;
|
|
break;
|
|
|
|
case SE_FactionModPct:
|
|
{
|
|
if((effect_value < 0) && (new_bonus->FactionModPct > effect_value))
|
|
new_bonus->FactionModPct = effect_value;
|
|
|
|
else if(new_bonus->FactionModPct < effect_value)
|
|
new_bonus->FactionModPct = effect_value;
|
|
break;
|
|
}
|
|
|
|
case SE_Illusion:
|
|
new_bonus->Illusion = spell_id;
|
|
break;
|
|
|
|
case SE_IllusionPersistence:
|
|
new_bonus->IllusionPersistence = effect_value;
|
|
break;
|
|
|
|
case SE_LimitToSkill: {
|
|
// Bad data or unsupported new skill
|
|
if (effect_value > EQ::skills::HIGHEST_SKILL) {
|
|
break;
|
|
}
|
|
if (effect_value <= EQ::skills::HIGHEST_SKILL){
|
|
new_bonus->LimitToSkill[effect_value] = true;
|
|
new_bonus->LimitToSkill[EQ::skills::HIGHEST_SKILL + 2] = true; //Used as a general exists check
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_SkillProcAttempt:{
|
|
|
|
for(int e = 0; e < MAX_SKILL_PROCS; e++)
|
|
{
|
|
if (new_bonus->SkillProc[e] && new_bonus->SkillProc[e] == spell_id) {
|
|
break; //Do not use the same spell id more than once.
|
|
}
|
|
else if(!new_bonus->SkillProc[e]){
|
|
new_bonus->SkillProc[e] = spell_id;
|
|
HasSkillProcs();//This returns it correctly as debug
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_SkillProcSuccess:{
|
|
|
|
for(int e = 0; e < MAX_SKILL_PROCS; e++)
|
|
{
|
|
if(new_bonus->SkillProcSuccess[e] && new_bonus->SkillProcSuccess[e] == spell_id)
|
|
break; //Do not use the same spell id more than once.
|
|
|
|
else if(!new_bonus->SkillProcSuccess[e]){
|
|
new_bonus->SkillProcSuccess[e] = spell_id;
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_SkillAttackProc: {
|
|
for (int i = 0; i < MAX_CAST_ON_SKILL_USE; i += 3) {
|
|
if (!new_bonus->SkillAttackProc[i + SBIndex::SKILLATK_PROC_SPELL_ID]) { // spell id
|
|
new_bonus->SkillAttackProc[i + SBIndex::SKILLATK_PROC_SPELL_ID] = max_value; // spell to proc
|
|
new_bonus->SkillAttackProc[i + SBIndex::SKILLATK_PROC_CHANCE] = effect_value; // Chance base 1000 = 100% proc rate
|
|
new_bonus->SkillAttackProc[i + SBIndex::SKILLATK_PROC_SKILL] = limit_value; // Skill to Proc Offr
|
|
|
|
if (limit_value <= EQ::skills::HIGHEST_SKILL) {
|
|
new_bonus->HasSkillAttackProc[limit_value] = true; //check first before looking for any effects.
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_PC_Pet_Rampage: {
|
|
new_bonus->PC_Pet_Rampage[SBIndex::PET_RAMPAGE_CHANCE] += effect_value; //Chance to rampage
|
|
if (new_bonus->PC_Pet_Rampage[SBIndex::PET_RAMPAGE_DMG_MOD] < limit_value)
|
|
new_bonus->PC_Pet_Rampage[SBIndex::PET_RAMPAGE_DMG_MOD] = limit_value; //Damage modifer - take highest
|
|
break;
|
|
}
|
|
|
|
case SE_PC_Pet_AE_Rampage: {
|
|
new_bonus->PC_Pet_AE_Rampage[SBIndex::PET_RAMPAGE_CHANCE] += effect_value; //Chance to rampage
|
|
if (new_bonus->PC_Pet_AE_Rampage[SBIndex::PET_RAMPAGE_DMG_MOD] < limit_value)
|
|
new_bonus->PC_Pet_AE_Rampage[SBIndex::PET_RAMPAGE_DMG_MOD] = limit_value; //Damage modifer - take highest
|
|
break;
|
|
}
|
|
|
|
case SE_PC_Pet_Flurry_Chance:
|
|
new_bonus->PC_Pet_Flurry += effect_value; //Chance to Flurry
|
|
break;
|
|
|
|
case SE_ShroudofStealth:
|
|
new_bonus->ShroudofStealth = true;
|
|
break;
|
|
|
|
case SE_ReduceFallDamage:
|
|
new_bonus->ReduceFallDamage += effect_value;
|
|
break;
|
|
|
|
case SE_ReduceTradeskillFail:{
|
|
|
|
if (limit_value > EQ::skills::HIGHEST_SKILL)
|
|
break;
|
|
|
|
new_bonus->ReduceTradeskillFail[limit_value] += effect_value;
|
|
break;
|
|
}
|
|
|
|
case SE_TradeSkillMastery:
|
|
if (new_bonus->TradeSkillMastery < effect_value)
|
|
new_bonus->TradeSkillMastery = effect_value;
|
|
break;
|
|
|
|
case SE_RaiseSkillCap: {
|
|
if (limit_value > EQ::skills::HIGHEST_SKILL)
|
|
break;
|
|
|
|
if (new_bonus->RaiseSkillCap[limit_value] < effect_value)
|
|
new_bonus->RaiseSkillCap[limit_value] = effect_value;
|
|
break;
|
|
}
|
|
|
|
case SE_NoBreakAESneak:
|
|
if (new_bonus->NoBreakAESneak < effect_value)
|
|
new_bonus->NoBreakAESneak = effect_value;
|
|
break;
|
|
|
|
case SE_FeignedCastOnChance:
|
|
if (new_bonus->FeignedCastOnChance < effect_value)
|
|
new_bonus->FeignedCastOnChance = effect_value;
|
|
break;
|
|
|
|
case SE_AdditionalAura:
|
|
if (new_bonus->aura_slots < effect_value)
|
|
new_bonus->aura_slots = effect_value;
|
|
break;
|
|
|
|
case SE_IncreaseTrapCount:
|
|
if (new_bonus->trap_slots < effect_value)
|
|
new_bonus->trap_slots = effect_value;
|
|
break;
|
|
|
|
case SE_Attack_Accuracy_Max_Percent:
|
|
new_bonus->Attack_Accuracy_Max_Percent += effect_value;
|
|
break;
|
|
|
|
|
|
case SE_AC_Mitigation_Max_Percent:
|
|
new_bonus->AC_Mitigation_Max_Percent += effect_value;
|
|
break;
|
|
|
|
case SE_AC_Avoidance_Max_Percent:
|
|
new_bonus->AC_Avoidance_Max_Percent += effect_value;
|
|
break;
|
|
|
|
case SE_Damage_Taken_Position_Mod:
|
|
{
|
|
//Mitigate if damage taken from behind base2 = 0, from front base2 = 1
|
|
if (limit_value < 0 || limit_value >= 2) {
|
|
break;
|
|
}
|
|
if (AdditiveWornBonus)
|
|
new_bonus->Damage_Taken_Position_Mod[limit_value] += effect_value;
|
|
else if (effect_value < 0 && new_bonus->Damage_Taken_Position_Mod[limit_value] > effect_value)
|
|
new_bonus->Damage_Taken_Position_Mod[limit_value] = effect_value;
|
|
else if (effect_value > 0 && new_bonus->Damage_Taken_Position_Mod[limit_value] < effect_value)
|
|
new_bonus->Damage_Taken_Position_Mod[limit_value] = effect_value;
|
|
break;
|
|
}
|
|
|
|
case SE_Melee_Damage_Position_Mod:
|
|
{
|
|
//Increase damage by percent from behind base2 = 0, from front base2 = 1
|
|
if (limit_value < 0 || limit_value >= 2) {
|
|
break;
|
|
}
|
|
if (AdditiveWornBonus)
|
|
new_bonus->Melee_Damage_Position_Mod[limit_value] += effect_value;
|
|
else if (effect_value < 0 && new_bonus->Melee_Damage_Position_Mod[limit_value] > effect_value)
|
|
new_bonus->Melee_Damage_Position_Mod[limit_value] = effect_value;
|
|
else if (effect_value > 0 && new_bonus->Melee_Damage_Position_Mod[limit_value] < effect_value)
|
|
new_bonus->Melee_Damage_Position_Mod[limit_value] = effect_value;
|
|
break;
|
|
}
|
|
|
|
case SE_Damage_Taken_Position_Amt:
|
|
{
|
|
//Mitigate if damage taken from behind base2 = 0, from front base2 = 1
|
|
if (limit_value < 0 || limit_value >= 2) {
|
|
break;
|
|
}
|
|
|
|
new_bonus->Damage_Taken_Position_Amt[limit_value] += effect_value;
|
|
break;
|
|
}
|
|
|
|
case SE_Melee_Damage_Position_Amt:
|
|
{
|
|
//Mitigate if damage taken from behind base2 = 0, from front base2 = 1
|
|
if (limit_value < 0 || limit_value >= 2) {
|
|
break;
|
|
}
|
|
|
|
new_bonus->Melee_Damage_Position_Amt[limit_value] += effect_value;
|
|
break;
|
|
}
|
|
|
|
case SE_DS_Mitigation_Amount:
|
|
new_bonus->DS_Mitigation_Amount += effect_value;
|
|
break;
|
|
|
|
case SE_DS_Mitigation_Percentage:
|
|
new_bonus->DS_Mitigation_Percentage += effect_value;
|
|
break;
|
|
|
|
case SE_Pet_Crit_Melee_Damage_Pct_Owner:
|
|
new_bonus->Pet_Crit_Melee_Damage_Pct_Owner += effect_value;
|
|
break;
|
|
|
|
case SE_Pet_Add_Atk:
|
|
new_bonus->Pet_Add_Atk += effect_value;
|
|
break;
|
|
|
|
case SE_ExtendedShielding:
|
|
{
|
|
if (AdditiveWornBonus) {
|
|
new_bonus->ExtendedShielding += effect_value;
|
|
}
|
|
else if (effect_value < 0 && new_bonus->ExtendedShielding > effect_value){
|
|
new_bonus->ExtendedShielding = effect_value;
|
|
}
|
|
else if (effect_value > 0 && new_bonus->ExtendedShielding < effect_value){
|
|
new_bonus->ExtendedShielding = effect_value;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_ShieldDuration:
|
|
{
|
|
if (AdditiveWornBonus) {
|
|
new_bonus->ShieldDuration += effect_value;
|
|
}
|
|
else if (effect_value < 0 && new_bonus->ShieldDuration > effect_value){
|
|
new_bonus->ShieldDuration = effect_value;
|
|
}
|
|
else if (effect_value > 0 && new_bonus->ShieldDuration < effect_value){
|
|
new_bonus->ShieldDuration = effect_value;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_Worn_Endurance_Regen_Cap:
|
|
new_bonus->ItemEnduranceRegenCap += effect_value;
|
|
break;
|
|
|
|
case SE_ItemManaRegenCapIncrease:
|
|
new_bonus->ItemManaRegenCap += effect_value;
|
|
break;
|
|
|
|
case SE_Weapon_Stance: {
|
|
if (IsValidSpell(effect_value)) { //base1 is the spell_id of buff
|
|
if (limit_value <= WEAPON_STANCE_TYPE_MAX) { //0=2H, 1=Shield, 2=DW
|
|
if (IsValidSpell(new_bonus->WeaponStance[limit_value])) { //Check if we already a spell_id saved for this effect
|
|
if (spells[new_bonus->WeaponStance[limit_value]].rank < spells[effect_value].rank) { //If so, check if any new spellids with higher rank exist (live spells for this are ranked).
|
|
new_bonus->WeaponStance[limit_value] = effect_value; //Overwrite with new effect
|
|
SetWeaponStanceEnabled(true);
|
|
|
|
if (WornType) {
|
|
weaponstance.itembonus_enabled = true;
|
|
}
|
|
else {
|
|
weaponstance.spellbonus_enabled = true;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
new_bonus->WeaponStance[limit_value] = effect_value; //If no prior effect exists, then apply
|
|
SetWeaponStanceEnabled(true);
|
|
|
|
if (WornType) {
|
|
weaponstance.itembonus_enabled = true;
|
|
}
|
|
else {
|
|
weaponstance.spellbonus_enabled = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_Invisibility:
|
|
case SE_Invisibility2:
|
|
effect_value = std::min({ effect_value, MAX_INVISIBILTY_LEVEL });
|
|
if (new_bonus->invisibility < effect_value)
|
|
new_bonus->invisibility = effect_value;
|
|
break;
|
|
|
|
case SE_InvisVsUndead:
|
|
case SE_InvisVsUndead2:
|
|
if (new_bonus->invisibility_verse_undead < effect_value)
|
|
new_bonus->invisibility_verse_undead = effect_value;
|
|
break;
|
|
|
|
case SE_InvisVsAnimals:
|
|
case SE_ImprovedInvisAnimals:
|
|
effect_value = std::min({ effect_value, MAX_INVISIBILTY_LEVEL });
|
|
if (new_bonus->invisibility_verse_animal < effect_value)
|
|
new_bonus->invisibility_verse_animal = effect_value;
|
|
break;
|
|
|
|
case SE_SeeInvis:
|
|
effect_value = std::min({ effect_value, MAX_INVISIBILTY_LEVEL });
|
|
if (new_bonus->SeeInvis < effect_value) {
|
|
new_bonus->SeeInvis = effect_value;
|
|
}
|
|
break;
|
|
|
|
case SE_ZoneSuspendMinion:
|
|
new_bonus->ZoneSuspendMinion = effect_value;
|
|
break;
|
|
|
|
case SE_CompleteHeal:
|
|
new_bonus->CompleteHealBuffBlocker = true;
|
|
break;
|
|
|
|
case SE_TrapCircumvention:
|
|
new_bonus->TrapCircumvention += effect_value;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Client::CalcItemScale() {
|
|
bool changed = false;
|
|
|
|
// MainAmmo excluded in helper function below
|
|
if (CalcItemScale(EQ::invslot::EQUIPMENT_BEGIN, EQ::invslot::EQUIPMENT_END)) // original coding excluded MainAmmo (< 21)
|
|
changed = true;
|
|
|
|
if (CalcItemScale(EQ::invslot::GENERAL_BEGIN, EQ::invslot::GENERAL_END)) // original coding excluded MainCursor (< 30)
|
|
changed = true;
|
|
|
|
// I excluded cursor bag slots here because cursor was excluded above..if this is incorrect, change 'slot_y' here to CURSOR_BAG_END
|
|
// and 'slot_y' above to CURSOR from GENERAL_END above - or however it is supposed to be...
|
|
if (CalcItemScale(EQ::invbag::GENERAL_BAGS_BEGIN, EQ::invbag::GENERAL_BAGS_END)) // (< 341)
|
|
changed = true;
|
|
|
|
if (CalcItemScale(EQ::invslot::TRIBUTE_BEGIN, EQ::invslot::TRIBUTE_END)) // (< 405)
|
|
changed = true;
|
|
|
|
if(changed)
|
|
{
|
|
CalcBonuses();
|
|
}
|
|
}
|
|
|
|
bool Client::CalcItemScale(uint32 slot_x, uint32 slot_y) {
|
|
// behavior change: 'slot_y' is now [RANGE]_END and not [RANGE]_END + 1
|
|
bool changed = false;
|
|
uint32 i;
|
|
for (i = slot_x; i <= slot_y; i++) {
|
|
if (i == EQ::invslot::slotAmmo) // moved here from calling procedure to facilitate future range changes where MainAmmo may not be the last slot
|
|
continue;
|
|
|
|
EQ::ItemInstance* inst = m_inv.GetItem(i);
|
|
|
|
if(inst == nullptr)
|
|
continue;
|
|
|
|
// TEST CODE: test for bazaar trader crashing with charm items
|
|
if (IsTrader())
|
|
if (i >= EQ::invbag::GENERAL_BAGS_BEGIN && i <= EQ::invbag::GENERAL_BAGS_END) {
|
|
EQ::ItemInstance* parent_item = m_inv.GetItem(EQ::InventoryProfile::CalcSlotId(i));
|
|
if (parent_item && parent_item->GetItem()->BagType == EQ::item::BagTypeTradersSatchel)
|
|
continue;
|
|
}
|
|
|
|
bool update_slot = false;
|
|
if(inst->IsScaling())
|
|
{
|
|
uint16 oldexp = inst->GetExp();
|
|
|
|
if (parse->ItemHasQuestSub(inst, EVENT_SCALE_CALC)) {
|
|
parse->EventItem(EVENT_SCALE_CALC, this, inst, nullptr, "", 0);
|
|
}
|
|
|
|
if (inst->GetExp() != oldexp) { // if the scaling factor changed, rescale the item and update the client
|
|
inst->ScaleItem();
|
|
changed = true;
|
|
update_slot = true;
|
|
}
|
|
}
|
|
|
|
//iterate all augments
|
|
for (int x = EQ::invaug::SOCKET_BEGIN; x <= EQ::invaug::SOCKET_END; ++x)
|
|
{
|
|
EQ::ItemInstance * a_inst = inst->GetAugment(x);
|
|
if(!a_inst)
|
|
continue;
|
|
|
|
if(a_inst->IsScaling())
|
|
{
|
|
uint16 oldexp = a_inst->GetExp();
|
|
|
|
if (parse->ItemHasQuestSub(a_inst, EVENT_SCALE_CALC)) {
|
|
parse->EventItem(EVENT_SCALE_CALC, this, a_inst, nullptr, "", 0);
|
|
}
|
|
|
|
if (a_inst->GetExp() != oldexp)
|
|
{
|
|
a_inst->ScaleItem();
|
|
changed = true;
|
|
update_slot = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(update_slot)
|
|
{
|
|
SendItemPacket(i, inst, ItemPacketCharmUpdate);
|
|
}
|
|
}
|
|
return changed;
|
|
}
|
|
|
|
void Client::DoItemEnterZone() {
|
|
bool changed = false;
|
|
|
|
// MainAmmo excluded in helper function below
|
|
if (DoItemEnterZone(EQ::invslot::EQUIPMENT_BEGIN, EQ::invslot::EQUIPMENT_END)) // original coding excluded MainAmmo (< 21)
|
|
changed = true;
|
|
|
|
if (DoItemEnterZone(EQ::invslot::GENERAL_BEGIN, EQ::invslot::GENERAL_END)) // original coding excluded MainCursor (< 30)
|
|
changed = true;
|
|
|
|
// I excluded cursor bag slots here because cursor was excluded above..if this is incorrect, change 'slot_y' here to CURSOR_BAG_END
|
|
// and 'slot_y' above to CURSOR from GENERAL_END above - or however it is supposed to be...
|
|
if (DoItemEnterZone(EQ::invbag::GENERAL_BAGS_BEGIN, EQ::invbag::GENERAL_BAGS_END)) // (< 341)
|
|
changed = true;
|
|
|
|
if (DoItemEnterZone(EQ::invslot::TRIBUTE_BEGIN, EQ::invslot::TRIBUTE_END)) // (< 405)
|
|
changed = true;
|
|
|
|
if(changed)
|
|
{
|
|
CalcBonuses();
|
|
}
|
|
}
|
|
|
|
bool Client::DoItemEnterZone(uint32 slot_x, uint32 slot_y) {
|
|
// behavior change: 'slot_y' is now [RANGE]_END and not [RANGE]_END + 1
|
|
bool changed = false;
|
|
for(uint32 i = slot_x; i <= slot_y; i++) {
|
|
if (i == EQ::invslot::slotAmmo) // moved here from calling procedure to facilitate future range changes where MainAmmo may not be the last slot
|
|
continue;
|
|
|
|
EQ::ItemInstance* inst = m_inv.GetItem(i);
|
|
|
|
if(!inst)
|
|
continue;
|
|
|
|
// TEST CODE: test for bazaar trader crashing with charm items
|
|
if (IsTrader())
|
|
if (i >= EQ::invbag::GENERAL_BAGS_BEGIN && i <= EQ::invbag::GENERAL_BAGS_END) {
|
|
EQ::ItemInstance* parent_item = m_inv.GetItem(EQ::InventoryProfile::CalcSlotId(i));
|
|
if (parent_item && parent_item->GetItem()->BagType == EQ::item::BagTypeTradersSatchel)
|
|
continue;
|
|
}
|
|
|
|
bool update_slot = false;
|
|
if(inst->IsScaling())
|
|
{
|
|
uint16 oldexp = inst->GetExp();
|
|
|
|
if (parse->ItemHasQuestSub(inst, EVENT_ITEM_ENTER_ZONE)) {
|
|
parse->EventItem(EVENT_ITEM_ENTER_ZONE, this, inst, nullptr, "", 0);
|
|
}
|
|
|
|
if (i <= EQ::invslot::EQUIPMENT_END) {
|
|
if (parse->ItemHasQuestSub(inst, EVENT_EQUIP_ITEM)) {
|
|
parse->EventItem(EVENT_EQUIP_ITEM, this, inst, nullptr, "", i);
|
|
}
|
|
}
|
|
|
|
if (inst->GetExp() != oldexp) { // if the scaling factor changed, rescale the item and update the client
|
|
inst->ScaleItem();
|
|
changed = true;
|
|
update_slot = true;
|
|
}
|
|
} else {
|
|
if (i <= EQ::invslot::EQUIPMENT_END) {
|
|
if (parse->ItemHasQuestSub(inst, EVENT_EQUIP_ITEM)) {
|
|
parse->EventItem(EVENT_EQUIP_ITEM, this, inst, nullptr, "", i);
|
|
}
|
|
}
|
|
|
|
if (parse->ItemHasQuestSub(inst, EVENT_ITEM_ENTER_ZONE)) {
|
|
parse->EventItem(EVENT_ITEM_ENTER_ZONE, this, inst, nullptr, "", 0);
|
|
}
|
|
}
|
|
|
|
//iterate all augments
|
|
for (int x = EQ::invaug::SOCKET_BEGIN; x <= EQ::invaug::SOCKET_END; ++x)
|
|
{
|
|
EQ::ItemInstance *a_inst = inst->GetAugment(x);
|
|
if(!a_inst)
|
|
continue;
|
|
|
|
if(a_inst->IsScaling())
|
|
{
|
|
uint16 oldexp = a_inst->GetExp();
|
|
|
|
if (parse->ItemHasQuestSub(a_inst, EVENT_ITEM_ENTER_ZONE)) {
|
|
parse->EventItem(EVENT_ITEM_ENTER_ZONE, this, a_inst, nullptr, "", 0);
|
|
}
|
|
|
|
if (a_inst->GetExp() != oldexp)
|
|
{
|
|
a_inst->ScaleItem();
|
|
changed = true;
|
|
update_slot = true;
|
|
}
|
|
} else {
|
|
if (parse->ItemHasQuestSub(a_inst, EVENT_ITEM_ENTER_ZONE)) {
|
|
parse->EventItem(EVENT_ITEM_ENTER_ZONE, this, a_inst, nullptr, "", 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
if(update_slot)
|
|
{
|
|
SendItemPacket(i, inst, ItemPacketCharmUpdate);
|
|
}
|
|
}
|
|
return changed;
|
|
}
|
|
|
|
uint8 Mob::IsFocusEffect(uint16 spell_id,int effect_index, bool AA,uint32 aa_effect)
|
|
{
|
|
uint16 effect = 0;
|
|
|
|
if (!AA)
|
|
effect = spells[spell_id].effect_id[effect_index];
|
|
else
|
|
effect = aa_effect;
|
|
|
|
switch (effect)
|
|
{
|
|
case SE_ImprovedDamage:
|
|
return focusImprovedDamage;
|
|
case SE_ImprovedDamage2:
|
|
return focusImprovedDamage2;
|
|
case SE_ImprovedHeal:
|
|
return focusImprovedHeal;
|
|
case SE_ReduceManaCost:
|
|
return focusManaCost;
|
|
case SE_IncreaseSpellHaste:
|
|
return focusSpellHaste;
|
|
case SE_IncreaseSpellDuration:
|
|
return focusSpellDuration;
|
|
case SE_SpellDurationIncByTic:
|
|
return focusSpellDurByTic;
|
|
case SE_SwarmPetDuration:
|
|
return focusSwarmPetDuration;
|
|
case SE_IncreaseRange:
|
|
return focusRange;
|
|
case SE_ReduceReagentCost:
|
|
return focusReagentCost;
|
|
case SE_PetPowerIncrease:
|
|
return focusPetPower;
|
|
case SE_SpellResistReduction:
|
|
return focusResistRate;
|
|
case SE_Fc_ResistIncoming:
|
|
return focusFcResistIncoming;
|
|
case SE_Fc_Amplify_Mod:
|
|
return focusFcAmplifyMod;
|
|
case SE_Fc_Amplify_Amt:
|
|
return focusFcAmplifyAmt;
|
|
case SE_SpellHateMod:
|
|
return focusSpellHateMod;
|
|
case SE_ReduceReuseTimer:
|
|
return focusReduceRecastTime;
|
|
case SE_TriggerOnCast:
|
|
return focusTriggerOnCast;
|
|
case SE_FcSpellVulnerability:
|
|
return focusSpellVulnerability;
|
|
case SE_Fc_Spell_Damage_Pct_IncomingPC:
|
|
return focusFcSpellDamagePctIncomingPC;
|
|
case SE_BlockNextSpellFocus:
|
|
return focusBlockNextSpell;
|
|
case SE_FcTwincast:
|
|
return focusTwincast;
|
|
case SE_SympatheticProc:
|
|
return focusSympatheticProc;
|
|
case SE_FcDamageAmt:
|
|
return focusFcDamageAmt;
|
|
case SE_FcDamageAmt2:
|
|
return focusFcDamageAmt2;
|
|
case SE_FcDamageAmtCrit:
|
|
return focusFcDamageAmtCrit;
|
|
case SE_FcDamagePctCrit:
|
|
return focusFcDamagePctCrit;
|
|
case SE_FcDamageAmtIncoming:
|
|
return focusFcDamageAmtIncoming;
|
|
case SE_Fc_Spell_Damage_Amt_IncomingPC:
|
|
return focusFcSpellDamageAmtIncomingPC;
|
|
case SE_FcHealAmtIncoming:
|
|
return focusFcHealAmtIncoming;
|
|
case SE_FcHealPctIncoming:
|
|
return focusFcHealPctIncoming;
|
|
case SE_FcBaseEffects:
|
|
return focusFcBaseEffects;
|
|
case SE_FcIncreaseNumHits:
|
|
return focusIncreaseNumHits;
|
|
case SE_FcLimitUse:
|
|
return focusFcLimitUse;
|
|
case SE_FcMute:
|
|
return focusFcMute;
|
|
case SE_FcTimerRefresh:
|
|
return focusFcTimerRefresh;
|
|
case SE_FcTimerLockout:
|
|
return focusFcTimerLockout;
|
|
case SE_Fc_Cast_Spell_On_Land:
|
|
return focusFcCastSpellOnLand;
|
|
case SE_FcStunTimeMod:
|
|
return focusFcStunTimeMod;
|
|
case SE_Fc_CastTimeMod2:
|
|
return focusFcCastTimeMod2;
|
|
case SE_Fc_CastTimeAmt:
|
|
return focusFcCastTimeAmt;
|
|
case SE_FcHealPctCritIncoming:
|
|
return focusFcHealPctCritIncoming;
|
|
case SE_FcHealAmt:
|
|
return focusFcHealAmt;
|
|
case SE_FcHealAmtCrit:
|
|
return focusFcHealAmtCrit;
|
|
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void Mob::NegateSpellEffectBonuses(uint16 spell_id)
|
|
{
|
|
if (!IsValidSpell(spell_id))
|
|
return;
|
|
|
|
int effect_value = 0;
|
|
|
|
for (int i = 0; i < EFFECT_COUNT; i++)
|
|
{
|
|
bool negate_spellbonus = false;
|
|
bool negate_aabonus = false;
|
|
bool negate_itembonus = false;
|
|
|
|
if (spells[spell_id].effect_id[i] == SE_NegateSpellEffect) {
|
|
|
|
//Set negate types
|
|
switch (spells[spell_id].base_value[i])
|
|
{
|
|
case NEGATE_SPA_ALL_BONUSES:
|
|
negate_spellbonus = true;
|
|
negate_aabonus = true;
|
|
negate_itembonus = true;
|
|
break;
|
|
|
|
case NEGATE_SPA_SPELLBONUS:
|
|
negate_spellbonus = true;
|
|
break;
|
|
|
|
case NEGATE_SPA_ITEMBONUS:
|
|
negate_itembonus = true;
|
|
break;
|
|
|
|
case NEGATE_SPA_AABONUS:
|
|
negate_aabonus = true;
|
|
break;
|
|
|
|
case NEGATE_SPA_ITEMBONUS_AND_AABONUS:
|
|
negate_aabonus = true;
|
|
negate_itembonus = true;
|
|
break;
|
|
|
|
case NEGATE_SPA_SPELLBONUS_AND_AABONUS:
|
|
negate_aabonus = true;
|
|
negate_spellbonus = true;
|
|
break;
|
|
|
|
case NEGATE_SPA_SPELLBONUS_AND_ITEMBONUS:
|
|
negate_spellbonus = true;
|
|
negate_itembonus = true;
|
|
break;
|
|
}
|
|
|
|
//Negate focus effects
|
|
for (int e = 0; e < HIGHEST_FOCUS + 1; e++)
|
|
{
|
|
if (spellbonuses.FocusEffects[e] == spells[spell_id].limit_value[i])
|
|
{
|
|
if (negate_spellbonus) { spellbonuses.FocusEffects[e] = effect_value; }
|
|
continue;
|
|
}
|
|
}
|
|
|
|
//Negate bonuses
|
|
switch (spells[spell_id].limit_value[i])
|
|
{
|
|
case SE_CurrentHP:
|
|
if (negate_spellbonus) { spellbonuses.HPRegen = effect_value; }
|
|
if (negate_aabonus) { aabonuses.HPRegen = effect_value; }
|
|
if (negate_itembonus) { itembonuses.HPRegen = effect_value; }
|
|
break;
|
|
|
|
case SE_CurrentEndurance:
|
|
if (negate_spellbonus) { spellbonuses.EnduranceRegen = effect_value; }
|
|
if (negate_aabonus) { aabonuses.EnduranceRegen = effect_value; }
|
|
if (negate_itembonus) { itembonuses.EnduranceRegen = effect_value; }
|
|
break;
|
|
|
|
case SE_ChangeFrenzyRad:
|
|
if (negate_spellbonus) { spellbonuses.AggroRange = static_cast<float>(effect_value); }
|
|
if (negate_aabonus) { aabonuses.AggroRange = static_cast<float>(effect_value); }
|
|
if (negate_itembonus) { itembonuses.AggroRange = static_cast<float>(effect_value); }
|
|
break;
|
|
|
|
case SE_Harmony:
|
|
if (negate_spellbonus) { spellbonuses.AssistRange = static_cast<float>(effect_value); }
|
|
if (negate_aabonus) { aabonuses.AssistRange = static_cast<float>(effect_value); }
|
|
if (negate_itembonus) { itembonuses.AssistRange = static_cast<float>(effect_value); }
|
|
break;
|
|
|
|
case SE_AttackSpeed:
|
|
if (negate_spellbonus) { spellbonuses.haste = effect_value; }
|
|
if (negate_aabonus) { aabonuses.haste = effect_value; }
|
|
if (negate_itembonus) { itembonuses.haste = effect_value; }
|
|
break;
|
|
|
|
case SE_AttackSpeed2:
|
|
if (negate_spellbonus) { spellbonuses.hastetype2 = effect_value; }
|
|
if (negate_aabonus) { aabonuses.hastetype2 = effect_value; }
|
|
if (negate_itembonus) { itembonuses.hastetype2 = effect_value; }
|
|
break;
|
|
|
|
case SE_AttackSpeed3:
|
|
{
|
|
if (negate_spellbonus) { spellbonuses.hastetype3 = effect_value; }
|
|
if (negate_aabonus) { aabonuses.hastetype3 = effect_value; }
|
|
if (negate_itembonus) { itembonuses.hastetype3 = effect_value; }
|
|
break;
|
|
}
|
|
|
|
case SE_AttackSpeed4:
|
|
if (negate_spellbonus) { spellbonuses.inhibitmelee = effect_value; }
|
|
if (negate_aabonus) { aabonuses.inhibitmelee = effect_value; }
|
|
if (negate_itembonus) { itembonuses.inhibitmelee = effect_value; }
|
|
break;
|
|
|
|
case SE_IncreaseArchery:
|
|
if (negate_spellbonus) { spellbonuses.increase_archery = effect_value; }
|
|
if (negate_aabonus) { aabonuses.increase_archery = effect_value; }
|
|
if (negate_itembonus) { itembonuses.increase_archery = effect_value; }
|
|
break;
|
|
|
|
case SE_TotalHP:
|
|
if (negate_spellbonus) { spellbonuses.FlatMaxHPChange = effect_value; }
|
|
if (negate_aabonus) { aabonuses.FlatMaxHPChange = effect_value; }
|
|
if (negate_itembonus) { itembonuses.FlatMaxHPChange = effect_value; }
|
|
break;
|
|
|
|
case SE_ManaRegen_v2:
|
|
case SE_CurrentMana:
|
|
if (negate_spellbonus) { spellbonuses.ManaRegen = effect_value; }
|
|
if (negate_aabonus) { aabonuses.ManaRegen = effect_value; }
|
|
if (negate_itembonus) { itembonuses.ManaRegen = effect_value; }
|
|
break;
|
|
|
|
case SE_ManaPool:
|
|
if (negate_spellbonus) { spellbonuses.Mana = effect_value; }
|
|
if (negate_itembonus) { itembonuses.Mana = effect_value; }
|
|
if (negate_aabonus) { aabonuses.Mana = effect_value; }
|
|
break;
|
|
|
|
case SE_Stamina:
|
|
if (negate_spellbonus) { spellbonuses.EnduranceReduction = effect_value; }
|
|
if (negate_itembonus) { itembonuses.EnduranceReduction = effect_value; }
|
|
if (negate_aabonus) { aabonuses.EnduranceReduction = effect_value; }
|
|
break;
|
|
|
|
case SE_ACv2:
|
|
case SE_ArmorClass:
|
|
if (negate_spellbonus) { spellbonuses.AC = effect_value; }
|
|
if (negate_aabonus) { aabonuses.AC = effect_value; }
|
|
if (negate_itembonus) { itembonuses.AC = effect_value; }
|
|
break;
|
|
|
|
case SE_ATK:
|
|
if (negate_spellbonus) { spellbonuses.ATK = effect_value; }
|
|
if (negate_aabonus) { aabonuses.ATK = effect_value; }
|
|
if (negate_itembonus) { itembonuses.ATK = effect_value; }
|
|
break;
|
|
|
|
case SE_STR:
|
|
if (negate_spellbonus) { spellbonuses.STR = effect_value; }
|
|
if (negate_itembonus) { itembonuses.STR = effect_value; }
|
|
if (negate_aabonus) { aabonuses.STR = effect_value; }
|
|
break;
|
|
|
|
case SE_DEX:
|
|
if (negate_spellbonus) { spellbonuses.DEX = effect_value; }
|
|
if (negate_aabonus) { aabonuses.DEX = effect_value; }
|
|
if (negate_itembonus) { itembonuses.DEX = effect_value; }
|
|
break;
|
|
|
|
case SE_AGI:
|
|
if (negate_itembonus) { itembonuses.AGI = effect_value; }
|
|
if (negate_aabonus) { aabonuses.AGI = effect_value; }
|
|
if (negate_spellbonus) { spellbonuses.AGI = effect_value; }
|
|
break;
|
|
|
|
case SE_STA:
|
|
if (negate_spellbonus) { spellbonuses.STA = effect_value; }
|
|
if (negate_itembonus) { itembonuses.STA = effect_value; }
|
|
if (negate_aabonus) { aabonuses.STA = effect_value; }
|
|
break;
|
|
|
|
case SE_INT:
|
|
if (negate_spellbonus) { spellbonuses.INT = effect_value; }
|
|
if (negate_aabonus) { aabonuses.INT = effect_value; }
|
|
if (negate_itembonus) { itembonuses.INT = effect_value; }
|
|
break;
|
|
|
|
case SE_WIS:
|
|
if (negate_spellbonus) { spellbonuses.WIS = effect_value; }
|
|
if (negate_aabonus) { aabonuses.WIS = effect_value; }
|
|
if (negate_itembonus) { itembonuses.WIS = effect_value; }
|
|
break;
|
|
|
|
case SE_CHA:
|
|
if (negate_itembonus) { itembonuses.CHA = effect_value; }
|
|
if (negate_spellbonus) { spellbonuses.CHA = effect_value; }
|
|
if (negate_aabonus) { aabonuses.CHA = effect_value; }
|
|
break;
|
|
|
|
case SE_AllStats:
|
|
{
|
|
if (negate_spellbonus) {
|
|
spellbonuses.STR = effect_value;
|
|
spellbonuses.DEX = effect_value;
|
|
spellbonuses.AGI = effect_value;
|
|
spellbonuses.STA = effect_value;
|
|
spellbonuses.INT = effect_value;
|
|
spellbonuses.WIS = effect_value;
|
|
spellbonuses.CHA = effect_value;
|
|
}
|
|
|
|
if (negate_itembonus) {
|
|
itembonuses.STR = effect_value;
|
|
itembonuses.DEX = effect_value;
|
|
itembonuses.AGI = effect_value;
|
|
itembonuses.STA = effect_value;
|
|
itembonuses.INT = effect_value;
|
|
itembonuses.WIS = effect_value;
|
|
itembonuses.CHA = effect_value;
|
|
}
|
|
|
|
if (negate_aabonus) {
|
|
aabonuses.STR = effect_value;
|
|
aabonuses.DEX = effect_value;
|
|
aabonuses.AGI = effect_value;
|
|
aabonuses.STA = effect_value;
|
|
aabonuses.INT = effect_value;
|
|
aabonuses.WIS = effect_value;
|
|
aabonuses.CHA = effect_value;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case SE_ResistFire:
|
|
if (negate_spellbonus) { spellbonuses.FR = effect_value; }
|
|
if (negate_itembonus) { itembonuses.FR = effect_value; }
|
|
if (negate_aabonus) { aabonuses.FR = effect_value; }
|
|
break;
|
|
|
|
case SE_ResistCold:
|
|
if (negate_spellbonus) { spellbonuses.CR = effect_value; }
|
|
if (negate_aabonus) { aabonuses.CR = effect_value; }
|
|
if (negate_itembonus) { itembonuses.CR = effect_value; }
|
|
break;
|
|
|
|
case SE_ResistPoison:
|
|
if (negate_spellbonus) { spellbonuses.PR = effect_value; }
|
|
if (negate_aabonus) { aabonuses.PR = effect_value; }
|
|
if (negate_itembonus) { itembonuses.PR = effect_value; }
|
|
break;
|
|
|
|
case SE_ResistDisease:
|
|
if (negate_spellbonus) { spellbonuses.DR = effect_value; }
|
|
if (negate_itembonus) { itembonuses.DR = effect_value; }
|
|
if (negate_aabonus) { aabonuses.DR = effect_value; }
|
|
break;
|
|
|
|
case SE_ResistMagic:
|
|
if (negate_spellbonus) { spellbonuses.MR = effect_value; }
|
|
if (negate_aabonus) { aabonuses.MR = effect_value; }
|
|
if (negate_itembonus) { itembonuses.MR = effect_value; }
|
|
break;
|
|
|
|
case SE_ResistAll:
|
|
{
|
|
if (negate_spellbonus) {
|
|
spellbonuses.MR = effect_value;
|
|
spellbonuses.DR = effect_value;
|
|
spellbonuses.PR = effect_value;
|
|
spellbonuses.CR = effect_value;
|
|
spellbonuses.FR = effect_value;
|
|
}
|
|
|
|
if (negate_aabonus) {
|
|
aabonuses.MR = effect_value;
|
|
aabonuses.DR = effect_value;
|
|
aabonuses.PR = effect_value;
|
|
aabonuses.CR = effect_value;
|
|
aabonuses.FR = effect_value;
|
|
}
|
|
|
|
if (negate_itembonus) {
|
|
itembonuses.MR = effect_value;
|
|
itembonuses.DR = effect_value;
|
|
itembonuses.PR = effect_value;
|
|
itembonuses.CR = effect_value;
|
|
itembonuses.FR = effect_value;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case SE_ResistCorruption:
|
|
if (negate_spellbonus) { spellbonuses.Corrup = effect_value; }
|
|
if (negate_itembonus) { itembonuses.Corrup = effect_value; }
|
|
if (negate_aabonus) { aabonuses.Corrup = effect_value; }
|
|
break;
|
|
|
|
case SE_CastingLevel: // Brilliance of Ro
|
|
if (negate_spellbonus) { spellbonuses.adjusted_casting_skill = effect_value; }
|
|
if (negate_aabonus) { aabonuses.adjusted_casting_skill = effect_value; }
|
|
if (negate_itembonus) { itembonuses.adjusted_casting_skill = effect_value; }
|
|
break;
|
|
|
|
case SE_CastingLevel2:
|
|
if (negate_spellbonus) { spellbonuses.effective_casting_level = effect_value; }
|
|
if (negate_aabonus) { aabonuses.effective_casting_level = effect_value; }
|
|
if (negate_itembonus) { itembonuses.effective_casting_level = effect_value; }
|
|
break;
|
|
|
|
|
|
case SE_MovementSpeed:
|
|
if (negate_spellbonus) { spellbonuses.movementspeed = effect_value; }
|
|
if (negate_aabonus) { aabonuses.movementspeed = effect_value; }
|
|
if (negate_itembonus) { itembonuses.movementspeed = effect_value; }
|
|
break;
|
|
|
|
case SE_SpellDamageShield:
|
|
if (negate_spellbonus) { spellbonuses.SpellDamageShield = effect_value; }
|
|
if (negate_aabonus) { aabonuses.SpellDamageShield = effect_value; }
|
|
if (negate_itembonus) { itembonuses.SpellDamageShield = effect_value; }
|
|
break;
|
|
|
|
case SE_DamageShield:
|
|
if (negate_spellbonus) { spellbonuses.DamageShield = effect_value; }
|
|
if (negate_aabonus) { aabonuses.DamageShield = effect_value; }
|
|
if (negate_itembonus) { itembonuses.DamageShield = effect_value; }
|
|
break;
|
|
|
|
case SE_ReverseDS:
|
|
if (negate_spellbonus) { spellbonuses.ReverseDamageShield = effect_value; }
|
|
if (negate_aabonus) { aabonuses.ReverseDamageShield = effect_value; }
|
|
if (negate_itembonus) { itembonuses.ReverseDamageShield = effect_value; }
|
|
break;
|
|
|
|
case SE_Reflect:
|
|
if (negate_spellbonus) { spellbonuses.reflect[SBIndex::REFLECT_CHANCE] = effect_value; }
|
|
if (negate_aabonus) { aabonuses.reflect[SBIndex::REFLECT_CHANCE] = effect_value; }
|
|
if (negate_itembonus) { itembonuses.reflect[SBIndex::REFLECT_CHANCE] = effect_value; }
|
|
break;
|
|
|
|
case SE_Amplification:
|
|
if (negate_spellbonus) { spellbonuses.Amplification = effect_value; }
|
|
if (negate_itembonus) { itembonuses.Amplification = effect_value; }
|
|
if (negate_aabonus) { aabonuses.Amplification = effect_value; }
|
|
break;
|
|
|
|
case SE_ChangeAggro:
|
|
if (negate_spellbonus) { spellbonuses.hatemod = effect_value; }
|
|
if (negate_itembonus) { itembonuses.hatemod = effect_value; }
|
|
if (negate_aabonus) { aabonuses.hatemod = effect_value; }
|
|
break;
|
|
|
|
case SE_MeleeMitigation:
|
|
if (negate_spellbonus) { spellbonuses.MeleeMitigationEffect = effect_value; }
|
|
if (negate_itembonus) { itembonuses.MeleeMitigationEffect = effect_value; }
|
|
if (negate_aabonus) { aabonuses.MeleeMitigationEffect = effect_value; }
|
|
break;
|
|
|
|
case SE_CriticalHitChance:
|
|
{
|
|
for (int e = 0; e < EQ::skills::HIGHEST_SKILL + 1; e++)
|
|
{
|
|
if (negate_spellbonus) { spellbonuses.CriticalHitChance[e] = effect_value; }
|
|
if (negate_aabonus) { aabonuses.CriticalHitChance[e] = effect_value; }
|
|
if (negate_itembonus) { itembonuses.CriticalHitChance[e] = effect_value; }
|
|
}
|
|
}
|
|
|
|
case SE_CrippBlowChance:
|
|
if (negate_spellbonus) { spellbonuses.CrippBlowChance = effect_value; }
|
|
if (negate_aabonus) { aabonuses.CrippBlowChance = effect_value; }
|
|
if (negate_itembonus) { itembonuses.CrippBlowChance = effect_value; }
|
|
break;
|
|
|
|
case SE_AvoidMeleeChance:
|
|
if (negate_spellbonus) { spellbonuses.AvoidMeleeChanceEffect = effect_value; }
|
|
if (negate_aabonus) { aabonuses.AvoidMeleeChanceEffect = effect_value; }
|
|
if (negate_itembonus) { itembonuses.AvoidMeleeChanceEffect = effect_value; }
|
|
break;
|
|
|
|
case SE_RiposteChance:
|
|
if (negate_spellbonus) { spellbonuses.RiposteChance = effect_value; }
|
|
if (negate_aabonus) { aabonuses.RiposteChance = effect_value; }
|
|
if (negate_itembonus) { itembonuses.RiposteChance = effect_value; }
|
|
break;
|
|
|
|
case SE_DodgeChance:
|
|
if (negate_spellbonus) { spellbonuses.DodgeChance = effect_value; }
|
|
if (negate_aabonus) { aabonuses.DodgeChance = effect_value; }
|
|
if (negate_itembonus) { itembonuses.DodgeChance = effect_value; }
|
|
break;
|
|
|
|
case SE_ParryChance:
|
|
if (negate_spellbonus) { spellbonuses.ParryChance = effect_value; }
|
|
if (negate_aabonus) { aabonuses.ParryChance = effect_value; }
|
|
if (negate_itembonus) { itembonuses.ParryChance = effect_value; }
|
|
break;
|
|
|
|
case SE_DualWieldChance:
|
|
if (negate_spellbonus) { spellbonuses.DualWieldChance = effect_value; }
|
|
if (negate_aabonus) { aabonuses.DualWieldChance = effect_value; }
|
|
if (negate_itembonus) { itembonuses.DualWieldChance = effect_value; }
|
|
break;
|
|
|
|
case SE_DoubleAttackChance:
|
|
if (negate_spellbonus) { spellbonuses.DoubleAttackChance = effect_value; }
|
|
if (negate_aabonus) { aabonuses.DoubleAttackChance = effect_value; }
|
|
if (negate_itembonus) { itembonuses.DoubleAttackChance = effect_value; }
|
|
break;
|
|
|
|
case SE_TripleAttackChance:
|
|
if (negate_spellbonus) { spellbonuses.TripleAttackChance = effect_value; }
|
|
if (negate_aabonus) { aabonuses.TripleAttackChance = effect_value; }
|
|
if (negate_itembonus) { itembonuses.TripleAttackChance = effect_value; }
|
|
break;
|
|
|
|
case SE_MeleeLifetap:
|
|
if (negate_spellbonus) { spellbonuses.MeleeLifetap = effect_value; }
|
|
if (negate_aabonus) { aabonuses.MeleeLifetap = effect_value; }
|
|
if (negate_itembonus) { itembonuses.MeleeLifetap = effect_value; }
|
|
break;
|
|
|
|
case SE_AllInstrumentMod:
|
|
{
|
|
if (negate_spellbonus) {
|
|
spellbonuses.singingMod = effect_value;
|
|
spellbonuses.brassMod = effect_value;
|
|
spellbonuses.percussionMod = effect_value;
|
|
spellbonuses.windMod = effect_value;
|
|
spellbonuses.stringedMod = effect_value;
|
|
}
|
|
|
|
if (negate_itembonus) {
|
|
itembonuses.singingMod = effect_value;
|
|
itembonuses.brassMod = effect_value;
|
|
itembonuses.percussionMod = effect_value;
|
|
itembonuses.windMod = effect_value;
|
|
itembonuses.stringedMod = effect_value;
|
|
}
|
|
|
|
if (negate_aabonus) {
|
|
aabonuses.singingMod = effect_value;
|
|
aabonuses.brassMod = effect_value;
|
|
aabonuses.percussionMod = effect_value;
|
|
aabonuses.windMod = effect_value;
|
|
aabonuses.stringedMod = effect_value;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_ResistSpellChance:
|
|
if (negate_spellbonus) { spellbonuses.ResistSpellChance = effect_value; }
|
|
if (negate_aabonus) { aabonuses.ResistSpellChance = effect_value; }
|
|
if (negate_itembonus) { itembonuses.ResistSpellChance = effect_value; }
|
|
break;
|
|
|
|
case SE_ResistFearChance:
|
|
if (negate_spellbonus) {spellbonuses.ResistFearChance = effect_value; }
|
|
if (negate_aabonus) { aabonuses.ResistFearChance = effect_value; }
|
|
if (negate_itembonus) { itembonuses.ResistFearChance = effect_value; }
|
|
break;
|
|
|
|
case SE_Fearless:
|
|
if (negate_spellbonus) { spellbonuses.Fearless = false; }
|
|
if (negate_aabonus) { aabonuses.Fearless = false; }
|
|
if (negate_itembonus) { itembonuses.Fearless = false; }
|
|
break;
|
|
|
|
case SE_HundredHands:
|
|
if (negate_spellbonus) { spellbonuses.HundredHands = effect_value; }
|
|
if (negate_aabonus) { aabonuses.HundredHands = effect_value; }
|
|
if (negate_itembonus) { itembonuses.HundredHands = effect_value; }
|
|
break;
|
|
|
|
case SE_MeleeSkillCheck:
|
|
{
|
|
if (negate_spellbonus) { spellbonuses.MeleeSkillCheck = effect_value; }
|
|
if (negate_spellbonus) { spellbonuses.MeleeSkillCheckSkill = effect_value; }
|
|
break;
|
|
}
|
|
|
|
case SE_HitChance:
|
|
{
|
|
for (int e = 0; e < EQ::skills::HIGHEST_SKILL + 1; e++)
|
|
{
|
|
if (negate_spellbonus) { spellbonuses.HitChanceEffect[e] = effect_value; }
|
|
if (negate_aabonus) { aabonuses.HitChanceEffect[e] = effect_value; }
|
|
if (negate_itembonus) { itembonuses.HitChanceEffect[e] = effect_value; }
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_DamageModifier:
|
|
{
|
|
for (int e = 0; e < EQ::skills::HIGHEST_SKILL + 1; e++)
|
|
{
|
|
if (negate_spellbonus) { spellbonuses.DamageModifier[e] = effect_value; }
|
|
if (negate_aabonus) { aabonuses.DamageModifier[e] = effect_value; }
|
|
if (negate_itembonus) { itembonuses.DamageModifier[e] = effect_value; }
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_DamageModifier2:
|
|
{
|
|
for (int e = 0; e < EQ::skills::HIGHEST_SKILL + 1; e++)
|
|
{
|
|
if (negate_spellbonus) { spellbonuses.DamageModifier2[e] = effect_value; }
|
|
if (negate_aabonus) { aabonuses.DamageModifier2[e] = effect_value; }
|
|
if (negate_itembonus) { itembonuses.DamageModifier2[e] = effect_value; }
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_Skill_Base_Damage_Mod:
|
|
{
|
|
for (int e = 0; e < EQ::skills::HIGHEST_SKILL + 1; e++)
|
|
{
|
|
if (negate_spellbonus) { spellbonuses.DamageModifier3[e] = effect_value; }
|
|
if (negate_aabonus) { aabonuses.DamageModifier3[e] = effect_value; }
|
|
if (negate_itembonus) { itembonuses.DamageModifier3[e] = effect_value; }
|
|
}
|
|
break;
|
|
}
|
|
|
|
|
|
case SE_MinDamageModifier:
|
|
{
|
|
for (int e = 0; e < EQ::skills::HIGHEST_SKILL + 1; e++)
|
|
{
|
|
if (negate_spellbonus) { spellbonuses.MinDamageModifier[e] = effect_value; }
|
|
if (negate_aabonus) { aabonuses.MinDamageModifier[e] = effect_value; }
|
|
if (negate_itembonus) { itembonuses.MinDamageModifier[e] = effect_value; }
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_StunResist:
|
|
if (negate_spellbonus) { spellbonuses.StunResist = effect_value; }
|
|
if (negate_aabonus) { aabonuses.StunResist = effect_value; }
|
|
if (negate_itembonus) { itembonuses.StunResist = effect_value; }
|
|
break;
|
|
|
|
case SE_ProcChance:
|
|
if (negate_spellbonus) { spellbonuses.ProcChanceSPA = effect_value; }
|
|
if (negate_aabonus) { aabonuses.ProcChanceSPA = effect_value; }
|
|
if (negate_itembonus) { itembonuses.ProcChanceSPA = effect_value; }
|
|
break;
|
|
|
|
case SE_ExtraAttackChance:
|
|
if (negate_spellbonus) { spellbonuses.ExtraAttackChance[SBIndex::EXTRA_ATTACK_CHANCE] = effect_value; }
|
|
if (negate_aabonus) { aabonuses.ExtraAttackChance[SBIndex::EXTRA_ATTACK_CHANCE] = effect_value; }
|
|
if (negate_itembonus) { itembonuses.ExtraAttackChance[SBIndex::EXTRA_ATTACK_CHANCE] = effect_value; }
|
|
break;
|
|
|
|
case SE_AddExtraAttackPct_1h_Primary:
|
|
if (negate_spellbonus) { spellbonuses.ExtraAttackChancePrimary[SBIndex::EXTRA_ATTACK_CHANCE] = effect_value; }
|
|
if (negate_aabonus) { aabonuses.ExtraAttackChancePrimary[SBIndex::EXTRA_ATTACK_CHANCE] = effect_value; }
|
|
if (negate_itembonus) { itembonuses.ExtraAttackChancePrimary[SBIndex::EXTRA_ATTACK_CHANCE] = effect_value; }
|
|
break;
|
|
|
|
case SE_AddExtraAttackPct_1h_Secondary:
|
|
if (negate_spellbonus) { spellbonuses.ExtraAttackChanceSecondary[SBIndex::EXTRA_ATTACK_CHANCE] = effect_value; }
|
|
if (negate_aabonus) { aabonuses.ExtraAttackChanceSecondary[SBIndex::EXTRA_ATTACK_CHANCE] = effect_value; }
|
|
if (negate_itembonus) { itembonuses.ExtraAttackChanceSecondary[SBIndex::EXTRA_ATTACK_CHANCE] = effect_value; }
|
|
break;
|
|
|
|
case SE_Double_Melee_Round:
|
|
if (negate_spellbonus) { spellbonuses.DoubleMeleeRound[SBIndex::DOUBLE_MELEE_ROUND_CHANCE] = effect_value; }
|
|
if (negate_aabonus) { aabonuses.DoubleMeleeRound[SBIndex::DOUBLE_MELEE_ROUND_CHANCE] = effect_value; }
|
|
if (negate_itembonus) { itembonuses.DoubleMeleeRound[SBIndex::DOUBLE_MELEE_ROUND_CHANCE] = effect_value; }
|
|
break;
|
|
|
|
case SE_PercentXPIncrease:
|
|
if (negate_spellbonus) { spellbonuses.XPRateMod = effect_value; }
|
|
if (negate_aabonus) { aabonuses.XPRateMod = effect_value; }
|
|
if (negate_itembonus) { itembonuses.XPRateMod = effect_value; }
|
|
break;
|
|
|
|
case SE_Flurry:
|
|
if (negate_spellbonus) { spellbonuses.FlurryChance = effect_value; }
|
|
if (negate_aabonus) { aabonuses.FlurryChance = effect_value; }
|
|
if (negate_itembonus) { itembonuses.FlurryChance = effect_value; }
|
|
break;
|
|
|
|
case SE_Accuracy:
|
|
{
|
|
if (negate_spellbonus) { spellbonuses.Accuracy[EQ::skills::HIGHEST_SKILL + 1] = effect_value; }
|
|
if (negate_itembonus) { itembonuses.Accuracy[EQ::skills::HIGHEST_SKILL + 1] = effect_value; }
|
|
|
|
for (int e = 0; e < EQ::skills::HIGHEST_SKILL + 1; e++)
|
|
{
|
|
if (negate_aabonus) { aabonuses.Accuracy[e] = effect_value; }
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_MaxHPChange:
|
|
if (negate_spellbonus) { spellbonuses.PercentMaxHPChange = effect_value; }
|
|
if (negate_aabonus) { aabonuses.PercentMaxHPChange = effect_value; }
|
|
if (negate_itembonus) { itembonuses.PercentMaxHPChange = effect_value; }
|
|
break;
|
|
|
|
case SE_EndurancePool:
|
|
if (negate_spellbonus) { spellbonuses.Endurance = effect_value; }
|
|
if (negate_aabonus) { aabonuses.Endurance = effect_value; }
|
|
if (negate_itembonus) { itembonuses.Endurance = effect_value; }
|
|
break;
|
|
|
|
case SE_HealRate:
|
|
if (negate_spellbonus) { spellbonuses.HealRate = effect_value; }
|
|
if (negate_aabonus) { aabonuses.HealRate = effect_value; }
|
|
if (negate_itembonus) { itembonuses.HealRate = effect_value; }
|
|
break;
|
|
|
|
case SE_SkillDamageTaken:
|
|
{
|
|
for (int e = 0; e < EQ::skills::HIGHEST_SKILL + 1; e++)
|
|
{
|
|
if (negate_spellbonus) { spellbonuses.SkillDmgTaken[e] = effect_value; }
|
|
if (negate_aabonus) { aabonuses.SkillDmgTaken[e] = effect_value; }
|
|
if (negate_itembonus) { itembonuses.SkillDmgTaken[e] = effect_value; }
|
|
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_SpellCritChance:
|
|
if (negate_spellbonus) { spellbonuses.CriticalSpellChance = effect_value; }
|
|
if (negate_aabonus) { aabonuses.CriticalSpellChance = effect_value; }
|
|
if (negate_itembonus) { itembonuses.CriticalSpellChance = effect_value; }
|
|
break;
|
|
|
|
case SE_CriticalSpellChance:
|
|
if (negate_spellbonus) {
|
|
spellbonuses.CriticalSpellChance = effect_value;
|
|
spellbonuses.SpellCritDmgIncrease = effect_value;
|
|
}
|
|
|
|
if (negate_aabonus) {
|
|
aabonuses.CriticalSpellChance = effect_value;
|
|
aabonuses.SpellCritDmgIncrease = effect_value;
|
|
}
|
|
|
|
if (negate_itembonus) {
|
|
itembonuses.CriticalSpellChance = effect_value;
|
|
itembonuses.SpellCritDmgIncrease = effect_value;
|
|
}
|
|
|
|
break;
|
|
|
|
case SE_SpellCritDmgIncrease:
|
|
if (negate_spellbonus) { spellbonuses.SpellCritDmgIncrease = effect_value; }
|
|
if (negate_aabonus) { aabonuses.SpellCritDmgIncrease = effect_value; }
|
|
if (negate_itembonus) { itembonuses.SpellCritDmgIncrease = effect_value; }
|
|
break;
|
|
|
|
case SE_DotCritDmgIncrease:
|
|
if (negate_spellbonus) { spellbonuses.DotCritDmgIncrease = effect_value; }
|
|
if (negate_aabonus) { aabonuses.DotCritDmgIncrease = effect_value; }
|
|
if (negate_itembonus) { itembonuses.DotCritDmgIncrease = effect_value; }
|
|
break;
|
|
|
|
case SE_CriticalHealChance:
|
|
if (negate_spellbonus) { spellbonuses.CriticalHealChance = effect_value; }
|
|
if (negate_aabonus) { aabonuses.CriticalHealChance = effect_value; }
|
|
if (negate_itembonus) { itembonuses.CriticalHealChance = effect_value; }
|
|
break;
|
|
|
|
case SE_CriticalHealOverTime:
|
|
if (negate_spellbonus) { spellbonuses.CriticalHealOverTime = effect_value; }
|
|
if (negate_aabonus) { aabonuses.CriticalHealOverTime = effect_value; }
|
|
if (negate_itembonus) { itembonuses.CriticalHealOverTime = effect_value; }
|
|
break;
|
|
|
|
case SE_MitigateDamageShield:
|
|
if (negate_spellbonus) { spellbonuses.DSMitigationOffHand = effect_value; }
|
|
if (negate_itembonus) { itembonuses.DSMitigationOffHand = effect_value; }
|
|
if (negate_aabonus) { aabonuses.DSMitigationOffHand = effect_value; }
|
|
break;
|
|
|
|
case SE_CriticalDoTChance:
|
|
if (negate_spellbonus) { spellbonuses.CriticalDoTChance = effect_value; }
|
|
if (negate_aabonus) { aabonuses.CriticalDoTChance = effect_value; }
|
|
if (negate_itembonus) { itembonuses.CriticalDoTChance = effect_value; }
|
|
break;
|
|
|
|
case SE_ProcOnKillShot:
|
|
{
|
|
for (int e = 0; e < MAX_SPELL_TRIGGER * 3; e += 3)
|
|
{
|
|
if (negate_spellbonus) {
|
|
spellbonuses.SpellOnKill[e] = effect_value;
|
|
spellbonuses.SpellOnKill[e + 1] = effect_value;
|
|
spellbonuses.SpellOnKill[e + 2] = effect_value;
|
|
}
|
|
|
|
if (negate_aabonus) {
|
|
aabonuses.SpellOnKill[e] = effect_value;
|
|
aabonuses.SpellOnKill[e + 1] = effect_value;
|
|
aabonuses.SpellOnKill[e + 2] = effect_value;
|
|
}
|
|
|
|
if (negate_itembonus) {
|
|
itembonuses.SpellOnKill[e] = effect_value;
|
|
itembonuses.SpellOnKill[e + 1] = effect_value;
|
|
itembonuses.SpellOnKill[e + 2] = effect_value;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
/*
|
|
case SE_SpellOnDeath:
|
|
{
|
|
for(int e = 0; e < MAX_SPELL_TRIGGER; e=2)
|
|
{
|
|
if (negate_spellbonus) { spellbonuses.SpellOnDeath[e] = SPELL_UNKNOWN;
|
|
if (negate_spellbonus) { spellbonuses.SpellOnDeath[e+1] = effect_value; }
|
|
}
|
|
break;
|
|
}
|
|
*/
|
|
|
|
case SE_CriticalDamageMob:
|
|
{
|
|
for (int e = 0; e < EQ::skills::HIGHEST_SKILL + 1; e++)
|
|
{
|
|
if (negate_spellbonus) { spellbonuses.CritDmgMod[e] = effect_value; }
|
|
if (negate_aabonus) { aabonuses.CritDmgMod[e] = effect_value; }
|
|
if (negate_itembonus) { itembonuses.CritDmgMod[e] = effect_value; }
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_Critical_Melee_Damage_Mod_Max:
|
|
{
|
|
for (int e = 0; e < EQ::skills::HIGHEST_SKILL + 1; e++)
|
|
{
|
|
if (negate_spellbonus) { spellbonuses.CritDmgModNoStack[e] = effect_value; }
|
|
if (negate_aabonus) { aabonuses.CritDmgModNoStack[e] = effect_value; }
|
|
if (negate_itembonus) { itembonuses.CritDmgModNoStack[e] = effect_value; }
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_SkillDamageAmount:
|
|
{
|
|
for (int e = 0; e < EQ::skills::HIGHEST_SKILL + 1; e++)
|
|
{
|
|
if (negate_spellbonus) { spellbonuses.SkillDamageAmount[e] = effect_value; }
|
|
if (negate_aabonus) { aabonuses.SkillDamageAmount[e] = effect_value; }
|
|
if (negate_itembonus) { itembonuses.SkillDamageAmount[e] = effect_value; }
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_IncreaseBlockChance:
|
|
if (negate_spellbonus) { spellbonuses.IncreaseBlockChance = effect_value; }
|
|
if (negate_aabonus) { aabonuses.IncreaseBlockChance = effect_value; }
|
|
if (negate_itembonus) { itembonuses.IncreaseBlockChance = effect_value; }
|
|
break;
|
|
|
|
case SE_PersistantCasting:
|
|
if (negate_spellbonus) { spellbonuses.PersistantCasting = effect_value; }
|
|
if (negate_itembonus) { itembonuses.PersistantCasting = effect_value; }
|
|
if (negate_aabonus) { aabonuses.PersistantCasting = effect_value; }
|
|
break;
|
|
|
|
case SE_ImmuneFleeing:
|
|
if (negate_spellbonus) { spellbonuses.ImmuneToFlee = false; }
|
|
break;
|
|
|
|
case SE_DelayDeath:
|
|
if (negate_spellbonus) { spellbonuses.DelayDeath = effect_value; }
|
|
if (negate_aabonus) { aabonuses.DelayDeath = effect_value; }
|
|
if (negate_itembonus) { itembonuses.DelayDeath = effect_value; }
|
|
break;
|
|
|
|
case SE_SpellProcChance:
|
|
if (negate_spellbonus) { spellbonuses.SpellProcChance = effect_value; }
|
|
if (negate_itembonus) { itembonuses.SpellProcChance = effect_value; }
|
|
if (negate_aabonus) { aabonuses.SpellProcChance = effect_value; }
|
|
break;
|
|
|
|
case SE_CharmBreakChance:
|
|
if (negate_spellbonus) { spellbonuses.CharmBreakChance = effect_value; }
|
|
if (negate_aabonus) { aabonuses.CharmBreakChance = effect_value; }
|
|
if (negate_itembonus) { itembonuses.CharmBreakChance = effect_value; }
|
|
break;
|
|
|
|
case SE_BardSongRange:
|
|
if (negate_spellbonus) { spellbonuses.SongRange = effect_value; }
|
|
if (negate_aabonus) { aabonuses.SongRange = effect_value; }
|
|
if (negate_itembonus) { itembonuses.SongRange = effect_value; }
|
|
break;
|
|
|
|
case SE_SkillDamageAmount2:
|
|
{
|
|
for (int e = 0; e < EQ::skills::HIGHEST_SKILL + 1; e++)
|
|
{
|
|
if (negate_spellbonus) { spellbonuses.SkillDamageAmount2[e] = effect_value; }
|
|
if (negate_aabonus) { aabonuses.SkillDamageAmount2[e] = effect_value; }
|
|
if (negate_itembonus) { itembonuses.SkillDamageAmount2[e] = effect_value; }
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_NegateAttacks:
|
|
if (negate_spellbonus) {
|
|
spellbonuses.NegateAttacks[SBIndex::NEGATE_ATK_EXISTS] = effect_value;
|
|
spellbonuses.NegateAttacks[SBIndex::NEGATE_ATK_BUFFSLOT] = effect_value;
|
|
}
|
|
|
|
break;
|
|
|
|
case SE_MitigateMeleeDamage:
|
|
if (negate_spellbonus) {
|
|
spellbonuses.MitigateMeleeRune[SBIndex::MITIGATION_RUNE_PERCENT] = effect_value;
|
|
spellbonuses.MitigateMeleeRune[SBIndex::MITIGATION_RUNE_BUFFSLOT] = -1;
|
|
}
|
|
|
|
break;
|
|
|
|
case SE_MeleeThresholdGuard:
|
|
if (negate_spellbonus) {
|
|
spellbonuses.MeleeThresholdGuard[SBIndex::THRESHOLDGUARD_MITIGATION_PERCENT] = effect_value;
|
|
spellbonuses.MeleeThresholdGuard[SBIndex::THRESHOLDGUARD_BUFFSLOT] = -1;
|
|
spellbonuses.MeleeThresholdGuard[SBIndex::THRESHOLDGUARD_BUFFSLOT] = effect_value;
|
|
}
|
|
|
|
break;
|
|
|
|
case SE_SpellThresholdGuard:
|
|
if (negate_spellbonus) {
|
|
spellbonuses.SpellThresholdGuard[SBIndex::THRESHOLDGUARD_MITIGATION_PERCENT] = effect_value;
|
|
spellbonuses.SpellThresholdGuard[SBIndex::THRESHOLDGUARD_BUFFSLOT] = -1;
|
|
spellbonuses.SpellThresholdGuard[SBIndex::THRESHOLDGUARD_BUFFSLOT] = effect_value;
|
|
}
|
|
|
|
break;
|
|
|
|
case SE_MitigateSpellDamage:
|
|
if (negate_spellbonus) {
|
|
spellbonuses.MitigateSpellRune[SBIndex::MITIGATION_RUNE_PERCENT] = effect_value;
|
|
spellbonuses.MitigateSpellRune[SBIndex::MITIGATION_RUNE_BUFFSLOT] = -1;
|
|
}
|
|
|
|
break;
|
|
|
|
case SE_MitigateDotDamage:
|
|
if (negate_spellbonus) {
|
|
spellbonuses.MitigateDotRune[SBIndex::MITIGATION_RUNE_PERCENT] = effect_value;
|
|
spellbonuses.MitigateDotRune[SBIndex::MITIGATION_RUNE_BUFFSLOT] = -1;
|
|
}
|
|
|
|
break;
|
|
|
|
case SE_ManaAbsorbPercentDamage:
|
|
if (negate_spellbonus) { spellbonuses.ManaAbsorbPercentDamage = effect_value; }
|
|
break;
|
|
|
|
case SE_Endurance_Absorb_Pct_Damage:
|
|
if (negate_spellbonus) {
|
|
spellbonuses.EnduranceAbsorbPercentDamage[SBIndex::ENDURANCE_ABSORD_MITIGIATION] = effect_value;
|
|
spellbonuses.EnduranceAbsorbPercentDamage[SBIndex::ENDURANCE_ABSORD_DRAIN_PER_HP] = effect_value;
|
|
}
|
|
|
|
break;
|
|
|
|
case SE_ShieldBlock:
|
|
if (negate_spellbonus) { spellbonuses.ShieldBlock = effect_value; }
|
|
if (negate_aabonus) { aabonuses.ShieldBlock = effect_value; }
|
|
if (negate_itembonus) { itembonuses.ShieldBlock = effect_value; }
|
|
|
|
case SE_BlockBehind:
|
|
if (negate_spellbonus) { spellbonuses.BlockBehind = effect_value; }
|
|
if (negate_aabonus) { aabonuses.BlockBehind = effect_value; }
|
|
if (negate_itembonus) { itembonuses.BlockBehind = effect_value; }
|
|
break;
|
|
|
|
case SE_Blind:
|
|
if (negate_spellbonus) { spellbonuses.IsBlind = false; }
|
|
break;
|
|
|
|
case SE_Fear:
|
|
if (negate_spellbonus) { spellbonuses.IsFeared = false; }
|
|
break;
|
|
|
|
case SE_FrontalStunResist:
|
|
if (negate_spellbonus) { spellbonuses.FrontalStunResist = effect_value; }
|
|
if (negate_aabonus) { aabonuses.FrontalStunResist = effect_value; }
|
|
if (negate_itembonus) { itembonuses.FrontalStunResist = effect_value; }
|
|
break;
|
|
|
|
case SE_ImprovedBindWound:
|
|
if (negate_aabonus) { aabonuses.BindWound = effect_value; }
|
|
if (negate_itembonus) { itembonuses.BindWound = effect_value; }
|
|
if (negate_spellbonus) { spellbonuses.BindWound = effect_value; }
|
|
break;
|
|
|
|
case SE_MaxBindWound:
|
|
if (negate_spellbonus) { spellbonuses.MaxBindWound = effect_value; }
|
|
if (negate_aabonus) { aabonuses.MaxBindWound = effect_value; }
|
|
if (negate_itembonus) { itembonuses.MaxBindWound = effect_value; }
|
|
break;
|
|
|
|
case SE_BaseMovementSpeed:
|
|
if (negate_spellbonus) { spellbonuses.BaseMovementSpeed = effect_value; }
|
|
if (negate_aabonus) { aabonuses.BaseMovementSpeed = effect_value; }
|
|
if (negate_itembonus) { itembonuses.BaseMovementSpeed = effect_value; }
|
|
break;
|
|
|
|
case SE_IncreaseRunSpeedCap:
|
|
if (negate_itembonus) { itembonuses.IncreaseRunSpeedCap = effect_value; }
|
|
if (negate_aabonus) { aabonuses.IncreaseRunSpeedCap = effect_value; }
|
|
if (negate_spellbonus) { spellbonuses.IncreaseRunSpeedCap = effect_value; }
|
|
break;
|
|
|
|
case SE_DoubleSpecialAttack:
|
|
if (negate_spellbonus) { spellbonuses.DoubleSpecialAttack = effect_value; }
|
|
if (negate_aabonus) { aabonuses.DoubleSpecialAttack = effect_value; }
|
|
if (negate_itembonus) { itembonuses.DoubleSpecialAttack = effect_value; }
|
|
break;
|
|
|
|
case SE_TripleBackstab:
|
|
if (negate_spellbonus) { spellbonuses.TripleBackstab = effect_value; }
|
|
if (negate_aabonus) { aabonuses.TripleBackstab = effect_value; }
|
|
if (negate_itembonus) { itembonuses.TripleBackstab = effect_value; }
|
|
break;
|
|
|
|
case SE_FrontalBackstabMinDmg:
|
|
if (negate_spellbonus) { spellbonuses.FrontalBackstabMinDmg = false; }
|
|
break;
|
|
|
|
case SE_FrontalBackstabChance:
|
|
if (negate_spellbonus) { spellbonuses.FrontalBackstabChance = effect_value; }
|
|
if (negate_aabonus) { aabonuses.FrontalBackstabChance = effect_value; }
|
|
if (negate_itembonus) { itembonuses.FrontalBackstabChance = effect_value; }
|
|
break;
|
|
|
|
case SE_Double_Backstab_Front:
|
|
if (negate_spellbonus) { spellbonuses.Double_Backstab_Front = effect_value; }
|
|
if (negate_aabonus) { aabonuses.Double_Backstab_Front = effect_value; }
|
|
if (negate_itembonus) { itembonuses.Double_Backstab_Front = effect_value; }
|
|
break;
|
|
|
|
case SE_ConsumeProjectile:
|
|
if (negate_spellbonus) { spellbonuses.ConsumeProjectile = effect_value; }
|
|
if (negate_aabonus) { aabonuses.ConsumeProjectile = effect_value; }
|
|
if (negate_itembonus) { itembonuses.ConsumeProjectile = effect_value; }
|
|
break;
|
|
|
|
case SE_ForageAdditionalItems:
|
|
if (negate_spellbonus) { spellbonuses.ForageAdditionalItems = effect_value; }
|
|
if (negate_aabonus) { aabonuses.ForageAdditionalItems = effect_value; }
|
|
if (negate_itembonus) { itembonuses.ForageAdditionalItems = effect_value; }
|
|
break;
|
|
|
|
case SE_Salvage:
|
|
if (negate_spellbonus) { spellbonuses.SalvageChance = effect_value; }
|
|
if (negate_aabonus) { aabonuses.SalvageChance = effect_value; }
|
|
if (negate_itembonus) { itembonuses.SalvageChance = effect_value; }
|
|
break;
|
|
|
|
case SE_ArcheryDamageModifier:
|
|
if (negate_spellbonus) { spellbonuses.ArcheryDamageModifier = effect_value; }
|
|
if (negate_aabonus) { aabonuses.ArcheryDamageModifier = effect_value; }
|
|
if (negate_itembonus) { itembonuses.ArcheryDamageModifier = effect_value; }
|
|
break;
|
|
|
|
case SE_SecondaryDmgInc:
|
|
if (negate_spellbonus) { spellbonuses.SecondaryDmgInc = false; }
|
|
if (negate_aabonus) { aabonuses.SecondaryDmgInc = false; }
|
|
if (negate_itembonus) { itembonuses.SecondaryDmgInc = false; }
|
|
break;
|
|
|
|
case SE_StrikeThrough:
|
|
case SE_StrikeThrough2:
|
|
if (negate_spellbonus) { spellbonuses.StrikeThrough = effect_value; }
|
|
if (negate_aabonus) { aabonuses.StrikeThrough = effect_value; }
|
|
if (negate_itembonus) { itembonuses.StrikeThrough = effect_value; }
|
|
break;
|
|
|
|
case SE_GiveDoubleAttack:
|
|
if (negate_spellbonus) { spellbonuses.GiveDoubleAttack = effect_value; }
|
|
if (negate_aabonus) { aabonuses.GiveDoubleAttack = effect_value; }
|
|
if (negate_itembonus) { itembonuses.GiveDoubleAttack = effect_value; }
|
|
break;
|
|
|
|
case SE_PetCriticalHit:
|
|
if (negate_spellbonus) { spellbonuses.PetCriticalHit = effect_value; }
|
|
if (negate_aabonus) { aabonuses.PetCriticalHit = effect_value; }
|
|
if (negate_itembonus) { itembonuses.PetCriticalHit = effect_value; }
|
|
break;
|
|
|
|
case SE_CombatStability:
|
|
if (negate_spellbonus) { spellbonuses.CombatStability = effect_value; }
|
|
if (negate_aabonus) { aabonuses.CombatStability = effect_value; }
|
|
if (negate_itembonus) { itembonuses.CombatStability = effect_value; }
|
|
break;
|
|
|
|
case SE_PetAvoidance:
|
|
if (negate_spellbonus) { spellbonuses.PetAvoidance = effect_value; }
|
|
if (negate_aabonus) { aabonuses.PetAvoidance = effect_value; }
|
|
if (negate_itembonus) { itembonuses.PetAvoidance = effect_value; }
|
|
break;
|
|
|
|
case SE_Ambidexterity:
|
|
if (negate_spellbonus) { spellbonuses.Ambidexterity = effect_value; }
|
|
if (negate_aabonus) { aabonuses.Ambidexterity = effect_value; }
|
|
if (negate_itembonus) { itembonuses.Ambidexterity = effect_value; }
|
|
break;
|
|
|
|
case SE_PetMaxHP:
|
|
if (negate_spellbonus) { spellbonuses.PetMaxHP = effect_value; }
|
|
if (negate_aabonus) { aabonuses.PetMaxHP = effect_value; }
|
|
if (negate_itembonus) { itembonuses.PetMaxHP = effect_value; }
|
|
break;
|
|
|
|
case SE_PetFlurry:
|
|
if (negate_spellbonus) { spellbonuses.PetFlurry = effect_value; }
|
|
if (negate_aabonus) { aabonuses.PetFlurry = effect_value; }
|
|
if (negate_itembonus) { itembonuses.PetFlurry = effect_value; }
|
|
break;
|
|
|
|
case SE_GivePetGroupTarget:
|
|
if (negate_spellbonus) { spellbonuses.GivePetGroupTarget = false; }
|
|
if (negate_aabonus) { aabonuses.GivePetGroupTarget = false; }
|
|
if (negate_itembonus) { itembonuses.GivePetGroupTarget = false; }
|
|
break;
|
|
|
|
case SE_PetMeleeMitigation:
|
|
if (negate_spellbonus) { spellbonuses.PetMeleeMitigation = effect_value; }
|
|
if (negate_itembonus) { itembonuses.PetMeleeMitigation = effect_value; }
|
|
if (negate_aabonus) { aabonuses.PetMeleeMitigation = effect_value; }
|
|
break;
|
|
|
|
case SE_RootBreakChance:
|
|
if (negate_spellbonus) { spellbonuses.RootBreakChance = effect_value; }
|
|
if (negate_aabonus) { aabonuses.RootBreakChance = effect_value; }
|
|
if (negate_itembonus) { itembonuses.RootBreakChance = effect_value; }
|
|
break;
|
|
|
|
case SE_ChannelChanceItems:
|
|
if (negate_spellbonus) { spellbonuses.ChannelChanceItems = effect_value; }
|
|
if (negate_aabonus) { aabonuses.ChannelChanceItems = effect_value; }
|
|
if (negate_itembonus) { itembonuses.ChannelChanceItems = effect_value; }
|
|
break;
|
|
|
|
case SE_ChannelChanceSpells:
|
|
if (negate_spellbonus) { spellbonuses.ChannelChanceSpells = effect_value; }
|
|
if (negate_aabonus) { aabonuses.ChannelChanceSpells = effect_value; }
|
|
if (negate_itembonus) { itembonuses.ChannelChanceSpells = effect_value; }
|
|
break;
|
|
|
|
case SE_UnfailingDivinity:
|
|
if (negate_spellbonus) { spellbonuses.UnfailingDivinity = effect_value; }
|
|
if (negate_aabonus) { aabonuses.UnfailingDivinity = effect_value; }
|
|
if (negate_itembonus) { itembonuses.UnfailingDivinity = effect_value; }
|
|
break;
|
|
|
|
case SE_ItemHPRegenCapIncrease:
|
|
if (negate_spellbonus) { spellbonuses.ItemHPRegenCap = effect_value; }
|
|
if (negate_aabonus) { aabonuses.ItemHPRegenCap = effect_value; }
|
|
if (negate_itembonus) { itembonuses.ItemHPRegenCap = effect_value; }
|
|
break;
|
|
|
|
case SE_Worn_Endurance_Regen_Cap:
|
|
if (negate_spellbonus) { spellbonuses.ItemEnduranceRegenCap = effect_value; }
|
|
if (negate_aabonus) { aabonuses.ItemEnduranceRegenCap = effect_value; }
|
|
if (negate_itembonus) { itembonuses.ItemEnduranceRegenCap = effect_value; }
|
|
break;
|
|
|
|
case SE_OffhandRiposteFail:
|
|
if (negate_spellbonus) { spellbonuses.OffhandRiposteFail = effect_value; }
|
|
if (negate_aabonus) { aabonuses.OffhandRiposteFail = effect_value; }
|
|
if (negate_itembonus) { itembonuses.OffhandRiposteFail = effect_value; }
|
|
break;
|
|
|
|
case SE_ItemAttackCapIncrease:
|
|
if (negate_aabonus) { aabonuses.ItemATKCap = effect_value; }
|
|
if (negate_itembonus) { itembonuses.ItemATKCap = effect_value; }
|
|
if (negate_spellbonus) { spellbonuses.ItemATKCap = effect_value; }
|
|
break;
|
|
|
|
case SE_SpellEffectResistChance:
|
|
{
|
|
for (int e = 0; e < MAX_RESISTABLE_EFFECTS * 2; e += 2)
|
|
{
|
|
if (negate_spellbonus) {
|
|
spellbonuses.SEResist[e] = effect_value;
|
|
spellbonuses.SEResist[e + 1] = effect_value;
|
|
}
|
|
if (negate_itembonus) {
|
|
itembonuses.SEResist[e] = effect_value;
|
|
itembonuses.SEResist[e + 1] = effect_value;
|
|
}
|
|
if (negate_aabonus) {
|
|
aabonuses.SEResist[e] = effect_value;
|
|
aabonuses.SEResist[e + 1] = effect_value;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_MasteryofPast:
|
|
if (negate_spellbonus) { spellbonuses.MasteryofPast = effect_value; }
|
|
if (negate_aabonus) { aabonuses.MasteryofPast = effect_value; }
|
|
if (negate_itembonus) { itembonuses.MasteryofPast = effect_value; }
|
|
break;
|
|
|
|
case SE_DoubleRiposte:
|
|
if (negate_spellbonus) { spellbonuses.DoubleRiposte = effect_value; }
|
|
if (negate_itembonus) { itembonuses.DoubleRiposte = effect_value; }
|
|
if (negate_aabonus) { aabonuses.DoubleRiposte = effect_value; }
|
|
break;
|
|
|
|
case SE_GiveDoubleRiposte:
|
|
if (negate_spellbonus) { spellbonuses.GiveDoubleRiposte[SBIndex::DOUBLE_RIPOSTE_CHANCE] = effect_value; }
|
|
if (negate_itembonus) { itembonuses.GiveDoubleRiposte[SBIndex::DOUBLE_RIPOSTE_CHANCE] = effect_value; }
|
|
if (negate_aabonus) { aabonuses.GiveDoubleRiposte[SBIndex::DOUBLE_RIPOSTE_CHANCE] = effect_value; }
|
|
break;
|
|
|
|
case SE_SlayUndead:
|
|
if (negate_spellbonus) {
|
|
spellbonuses.SlayUndead[SBIndex::SLAYUNDEAD_RATE_MOD] = effect_value;
|
|
spellbonuses.SlayUndead[SBIndex::SLAYUNDEAD_DMG_MOD] = effect_value;
|
|
}
|
|
|
|
if (negate_itembonus) {
|
|
itembonuses.SlayUndead[SBIndex::SLAYUNDEAD_RATE_MOD] = effect_value;
|
|
itembonuses.SlayUndead[SBIndex::SLAYUNDEAD_DMG_MOD] = effect_value;
|
|
}
|
|
|
|
if (negate_aabonus) {
|
|
aabonuses.SlayUndead[SBIndex::SLAYUNDEAD_RATE_MOD] = effect_value;
|
|
aabonuses.SlayUndead[SBIndex::SLAYUNDEAD_DMG_MOD] = effect_value;
|
|
}
|
|
|
|
break;
|
|
|
|
case SE_DoubleRangedAttack:
|
|
if (negate_spellbonus) { spellbonuses.DoubleRangedAttack = effect_value; }
|
|
if (negate_aabonus) { aabonuses.DoubleRangedAttack = effect_value; }
|
|
if (negate_itembonus) { itembonuses.DoubleRangedAttack = effect_value; }
|
|
break;
|
|
|
|
case SE_ShieldEquipDmgMod:
|
|
if (negate_spellbonus) { spellbonuses.ShieldEquipDmgMod = effect_value; }
|
|
if (negate_aabonus) { aabonuses.ShieldEquipDmgMod = effect_value; }
|
|
if (negate_itembonus) { itembonuses.ShieldEquipDmgMod = effect_value; }
|
|
break;
|
|
|
|
case SE_TriggerMeleeThreshold:
|
|
if (negate_spellbonus) { spellbonuses.TriggerMeleeThreshold = false; }
|
|
break;
|
|
|
|
case SE_TriggerSpellThreshold:
|
|
if (negate_spellbonus) { spellbonuses.TriggerSpellThreshold = false; }
|
|
break;
|
|
|
|
case SE_DivineAura:
|
|
if (negate_spellbonus) { spellbonuses.DivineAura = false; }
|
|
break;
|
|
|
|
case SE_StunBashChance:
|
|
if (negate_spellbonus) { spellbonuses.StunBashChance = effect_value; }
|
|
if (negate_itembonus) { itembonuses.StunBashChance = effect_value; }
|
|
if (negate_aabonus) { aabonuses.StunBashChance = effect_value; }
|
|
break;
|
|
|
|
case SE_IncreaseChanceMemwipe:
|
|
if (negate_spellbonus) { spellbonuses.IncreaseChanceMemwipe = effect_value; }
|
|
if (negate_itembonus) { itembonuses.IncreaseChanceMemwipe = effect_value; }
|
|
if (negate_aabonus) { aabonuses.IncreaseChanceMemwipe = effect_value; }
|
|
break;
|
|
|
|
case SE_CriticalMend:
|
|
if (negate_spellbonus) { spellbonuses.CriticalMend = effect_value; }
|
|
if (negate_itembonus) { itembonuses.CriticalMend = effect_value; }
|
|
if (negate_aabonus) { aabonuses.CriticalMend = effect_value; }
|
|
break;
|
|
|
|
case SE_DistanceRemoval:
|
|
if (negate_spellbonus) { spellbonuses.DistanceRemoval = false; }
|
|
break;
|
|
|
|
case SE_ImprovedTaunt:
|
|
if (negate_spellbonus) {
|
|
spellbonuses.ImprovedTaunt[SBIndex::IMPROVED_TAUNT_MAX_LVL] = effect_value;
|
|
spellbonuses.ImprovedTaunt[SBIndex::IMPROVED_TAUNT_AGGRO_MOD] = effect_value;
|
|
spellbonuses.ImprovedTaunt[SBIndex::IMPROVED_TAUNT_BUFFSLOT] = -1;
|
|
}
|
|
|
|
break;
|
|
|
|
case SE_FrenziedDevastation:
|
|
if (negate_spellbonus) { spellbonuses.FrenziedDevastation = effect_value; }
|
|
if (negate_aabonus) { aabonuses.FrenziedDevastation = effect_value; }
|
|
if (negate_itembonus) { itembonuses.FrenziedDevastation = effect_value; }
|
|
break;
|
|
|
|
case SE_Root:
|
|
if (negate_spellbonus) {
|
|
spellbonuses.Root[SBIndex::ROOT_EXISTS] = effect_value;
|
|
spellbonuses.Root[SBIndex::ROOT_BUFFSLOT] = -1;
|
|
}
|
|
|
|
break;
|
|
|
|
case SE_Rune:
|
|
if (negate_spellbonus) {
|
|
spellbonuses.MeleeRune[SBIndex::RUNE_AMOUNT] = effect_value;
|
|
spellbonuses.MeleeRune[SBIndex::RUNE_BUFFSLOT] = -1;
|
|
}
|
|
|
|
break;
|
|
|
|
case SE_AbsorbMagicAtt:
|
|
if (negate_spellbonus) {
|
|
spellbonuses.AbsorbMagicAtt[SBIndex::RUNE_AMOUNT] = effect_value;
|
|
spellbonuses.AbsorbMagicAtt[SBIndex::RUNE_BUFFSLOT] = -1;
|
|
}
|
|
|
|
break;
|
|
|
|
case SE_Berserk:
|
|
if (negate_spellbonus) { spellbonuses.BerserkSPA = false; }
|
|
if (negate_aabonus) { aabonuses.BerserkSPA = false; }
|
|
if (negate_itembonus) { itembonuses.BerserkSPA = false; }
|
|
break;
|
|
|
|
case SE_Vampirism:
|
|
if (negate_spellbonus) { spellbonuses.Vampirism = effect_value; }
|
|
if (negate_aabonus) { aabonuses.Vampirism = effect_value; }
|
|
if (negate_itembonus) { itembonuses.Vampirism = effect_value; }
|
|
break;
|
|
|
|
case SE_Metabolism:
|
|
if (negate_spellbonus) { spellbonuses.Metabolism = effect_value; }
|
|
if (negate_aabonus) { aabonuses.Metabolism = effect_value; }
|
|
if (negate_itembonus) { itembonuses.Metabolism = effect_value; }
|
|
break;
|
|
|
|
case SE_ImprovedReclaimEnergy:
|
|
if (negate_spellbonus) { spellbonuses.ImprovedReclaimEnergy = effect_value; }
|
|
if (negate_aabonus) { aabonuses.ImprovedReclaimEnergy = effect_value; }
|
|
if (negate_itembonus) { itembonuses.ImprovedReclaimEnergy = effect_value; }
|
|
break;
|
|
|
|
case SE_HeadShot:
|
|
if (negate_spellbonus) {
|
|
spellbonuses.HeadShot[SBIndex::FINISHING_EFFECT_PROC_CHANCE] = effect_value;
|
|
spellbonuses.HeadShot[SBIndex::FINISHING_EFFECT_DMG] = effect_value;
|
|
}
|
|
|
|
if (negate_aabonus) {
|
|
aabonuses.HeadShot[SBIndex::FINISHING_EFFECT_PROC_CHANCE] = effect_value;
|
|
aabonuses.HeadShot[SBIndex::FINISHING_EFFECT_DMG] = effect_value;
|
|
}
|
|
|
|
if (negate_itembonus) {
|
|
itembonuses.HeadShot[SBIndex::FINISHING_EFFECT_PROC_CHANCE] = effect_value;
|
|
itembonuses.HeadShot[SBIndex::FINISHING_EFFECT_DMG] = effect_value;
|
|
}
|
|
|
|
break;
|
|
|
|
case SE_HeadShotLevel:
|
|
if (negate_spellbonus) {
|
|
spellbonuses.HSLevel[SBIndex::FINISHING_EFFECT_LEVEL_MAX] = effect_value;
|
|
spellbonuses.HSLevel[SBIndex::FINISHING_EFFECT_LEVEL_CHANCE_BONUS] = effect_value;
|
|
}
|
|
|
|
if (negate_aabonus) {
|
|
aabonuses.HSLevel[SBIndex::FINISHING_EFFECT_LEVEL_MAX] = effect_value;
|
|
aabonuses.HSLevel[SBIndex::FINISHING_EFFECT_LEVEL_CHANCE_BONUS] = effect_value;
|
|
}
|
|
|
|
if (negate_itembonus) {
|
|
itembonuses.HSLevel[SBIndex::FINISHING_EFFECT_LEVEL_MAX] = effect_value;
|
|
itembonuses.HSLevel[SBIndex::FINISHING_EFFECT_LEVEL_CHANCE_BONUS] = effect_value;
|
|
}
|
|
|
|
break;
|
|
|
|
case SE_Assassinate:
|
|
if (negate_spellbonus) {
|
|
spellbonuses.Assassinate[SBIndex::FINISHING_EFFECT_PROC_CHANCE] = effect_value;
|
|
spellbonuses.Assassinate[SBIndex::FINISHING_EFFECT_DMG] = effect_value;
|
|
}
|
|
|
|
if (negate_aabonus) {
|
|
aabonuses.Assassinate[SBIndex::FINISHING_EFFECT_PROC_CHANCE] = effect_value;
|
|
aabonuses.Assassinate[SBIndex::FINISHING_EFFECT_DMG] = effect_value;
|
|
}
|
|
|
|
if (negate_itembonus) {
|
|
itembonuses.Assassinate[SBIndex::FINISHING_EFFECT_PROC_CHANCE] = effect_value;
|
|
itembonuses.Assassinate[SBIndex::FINISHING_EFFECT_DMG] = effect_value;
|
|
}
|
|
|
|
break;
|
|
|
|
case SE_AssassinateLevel:
|
|
if (negate_spellbonus) {
|
|
spellbonuses.AssassinateLevel[SBIndex::FINISHING_EFFECT_LEVEL_MAX] = effect_value;
|
|
spellbonuses.AssassinateLevel[SBIndex::FINISHING_EFFECT_LEVEL_CHANCE_BONUS] = effect_value;
|
|
}
|
|
|
|
if (negate_aabonus) {
|
|
aabonuses.AssassinateLevel[SBIndex::FINISHING_EFFECT_LEVEL_MAX] = effect_value;
|
|
aabonuses.AssassinateLevel[SBIndex::FINISHING_EFFECT_LEVEL_CHANCE_BONUS] = effect_value;
|
|
}
|
|
|
|
if (negate_itembonus) {
|
|
itembonuses.AssassinateLevel[SBIndex::FINISHING_EFFECT_LEVEL_MAX] = effect_value;
|
|
itembonuses.AssassinateLevel[SBIndex::FINISHING_EFFECT_LEVEL_CHANCE_BONUS] = effect_value;
|
|
}
|
|
|
|
break;
|
|
|
|
case SE_FinishingBlow:
|
|
if (negate_spellbonus) {
|
|
spellbonuses.FinishingBlow[SBIndex::FINISHING_EFFECT_PROC_CHANCE] = effect_value;
|
|
spellbonuses.FinishingBlow[SBIndex::FINISHING_EFFECT_DMG] = effect_value;
|
|
}
|
|
|
|
if (negate_aabonus) {
|
|
aabonuses.FinishingBlow[SBIndex::FINISHING_EFFECT_PROC_CHANCE] = effect_value;
|
|
aabonuses.FinishingBlow[SBIndex::FINISHING_EFFECT_DMG] = effect_value;
|
|
}
|
|
|
|
if (negate_itembonus) {
|
|
itembonuses.FinishingBlow[SBIndex::FINISHING_EFFECT_PROC_CHANCE] = effect_value;
|
|
itembonuses.FinishingBlow[SBIndex::FINISHING_EFFECT_DMG] = effect_value;
|
|
}
|
|
|
|
break;
|
|
|
|
case SE_FinishingBlowLvl:
|
|
if (negate_spellbonus) {
|
|
spellbonuses.FinishingBlowLvl[SBIndex::FINISHING_EFFECT_LEVEL_MAX] = effect_value;
|
|
spellbonuses.FinishingBlowLvl[SBIndex::FINISHING_BLOW_LEVEL_HP_RATIO] = effect_value;
|
|
}
|
|
|
|
if (negate_aabonus) {
|
|
aabonuses.FinishingBlowLvl[SBIndex::FINISHING_EFFECT_LEVEL_MAX] = effect_value;
|
|
aabonuses.FinishingBlowLvl[SBIndex::FINISHING_BLOW_LEVEL_HP_RATIO] = effect_value;
|
|
}
|
|
|
|
if (negate_itembonus) {
|
|
itembonuses.FinishingBlowLvl[SBIndex::FINISHING_EFFECT_LEVEL_MAX] = effect_value;
|
|
itembonuses.FinishingBlowLvl[SBIndex::FINISHING_BLOW_LEVEL_HP_RATIO] = effect_value;
|
|
}
|
|
|
|
break;
|
|
|
|
case SE_Sanctuary:
|
|
if (negate_spellbonus) { spellbonuses.Sanctuary = false; }
|
|
break;
|
|
|
|
case SE_FactionModPct:
|
|
if (negate_spellbonus) { spellbonuses.FactionModPct = effect_value; }
|
|
if (negate_itembonus) { itembonuses.FactionModPct = effect_value; }
|
|
if (negate_aabonus) { aabonuses.FactionModPct = effect_value; }
|
|
break;
|
|
|
|
case SE_IllusionPersistence:
|
|
if (negate_spellbonus) { spellbonuses.IllusionPersistence = effect_value; }
|
|
if (negate_itembonus) { itembonuses.IllusionPersistence = effect_value; }
|
|
if (negate_aabonus) { aabonuses.IllusionPersistence = effect_value; }
|
|
break;
|
|
|
|
case SE_Attack_Accuracy_Max_Percent:
|
|
if (negate_spellbonus) { spellbonuses.Attack_Accuracy_Max_Percent = effect_value; }
|
|
if (negate_itembonus) { itembonuses.Attack_Accuracy_Max_Percent = effect_value; }
|
|
if (negate_aabonus) { aabonuses.Attack_Accuracy_Max_Percent = effect_value; }
|
|
break;
|
|
|
|
|
|
case SE_AC_Mitigation_Max_Percent:
|
|
if (negate_spellbonus) { spellbonuses.AC_Mitigation_Max_Percent = effect_value; }
|
|
if (negate_itembonus) { itembonuses.AC_Mitigation_Max_Percent = effect_value; }
|
|
if (negate_aabonus) { aabonuses.AC_Mitigation_Max_Percent = effect_value; }
|
|
break;
|
|
|
|
case SE_AC_Avoidance_Max_Percent:
|
|
if (negate_spellbonus) { spellbonuses.AC_Avoidance_Max_Percent = effect_value; }
|
|
if (negate_itembonus) { itembonuses.AC_Avoidance_Max_Percent = effect_value; }
|
|
if (negate_aabonus) { aabonuses.AC_Avoidance_Max_Percent = effect_value; }
|
|
break;
|
|
|
|
case SE_Melee_Damage_Position_Mod:
|
|
if (negate_spellbonus) {
|
|
spellbonuses.Melee_Damage_Position_Mod[SBIndex::POSITION_BACK] = effect_value;
|
|
spellbonuses.Melee_Damage_Position_Mod[SBIndex::POSITION_FRONT] = effect_value;
|
|
}
|
|
|
|
if (negate_aabonus) {
|
|
aabonuses.Melee_Damage_Position_Mod[SBIndex::POSITION_BACK] = effect_value;
|
|
aabonuses.Melee_Damage_Position_Mod[SBIndex::POSITION_FRONT] = effect_value;
|
|
}
|
|
|
|
if (negate_itembonus) {
|
|
itembonuses.Melee_Damage_Position_Mod[SBIndex::POSITION_BACK] = effect_value;
|
|
itembonuses.Melee_Damage_Position_Mod[SBIndex::POSITION_FRONT] = effect_value;
|
|
}
|
|
|
|
break;
|
|
|
|
case SE_Damage_Taken_Position_Mod:
|
|
if (negate_spellbonus) {
|
|
spellbonuses.Damage_Taken_Position_Mod[SBIndex::POSITION_BACK] = effect_value;
|
|
spellbonuses.Damage_Taken_Position_Mod[SBIndex::POSITION_FRONT] = effect_value;
|
|
}
|
|
|
|
if (negate_aabonus) {
|
|
aabonuses.Damage_Taken_Position_Mod[SBIndex::POSITION_BACK] = effect_value;
|
|
aabonuses.Damage_Taken_Position_Mod[SBIndex::POSITION_FRONT] = effect_value;
|
|
}
|
|
|
|
if (negate_itembonus) {
|
|
itembonuses.Damage_Taken_Position_Mod[SBIndex::POSITION_BACK] = effect_value;
|
|
itembonuses.Damage_Taken_Position_Mod[SBIndex::POSITION_FRONT] = effect_value;
|
|
}
|
|
|
|
break;
|
|
|
|
case SE_Melee_Damage_Position_Amt:
|
|
if (negate_spellbonus) {
|
|
spellbonuses.Melee_Damage_Position_Amt[SBIndex::POSITION_BACK] = effect_value;
|
|
spellbonuses.Melee_Damage_Position_Amt[SBIndex::POSITION_FRONT] = effect_value;
|
|
}
|
|
|
|
if (negate_aabonus) {
|
|
aabonuses.Melee_Damage_Position_Amt[SBIndex::POSITION_BACK] = effect_value;
|
|
aabonuses.Melee_Damage_Position_Amt[SBIndex::POSITION_FRONT] = effect_value;
|
|
}
|
|
|
|
if (negate_itembonus) {
|
|
itembonuses.Melee_Damage_Position_Amt[SBIndex::POSITION_BACK] = effect_value;
|
|
itembonuses.Melee_Damage_Position_Amt[SBIndex::POSITION_FRONT] = effect_value;
|
|
}
|
|
|
|
break;
|
|
|
|
case SE_Damage_Taken_Position_Amt:
|
|
if (negate_spellbonus) {
|
|
spellbonuses.Damage_Taken_Position_Amt[SBIndex::POSITION_BACK] = effect_value;
|
|
spellbonuses.Damage_Taken_Position_Amt[SBIndex::POSITION_FRONT] = effect_value;
|
|
}
|
|
|
|
if (negate_aabonus) {
|
|
aabonuses.Damage_Taken_Position_Amt[SBIndex::POSITION_BACK] = effect_value;
|
|
aabonuses.Damage_Taken_Position_Amt[SBIndex::POSITION_FRONT] = effect_value;
|
|
}
|
|
|
|
if (negate_itembonus) {
|
|
itembonuses.Damage_Taken_Position_Amt[SBIndex::POSITION_BACK] = effect_value;
|
|
itembonuses.Damage_Taken_Position_Amt[SBIndex::POSITION_FRONT] = effect_value;
|
|
}
|
|
|
|
break;
|
|
|
|
case SE_DS_Mitigation_Amount:
|
|
if (negate_spellbonus) { spellbonuses.DS_Mitigation_Amount = effect_value; }
|
|
if (negate_itembonus) { itembonuses.DS_Mitigation_Amount = effect_value; }
|
|
if (negate_aabonus) { aabonuses.DS_Mitigation_Amount = effect_value; }
|
|
break;
|
|
|
|
case SE_DS_Mitigation_Percentage:
|
|
if (negate_spellbonus) { spellbonuses.DS_Mitigation_Percentage = effect_value; }
|
|
if (negate_itembonus) { itembonuses.DS_Mitigation_Percentage = effect_value; }
|
|
if (negate_aabonus) { aabonuses.DS_Mitigation_Percentage = effect_value; }
|
|
break;
|
|
|
|
case SE_Pet_Crit_Melee_Damage_Pct_Owner:
|
|
if (negate_spellbonus) { spellbonuses.Pet_Crit_Melee_Damage_Pct_Owner = effect_value; }
|
|
if (negate_itembonus) { itembonuses.Pet_Crit_Melee_Damage_Pct_Owner = effect_value; }
|
|
if (negate_aabonus) { aabonuses.Pet_Crit_Melee_Damage_Pct_Owner = effect_value; }
|
|
break;
|
|
|
|
case SE_Pet_Add_Atk:
|
|
if (negate_spellbonus) { spellbonuses.Pet_Add_Atk = effect_value; }
|
|
if (negate_itembonus) { itembonuses.Pet_Add_Atk = effect_value; }
|
|
if (negate_aabonus) { aabonuses.Pet_Add_Atk = effect_value; }
|
|
break;
|
|
|
|
case SE_PC_Pet_Rampage:
|
|
if (negate_spellbonus) {
|
|
spellbonuses.PC_Pet_Rampage[SBIndex::PET_RAMPAGE_CHANCE] = effect_value;
|
|
spellbonuses.PC_Pet_Rampage[SBIndex::PET_RAMPAGE_DMG_MOD] = effect_value;
|
|
}
|
|
|
|
if (negate_itembonus) {
|
|
itembonuses.PC_Pet_Rampage[SBIndex::PET_RAMPAGE_CHANCE] = effect_value;
|
|
itembonuses.PC_Pet_Rampage[SBIndex::PET_RAMPAGE_DMG_MOD] = effect_value;
|
|
}
|
|
|
|
if (negate_aabonus) {
|
|
aabonuses.PC_Pet_Rampage[SBIndex::PET_RAMPAGE_CHANCE] = effect_value;
|
|
aabonuses.PC_Pet_Rampage[SBIndex::PET_RAMPAGE_DMG_MOD] = effect_value;
|
|
}
|
|
|
|
break;
|
|
|
|
case SE_PC_Pet_AE_Rampage:
|
|
if (negate_spellbonus) {
|
|
spellbonuses.PC_Pet_AE_Rampage[SBIndex::PET_RAMPAGE_CHANCE] = effect_value;
|
|
spellbonuses.PC_Pet_AE_Rampage[SBIndex::PET_RAMPAGE_DMG_MOD] = effect_value;
|
|
}
|
|
|
|
if (negate_itembonus) {
|
|
itembonuses.PC_Pet_AE_Rampage[SBIndex::PET_RAMPAGE_CHANCE] = effect_value;
|
|
itembonuses.PC_Pet_AE_Rampage[SBIndex::PET_RAMPAGE_DMG_MOD] = effect_value;
|
|
}
|
|
|
|
if (negate_aabonus) {
|
|
aabonuses.PC_Pet_AE_Rampage[SBIndex::PET_RAMPAGE_CHANCE] = effect_value;
|
|
aabonuses.PC_Pet_AE_Rampage[SBIndex::PET_RAMPAGE_DMG_MOD] = effect_value;
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
case SE_SkillProcSuccess: {
|
|
for (int e = 0; e < MAX_SKILL_PROCS; e++)
|
|
{
|
|
if (negate_spellbonus) { spellbonuses.SkillProcSuccess[e] = effect_value; }
|
|
if (negate_itembonus) { itembonuses.SkillProcSuccess[e] = effect_value; }
|
|
if (negate_aabonus) { aabonuses.SkillProcSuccess[e] = effect_value; }
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_SkillProcAttempt: {
|
|
for (int e = 0; e < MAX_SKILL_PROCS; e++)
|
|
{
|
|
if (negate_spellbonus) { spellbonuses.SkillProc[e] = effect_value; }
|
|
if (negate_itembonus) { itembonuses.SkillProc[e] = effect_value; }
|
|
if (negate_aabonus) { aabonuses.SkillProc[e] = effect_value; }
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SE_Shield_Target: {
|
|
if (negate_spellbonus) {
|
|
spellbonuses.ShieldTargetSpa[SBIndex::SHIELD_TARGET_MITIGATION_PERCENT] = effect_value;
|
|
spellbonuses.ShieldTargetSpa[SBIndex::SHIELD_TARGET_BUFFSLOT] = effect_value;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Mob::CalcHeroicBonuses(StatBonuses* newbon)
|
|
{
|
|
if (GetHeroicSTR()) {
|
|
SetHeroicStrBonuses(newbon);
|
|
}
|
|
|
|
if (GetHeroicSTA()) {
|
|
SetHeroicStaBonuses(newbon);
|
|
}
|
|
|
|
if (GetHeroicAGI()) {
|
|
SetHeroicAgiBonuses(newbon);
|
|
}
|
|
|
|
if (GetHeroicDEX()) {
|
|
SetHeroicDexBonuses(newbon);
|
|
}
|
|
|
|
if (GetHeroicINT()) {
|
|
SetHeroicIntBonuses(newbon);
|
|
}
|
|
|
|
if (GetHeroicWIS()) {
|
|
SetHeroicWisBonuses(newbon);
|
|
}
|
|
}
|
|
|
|
void Mob::SetHeroicWisBonuses(StatBonuses* n)
|
|
{
|
|
n->heroic_max_mana += IsHeroicWISCasterClass(GetClass()) ? GetHeroicWIS() * RuleR(Character, HeroicWisdomMultiplier) * 10 : 0;
|
|
n->heroic_mana_regen += IsHeroicWISCasterClass(GetClass()) ? GetHeroicWIS() * RuleR(Character, HeroicWisdomMultiplier) / 25 : 0;
|
|
n->HealAmt += GetHeroicWIS() * RuleR(Character, HeroicWisdomIncreaseHealAmtMultiplier);
|
|
|
|
if (RuleB(Character, HeroicStatsUseDataBucketsToScale)) {
|
|
n->heroic_max_mana += IsHeroicWISCasterClass(GetClass()) ? GetHeroicWIS() * CheckHeroicBonusesDataBuckets(HeroicBonusBucket::WisMaxMana) * 10 : 0;
|
|
n->heroic_mana_regen += IsHeroicWISCasterClass(GetClass()) ? GetHeroicWIS() * CheckHeroicBonusesDataBuckets(HeroicBonusBucket::WisManaRegen) / 25 : 0;
|
|
n->HealAmt += GetHeroicWIS() * CheckHeroicBonusesDataBuckets(HeroicBonusBucket::WisHealAmt);
|
|
}
|
|
}
|
|
|
|
void Mob::SetHeroicIntBonuses(StatBonuses* n)
|
|
{
|
|
n->heroic_max_mana += IsHeroicINTCasterClass(GetClass()) ? GetHeroicINT() * RuleR(Character, HeroicIntelligenceMultiplier) * 10 : 0;
|
|
n->heroic_mana_regen += IsHeroicINTCasterClass(GetClass()) ? GetHeroicINT() * RuleR(Character, HeroicIntelligenceMultiplier) / 25 : 0;
|
|
n->SpellDmg += GetHeroicINT() * RuleR(Character, HeroicIntelligenceIncreaseSpellDmgMultiplier);
|
|
|
|
if (RuleB(Character, HeroicStatsUseDataBucketsToScale)) {
|
|
n->heroic_max_mana += IsHeroicINTCasterClass(GetClass()) ? GetHeroicINT() * CheckHeroicBonusesDataBuckets(HeroicBonusBucket::IntMaxMana) * 10 : 0;
|
|
n->heroic_mana_regen += IsHeroicINTCasterClass(GetClass()) ? GetHeroicINT() * CheckHeroicBonusesDataBuckets(HeroicBonusBucket::IntManaRegen) / 25 : 0;
|
|
n->SpellDmg += GetHeroicINT() * CheckHeroicBonusesDataBuckets(HeroicBonusBucket::IntSpellDmg);
|
|
}
|
|
}
|
|
|
|
void Mob::SetHeroicDexBonuses(StatBonuses* n)
|
|
{
|
|
n->heroic_dex_ranged_damage += GetHeroicDEX() * RuleR(Character, HeroicDexterityMultiplier) / 10;
|
|
n->heroic_max_end += GetHeroicDEX() * RuleR(Character, HeroicDexterityMultiplier) / 4 * 10.0f;
|
|
n->heroic_end_regen += GetHeroicDEX() * RuleR(Character, HeroicDexterityMultiplier) / 4 / 50;
|
|
|
|
if (RuleB(Character, HeroicStatsUseDataBucketsToScale)) {
|
|
n->heroic_dex_ranged_damage += GetHeroicDEX() * CheckHeroicBonusesDataBuckets(HeroicBonusBucket::DexRangedDamage) / 10;
|
|
n->heroic_max_end += GetHeroicDEX() * CheckHeroicBonusesDataBuckets(HeroicBonusBucket::DexMaxEndurance) / 4 * 10.0f;
|
|
n->heroic_end_regen += GetHeroicDEX() * CheckHeroicBonusesDataBuckets(HeroicBonusBucket::DexEnduranceRegen) / 4 / 50;
|
|
}
|
|
}
|
|
|
|
void Mob::SetHeroicAgiBonuses(StatBonuses* n)
|
|
{
|
|
n->heroic_agi_avoidance += GetHeroicAGI() * RuleR(Character, HeroicAgilityMultiplier) / 10;
|
|
n->heroic_max_end += GetHeroicAGI() * RuleR(Character, HeroicAgilityMultiplier) / 4 * 10.0f;
|
|
n->heroic_end_regen += GetHeroicAGI() * RuleR(Character, HeroicAgilityMultiplier) / 4 / 50;
|
|
|
|
if (RuleB(Character, HeroicStatsUseDataBucketsToScale)) {
|
|
n->heroic_agi_avoidance += GetHeroicAGI() * CheckHeroicBonusesDataBuckets(HeroicBonusBucket::AgiAvoidance) / 10;
|
|
n->heroic_max_end += GetHeroicAGI() * CheckHeroicBonusesDataBuckets(HeroicBonusBucket::AgiMaxEndurance) / 4 * 10.0f;
|
|
n->heroic_end_regen += GetHeroicAGI() * CheckHeroicBonusesDataBuckets(HeroicBonusBucket::AgiEnduranceRegen) / 4 / 50;
|
|
}
|
|
}
|
|
|
|
void Mob::SetHeroicStaBonuses(StatBonuses* n)
|
|
{
|
|
n->heroic_max_hp += GetHeroicSTA() * RuleR(Character, HeroicStaminaMultiplier) * 10;
|
|
n->heroic_hp_regen += GetHeroicSTA() * RuleR(Character, HeroicStaminaMultiplier) / 20;
|
|
n->heroic_max_end += GetHeroicSTA() * RuleR(Character, HeroicStaminaMultiplier) / 4 * 10.0f;
|
|
n->heroic_end_regen += GetHeroicSTA() * RuleR(Character, HeroicStaminaMultiplier) / 4 / 50;
|
|
|
|
if (RuleB(Character, HeroicStatsUseDataBucketsToScale)) {
|
|
n->heroic_max_hp += GetHeroicSTA() * CheckHeroicBonusesDataBuckets(HeroicBonusBucket::StaMaxHP) * 10;
|
|
n->heroic_hp_regen += GetHeroicSTA() * CheckHeroicBonusesDataBuckets(HeroicBonusBucket::StaHPRegen) / 20;
|
|
n->heroic_max_end += GetHeroicSTA() * CheckHeroicBonusesDataBuckets(HeroicBonusBucket::StaMaxEndurance) / 4 * 10.0f;
|
|
n->heroic_end_regen += GetHeroicSTA() * CheckHeroicBonusesDataBuckets(HeroicBonusBucket::StaEnduranceRegen) / 4 / 50;
|
|
}
|
|
}
|
|
|
|
void Mob::SetHeroicStrBonuses(StatBonuses* n)
|
|
{
|
|
n->heroic_str_shield_ac += GetHeroicSTR() * RuleR(Character, HeroicStrengthMultiplier) / 10;
|
|
n->heroic_str_melee_damage += GetHeroicSTR() * RuleR(Character, HeroicStrengthMultiplier) / 10;
|
|
n->heroic_max_end += GetHeroicSTR() * RuleR(Character, HeroicStrengthMultiplier) / 4 * 10.0f;
|
|
n->heroic_end_regen += GetHeroicSTR() * RuleR(Character, HeroicStrengthMultiplier) / 4 / 50;
|
|
|
|
if (RuleB(Character, HeroicStatsUseDataBucketsToScale)) {
|
|
n->heroic_str_shield_ac += GetHeroicSTR() * CheckHeroicBonusesDataBuckets(HeroicBonusBucket::StrShieldAC) / 10;
|
|
n->heroic_str_melee_damage += GetHeroicSTR() * CheckHeroicBonusesDataBuckets(HeroicBonusBucket::StrMeleeDamage) / 10;
|
|
n->heroic_max_end += GetHeroicSTR() * CheckHeroicBonusesDataBuckets(HeroicBonusBucket::StrMaxEndurance) / 4 * 10.0f;
|
|
n->heroic_end_regen += GetHeroicSTR() * CheckHeroicBonusesDataBuckets(HeroicBonusBucket::StrEnduranceRegen) / 4 / 50;
|
|
}
|
|
}
|
|
|
|
float Mob::CheckHeroicBonusesDataBuckets(std::string bucket_name)
|
|
{
|
|
std::string bucket_value;
|
|
if (!bucket_name.empty()) {
|
|
DataBucketKey k = GetScopedBucketKeys();
|
|
k.key = bucket_name;
|
|
if (IsOfClientBot()) {
|
|
bucket_value = DataBucket::GetData(k).value;
|
|
}
|
|
|
|
if (bucket_value.empty() || !Strings::IsNumber(bucket_value)) {
|
|
return 0.00f;
|
|
}
|
|
}
|
|
|
|
return Strings::ToFloat(bucket_value);
|
|
}
|