mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-11 21:01:29 +00:00
* SPA 378 update Update to SPA 378 SE_SpellEffectResistChance provides chance to resist specific spell effects. This updates allows support for multiple resistance checks against different effects in same spell. Example. If a spell has a silence and a blind effect and the target has an AA that gives 10% chance to resist silence and 5% chance to resist blind. It will roll against effect respectively each giving a chance to resist the spell. * Update spells.cpp Unresistable spells (resisttype = 0) do not ever resist a spell even with SPA378 Example: Pheonix Charm in Plane of Fire, or Storm Comet in Bastion of Thunder. Parsed both and never got a resist despite having the AA that has effect specific resists which both those spells match.
5925 lines
183 KiB
C++
5925 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: {
|
|
if (base_value == 100) // If we reach 100% in a single spell/item then we should be immune to
|
|
// negative fear resist effects until our immunity is over
|
|
newbon->Fearless = true;
|
|
|
|
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:
|
|
{
|
|
if(effect_value == 100) // If we reach 100% in a single spell/item then we should be immune to negative fear resist effects until our immunity is over
|
|
new_bonus->Fearless = true;
|
|
|
|
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.Fearless = false;
|
|
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);
|
|
}
|