diff --git a/zone/bot.cpp b/zone/bot.cpp index 8765fbb75..560dfd45a 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -8821,6 +8821,10 @@ void Bot::CalcBotStats(bool showtext) { CalcBonuses(); AI_AddNPCSpells(this->GetBotSpellID()); + if (RuleB(Bot, IsBotsElixirEnabled)) { + isElixirSpellCacheBuilt = false; + ElixirSpellCacheRefresh(); + } if(showtext) { GetBotOwner()->Message(Chat::Yellow, "%s has been updated.", GetCleanName()); diff --git a/zone/bot.h b/zone/bot.h index 3c7dfb415..e5fe77047 100644 --- a/zone/bot.h +++ b/zone/bot.h @@ -322,7 +322,7 @@ public: void SetGuardMode(); void SetHoldMode(); bool ElixirAIDetermineSpellToCast(); - bool ElixirAITryCastSpell(BotSpell botSpell, bool isHeal = false); + bool ElixirAITryCastSpell(uint16 spellID, bool isHeal = false); // Mob AI Virtual Override Methods virtual void AI_Process(); @@ -608,6 +608,7 @@ protected: virtual int32 CalcBotAAFocus(focusType type, uint32 aa_ID, uint32 points, uint16 spell_id); virtual void PerformTradeWithClient(int16 beginSlotID, int16 endSlotID, Client* client); virtual bool AIDoSpellCast(uint8 i, Mob* tar, int32 mana_cost, uint32* oDontDoAgainBefore = 0); + virtual bool AIElixirDoSpellCast(uint16 spellID, Mob* tar, int32 mana_cost); BotCastingRoles& GetCastingRoles() { return m_CastingRoles; } void SetGroupHealer(bool flag = true) { m_CastingRoles.GroupHealer = flag; } @@ -657,6 +658,8 @@ private: int32 max_end; int32 end_regen; uint32 timers[MaxTimer]; + bool isElixirSpellCacheBuilt; + int elixirCacheSpells[15]{ -1,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; Timer m_evade_timer; // can be moved to pTimers at some point Timer m_alt_combat_hate_timer; @@ -716,6 +719,7 @@ private: void SetAttackingFlag(bool flag = true) { m_attacking_flag = flag; } void SetPullingFlag(bool flag = true) { m_pulling_flag = flag; } void SetReturningFlag(bool flag = true) { m_returning_flag = flag; } + void ElixirSpellCacheRefresh(); // Private "Inventory" Methods void GetBotItems(EQ::InventoryProfile &inv, std::string* errorMessage); diff --git a/zone/botspellsai.cpp b/zone/botspellsai.cpp index e6f4440d0..06b9f6ebc 100644 --- a/zone/botspellsai.cpp +++ b/zone/botspellsai.cpp @@ -22,11 +22,11 @@ #include "../common/string_util.h" #if EQDEBUG >= 12 - #define BotAI_DEBUG_Spells 25 +#define BotAI_DEBUG_Spells 25 #elif EQDEBUG >= 9 - #define BotAI_DEBUG_Spells 10 +#define BotAI_DEBUG_Spells 10 #else - #define BotAI_DEBUG_Spells -1 +#define BotAI_DEBUG_Spells -1 #endif bool Bot::AICastSpell(Mob* tar, uint8 iChance, uint32 iSpellTypes) { @@ -44,8 +44,8 @@ bool Bot::AICastSpell(Mob* tar, uint8 iChance, uint32 iSpellTypes) { } } - if(tar->GetAppearance() == eaDead) { - if((tar->IsClient() && tar->CastToClient()->GetFeigned()) || tar->IsBot()) { + if (tar->GetAppearance() == eaDead) { + if ((tar->IsClient() && tar->CastToClient()->GetFeigned()) || tar->IsBot()) { // do nothing } else { @@ -66,897 +66,782 @@ bool Bot::AICastSpell(Mob* tar, uint8 iChance, uint32 iSpellTypes) { botSpell.ManaCost = 0; switch (iSpellTypes) { - case SpellType_Mez: { - if (tar->GetBodyType() != BT_Giant) { - if(!checked_los) { - if(!CheckLosFN(tar)) - break; //cannot see target... we assume that no spell is going to work since we will only be casting detrimental spells in this call + case SpellType_Mez: { + if (tar->GetBodyType() != BT_Giant) { + if (!checked_los) { + if (!CheckLosFN(tar)) + break; //cannot see target... we assume that no spell is going to work since we will only be casting detrimental spells in this call - checked_los = true; - } - - //TODO - //Check if single target or AoE mez is best - //if (TARGETS ON MT IS => 3 THEN botSpell = AoEMez) - //if (TARGETS ON MT IS <= 2 THEN botSpell = BestMez) - - botSpell = GetBestBotSpellForMez(this); - - if(botSpell.SpellId == 0) - break; - - Mob* addMob = GetFirstIncomingMobToMez(this, botSpell); - - if(!addMob){ - //Say("!addMob."); - break;} - - if(!(!addMob->IsImmuneToSpell(botSpell.SpellId, this) && addMob->CanBuffStack(botSpell.SpellId, botLevel, true) >= 0)) - break; - - castedSpell = AIDoSpellCast(botSpell.SpellIndex, addMob, botSpell.ManaCost); - - if(castedSpell) - BotGroupSay(this, "Attempting to mez %s.", addMob->GetCleanName()); + checked_los = true; } - break; - } - case SpellType_Heal: { - if (tar->DontHealMeBefore() < Timer::GetCurrentTime()) { - uint8 hpr = (uint8)tar->GetHPRatio(); - bool hasAggro = false; - bool isPrimaryHealer = false; - if(HasGroup()) { - isPrimaryHealer = IsGroupHealer(); + //TODO + //Check if single target or AoE mez is best + //if (TARGETS ON MT IS => 3 THEN botSpell = AoEMez) + //if (TARGETS ON MT IS <= 2 THEN botSpell = BestMez) + + botSpell = GetBestBotSpellForMez(this); + + if (botSpell.SpellId == 0) + break; + + Mob* addMob = GetFirstIncomingMobToMez(this, botSpell); + + if (!addMob) { + //Say("!addMob."); + break; + } + + if (!(!addMob->IsImmuneToSpell(botSpell.SpellId, this) && addMob->CanBuffStack(botSpell.SpellId, botLevel, true) >= 0)) + break; + + castedSpell = AIDoSpellCast(botSpell.SpellIndex, addMob, botSpell.ManaCost); + + if (castedSpell) + BotGroupSay(this, "Attempting to mez %s.", addMob->GetCleanName()); + } + break; + } + case SpellType_Heal: { + if (tar->DontHealMeBefore() < Timer::GetCurrentTime()) { + uint8 hpr = (uint8)tar->GetHPRatio(); + bool hasAggro = false; + bool isPrimaryHealer = false; + + if (HasGroup()) { + isPrimaryHealer = IsGroupHealer(); + } + + if (hpr < 95 || (tar->IsClient() && (hpr < 95)) || (botClass == BARD)) { + if (tar->GetClass() == NECROMANCER) { + // Give necromancers a chance to go lifetap something or cleric can spend too much mana on a necro + if (hpr >= 40) { + break; + } } - if(hpr < 95 || (tar->IsClient() && (hpr < 95)) || (botClass == BARD)) { - if(tar->GetClass() == NECROMANCER) { - // Give necromancers a chance to go lifetap something or cleric can spend too much mana on a necro - if(hpr >= 40) { - break; - } + if (tar->GetClass() == SHAMAN) { + // Give shaman the chance to canni without wasting the cleric's mana + if (hpr >= 80) { + break; + } + } + + // Evaluate the situation + if ((IsEngaged()) && ((botClass == CLERIC) || (botClass == DRUID) || (botClass == SHAMAN) || (botClass == PALADIN))) { + if (tar->GetTarget() && tar->GetTarget()->GetHateTop() && tar->GetTarget()->GetHateTop() == tar) { + hasAggro = true; } - if(tar->GetClass() == SHAMAN) { - // Give shaman the chance to canni without wasting the cleric's mana - if(hpr >= 80) { - break; - } + if (hpr < 35) { + botSpell = GetBestBotSpellForFastHeal(this); } - - // Evaluate the situation - if((IsEngaged()) && ((botClass == CLERIC) || (botClass == DRUID) || (botClass == SHAMAN) || (botClass == PALADIN))) { - if(tar->GetTarget() && tar->GetTarget()->GetHateTop() && tar->GetTarget()->GetHateTop() == tar) { - hasAggro = true; - } - - if(hpr < 35) { - botSpell = GetBestBotSpellForFastHeal(this); - } - else if(hpr >= 35 && hpr < 70){ - if(GetNumberNeedingHealedInGroup(60, false) >= 3) - botSpell = GetBestBotSpellForGroupHeal(this); - - if(botSpell.SpellId == 0) - botSpell = GetBestBotSpellForPercentageHeal(this); - } - else if(hpr >= 70 && hpr < 95){ - if(GetNumberNeedingHealedInGroup(80, false) >= 3) - botSpell = GetBestBotSpellForGroupHealOverTime(this); - - if(hasAggro) - botSpell = GetBestBotSpellForPercentageHeal(this); - } - else { - if(!tar->FindType(SE_HealOverTime)) - botSpell = GetBestBotSpellForHealOverTime(this); - } - } - else if ((botClass == CLERIC) || (botClass == DRUID) || (botClass == SHAMAN) || (botClass == PALADIN)) { - if(GetNumberNeedingHealedInGroup(40, true) >= 2){ - botSpell = GetBestBotSpellForGroupCompleteHeal(this); - - if(botSpell.SpellId == 0) - botSpell = GetBestBotSpellForGroupHeal(this); - - if(botSpell.SpellId == 0) - botSpell = GetBestBotSpellForGroupHealOverTime(this); - - if(hpr < 40) { - if(botSpell.SpellId == 0) - botSpell = GetBestBotSpellForPercentageHeal(this); - } - } - else if(GetNumberNeedingHealedInGroup(60, true) >= 2){ + else if (hpr >= 35 && hpr < 70) { + if (GetNumberNeedingHealedInGroup(60, false) >= 3) botSpell = GetBestBotSpellForGroupHeal(this); - if(botSpell.SpellId == 0) - botSpell = GetBestBotSpellForGroupHealOverTime(this); - - if(hpr < 40) { - if(botSpell.SpellId == 0) - botSpell = GetBestBotSpellForPercentageHeal(this); - } - } - else if(hpr < 40) + if (botSpell.SpellId == 0) + botSpell = GetBestBotSpellForPercentageHeal(this); + } + else if (hpr >= 70 && hpr < 95) { + if (GetNumberNeedingHealedInGroup(80, false) >= 3) + botSpell = GetBestBotSpellForGroupHealOverTime(this); + + if (hasAggro) botSpell = GetBestBotSpellForPercentageHeal(this); - else if(hpr >= 40 && hpr < 75) - botSpell = GetBestBotSpellForRegularSingleTargetHeal(this); - else { - if(hpr < 90 && !tar->FindType(SE_HealOverTime)) - botSpell = GetBestBotSpellForHealOverTime(this); - } } else { - float hpRatioToCast = 0.0f; + if (!tar->FindType(SE_HealOverTime)) + botSpell = GetBestBotSpellForHealOverTime(this); + } + } + else if ((botClass == CLERIC) || (botClass == DRUID) || (botClass == SHAMAN) || (botClass == PALADIN)) { + if (GetNumberNeedingHealedInGroup(40, true) >= 2) { + botSpell = GetBestBotSpellForGroupCompleteHeal(this); - switch(this->GetBotStance()) { - case EQ::constants::stanceEfficient: - case EQ::constants::stanceAggressive: - hpRatioToCast = isPrimaryHealer?90.0f:50.0f; - break; - case EQ::constants::stanceBalanced: - hpRatioToCast = isPrimaryHealer?95.0f:75.0f; - break; - case EQ::constants::stanceReactive: - hpRatioToCast = isPrimaryHealer?100.0f:90.0f; - break; - case EQ::constants::stanceBurn: - case EQ::constants::stanceBurnAE: - hpRatioToCast = isPrimaryHealer?75.0f:25.0f; - break; - default: - hpRatioToCast = isPrimaryHealer?100.0f:0.0f; - break; + if (botSpell.SpellId == 0) + botSpell = GetBestBotSpellForGroupHeal(this); + + if (botSpell.SpellId == 0) + botSpell = GetBestBotSpellForGroupHealOverTime(this); + + if (hpr < 40) { + if (botSpell.SpellId == 0) + botSpell = GetBestBotSpellForPercentageHeal(this); } - - //If we're at specified mana % or below, don't heal as hybrid - if(tar->GetHPRatio() <= hpRatioToCast) - botSpell = GetBestBotSpellForRegularSingleTargetHeal(this); } + else if (GetNumberNeedingHealedInGroup(60, true) >= 2) { + botSpell = GetBestBotSpellForGroupHeal(this); - if(botSpell.SpellId == 0) + if (botSpell.SpellId == 0) + botSpell = GetBestBotSpellForGroupHealOverTime(this); + + if (hpr < 40) { + if (botSpell.SpellId == 0) + botSpell = GetBestBotSpellForPercentageHeal(this); + } + } + else if (hpr < 40) + botSpell = GetBestBotSpellForPercentageHeal(this); + else if (hpr >= 40 && hpr < 75) botSpell = GetBestBotSpellForRegularSingleTargetHeal(this); + else { + if (hpr < 90 && !tar->FindType(SE_HealOverTime)) + botSpell = GetBestBotSpellForHealOverTime(this); + } + } + else { + float hpRatioToCast = 0.0f; - if(botSpell.SpellId == 0) - botSpell = GetFirstBotSpellForSingleTargetHeal(this); - - if(botSpell.SpellId == 0 && botClass == BARD){ - botSpell = GetFirstBotSpellBySpellType(this, SpellType_Heal); + switch (this->GetBotStance()) { + case EQ::constants::stanceEfficient: + case EQ::constants::stanceAggressive: + hpRatioToCast = isPrimaryHealer ? 90.0f : 50.0f; + break; + case EQ::constants::stanceBalanced: + hpRatioToCast = isPrimaryHealer ? 95.0f : 75.0f; + break; + case EQ::constants::stanceReactive: + hpRatioToCast = isPrimaryHealer ? 100.0f : 90.0f; + break; + case EQ::constants::stanceBurn: + case EQ::constants::stanceBurnAE: + hpRatioToCast = isPrimaryHealer ? 75.0f : 25.0f; + break; + default: + hpRatioToCast = isPrimaryHealer ? 100.0f : 0.0f; + break; } - // If there is still no spell id, then there isn't going to be one so we are done - if(botSpell.SpellId == 0) - break; + //If we're at specified mana % or below, don't heal as hybrid + if (tar->GetHPRatio() <= hpRatioToCast) + botSpell = GetBestBotSpellForRegularSingleTargetHeal(this); + } - // Can we cast this spell on this target? - if(!(spells[botSpell.SpellId].target_type==ST_GroupTeleport || spells[botSpell.SpellId].target_type == ST_Target || tar == this) - && !(tar->CanBuffStack(botSpell.SpellId, botLevel, true) >= 0)) - break; + if (botSpell.SpellId == 0) + botSpell = GetBestBotSpellForRegularSingleTargetHeal(this); - uint32 TempDontHealMeBeforeTime = tar->DontHealMeBefore(); + if (botSpell.SpellId == 0) + botSpell = GetFirstBotSpellForSingleTargetHeal(this); - castedSpell = AIDoSpellCast(botSpell.SpellIndex, tar, botSpell.ManaCost, &TempDontHealMeBeforeTime); + if (botSpell.SpellId == 0 && botClass == BARD) { + botSpell = GetFirstBotSpellBySpellType(this, SpellType_Heal); + } - if(castedSpell) { - /*if(TempDontHealMeBeforeTime != tar->DontHealMeBefore()) - tar->SetDontHealMeBefore(TempDontHealMeBeforeTime); + // If there is still no spell id, then there isn't going to be one so we are done + if (botSpell.SpellId == 0) + break; - // For non-HoT heals, do a 4 second delay - // TODO: Replace this code with logic that calculates the delay based on number of clerics in rotation - // and ignores heals for anyone except the main tank - if(!IsHealOverTimeSpell(botSpell.SpellId)) { - if(IsCompleteHealSpell(botSpell.SpellId)) { - // Complete Heal 4 second rotation - tar->SetDontHealMeBefore(Timer::GetCurrentTime() + 4000); - } - else { - tar->SetDontHealMeBefore(Timer::GetCurrentTime() + 1000); - } - }*/ - if(botClass != BARD) { - if(IsGroupSpell(botSpell.SpellId)){ - if(this->HasGroup()) { - Group *g = this->GetGroup(); + // Can we cast this spell on this target? + if (!(spells[botSpell.SpellId].target_type == ST_GroupTeleport || spells[botSpell.SpellId].target_type == ST_Target || tar == this) + && !(tar->CanBuffStack(botSpell.SpellId, botLevel, true) >= 0)) + break; - if(g) { - BotGroupSay(this, "Casting %s.", spells[botSpell.SpellId].name); + uint32 TempDontHealMeBeforeTime = tar->DontHealMeBefore(); - for( int i = 0; imembers[i] && !g->members[i]->qglobal) { - g->members[i]->SetDontHealMeBefore(Timer::GetCurrentTime() + 1000); - } + castedSpell = AIDoSpellCast(botSpell.SpellIndex, tar, botSpell.ManaCost, &TempDontHealMeBeforeTime); + + if (castedSpell) { + /*if(TempDontHealMeBeforeTime != tar->DontHealMeBefore()) + tar->SetDontHealMeBefore(TempDontHealMeBeforeTime); + + // For non-HoT heals, do a 4 second delay + // TODO: Replace this code with logic that calculates the delay based on number of clerics in rotation + // and ignores heals for anyone except the main tank + if(!IsHealOverTimeSpell(botSpell.SpellId)) { + if(IsCompleteHealSpell(botSpell.SpellId)) { + // Complete Heal 4 second rotation + tar->SetDontHealMeBefore(Timer::GetCurrentTime() + 4000); + } + else { + tar->SetDontHealMeBefore(Timer::GetCurrentTime() + 1000); + } + }*/ + if (botClass != BARD) { + if (IsGroupSpell(botSpell.SpellId)) { + if (this->HasGroup()) { + Group* g = this->GetGroup(); + + if (g) { + BotGroupSay(this, "Casting %s.", spells[botSpell.SpellId].name); + + for (int i = 0; i < MAX_GROUP_MEMBERS; i++) { + if (g->members[i] && !g->members[i]->qglobal) { + g->members[i]->SetDontHealMeBefore(Timer::GetCurrentTime() + 1000); } } } } - else { - if(tar != this) //we don't need spam of bots healing themselves - BotGroupSay(this, "Casting %s on %s", spells[botSpell.SpellId].name, tar->GetCleanName()); + } + else { + if (tar != this) //we don't need spam of bots healing themselves + BotGroupSay(this, "Casting %s on %s", spells[botSpell.SpellId].name, tar->GetCleanName()); - tar->SetDontHealMeBefore(Timer::GetCurrentTime() + 2000); - } + tar->SetDontHealMeBefore(Timer::GetCurrentTime() + 2000); } } } } - break; } - case SpellType_Root: { - if (!tar->IsRooted() && tar->DontRootMeBefore() < Timer::GetCurrentTime()) { - if(!checked_los) { - if(!CheckLosFN(tar)) - break; //cannot see target... we assume that no spell is going to work since we will only be casting detrimental spells in this call + break; + } + case SpellType_Root: { + if (!tar->IsRooted() && tar->DontRootMeBefore() < Timer::GetCurrentTime()) { + if (!checked_los) { + if (!CheckLosFN(tar)) + break; //cannot see target... we assume that no spell is going to work since we will only be casting detrimental spells in this call - checked_los = true; - } - - // TODO: If there is a ranger in the group then don't allow root spells - - botSpell = GetFirstBotSpellBySpellType(this, iSpellTypes); - - if(botSpell.SpellId == 0) - break; - - if(tar->CanBuffStack(botSpell.SpellId, botLevel, true) == 0) - break; - - uint32 TempDontRootMeBefore = tar->DontRootMeBefore(); - - castedSpell = AIDoSpellCast(botSpell.SpellIndex, tar, botSpell.ManaCost, &TempDontRootMeBefore); - - if(TempDontRootMeBefore != tar->DontRootMeBefore()) - tar->SetDontRootMeBefore(TempDontRootMeBefore); + checked_los = true; } - break; + + // TODO: If there is a ranger in the group then don't allow root spells + + botSpell = GetFirstBotSpellBySpellType(this, iSpellTypes); + + if (botSpell.SpellId == 0) + break; + + if (tar->CanBuffStack(botSpell.SpellId, botLevel, true) == 0) + break; + + uint32 TempDontRootMeBefore = tar->DontRootMeBefore(); + + castedSpell = AIDoSpellCast(botSpell.SpellIndex, tar, botSpell.ManaCost, &TempDontRootMeBefore); + + if (TempDontRootMeBefore != tar->DontRootMeBefore()) + tar->SetDontRootMeBefore(TempDontRootMeBefore); } - case SpellType_Buff: { - if (tar->DontBuffMeBefore() < Timer::GetCurrentTime()) { - std::list buffSpellList = GetBotSpellsBySpellType(this, SpellType_Buff); + break; + } + case SpellType_Buff: { + if (tar->DontBuffMeBefore() < Timer::GetCurrentTime()) { + std::list buffSpellList = GetBotSpellsBySpellType(this, SpellType_Buff); - for(std::list::iterator itr = buffSpellList.begin(); itr != buffSpellList.end(); ++itr) { - BotSpell selectedBotSpell = *itr; + for (std::list::iterator itr = buffSpellList.begin(); itr != buffSpellList.end(); ++itr) { + BotSpell selectedBotSpell = *itr; - if(selectedBotSpell.SpellId == 0) - continue; + if (selectedBotSpell.SpellId == 0) + continue; - // no buffs with illusions.. use #bot command to cast illusions - if(IsEffectInSpell(selectedBotSpell.SpellId, SE_Illusion) && tar != this) - continue; + // no buffs with illusions.. use #bot command to cast illusions + if (IsEffectInSpell(selectedBotSpell.SpellId, SE_Illusion) && tar != this) + continue; - //no teleport spells use #bot command to cast teleports - if(IsEffectInSpell(selectedBotSpell.SpellId, SE_Teleport) || IsEffectInSpell(selectedBotSpell.SpellId, SE_Succor)) - continue; + //no teleport spells use #bot command to cast teleports + if (IsEffectInSpell(selectedBotSpell.SpellId, SE_Teleport) || IsEffectInSpell(selectedBotSpell.SpellId, SE_Succor)) + continue; - // can not cast buffs for your own pet only on another pet that isn't yours - if((spells[selectedBotSpell.SpellId].target_type == ST_Pet) && (tar != this->GetPet())) - continue; + // can not cast buffs for your own pet only on another pet that isn't yours + if ((spells[selectedBotSpell.SpellId].target_type == ST_Pet) && (tar != this->GetPet())) + continue; - // Validate target + // Validate target - if(!((spells[selectedBotSpell.SpellId].target_type == ST_Target || spells[selectedBotSpell.SpellId].target_type == ST_Pet || tar == this || - spells[selectedBotSpell.SpellId].target_type == ST_Group || spells[selectedBotSpell.SpellId].target_type == ST_GroupTeleport || - (botClass == BARD && spells[selectedBotSpell.SpellId].target_type == ST_AEBard)) - && !tar->IsImmuneToSpell(selectedBotSpell.SpellId, this) - && (tar->CanBuffStack(selectedBotSpell.SpellId, botLevel, true) >= 0))) { - continue; - } - - // Put the zone levitate and movement check here since bots are able to bypass the client casting check - if((IsEffectInSpell(selectedBotSpell.SpellId, SE_Levitate) && !zone->CanLevitate()) - || (IsEffectInSpell(selectedBotSpell.SpellId, SE_MovementSpeed) && !zone->CanCastOutdoor())) { - if(botClass != BARD || !IsSpellUsableThisZoneType(selectedBotSpell.SpellId, zone->GetZoneType())){ - continue; - } - } - - switch(tar->GetArchetype()) - { - case ARCHETYPE_CASTER: - //TODO: probably more caster specific spell effects in here - if(IsEffectInSpell(selectedBotSpell.SpellId, SE_AttackSpeed) || IsEffectInSpell(selectedBotSpell.SpellId, SE_ATK) || - IsEffectInSpell(selectedBotSpell.SpellId, SE_STR) || IsEffectInSpell(selectedBotSpell.SpellId, SE_ReverseDS)) - { - continue; - } - break; - case ARCHETYPE_MELEE: - if(IsEffectInSpell(selectedBotSpell.SpellId, SE_IncreaseSpellHaste) || IsEffectInSpell(selectedBotSpell.SpellId, SE_ManaPool) || - IsEffectInSpell(selectedBotSpell.SpellId, SE_CastingLevel) || IsEffectInSpell(selectedBotSpell.SpellId, SE_ManaRegen_v2) || - IsEffectInSpell(selectedBotSpell.SpellId, SE_CurrentMana)) - { - continue; - } - break; - case ARCHETYPE_HYBRID: - //Hybrids get all buffs - default: - break; - } - - if(botClass == ENCHANTER && IsEffectInSpell(selectedBotSpell.SpellId, SE_Rune)) - { - float manaRatioToCast = 75.0f; - - switch(this->GetBotStance()) { - case EQ::constants::stanceEfficient: - manaRatioToCast = 90.0f; - break; - case EQ::constants::stanceBalanced: - case EQ::constants::stanceAggressive: - manaRatioToCast = 75.0f; - break; - case EQ::constants::stanceReactive: - case EQ::constants::stanceBurn: - case EQ::constants::stanceBurnAE: - manaRatioToCast = 50.0f; - break; - default: - manaRatioToCast = 75.0f; - break; - } - - //If we're at specified mana % or below, don't rune as enchanter - if(this->GetManaRatio() <= manaRatioToCast) - break; - } - - if(CheckSpellRecastTimers(this, itr->SpellIndex)) - { - - uint32 TempDontBuffMeBefore = tar->DontBuffMeBefore(); - - castedSpell = AIDoSpellCast(selectedBotSpell.SpellIndex, tar, selectedBotSpell.ManaCost, &TempDontBuffMeBefore); - - if(TempDontBuffMeBefore != tar->DontBuffMeBefore()) - tar->SetDontBuffMeBefore(TempDontBuffMeBefore); - } - - if(castedSpell) - break; + if (!((spells[selectedBotSpell.SpellId].target_type == ST_Target || spells[selectedBotSpell.SpellId].target_type == ST_Pet || tar == this || + spells[selectedBotSpell.SpellId].target_type == ST_Group || spells[selectedBotSpell.SpellId].target_type == ST_GroupTeleport || + (botClass == BARD && spells[selectedBotSpell.SpellId].target_type == ST_AEBard)) + && !tar->IsImmuneToSpell(selectedBotSpell.SpellId, this) + && (tar->CanBuffStack(selectedBotSpell.SpellId, botLevel, true) >= 0))) { + continue; } - } - break; - } - case SpellType_Escape: { - uint8 hpr = (uint8)GetHPRatio(); - bool mayGetAggro = false; -#ifdef IPC - if (hpr <= 5 || (IsNPC() && CastToNPC()->IsInteractive() && tar != this) ) -#else - if(hpr > 15 && ((botClass == WIZARD) || (botClass == ENCHANTER) || (botClass == RANGER))) - mayGetAggro = HasOrMayGetAggro(); //classes have hate reducing spells + // Put the zone levitate and movement check here since bots are able to bypass the client casting check + if ((IsEffectInSpell(selectedBotSpell.SpellId, SE_Levitate) && !zone->CanLevitate()) + || (IsEffectInSpell(selectedBotSpell.SpellId, SE_MovementSpeed) && !zone->CanCastOutdoor())) { + if (botClass != BARD || !IsSpellUsableThisZoneType(selectedBotSpell.SpellId, zone->GetZoneType())) { + continue; + } + } - if (hpr <= 15 || mayGetAggro) -#endif - { - botSpell = GetFirstBotSpellBySpellType(this, iSpellTypes); - - if(botSpell.SpellId == 0) + switch (tar->GetArchetype()) + { + case ARCHETYPE_CASTER: + //TODO: probably more caster specific spell effects in here + if (IsEffectInSpell(selectedBotSpell.SpellId, SE_AttackSpeed) || IsEffectInSpell(selectedBotSpell.SpellId, SE_ATK) || + IsEffectInSpell(selectedBotSpell.SpellId, SE_STR) || IsEffectInSpell(selectedBotSpell.SpellId, SE_ReverseDS)) + { + continue; + } + break; + case ARCHETYPE_MELEE: + if (IsEffectInSpell(selectedBotSpell.SpellId, SE_IncreaseSpellHaste) || IsEffectInSpell(selectedBotSpell.SpellId, SE_ManaPool) || + IsEffectInSpell(selectedBotSpell.SpellId, SE_CastingLevel) || IsEffectInSpell(selectedBotSpell.SpellId, SE_ManaRegen_v2) || + IsEffectInSpell(selectedBotSpell.SpellId, SE_CurrentMana)) + { + continue; + } + break; + case ARCHETYPE_HYBRID: + //Hybrids get all buffs + default: break; - - if(IsInvulnerabilitySpell(botSpell.SpellId)) - tar = this; //target self for invul type spells - - castedSpell = AIDoSpellCast(botSpell.SpellIndex, tar, botSpell.ManaCost); - } - break; - } - case SpellType_Nuke: { - if((tar->GetHPRatio() <= 95.0f) || ((botClass == BARD) || (botClass == SHAMAN) || (botClass == ENCHANTER))) - { - if(!checked_los) { - if(!CheckLosFN(tar)) - break; //cannot see target... we assume that no spell is going to work since we will only be casting detrimental spells in this call - - checked_los = true; } - if(botClass == CLERIC || botClass == ENCHANTER) + if (botClass == ENCHANTER && IsEffectInSpell(selectedBotSpell.SpellId, SE_Rune)) { float manaRatioToCast = 75.0f; - switch(this->GetBotStance()) { + switch (this->GetBotStance()) { case EQ::constants::stanceEfficient: manaRatioToCast = 90.0f; break; case EQ::constants::stanceBalanced: + case EQ::constants::stanceAggressive: manaRatioToCast = 75.0f; break; case EQ::constants::stanceReactive: - case EQ::constants::stanceAggressive: - manaRatioToCast = 50.0f; - break; case EQ::constants::stanceBurn: case EQ::constants::stanceBurnAE: - manaRatioToCast = 25.0f; - break; - default: manaRatioToCast = 50.0f; break; - } - - //If we're at specified mana % or below, don't nuke as cleric or enchanter - if(this->GetManaRatio() <= manaRatioToCast) - break; - } - - if(botClass == MAGICIAN || botClass == SHADOWKNIGHT || botClass == NECROMANCER || botClass == PALADIN || botClass == RANGER || botClass == DRUID || botClass == CLERIC) { - if(tar->GetBodyType() == BT_Undead || tar->GetBodyType() == BT_SummonedUndead || tar->GetBodyType() == BT_Vampire) - botSpell = GetBestBotSpellForNukeByTargetType(this, ST_Undead); - else if(tar->GetBodyType() == BT_Summoned || tar->GetBodyType() == BT_Summoned2 || tar->GetBodyType() == BT_Summoned3) - botSpell = GetBestBotSpellForNukeByTargetType(this, ST_Summoned); - } - - if(botClass == PALADIN || botClass == DRUID || botClass == CLERIC || botClass == ENCHANTER || botClass == WIZARD) { - if(botSpell.SpellId == 0) { - uint8 stunChance = (tar->IsCasting() ? 30: 15); - - if(botClass == PALADIN) - stunChance = 50; - - if(!tar->GetSpecialAbility(UNSTUNABLE) && !tar->IsStunned() && (zone->random.Int(1, 100) <= stunChance)) { - botSpell = GetBestBotSpellForStunByTargetType(this, ST_Target); - } - } - } - - if(botClass == WIZARD && botSpell.SpellId == 0) { - botSpell = GetBestBotWizardNukeSpellByTargetResists(this, tar); - } - - if(botSpell.SpellId == 0) - botSpell = GetBestBotSpellForNukeByTargetType(this, ST_Target); - - if(botSpell.SpellId == 0) - break; - - if(!(!tar->IsImmuneToSpell(botSpell.SpellId, this) && (tar->CanBuffStack(botSpell.SpellId, botLevel, true) >= 0))) - break; - - if(IsFearSpell(botSpell.SpellId)) { - // don't let fear cast if the npc isn't snared or rooted - if(tar->GetSnaredAmount() == -1) { - if(!tar->IsRooted()) - break; - } - } - - castedSpell = AIDoSpellCast(botSpell.SpellIndex, tar, botSpell.ManaCost); - } - break; - } - case SpellType_Dispel: { - if(tar->GetHPRatio() > 95.0f) { - if(!checked_los) { - if(!CheckLosFN(tar)) - break; //cannot see target... we assume that no spell is going to work since we will only be casting detrimental spells in this call - - checked_los = true; - } - - botSpell = GetFirstBotSpellBySpellType(this, iSpellTypes); - - if(botSpell.SpellId == 0) - break; - - // TODO: Check target to see if there is anything to dispel - - if(tar->CountDispellableBuffs() > 0) { - castedSpell = AIDoSpellCast(botSpell.SpellIndex, tar, botSpell.ManaCost); - } - } - break; - } - case SpellType_Pet: { - //keep mobs from recasting pets when they have them. - if (!IsPet() && !GetPetID() && !IsBotCharmer()) { - if (botClass == WIZARD) { - auto buffs_max = GetMaxBuffSlots(); - auto my_buffs = GetBuffs(); - int familiar_buff_slot = -1; - if (buffs_max && my_buffs) { - for (int index = 0; index < buffs_max; ++index) { - if (IsEffectInSpell(my_buffs[index].spellid, SE_Familiar)) { - MakePet(my_buffs[index].spellid, spells[my_buffs[index].spellid].teleport_zone); - familiar_buff_slot = index; - break; - } - } - } - if (GetPetID()) - break; - - if (familiar_buff_slot >= 0) { - BuffFadeBySlot(familiar_buff_slot); + default: + manaRatioToCast = 75.0f; break; } - botSpell = GetFirstBotSpellBySpellType(this, SpellType_Pet); - } - else if (botClass == MAGICIAN) { - botSpell = GetBestBotMagicianPetSpell(this); - } - else { - botSpell = GetFirstBotSpellBySpellType(this, SpellType_Pet); + //If we're at specified mana % or below, don't rune as enchanter + if (this->GetManaRatio() <= manaRatioToCast) + break; } - if(botSpell.SpellId == 0) + if (CheckSpellRecastTimers(this, itr->SpellIndex)) + { + + uint32 TempDontBuffMeBefore = tar->DontBuffMeBefore(); + + castedSpell = AIDoSpellCast(selectedBotSpell.SpellIndex, tar, selectedBotSpell.ManaCost, &TempDontBuffMeBefore); + + if (TempDontBuffMeBefore != tar->DontBuffMeBefore()) + tar->SetDontBuffMeBefore(TempDontBuffMeBefore); + } + + if (castedSpell) break; - - castedSpell = AIDoSpellCast(botSpell.SpellIndex, tar, botSpell.ManaCost); } - break; } - case SpellType_InCombatBuff: { + break; + } + case SpellType_Escape: { + uint8 hpr = (uint8)GetHPRatio(); + bool mayGetAggro = false; + +#ifdef IPC + if (hpr <= 5 || (IsNPC() && CastToNPC()->IsInteractive() && tar != this)) +#else + if (hpr > 15 && ((botClass == WIZARD) || (botClass == ENCHANTER) || (botClass == RANGER))) + mayGetAggro = HasOrMayGetAggro(); //classes have hate reducing spells + + if (hpr <= 15 || mayGetAggro) +#endif + { + botSpell = GetFirstBotSpellBySpellType(this, iSpellTypes); + + if (botSpell.SpellId == 0) + break; + + if (IsInvulnerabilitySpell(botSpell.SpellId)) + tar = this; //target self for invul type spells + + castedSpell = AIDoSpellCast(botSpell.SpellIndex, tar, botSpell.ManaCost); + } + break; + } + case SpellType_Nuke: { + if ((tar->GetHPRatio() <= 95.0f) || ((botClass == BARD) || (botClass == SHAMAN) || (botClass == ENCHANTER))) + { + if (!checked_los) { + if (!CheckLosFN(tar)) + break; //cannot see target... we assume that no spell is going to work since we will only be casting detrimental spells in this call - if(botClass == SHAMAN) { checked_los = true; + } - std::list inCombatBuffList = GetBotSpellsBySpellType(this, SpellType_InCombatBuff); + if (botClass == CLERIC || botClass == ENCHANTER) + { + float manaRatioToCast = 75.0f; - for(std::list::iterator itr = inCombatBuffList.begin(); itr != inCombatBuffList.end(); ++itr) { - BotSpell selectedBotSpell = *itr; + switch (this->GetBotStance()) { + case EQ::constants::stanceEfficient: + manaRatioToCast = 90.0f; + break; + case EQ::constants::stanceBalanced: + manaRatioToCast = 75.0f; + break; + case EQ::constants::stanceReactive: + case EQ::constants::stanceAggressive: + manaRatioToCast = 50.0f; + break; + case EQ::constants::stanceBurn: + case EQ::constants::stanceBurnAE: + manaRatioToCast = 25.0f; + break; + default: + manaRatioToCast = 50.0f; + break; + } - if(selectedBotSpell.SpellId == 0) + //If we're at specified mana % or below, don't nuke as cleric or enchanter + if (this->GetManaRatio() <= manaRatioToCast) + break; + } + + if (botClass == MAGICIAN || botClass == SHADOWKNIGHT || botClass == NECROMANCER || botClass == PALADIN || botClass == RANGER || botClass == DRUID || botClass == CLERIC) { + if (tar->GetBodyType() == BT_Undead || tar->GetBodyType() == BT_SummonedUndead || tar->GetBodyType() == BT_Vampire) + botSpell = GetBestBotSpellForNukeByTargetType(this, ST_Undead); + else if (tar->GetBodyType() == BT_Summoned || tar->GetBodyType() == BT_Summoned2 || tar->GetBodyType() == BT_Summoned3) + botSpell = GetBestBotSpellForNukeByTargetType(this, ST_Summoned); + } + + if (botClass == PALADIN || botClass == DRUID || botClass == CLERIC || botClass == ENCHANTER || botClass == WIZARD) { + if (botSpell.SpellId == 0) { + uint8 stunChance = (tar->IsCasting() ? 30 : 15); + + if (botClass == PALADIN) + stunChance = 50; + + if (!tar->GetSpecialAbility(UNSTUNABLE) && !tar->IsStunned() && (zone->random.Int(1, 100) <= stunChance)) { + botSpell = GetBestBotSpellForStunByTargetType(this, ST_Target); + } + } + } + + if (botClass == WIZARD && botSpell.SpellId == 0) { + botSpell = GetBestBotWizardNukeSpellByTargetResists(this, tar); + } + + if (botSpell.SpellId == 0) + botSpell = GetBestBotSpellForNukeByTargetType(this, ST_Target); + + if (botSpell.SpellId == 0) + break; + + if (!(!tar->IsImmuneToSpell(botSpell.SpellId, this) && (tar->CanBuffStack(botSpell.SpellId, botLevel, true) >= 0))) + break; + + if (IsFearSpell(botSpell.SpellId)) { + // don't let fear cast if the npc isn't snared or rooted + if (tar->GetSnaredAmount() == -1) { + if (!tar->IsRooted()) + break; + } + } + + castedSpell = AIDoSpellCast(botSpell.SpellIndex, tar, botSpell.ManaCost); + } + break; + } + case SpellType_Dispel: { + if (tar->GetHPRatio() > 95.0f) { + if (!checked_los) { + if (!CheckLosFN(tar)) + break; //cannot see target... we assume that no spell is going to work since we will only be casting detrimental spells in this call + + checked_los = true; + } + + botSpell = GetFirstBotSpellBySpellType(this, iSpellTypes); + + if (botSpell.SpellId == 0) + break; + + // TODO: Check target to see if there is anything to dispel + + if (tar->CountDispellableBuffs() > 0) { + castedSpell = AIDoSpellCast(botSpell.SpellIndex, tar, botSpell.ManaCost); + } + } + break; + } + case SpellType_Pet: { + //keep mobs from recasting pets when they have them. + if (!IsPet() && !GetPetID() && !IsBotCharmer()) { + if (botClass == WIZARD) { + auto buffs_max = GetMaxBuffSlots(); + auto my_buffs = GetBuffs(); + int familiar_buff_slot = -1; + if (buffs_max && my_buffs) { + for (int index = 0; index < buffs_max; ++index) { + if (IsEffectInSpell(my_buffs[index].spellid, SE_Familiar)) { + MakePet(my_buffs[index].spellid, spells[my_buffs[index].spellid].teleport_zone); + familiar_buff_slot = index; + break; + } + } + } + if (GetPetID()) + break; + + if (familiar_buff_slot >= 0) { + BuffFadeBySlot(familiar_buff_slot); + break; + } + + botSpell = GetFirstBotSpellBySpellType(this, SpellType_Pet); + } + else if (botClass == MAGICIAN) { + botSpell = GetBestBotMagicianPetSpell(this); + } + else { + botSpell = GetFirstBotSpellBySpellType(this, SpellType_Pet); + } + + if (botSpell.SpellId == 0) + break; + + castedSpell = AIDoSpellCast(botSpell.SpellIndex, tar, botSpell.ManaCost); + } + break; + } + case SpellType_InCombatBuff: { + + if (botClass == SHAMAN) { + checked_los = true; + + std::list inCombatBuffList = GetBotSpellsBySpellType(this, SpellType_InCombatBuff); + + for (std::list::iterator itr = inCombatBuffList.begin(); itr != inCombatBuffList.end(); ++itr) { + BotSpell selectedBotSpell = *itr; + + if (selectedBotSpell.SpellId == 0) + continue; + + if (CheckSpellRecastTimers(this, itr->SpellIndex)) + { + if (!(!tar->IsImmuneToSpell(selectedBotSpell.SpellId, this) && (spells[selectedBotSpell.SpellId].buff_duration < 1 || tar->CanBuffStack(selectedBotSpell.SpellId, botLevel, true) >= 0))) continue; - if(CheckSpellRecastTimers(this, itr->SpellIndex)) - { - if(!(!tar->IsImmuneToSpell(selectedBotSpell.SpellId, this) && (spells[selectedBotSpell.SpellId].buff_duration < 1 || tar->CanBuffStack(selectedBotSpell.SpellId, botLevel, true) >= 0))) - continue; - - //short duration buffs or other buffs only to be cast during combat. - if (IsSelfConversionSpell(selectedBotSpell.SpellId)) { - if(GetManaRatio() > 90.0f || GetHPRatio() < 50.0f || GetHPRatio() < (GetManaRatio() + 10.0f)) - break; //don't cast if low hp, lots of mana, or if mana is higher than hps - } - - castedSpell = AIDoSpellCast(selectedBotSpell.SpellIndex, tar, selectedBotSpell.ManaCost); + //short duration buffs or other buffs only to be cast during combat. + if (IsSelfConversionSpell(selectedBotSpell.SpellId)) { + if (GetManaRatio() > 90.0f || GetHPRatio() < 50.0f || GetHPRatio() < (GetManaRatio() + 10.0f)) + break; //don't cast if low hp, lots of mana, or if mana is higher than hps } - if(castedSpell) - break; + castedSpell = AIDoSpellCast(selectedBotSpell.SpellIndex, tar, selectedBotSpell.ManaCost); } + + if (castedSpell) + break; } - else if(botClass == BARD) { - if (tar->DontBuffMeBefore() < Timer::GetCurrentTime()) { - std::list inCombatBuffList = GetBotSpellsBySpellType(this, SpellType_InCombatBuff); + } + else if (botClass == BARD) { + if (tar->DontBuffMeBefore() < Timer::GetCurrentTime()) { + std::list inCombatBuffList = GetBotSpellsBySpellType(this, SpellType_InCombatBuff); - for(std::list::iterator itr = inCombatBuffList.begin(); itr != inCombatBuffList.end(); ++itr) { - BotSpell selectedBotSpell = *itr; + for (std::list::iterator itr = inCombatBuffList.begin(); itr != inCombatBuffList.end(); ++itr) { + BotSpell selectedBotSpell = *itr; - if(selectedBotSpell.SpellId == 0) + if (selectedBotSpell.SpellId == 0) + continue; + + if (CheckSpellRecastTimers(this, itr->SpellIndex)) { + uint32 TempDontBuffMeBefore = tar->DontBuffMeBefore(); + + // no buffs with illusions.. use #bot command to cast illusions + if (IsEffectInSpell(selectedBotSpell.SpellId, SE_Illusion) && tar != this) continue; - if(CheckSpellRecastTimers(this, itr->SpellIndex)) { - uint32 TempDontBuffMeBefore = tar->DontBuffMeBefore(); + //no teleport spells use #bot command to cast teleports + if (IsEffectInSpell(selectedBotSpell.SpellId, SE_Teleport) || IsEffectInSpell(selectedBotSpell.SpellId, SE_Succor)) + continue; - // no buffs with illusions.. use #bot command to cast illusions - if(IsEffectInSpell(selectedBotSpell.SpellId, SE_Illusion) && tar != this) + // can not cast buffs for your own pet only on another pet that isn't yours + if ((spells[selectedBotSpell.SpellId].target_type == ST_Pet) && (tar != this->GetPet())) + continue; + + // Validate target + + if (!((spells[selectedBotSpell.SpellId].target_type == ST_Target || spells[selectedBotSpell.SpellId].target_type == ST_Pet || tar == this || + spells[selectedBotSpell.SpellId].target_type == ST_Group || spells[selectedBotSpell.SpellId].target_type == ST_GroupTeleport || + (botClass == BARD && spells[selectedBotSpell.SpellId].target_type == ST_AEBard)) + && !tar->IsImmuneToSpell(selectedBotSpell.SpellId, this) + && (tar->CanBuffStack(selectedBotSpell.SpellId, botLevel, true) >= 0))) { + continue; + } + + // Put the zone levitate and movement check here since bots are able to bypass the client casting check + if ((IsEffectInSpell(selectedBotSpell.SpellId, SE_Levitate) && !zone->CanLevitate()) + || (IsEffectInSpell(selectedBotSpell.SpellId, SE_MovementSpeed) && !zone->CanCastOutdoor())) { + if (!IsSpellUsableThisZoneType(selectedBotSpell.SpellId, zone->GetZoneType())) { continue; + } + } - //no teleport spells use #bot command to cast teleports - if(IsEffectInSpell(selectedBotSpell.SpellId, SE_Teleport) || IsEffectInSpell(selectedBotSpell.SpellId, SE_Succor)) - continue; - - // can not cast buffs for your own pet only on another pet that isn't yours - if((spells[selectedBotSpell.SpellId].target_type == ST_Pet) && (tar != this->GetPet())) - continue; - - // Validate target - - if(!((spells[selectedBotSpell.SpellId].target_type == ST_Target || spells[selectedBotSpell.SpellId].target_type == ST_Pet || tar == this || - spells[selectedBotSpell.SpellId].target_type == ST_Group || spells[selectedBotSpell.SpellId].target_type == ST_GroupTeleport || - (botClass == BARD && spells[selectedBotSpell.SpellId].target_type == ST_AEBard)) - && !tar->IsImmuneToSpell(selectedBotSpell.SpellId, this) - && (tar->CanBuffStack(selectedBotSpell.SpellId, botLevel, true) >= 0))) { + if (!IsGroupSpell(selectedBotSpell.SpellId)) { + //Only check archetype if song is not a group spell + switch (tar->GetArchetype()) { + case ARCHETYPE_CASTER: + //TODO: probably more caster specific spell effects in here + if (IsEffectInSpell(selectedBotSpell.SpellId, SE_AttackSpeed) || IsEffectInSpell(selectedBotSpell.SpellId, SE_ATK) || + IsEffectInSpell(selectedBotSpell.SpellId, SE_STR) || IsEffectInSpell(selectedBotSpell.SpellId, SE_ReverseDS)) + { continue; - } - - // Put the zone levitate and movement check here since bots are able to bypass the client casting check - if((IsEffectInSpell(selectedBotSpell.SpellId, SE_Levitate) && !zone->CanLevitate()) - || (IsEffectInSpell(selectedBotSpell.SpellId, SE_MovementSpeed) && !zone->CanCastOutdoor())) { - if(!IsSpellUsableThisZoneType(selectedBotSpell.SpellId, zone->GetZoneType())) { - continue; - } - } - - if(!IsGroupSpell(selectedBotSpell.SpellId)) { - //Only check archetype if song is not a group spell - switch(tar->GetArchetype()) { - case ARCHETYPE_CASTER: - //TODO: probably more caster specific spell effects in here - if(IsEffectInSpell(selectedBotSpell.SpellId, SE_AttackSpeed) || IsEffectInSpell(selectedBotSpell.SpellId, SE_ATK) || - IsEffectInSpell(selectedBotSpell.SpellId, SE_STR) || IsEffectInSpell(selectedBotSpell.SpellId, SE_ReverseDS)) - { - continue; - } - break; - case ARCHETYPE_MELEE: - if(IsEffectInSpell(selectedBotSpell.SpellId, SE_IncreaseSpellHaste) || IsEffectInSpell(selectedBotSpell.SpellId, SE_ManaPool) || - IsEffectInSpell(selectedBotSpell.SpellId, SE_CastingLevel) || IsEffectInSpell(selectedBotSpell.SpellId, SE_ManaRegen_v2) || - IsEffectInSpell(selectedBotSpell.SpellId, SE_CurrentMana)) - { - continue; - } - break; - case ARCHETYPE_HYBRID: - //Hybrids get all buffs - default: - break; } - } - - castedSpell = AIDoSpellCast(selectedBotSpell.SpellIndex, tar, selectedBotSpell.ManaCost, &TempDontBuffMeBefore); - - if(TempDontBuffMeBefore != tar->DontBuffMeBefore()) - tar->SetDontBuffMeBefore(TempDontBuffMeBefore); - } - - if(castedSpell) - break; - } - } - } - break; - } - case SpellType_Lifetap: { - if (GetHPRatio() < 90.0f) { - if(!checked_los) { - if(!CheckLosFN(tar)) - break; //cannot see target... we assume that no spell is going to work since we will only be casting detrimental spells in this call - - checked_los = true; - } - - botSpell = GetFirstBotSpellBySpellType(this, iSpellTypes); - - if(botSpell.SpellId == 0) - break; - - if(!(!tar->IsImmuneToSpell(botSpell.SpellId, this) && (tar->CanBuffStack(botSpell.SpellId, botLevel, true) >= 0))) - break; - - castedSpell = AIDoSpellCast(botSpell.SpellIndex, tar, botSpell.ManaCost); - } - break; - } - case SpellType_Snare: { - if (tar->DontSnareMeBefore() < Timer::GetCurrentTime()) { - if(!checked_los) { - if(!CheckLosFN(tar)) - break; //cannot see target... we assume that no spell is going to work since we will only be casting detrimental spells in this call - - checked_los = true; - } - - botSpell = GetFirstBotSpellBySpellType(this, iSpellTypes); - - if(botSpell.SpellId == 0) - break; - - if(!(!tar->IsImmuneToSpell(botSpell.SpellId, this) && tar->CanBuffStack(botSpell.SpellId, botLevel, true) >= 0)) - break; - - uint32 TempDontSnareMeBefore = tar->DontSnareMeBefore(); - - castedSpell = AIDoSpellCast(botSpell.SpellIndex, tar, botSpell.ManaCost, &TempDontSnareMeBefore); - - if(TempDontSnareMeBefore != tar->DontSnareMeBefore()) - tar->SetDontSnareMeBefore(TempDontSnareMeBefore); - } - break; - } - case SpellType_DOT: { - if ((tar->GetHPRatio() <= 98.0f) && (tar->DontDotMeBefore() < Timer::GetCurrentTime()) && (tar->GetHPRatio() > 15.0f)) { - if(!checked_los) { - if(!CheckLosFN(tar)) - break; //cannot see target... we assume that no spell is going to work since we will only be casting detrimental spells in this call - - checked_los = true; - } - - if (GetClass() == BARD) { - std::list dotList = GetPrioritizedBotSpellsBySpellType(this, SpellType_DOT); - - const int maxDotSelect = 5; - int dotSelectCounter = 0; - - for (std::list::iterator itr = dotList.begin(); itr != dotList.end(); ++itr) { - BotSpell selectedBotSpell = *itr; - - if (selectedBotSpell.SpellId == 0) - continue; - - if (CheckSpellRecastTimers(this, itr->SpellIndex)) - { - - if (!(!tar->IsImmuneToSpell(selectedBotSpell.SpellId, this) && tar->CanBuffStack(selectedBotSpell.SpellId, botLevel, true) >= 0)) - continue; - - uint32 TempDontDotMeBefore = tar->DontDotMeBefore(); - - castedSpell = AIDoSpellCast(selectedBotSpell.SpellIndex, tar, selectedBotSpell.ManaCost, &TempDontDotMeBefore); - - if (TempDontDotMeBefore != tar->DontDotMeBefore()) - tar->SetDontDotMeBefore(TempDontDotMeBefore); - } - - dotSelectCounter++; - - if ((dotSelectCounter == maxDotSelect) || castedSpell) - break; - } - } - else { - std::list dotList = GetBotSpellsBySpellType(this, SpellType_DOT); - - const int maxDotSelect = 5; - int dotSelectCounter = 0; - - for (std::list::iterator itr = dotList.begin(); itr != dotList.end(); ++itr) { - BotSpell selectedBotSpell = *itr; - - if (selectedBotSpell.SpellId == 0) - continue; - - if (CheckSpellRecastTimers(this, itr->SpellIndex)) - { - - if (!(!tar->IsImmuneToSpell(selectedBotSpell.SpellId, this) && tar->CanBuffStack(selectedBotSpell.SpellId, botLevel, true) >= 0)) - continue; - - uint32 TempDontDotMeBefore = tar->DontDotMeBefore(); - - castedSpell = AIDoSpellCast(selectedBotSpell.SpellIndex, tar, selectedBotSpell.ManaCost, &TempDontDotMeBefore); - - if (TempDontDotMeBefore != tar->DontDotMeBefore()) - tar->SetDontDotMeBefore(TempDontDotMeBefore); - } - - dotSelectCounter++; - - if ((dotSelectCounter == maxDotSelect) || castedSpell) - break; - } - } - } - break; - } - case SpellType_Slow: { - if (tar->GetHPRatio() <= 99.0f) { - - if(!checked_los) { - if(!CheckLosFN(tar)) - break; //cannot see target... we assume that no spell is going to work since we will only be casting detrimental spells in this call - - checked_los = true; - } - - switch (botClass) { - case BARD: { - // probably needs attackable check - std::list botSongList = GetPrioritizedBotSpellsBySpellType(this, SpellType_Slow); - for (auto iter : botSongList) { - if (!iter.SpellId) - continue; - if (!CheckSpellRecastTimers(this, iter.SpellIndex)) - continue; - if (spells[iter.SpellId].zone_type != -1 && zone->GetZoneType() != -1 && spells[iter.SpellId].zone_type != zone->GetZoneType()) // is this bit or index? - continue; - if (spells[iter.SpellId].target_type != ST_Target) - continue; - if (tar->CanBuffStack(iter.SpellId, botLevel, true) < 0) - continue; - - castedSpell = AIDoSpellCast(iter.SpellIndex, tar, iter.ManaCost); - if (castedSpell) break; - } - - break; - } - case ENCHANTER: { - botSpell = GetBestBotSpellForMagicBasedSlow(this); - break; - } - case SHAMAN: - case BEASTLORD: { - botSpell = GetBestBotSpellForDiseaseBasedSlow(this); - - if(botSpell.SpellId == 0 || ((tar->GetMR() - 50) < (tar->GetDR() + spells[botSpell.SpellId].resist_difficulty))) - botSpell = GetBestBotSpellForMagicBasedSlow(this); - break; - } - } - - if(botSpell.SpellId == 0) - break; - - if(!(!tar->IsImmuneToSpell(botSpell.SpellId, this) && tar->CanBuffStack(botSpell.SpellId, botLevel, true) >= 0)) - break; - - castedSpell = AIDoSpellCast(botSpell.SpellIndex, tar, botSpell.ManaCost); - - if(castedSpell && GetClass() != BARD) - BotGroupSay(this, "Attempting to slow %s.", tar->GetCleanName()); - } - break; - } - case SpellType_Debuff: { - if((tar->GetHPRatio() <= 99.0f) || ((botClass == BARD) || (botClass == SHAMAN) || (botClass == ENCHANTER) || (botClass == DRUID)) && (tar->GetHPRatio() > 40.0f)) - { - if(!checked_los) { - if(!CheckLosFN(tar)) - break; //cannot see target... we assume that no spell is going to work since we will only be casting detrimental spells in this call - - checked_los = true; - } - - botSpell = GetBestBotSpellForResistDebuff(this, tar); - - if(botSpell.SpellId == 0) - botSpell = GetDebuffBotSpell(this, tar); - - if(botSpell.SpellId == 0) - break; - - if(!(!tar->IsImmuneToSpell(botSpell.SpellId, this) && (tar->CanBuffStack(botSpell.SpellId, botLevel, true) >= 0))) - break; - - castedSpell = AIDoSpellCast(botSpell.SpellIndex, tar, botSpell.ManaCost); - } - break; - } - case SpellType_Cure: { - if(GetNeedsCured(tar) && (tar->DontCureMeBefore() < Timer::GetCurrentTime()) && !(GetNumberNeedingHealedInGroup(25, false) > 0) && !(GetNumberNeedingHealedInGroup(40, false) > 2)) - { - botSpell = GetBestBotSpellForCure(this, tar); - - if(botSpell.SpellId == 0) - break; - - uint32 TempDontCureMeBeforeTime = tar->DontCureMeBefore(); - - castedSpell = AIDoSpellCast(botSpell.SpellIndex, tar, botSpell.ManaCost, &TempDontCureMeBeforeTime); - - if(castedSpell) { - if(botClass != BARD) { - if(IsGroupSpell(botSpell.SpellId)){ - Group *g; - - if(this->HasGroup()) { - Group *g = this->GetGroup(); - - if(g) { - for( int i = 0; imembers[i] && !g->members[i]->qglobal) { - if(TempDontCureMeBeforeTime != tar->DontCureMeBefore()) - g->members[i]->SetDontCureMeBefore(Timer::GetCurrentTime() + 4000); - } - } + case ARCHETYPE_MELEE: + if (IsEffectInSpell(selectedBotSpell.SpellId, SE_IncreaseSpellHaste) || IsEffectInSpell(selectedBotSpell.SpellId, SE_ManaPool) || + IsEffectInSpell(selectedBotSpell.SpellId, SE_CastingLevel) || IsEffectInSpell(selectedBotSpell.SpellId, SE_ManaRegen_v2) || + IsEffectInSpell(selectedBotSpell.SpellId, SE_CurrentMana)) + { + continue; } + break; + case ARCHETYPE_HYBRID: + //Hybrids get all buffs + default: + break; } } - else { - if(TempDontCureMeBeforeTime != tar->DontCureMeBefore()) - tar->SetDontCureMeBefore(Timer::GetCurrentTime() + 4000); - } + + castedSpell = AIDoSpellCast(selectedBotSpell.SpellIndex, tar, selectedBotSpell.ManaCost, &TempDontBuffMeBefore); + + if (TempDontBuffMeBefore != tar->DontBuffMeBefore()) + tar->SetDontBuffMeBefore(TempDontBuffMeBefore); } + + if (castedSpell) + break; } } - break; } - case SpellType_Resurrect: - break; - case SpellType_HateRedux: { - // assumed group member at this point + break; + } + case SpellType_Lifetap: { + if (GetHPRatio() < 90.0f) { + if (!checked_los) { + if (!CheckLosFN(tar)) + break; //cannot see target... we assume that no spell is going to work since we will only be casting detrimental spells in this call + + checked_los = true; + } + + botSpell = GetFirstBotSpellBySpellType(this, iSpellTypes); + + if (botSpell.SpellId == 0) + break; + + if (!(!tar->IsImmuneToSpell(botSpell.SpellId, this) && (tar->CanBuffStack(botSpell.SpellId, botLevel, true) >= 0))) + break; + + castedSpell = AIDoSpellCast(botSpell.SpellIndex, tar, botSpell.ManaCost); + } + break; + } + case SpellType_Snare: { + if (tar->DontSnareMeBefore() < Timer::GetCurrentTime()) { + if (!checked_los) { + if (!CheckLosFN(tar)) + break; //cannot see target... we assume that no spell is going to work since we will only be casting detrimental spells in this call + + checked_los = true; + } + + botSpell = GetFirstBotSpellBySpellType(this, iSpellTypes); + + if (botSpell.SpellId == 0) + break; + + if (!(!tar->IsImmuneToSpell(botSpell.SpellId, this) && tar->CanBuffStack(botSpell.SpellId, botLevel, true) >= 0)) + break; + + uint32 TempDontSnareMeBefore = tar->DontSnareMeBefore(); + + castedSpell = AIDoSpellCast(botSpell.SpellIndex, tar, botSpell.ManaCost, &TempDontSnareMeBefore); + + if (TempDontSnareMeBefore != tar->DontSnareMeBefore()) + tar->SetDontSnareMeBefore(TempDontSnareMeBefore); + } + break; + } + case SpellType_DOT: { + if ((tar->GetHPRatio() <= 98.0f) && (tar->DontDotMeBefore() < Timer::GetCurrentTime()) && (tar->GetHPRatio() > 15.0f)) { + if (!checked_los) { + if (!CheckLosFN(tar)) + break; //cannot see target... we assume that no spell is going to work since we will only be casting detrimental spells in this call + + checked_los = true; + } + if (GetClass() == BARD) { - std::list botSongList = GetPrioritizedBotSpellsBySpellType(this, SpellType_HateRedux); + std::list dotList = GetPrioritizedBotSpellsBySpellType(this, SpellType_DOT); + + const int maxDotSelect = 5; + int dotSelectCounter = 0; + + for (std::list::iterator itr = dotList.begin(); itr != dotList.end(); ++itr) { + BotSpell selectedBotSpell = *itr; + + if (selectedBotSpell.SpellId == 0) + continue; + + if (CheckSpellRecastTimers(this, itr->SpellIndex)) + { + + if (!(!tar->IsImmuneToSpell(selectedBotSpell.SpellId, this) && tar->CanBuffStack(selectedBotSpell.SpellId, botLevel, true) >= 0)) + continue; + + uint32 TempDontDotMeBefore = tar->DontDotMeBefore(); + + castedSpell = AIDoSpellCast(selectedBotSpell.SpellIndex, tar, selectedBotSpell.ManaCost, &TempDontDotMeBefore); + + if (TempDontDotMeBefore != tar->DontDotMeBefore()) + tar->SetDontDotMeBefore(TempDontDotMeBefore); + } + + dotSelectCounter++; + + if ((dotSelectCounter == maxDotSelect) || castedSpell) + break; + } + } + else { + std::list dotList = GetBotSpellsBySpellType(this, SpellType_DOT); + + const int maxDotSelect = 5; + int dotSelectCounter = 0; + + for (std::list::iterator itr = dotList.begin(); itr != dotList.end(); ++itr) { + BotSpell selectedBotSpell = *itr; + + if (selectedBotSpell.SpellId == 0) + continue; + + if (CheckSpellRecastTimers(this, itr->SpellIndex)) + { + + if (!(!tar->IsImmuneToSpell(selectedBotSpell.SpellId, this) && tar->CanBuffStack(selectedBotSpell.SpellId, botLevel, true) >= 0)) + continue; + + uint32 TempDontDotMeBefore = tar->DontDotMeBefore(); + + castedSpell = AIDoSpellCast(selectedBotSpell.SpellIndex, tar, selectedBotSpell.ManaCost, &TempDontDotMeBefore); + + if (TempDontDotMeBefore != tar->DontDotMeBefore()) + tar->SetDontDotMeBefore(TempDontDotMeBefore); + } + + dotSelectCounter++; + + if ((dotSelectCounter == maxDotSelect) || castedSpell) + break; + } + } + } + break; + } + case SpellType_Slow: { + if (tar->GetHPRatio() <= 99.0f) { + + if (!checked_los) { + if (!CheckLosFN(tar)) + break; //cannot see target... we assume that no spell is going to work since we will only be casting detrimental spells in this call + + checked_los = true; + } + + switch (botClass) { + case BARD: { + // probably needs attackable check + std::list botSongList = GetPrioritizedBotSpellsBySpellType(this, SpellType_Slow); for (auto iter : botSongList) { if (!iter.SpellId) continue; @@ -970,20 +855,109 @@ bool Bot::AICastSpell(Mob* tar, uint8 iChance, uint32 iSpellTypes) { continue; castedSpell = AIDoSpellCast(iter.SpellIndex, tar, iter.ManaCost); - if (castedSpell) { - BotGroupSay(this, "Attempting to reduce hate on %s.", tar->GetCleanName()); + if (castedSpell) break; + } + + break; + } + case ENCHANTER: { + botSpell = GetBestBotSpellForMagicBasedSlow(this); + break; + } + case SHAMAN: + case BEASTLORD: { + botSpell = GetBestBotSpellForDiseaseBasedSlow(this); + + if (botSpell.SpellId == 0 || ((tar->GetMR() - 50) < (tar->GetDR() + spells[botSpell.SpellId].resist_difficulty))) + botSpell = GetBestBotSpellForMagicBasedSlow(this); + break; + } + } + + if (botSpell.SpellId == 0) + break; + + if (!(!tar->IsImmuneToSpell(botSpell.SpellId, this) && tar->CanBuffStack(botSpell.SpellId, botLevel, true) >= 0)) + break; + + castedSpell = AIDoSpellCast(botSpell.SpellIndex, tar, botSpell.ManaCost); + + if (castedSpell && GetClass() != BARD) + BotGroupSay(this, "Attempting to slow %s.", tar->GetCleanName()); + } + break; + } + case SpellType_Debuff: { + if ((tar->GetHPRatio() <= 99.0f) || ((botClass == BARD) || (botClass == SHAMAN) || (botClass == ENCHANTER) || (botClass == DRUID)) && (tar->GetHPRatio() > 40.0f)) + { + if (!checked_los) { + if (!CheckLosFN(tar)) + break; //cannot see target... we assume that no spell is going to work since we will only be casting detrimental spells in this call + + checked_los = true; + } + + botSpell = GetBestBotSpellForResistDebuff(this, tar); + + if (botSpell.SpellId == 0) + botSpell = GetDebuffBotSpell(this, tar); + + if (botSpell.SpellId == 0) + break; + + if (!(!tar->IsImmuneToSpell(botSpell.SpellId, this) && (tar->CanBuffStack(botSpell.SpellId, botLevel, true) >= 0))) + break; + + castedSpell = AIDoSpellCast(botSpell.SpellIndex, tar, botSpell.ManaCost); + } + break; + } + case SpellType_Cure: { + if (GetNeedsCured(tar) && (tar->DontCureMeBefore() < Timer::GetCurrentTime()) && !(GetNumberNeedingHealedInGroup(25, false) > 0) && !(GetNumberNeedingHealedInGroup(40, false) > 2)) + { + botSpell = GetBestBotSpellForCure(this, tar); + + if (botSpell.SpellId == 0) + break; + + uint32 TempDontCureMeBeforeTime = tar->DontCureMeBefore(); + + castedSpell = AIDoSpellCast(botSpell.SpellIndex, tar, botSpell.ManaCost, &TempDontCureMeBeforeTime); + + if (castedSpell) { + if (botClass != BARD) { + if (IsGroupSpell(botSpell.SpellId)) { + Group* g; + + if (this->HasGroup()) { + Group* g = this->GetGroup(); + + if (g) { + for (int i = 0; i < MAX_GROUP_MEMBERS; i++) { + if (g->members[i] && !g->members[i]->qglobal) { + if (TempDontCureMeBeforeTime != tar->DontCureMeBefore()) + g->members[i]->SetDontCureMeBefore(Timer::GetCurrentTime() + 4000); + } + } + } + } + } + else { + if (TempDontCureMeBeforeTime != tar->DontCureMeBefore()) + tar->SetDontCureMeBefore(Timer::GetCurrentTime() + 4000); } } } - - break; } - case SpellType_InCombatBuffSong: { - if (GetClass() != BARD || tar != this) // In-Combat songs can be cast Out-of-Combat in preparation for battle - break; - - std::list botSongList = GetPrioritizedBotSpellsBySpellType(this, SpellType_InCombatBuffSong); + break; + } + case SpellType_Resurrect: + break; + case SpellType_HateRedux: { + // assumed group member at this point + if (GetClass() == BARD) { + std::list botSongList = GetPrioritizedBotSpellsBySpellType(this, SpellType_HateRedux); for (auto iter : botSongList) { if (!iter.SpellId) continue; @@ -991,66 +965,93 @@ bool Bot::AICastSpell(Mob* tar, uint8 iChance, uint32 iSpellTypes) { continue; if (spells[iter.SpellId].zone_type != -1 && zone->GetZoneType() != -1 && spells[iter.SpellId].zone_type != zone->GetZoneType()) // is this bit or index? continue; - switch (spells[iter.SpellId].target_type) { - case ST_AEBard: - case ST_AECaster: - case ST_GroupTeleport: - case ST_Group: - case ST_Self: - break; - default: + if (spells[iter.SpellId].target_type != ST_Target) continue; - } if (tar->CanBuffStack(iter.SpellId, botLevel, true) < 0) continue; castedSpell = AIDoSpellCast(iter.SpellIndex, tar, iter.ManaCost); - if (castedSpell) + if (castedSpell) { + BotGroupSay(this, "Attempting to reduce hate on %s.", tar->GetCleanName()); break; + } } - - break; } - case SpellType_OutOfCombatBuffSong: { - if (GetClass() != BARD || tar != this || IsEngaged()) // Out-of-Combat songs can not be cast in combat + + break; + } + case SpellType_InCombatBuffSong: { + if (GetClass() != BARD || tar != this) // In-Combat songs can be cast Out-of-Combat in preparation for battle + break; + + std::list botSongList = GetPrioritizedBotSpellsBySpellType(this, SpellType_InCombatBuffSong); + for (auto iter : botSongList) { + if (!iter.SpellId) + continue; + if (!CheckSpellRecastTimers(this, iter.SpellIndex)) + continue; + if (spells[iter.SpellId].zone_type != -1 && zone->GetZoneType() != -1 && spells[iter.SpellId].zone_type != zone->GetZoneType()) // is this bit or index? + continue; + switch (spells[iter.SpellId].target_type) { + case ST_AEBard: + case ST_AECaster: + case ST_GroupTeleport: + case ST_Group: + case ST_Self: break; - - std::list botSongList = GetPrioritizedBotSpellsBySpellType(this, SpellType_OutOfCombatBuffSong); - for (auto iter : botSongList) { - if (!iter.SpellId) - continue; - if (!CheckSpellRecastTimers(this, iter.SpellIndex)) - continue; - if (spells[iter.SpellId].zone_type != -1 && zone->GetZoneType() != -1 && spells[iter.SpellId].zone_type != zone->GetZoneType()) // is this bit or index? - continue; - switch (spells[iter.SpellId].target_type) { - case ST_AEBard: - case ST_AECaster: - case ST_GroupTeleport: - case ST_Group: - case ST_Self: - break; - default: - continue; - } - if (tar->CanBuffStack(iter.SpellId, botLevel, true) < 0) - continue; - - castedSpell = AIDoSpellCast(iter.SpellIndex, tar, iter.ManaCost); - if (castedSpell) - break; + default: + continue; } + if (tar->CanBuffStack(iter.SpellId, botLevel, true) < 0) + continue; - break; + castedSpell = AIDoSpellCast(iter.SpellIndex, tar, iter.ManaCost); + if (castedSpell) + break; } - case SpellType_PreCombatBuff: { + + break; + } + case SpellType_OutOfCombatBuffSong: { + if (GetClass() != BARD || tar != this || IsEngaged()) // Out-of-Combat songs can not be cast in combat break; + + std::list botSongList = GetPrioritizedBotSpellsBySpellType(this, SpellType_OutOfCombatBuffSong); + for (auto iter : botSongList) { + if (!iter.SpellId) + continue; + if (!CheckSpellRecastTimers(this, iter.SpellIndex)) + continue; + if (spells[iter.SpellId].zone_type != -1 && zone->GetZoneType() != -1 && spells[iter.SpellId].zone_type != zone->GetZoneType()) // is this bit or index? + continue; + switch (spells[iter.SpellId].target_type) { + case ST_AEBard: + case ST_AECaster: + case ST_GroupTeleport: + case ST_Group: + case ST_Self: + break; + default: + continue; + } + if (tar->CanBuffStack(iter.SpellId, botLevel, true) < 0) + continue; + + castedSpell = AIDoSpellCast(iter.SpellIndex, tar, iter.ManaCost); + if (castedSpell) + break; } - case SpellType_PreCombatBuffSong: { - break; - } - default: - break; + + break; + } + case SpellType_PreCombatBuff: { + break; + } + case SpellType_PreCombatBuffSong: { + break; + } + default: + break; } return castedSpell; @@ -1058,7 +1059,6 @@ bool Bot::AICastSpell(Mob* tar, uint8 iChance, uint32 iSpellTypes) { bool Bot::AIDoSpellCast(uint8 i, Mob* tar, int32 mana_cost, uint32* oDontDoAgainBefore) { bool result = false; - // manacost has special values, -1 is no mana cost, -2 is instant cast (no mana) int32 manaCost = mana_cost; @@ -1070,11 +1070,13 @@ bool Bot::AIDoSpellCast(uint8 i, Mob* tar, int32 mana_cost, uint32* oDontDoAgain int32 extraMana = 0; int32 hasMana = GetMana(); + Log(Logs::General, Logs::Mercenaries, "Attempting to cast %s on %s", spells[AIspells[i].spellid].name, tar == nullptr ? "no target" : tar->GetCleanName()); + // Allow bots to cast buff spells even if they are out of mana - if(RuleB(Bots, FinishBuffing)) { - if(manaCost > hasMana) { + if (RuleB(Bots, FinishBuffing)) { + if (manaCost > hasMana) { // Let's have the bots complete the buff time process - if(AIspells[i].type & SpellType_Buff) { + if (AIspells[i].type & SpellType_Buff) { extraMana = manaCost - hasMana; SetMana(manaCost); } @@ -1085,24 +1087,25 @@ bool Bot::AIDoSpellCast(uint8 i, Mob* tar, int32 mana_cost, uint32* oDontDoAgain if (AIspells[i].type & SpellType_Escape) { dist2 = 0; - } else + } + else dist2 = DistanceSquared(m_Position, tar->GetPosition()); - if (((((spells[AIspells[i].spellid].target_type==ST_GroupTeleport && AIspells[i].type==2) - || spells[AIspells[i].spellid].target_type==ST_AECaster - || spells[AIspells[i].spellid].target_type==ST_Group - || spells[AIspells[i].spellid].target_type==ST_AEBard) - && dist2 <= spells[AIspells[i].spellid].aoe_range*spells[AIspells[i].spellid].aoe_range) - || dist2 <= GetActSpellRange(AIspells[i].spellid, spells[AIspells[i].spellid].range)*GetActSpellRange(AIspells[i].spellid, spells[AIspells[i].spellid].range)) && (mana_cost <= GetMana() || GetMana() == GetMaxMana())) + if (((((spells[AIspells[i].spellid].target_type == ST_GroupTeleport && AIspells[i].type == 2) + || spells[AIspells[i].spellid].target_type == ST_AECaster + || spells[AIspells[i].spellid].target_type == ST_Group + || spells[AIspells[i].spellid].target_type == ST_AEBard) + && dist2 <= spells[AIspells[i].spellid].aoe_range * spells[AIspells[i].spellid].aoe_range) + || dist2 <= GetActSpellRange(AIspells[i].spellid, spells[AIspells[i].spellid].range) * GetActSpellRange(AIspells[i].spellid, spells[AIspells[i].spellid].range)) && (mana_cost <= GetMana() || GetMana() == GetMaxMana())) { result = NPC::AIDoSpellCast(i, tar, mana_cost, oDontDoAgainBefore); - if(IsCasting() && IsSitting()) + if (IsCasting() && IsSitting()) Stand(); } // if the spell wasn't casted, then take back any extra mana that was given to the bot to cast that spell - if(!result) { + if (!result) { SetMana(hasMana); extraMana = false; } @@ -1119,7 +1122,7 @@ bool Bot::AIDoSpellCast(uint8 i, Mob* tar, int32 mana_cost, uint32* oDontDoAgain AIspells[i].time_cancast = Timer::GetCurrentTime() + spells[AIspells[i].spellid].recast_time; - if(spells[AIspells[i].spellid].timer_id > 0) { + if (spells[AIspells[i].spellid].timer_id > 0) { SetSpellRecastTimer(spells[AIspells[i].spellid].timer_id, spells[AIspells[i].spellid].recast_time); } } @@ -1132,21 +1135,21 @@ bool Bot::AI_PursueCastCheck() { if (AIautocastspell_timer->Check(false)) { - AIautocastspell_timer->Disable(); //prevent the timer from going off AGAIN while we are casting. - if (RuleB(Bots, IsBotsElixirEnabled)) { + AIautocastspell_timer->Start(3000, false); // avg human response is much less than 5 seconds..even for non-combat situations... if (ElixirAIDetermineSpellToCast()) { - AIautocastspell_timer->Start(RandomTimer(500, 2000), false); // avg human response is much less than 5 seconds..even for non-combat situations... return true; } return false; } + AIautocastspell_timer->Disable(); //prevent the timer from going off AGAIN while we are casting. + LogAI("Bot Engaged (pursuing) autocast check triggered. Trying to cast offensive spells"); - if(!AICastSpell(GetTarget(), 100, SpellType_Snare)) { - if(!AICastSpell(GetTarget(), 100, SpellType_Lifetap)) { - if(!AICastSpell(GetTarget(), 100, SpellType_Nuke)) { + if (!AICastSpell(GetTarget(), 100, SpellType_Snare)) { + if (!AICastSpell(GetTarget(), 100, SpellType_Lifetap)) { + if (!AICastSpell(GetTarget(), 100, SpellType_Nuke)) { /*AIautocastspell_timer->Start(RandomTimer(500, 2000), false); result = true;*/ result = true; @@ -1158,7 +1161,7 @@ bool Bot::AI_PursueCastCheck() { result = true; } - if(!AIautocastspell_timer->Enabled()) + if (!AIautocastspell_timer->Enabled()) AIautocastspell_timer->Start(RandomTimer(100, 250), false); } @@ -1172,15 +1175,16 @@ bool Bot::AI_IdleCastCheck() { #if BotAI_DEBUG_Spells >= 25 LogAI("Bot Non-Engaged autocast check triggered: [{}]", this->GetCleanName()); #endif - AIautocastspell_timer->Disable(); //prevent the timer from going off AGAIN while we are casting. if (RuleB(Bots, IsBotsElixirEnabled)) { + AIautocastspell_timer->Start(3000, false); // avg human response is much less than 5 seconds..even for non-combat situations... if (ElixirAIDetermineSpellToCast()) { - AIautocastspell_timer->Start(RandomTimer(500, 2000), false); // avg human response is much less than 5 seconds..even for non-combat situations... return true; } return false; } + AIautocastspell_timer->Disable(); //prevent the timer from going off AGAIN while we are casting. + bool pre_combat = false; Client* test_against = nullptr; @@ -1198,7 +1202,7 @@ bool Bot::AI_IdleCastCheck() { //Ok, IdleCastCheck depends of class. switch (GetClass()) { - // Healers WITHOUT pets will check if a heal is needed before buffing. + // Healers WITHOUT pets will check if a heal is needed before buffing. case CLERIC: case PALADIN: case RANGER: { @@ -1217,7 +1221,7 @@ bool Bot::AI_IdleCastCheck() { result = true; break; } - // Pets class will first cast their pet, then buffs + // Pets class will first cast their pet, then buffs case DRUID: case MAGICIAN: case SHADOWKNIGHT: @@ -1281,7 +1285,7 @@ bool Bot::AI_IdleCastCheck() { } } } - + result = true; break; } @@ -1310,7 +1314,7 @@ bool Bot::AI_IdleCastCheck() { break; } - if(!AIautocastspell_timer->Enabled()) + if (!AIautocastspell_timer->Enabled()) AIautocastspell_timer->Start(RandomTimer(500, 2000), false); // avg human response is much less than 5 seconds..even for non-combat situations... } @@ -1323,14 +1327,14 @@ bool Bot::AI_EngagedCastCheck() { if (GetTarget() && AIautocastspell_timer->Check(false)) { - AIautocastspell_timer->Disable(); //prevent the timer from going off AGAIN while we are casting. if (RuleB(Bots, IsBotsElixirEnabled)) { + AIautocastspell_timer->Start(3000, false); // avg human response is much less than 5 seconds..even for non-combat situations... if (ElixirAIDetermineSpellToCast()) { - AIautocastspell_timer->Start(RandomTimer(500, 2000), false); // avg human response is much less than 5 seconds..even for non-combat situations... return true; } return false; } + AIautocastspell_timer->Disable(); //prevent the timer from going off AGAIN while we are casting. uint8 botClass = GetClass(); EQ::constants::StanceType botStance = GetBotStance(); @@ -1338,11 +1342,11 @@ bool Bot::AI_EngagedCastCheck() { LogAI("Engaged autocast check triggered (BOTS). Trying to cast healing spells then maybe offensive spells"); - if(botClass == CLERIC) { - if(!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Escape), SpellType_Escape)) { - if(!AICastSpell(this, GetChanceToCastBySpellType(SpellType_Heal), SpellType_Heal)) { - if(!entity_list.Bot_AICheckCloseBeneficialSpells(this, GetChanceToCastBySpellType(SpellType_Heal), BotAISpellRange, SpellType_Heal)) { - if(!AICastSpell(GetTarget(), mayGetAggro?0:GetChanceToCastBySpellType(SpellType_Nuke), SpellType_Nuke)) { + if (botClass == CLERIC) { + if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Escape), SpellType_Escape)) { + if (!AICastSpell(this, GetChanceToCastBySpellType(SpellType_Heal), SpellType_Heal)) { + if (!entity_list.Bot_AICheckCloseBeneficialSpells(this, GetChanceToCastBySpellType(SpellType_Heal), BotAISpellRange, SpellType_Heal)) { + if (!AICastSpell(GetTarget(), mayGetAggro ? 0 : GetChanceToCastBySpellType(SpellType_Nuke), SpellType_Nuke)) { if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_InCombatBuff), SpellType_InCombatBuff)) { //AIautocastspell_timer->Start(RandomTimer(100, 250), false); // Do not give healer classes a lot of time off or your tank's die failedToCast = true; @@ -1352,13 +1356,13 @@ bool Bot::AI_EngagedCastCheck() { } } } - else if(botClass == DRUID) { - if(!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Escape), SpellType_Escape)) { - if(!AICastSpell(this, GetChanceToCastBySpellType(SpellType_Heal), SpellType_Heal)) { - if(!entity_list.Bot_AICheckCloseBeneficialSpells(this, GetChanceToCastBySpellType(SpellType_Heal), BotAISpellRange, SpellType_Heal)) { + else if (botClass == DRUID) { + if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Escape), SpellType_Escape)) { + if (!AICastSpell(this, GetChanceToCastBySpellType(SpellType_Heal), SpellType_Heal)) { + if (!entity_list.Bot_AICheckCloseBeneficialSpells(this, GetChanceToCastBySpellType(SpellType_Heal), BotAISpellRange, SpellType_Heal)) { if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Debuff), SpellType_Debuff)) { if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_DOT), SpellType_DOT)) { - if(!AICastSpell(GetTarget(), mayGetAggro?0:GetChanceToCastBySpellType(SpellType_Nuke), SpellType_Nuke)) { + if (!AICastSpell(GetTarget(), mayGetAggro ? 0 : GetChanceToCastBySpellType(SpellType_Nuke), SpellType_Nuke)) { //AIautocastspell_timer->Start(RandomTimer(100, 250), false); // Do not give healer classes a lot of time off or your tank's die failedToCast = true; } @@ -1368,16 +1372,16 @@ bool Bot::AI_EngagedCastCheck() { } } } - else if(botClass == SHAMAN) { - if(!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Escape), SpellType_Escape)) { + else if (botClass == SHAMAN) { + if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Escape), SpellType_Escape)) { if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Slow), SpellType_Slow)) { - if(!AICastSpell(this, GetChanceToCastBySpellType(SpellType_Heal), SpellType_Heal)) { - if(!entity_list.Bot_AICheckCloseBeneficialSpells(this, GetChanceToCastBySpellType(SpellType_Heal), BotAISpellRange, SpellType_Heal)) { + if (!AICastSpell(this, GetChanceToCastBySpellType(SpellType_Heal), SpellType_Heal)) { + if (!entity_list.Bot_AICheckCloseBeneficialSpells(this, GetChanceToCastBySpellType(SpellType_Heal), BotAISpellRange, SpellType_Heal)) { if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Debuff), SpellType_Debuff)) { if (!AICastSpell(GetPet(), GetChanceToCastBySpellType(SpellType_Heal), SpellType_Heal)) { - if(!AICastSpell(this, GetChanceToCastBySpellType(SpellType_InCombatBuff), SpellType_InCombatBuff)) { + if (!AICastSpell(this, GetChanceToCastBySpellType(SpellType_InCombatBuff), SpellType_InCombatBuff)) { if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_DOT), SpellType_DOT)) { - if(!AICastSpell(GetTarget(), mayGetAggro?0:GetChanceToCastBySpellType(SpellType_Nuke), SpellType_Nuke)) { + if (!AICastSpell(GetTarget(), mayGetAggro ? 0 : GetChanceToCastBySpellType(SpellType_Nuke), SpellType_Nuke)) { //AIautocastspell_timer->Start(RandomTimer(100, 250), false); // Do not give healer classes a lot of time off or your tank's die failedToCast = true; } @@ -1390,12 +1394,12 @@ bool Bot::AI_EngagedCastCheck() { } } } - else if(botClass == RANGER) { - if(!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Escape), SpellType_Escape)) { + else if (botClass == RANGER) { + if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Escape), SpellType_Escape)) { if (!AICastSpell(this, GetChanceToCastBySpellType(SpellType_Heal), SpellType_Heal)) { if (!entity_list.Bot_AICheckCloseBeneficialSpells(this, GetChanceToCastBySpellType(SpellType_Heal), BotAISpellRange, SpellType_Heal)) { if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_DOT), SpellType_DOT)) { - if (!AICastSpell(GetTarget(), mayGetAggro?0:GetChanceToCastBySpellType(SpellType_Nuke), SpellType_Nuke)) { + if (!AICastSpell(GetTarget(), mayGetAggro ? 0 : GetChanceToCastBySpellType(SpellType_Nuke), SpellType_Nuke)) { // failedToCast = true; } @@ -1404,7 +1408,7 @@ bool Bot::AI_EngagedCastCheck() { } } } - else if(botClass == BEASTLORD) { + else if (botClass == BEASTLORD) { if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Slow), SpellType_Slow)) { if (!AICastSpell(this, GetChanceToCastBySpellType(SpellType_Heal), SpellType_Heal)) { if (!entity_list.Bot_AICheckCloseBeneficialSpells(this, GetChanceToCastBySpellType(SpellType_Heal), BotAISpellRange, SpellType_Heal)) { @@ -1412,7 +1416,7 @@ bool Bot::AI_EngagedCastCheck() { if (!AICastSpell(this, GetChanceToCastBySpellType(SpellType_Pet), SpellType_Pet)) { if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_DOT), SpellType_DOT)) { if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Debuff), SpellType_Debuff)) { - if(!AICastSpell(GetTarget(), mayGetAggro?0:GetChanceToCastBySpellType(SpellType_Nuke), SpellType_Nuke)) { + if (!AICastSpell(GetTarget(), mayGetAggro ? 0 : GetChanceToCastBySpellType(SpellType_Nuke), SpellType_Nuke)) { // failedToCast = true; } @@ -1424,16 +1428,16 @@ bool Bot::AI_EngagedCastCheck() { } } } - else if(botClass == WIZARD) { - if(!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Escape), SpellType_Escape)) { - if (!AICastSpell(GetTarget(), mayGetAggro?0:GetChanceToCastBySpellType(SpellType_Nuke), SpellType_Nuke)) { + else if (botClass == WIZARD) { + if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Escape), SpellType_Escape)) { + if (!AICastSpell(GetTarget(), mayGetAggro ? 0 : GetChanceToCastBySpellType(SpellType_Nuke), SpellType_Nuke)) { // failedToCast = true; } } } - else if(botClass == PALADIN) { - if(!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Escape), SpellType_Escape)) { + else if (botClass == PALADIN) { + if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Escape), SpellType_Escape)) { if (!AICastSpell(this, GetChanceToCastBySpellType(SpellType_Heal), SpellType_Heal)) { if (!entity_list.Bot_AICheckCloseBeneficialSpells(this, GetChanceToCastBySpellType(SpellType_Heal), BotAISpellRange, SpellType_Heal)) { if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Nuke), SpellType_Nuke)) { @@ -1446,8 +1450,8 @@ bool Bot::AI_EngagedCastCheck() { } } } - else if(botClass == SHADOWKNIGHT) { - if(!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Escape), SpellType_Escape)) { + else if (botClass == SHADOWKNIGHT) { + if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Escape), SpellType_Escape)) { if (!AICastSpell(this, GetChanceToCastBySpellType(SpellType_Pet), SpellType_Pet)) { if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Lifetap), SpellType_Lifetap)) { if (!AICastSpell(GetPet(), GetChanceToCastBySpellType(SpellType_Heal), SpellType_Heal)) { @@ -1464,11 +1468,11 @@ bool Bot::AI_EngagedCastCheck() { } } } - else if(botClass == MAGICIAN) { + else if (botClass == MAGICIAN) { if (!AICastSpell(this, GetChanceToCastBySpellType(SpellType_Pet), SpellType_Pet)) { if (!AICastSpell(GetPet(), GetChanceToCastBySpellType(SpellType_Heal), SpellType_Heal)) { if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Debuff), SpellType_Debuff)) { - if (!AICastSpell(GetTarget(), mayGetAggro?0:GetChanceToCastBySpellType(SpellType_Nuke), SpellType_Nuke)) { + if (!AICastSpell(GetTarget(), mayGetAggro ? 0 : GetChanceToCastBySpellType(SpellType_Nuke), SpellType_Nuke)) { // failedToCast = true; } @@ -1476,14 +1480,14 @@ bool Bot::AI_EngagedCastCheck() { } } } - else if(botClass == NECROMANCER) { - if(!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Escape), SpellType_Escape)) { + else if (botClass == NECROMANCER) { + if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Escape), SpellType_Escape)) { if (!AICastSpell(this, GetChanceToCastBySpellType(SpellType_Pet), SpellType_Pet)) { if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Lifetap), SpellType_Lifetap)) { if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_DOT), SpellType_DOT)) { if (!AICastSpell(GetPet(), GetChanceToCastBySpellType(SpellType_Heal), SpellType_Heal)) { if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Debuff), SpellType_Debuff)) { - if (!AICastSpell(GetTarget(), mayGetAggro?0:GetChanceToCastBySpellType(SpellType_Nuke), SpellType_Nuke)) { + if (!AICastSpell(GetTarget(), mayGetAggro ? 0 : GetChanceToCastBySpellType(SpellType_Nuke), SpellType_Nuke)) { // failedToCast = true; } @@ -1494,13 +1498,13 @@ bool Bot::AI_EngagedCastCheck() { } } } - else if(botClass == ENCHANTER) { + else if (botClass == ENCHANTER) { if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Mez), SpellType_Mez)) { - if(!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Escape), SpellType_Escape)) { + if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Escape), SpellType_Escape)) { if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Slow), SpellType_Slow)) { if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Debuff), SpellType_Debuff)) { - if (!AICastSpell(GetTarget(), mayGetAggro?0:GetChanceToCastBySpellType(SpellType_DOT), SpellType_DOT)) { - if (!AICastSpell(GetTarget(), mayGetAggro?0:GetChanceToCastBySpellType(SpellType_Nuke), SpellType_Nuke)) { + if (!AICastSpell(GetTarget(), mayGetAggro ? 0 : GetChanceToCastBySpellType(SpellType_DOT), SpellType_DOT)) { + if (!AICastSpell(GetTarget(), mayGetAggro ? 0 : GetChanceToCastBySpellType(SpellType_Nuke), SpellType_Nuke)) { // failedToCast = true; } @@ -1510,7 +1514,7 @@ bool Bot::AI_EngagedCastCheck() { } } } - else if(botClass == BARD) { + else if (botClass == BARD) { if (!entity_list.Bot_AICheckCloseBeneficialSpells(this, GetChanceToCastBySpellType(SpellType_HateRedux), BotAISpellRange, SpellType_HateRedux)) { if (!AICastSpell(this, GetChanceToCastBySpellType(SpellType_InCombatBuffSong), SpellType_InCombatBuffSong)) { if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Slow), SpellType_Slow)) { @@ -1527,11 +1531,11 @@ bool Bot::AI_EngagedCastCheck() { } } - if(!AIautocastspell_timer->Enabled()) { + if (!AIautocastspell_timer->Enabled()) { AIautocastspell_timer->Start(RandomTimer(150, 300), false); } - if(!failedToCast) + if (!failedToCast) result = true; } @@ -1547,8 +1551,8 @@ bool Bot::AIHealRotation(Mob* tar, bool useFastHeals) { if (!AI_HasSpells()) return false; - if(tar->GetAppearance() == eaDead) { - if((tar->IsClient() && tar->CastToClient()->GetFeigned()) || tar->IsBot()) { + if (tar->GetAppearance() == eaDead) { + if ((tar->IsClient() && tar->CastToClient()->GetFeigned()) || tar->IsBot()) { // do nothing } else { @@ -1568,19 +1572,19 @@ bool Bot::AIHealRotation(Mob* tar, bool useFastHeals) { if (useFastHeals) { botSpell = GetBestBotSpellForRegularSingleTargetHeal(this); - if(botSpell.SpellId == 0) + if (botSpell.SpellId == 0) botSpell = GetBestBotSpellForFastHeal(this); } else { botSpell = GetBestBotSpellForPercentageHeal(this); - if(botSpell.SpellId == 0) + if (botSpell.SpellId == 0) botSpell = GetBestBotSpellForRegularSingleTargetHeal(this); - if(botSpell.SpellId == 0) + if (botSpell.SpellId == 0) botSpell = GetFirstBotSpellForSingleTargetHeal(this); - if(botSpell.SpellId == 0){ + if (botSpell.SpellId == 0) { botSpell = GetFirstBotSpellBySpellType(this, SpellType_Heal); } } @@ -1606,7 +1610,7 @@ bool Bot::AIHealRotation(Mob* tar, bool useFastHeals) { castedSpell = AIDoSpellCast(botSpell.SpellIndex, tar, botSpell.ManaCost, &TempDontHealMeBeforeTime); - if(castedSpell) + if (castedSpell) Say("Casting %s on %s, please stay in range!", spells[botSpell.SpellId].name, tar->GetCleanName()); return castedSpell; @@ -1615,7 +1619,7 @@ bool Bot::AIHealRotation(Mob* tar, bool useFastHeals) { std::list Bot::GetBotSpellsForSpellEffect(Bot* botCaster, int spellEffect) { std::list result; - if(botCaster && botCaster->AI_HasSpells()) { + if (botCaster && botCaster->AI_HasSpells()) { std::vector botSpellList = botCaster->GetBotSpells(); for (int i = botSpellList.size() - 1; i >= 0; i--) { @@ -1625,7 +1629,7 @@ std::list Bot::GetBotSpellsForSpellEffect(Bot* botCaster, int spellEff continue; } - if(IsEffectInSpell(botSpellList[i].spellid, spellEffect)) { + if (IsEffectInSpell(botSpellList[i].spellid, spellEffect)) { BotSpell botSpell; botSpell.SpellId = botSpellList[i].spellid; botSpell.SpellIndex = i; @@ -1642,7 +1646,7 @@ std::list Bot::GetBotSpellsForSpellEffect(Bot* botCaster, int spellEff std::list Bot::GetBotSpellsForSpellEffectAndTargetType(Bot* botCaster, int spellEffect, SpellTargetType targetType) { std::list result; - if(botCaster && botCaster->AI_HasSpells()) { + if (botCaster && botCaster->AI_HasSpells()) { std::vector botSpellList = botCaster->GetBotSpells(); for (int i = botSpellList.size() - 1; i >= 0; i--) { @@ -1652,8 +1656,8 @@ std::list Bot::GetBotSpellsForSpellEffectAndTargetType(Bot* botCaster, continue; } - if(IsEffectInSpell(botSpellList[i].spellid, spellEffect)) { - if(spells[botSpellList[i].spellid].target_type == targetType) { + if (IsEffectInSpell(botSpellList[i].spellid, spellEffect)) { + if (spells[botSpellList[i].spellid].target_type == targetType) { BotSpell botSpell; botSpell.SpellId = botSpellList[i].spellid; botSpell.SpellIndex = i; @@ -1671,7 +1675,7 @@ std::list Bot::GetBotSpellsForSpellEffectAndTargetType(Bot* botCaster, std::list Bot::GetBotSpellsBySpellType(Bot* botCaster, uint32 spellType) { std::list result; - if(botCaster && botCaster->AI_HasSpells()) { + if (botCaster && botCaster->AI_HasSpells()) { std::vector botSpellList = botCaster->GetBotSpells(); for (int i = botSpellList.size() - 1; i >= 0; i--) { @@ -1681,7 +1685,7 @@ std::list Bot::GetBotSpellsBySpellType(Bot* botCaster, uint32 spellTyp continue; } - if(botSpellList[i].type & spellType) { + if (botSpellList[i].type & spellType) { BotSpell botSpell; botSpell.SpellId = botSpellList[i].spellid; botSpell.SpellIndex = i; @@ -1733,7 +1737,7 @@ BotSpell Bot::GetFirstBotSpellBySpellType(Bot* botCaster, uint32 spellType) { result.SpellIndex = 0; result.ManaCost = 0; - if(botCaster && botCaster->AI_HasSpells()) { + if (botCaster && botCaster->AI_HasSpells()) { std::vector botSpellList = botCaster->GetBotSpells(); for (int i = botSpellList.size() - 1; i >= 0; i--) { @@ -1743,7 +1747,7 @@ BotSpell Bot::GetFirstBotSpellBySpellType(Bot* botCaster, uint32 spellType) { continue; } - if((botSpellList[i].type & spellType) && CheckSpellRecastTimers(botCaster, i)) { + if ((botSpellList[i].type & spellType) && CheckSpellRecastTimers(botCaster, i)) { result.SpellId = botSpellList[i].spellid; result.SpellIndex = i; result.ManaCost = botSpellList[i].manacost; @@ -1756,19 +1760,19 @@ BotSpell Bot::GetFirstBotSpellBySpellType(Bot* botCaster, uint32 spellType) { return result; } -BotSpell Bot::GetBestBotSpellForFastHeal(Bot *botCaster) { +BotSpell Bot::GetBestBotSpellForFastHeal(Bot* botCaster) { BotSpell result; result.SpellId = 0; result.SpellIndex = 0; result.ManaCost = 0; - if(botCaster) { + if (botCaster) { std::list botSpellList = GetBotSpellsForSpellEffect(botCaster, SE_CurrentHP); - for(std::list::iterator botSpellListItr = botSpellList.begin(); botSpellListItr != botSpellList.end(); ++botSpellListItr) { + for (std::list::iterator botSpellListItr = botSpellList.begin(); botSpellListItr != botSpellList.end(); ++botSpellListItr) { // Assuming all the spells have been loaded into this list by level and in descending order - if(IsFastHealSpell(botSpellListItr->SpellId) && CheckSpellRecastTimers(botCaster, botSpellListItr->SpellIndex)) { + if (IsFastHealSpell(botSpellListItr->SpellId) && CheckSpellRecastTimers(botCaster, botSpellListItr->SpellIndex)) { result.SpellId = botSpellListItr->SpellId; result.SpellIndex = botSpellListItr->SpellIndex; result.ManaCost = botSpellListItr->ManaCost; @@ -1788,13 +1792,13 @@ BotSpell Bot::GetBestBotSpellForHealOverTime(Bot* botCaster) { result.SpellIndex = 0; result.ManaCost = 0; - if(botCaster) { + if (botCaster) { std::list botHoTSpellList = GetBotSpellsForSpellEffect(botCaster, SE_HealOverTime); std::vector botSpellList = botCaster->GetBotSpells(); - for(std::list::iterator botSpellListItr = botHoTSpellList.begin(); botSpellListItr != botHoTSpellList.end(); ++botSpellListItr) { + for (std::list::iterator botSpellListItr = botHoTSpellList.begin(); botSpellListItr != botHoTSpellList.end(); ++botSpellListItr) { // Assuming all the spells have been loaded into this list by level and in descending order - if(IsHealOverTimeSpell(botSpellListItr->SpellId)) { + if (IsHealOverTimeSpell(botSpellListItr->SpellId)) { for (int i = botSpellList.size() - 1; i >= 0; i--) { if (botSpellList[i].spellid <= 0 || botSpellList[i].spellid >= SPDAT_RECORDS) { @@ -1803,7 +1807,7 @@ BotSpell Bot::GetBestBotSpellForHealOverTime(Bot* botCaster) { continue; } - if(botSpellList[i].spellid == botSpellListItr->SpellId && (botSpellList[i].type & SpellType_Heal) && CheckSpellRecastTimers(botCaster, botSpellListItr->SpellIndex)) { + if (botSpellList[i].spellid == botSpellListItr->SpellId && (botSpellList[i].type & SpellType_Heal) && CheckSpellRecastTimers(botCaster, botSpellListItr->SpellIndex)) { result.SpellId = botSpellListItr->SpellId; result.SpellIndex = botSpellListItr->SpellIndex; result.ManaCost = botSpellListItr->ManaCost; @@ -1818,14 +1822,14 @@ BotSpell Bot::GetBestBotSpellForHealOverTime(Bot* botCaster) { return result; } -BotSpell Bot::GetBestBotSpellForPercentageHeal(Bot *botCaster) { +BotSpell Bot::GetBestBotSpellForPercentageHeal(Bot* botCaster) { BotSpell result; result.SpellId = 0; result.SpellIndex = 0; result.ManaCost = 0; - if(botCaster && botCaster->AI_HasSpells()) { + if (botCaster && botCaster->AI_HasSpells()) { std::vector botSpellList = botCaster->GetBotSpells(); for (int i = botSpellList.size() - 1; i >= 0; i--) { @@ -1835,7 +1839,7 @@ BotSpell Bot::GetBestBotSpellForPercentageHeal(Bot *botCaster) { continue; } - if(IsCompleteHealSpell(botSpellList[i].spellid) && CheckSpellRecastTimers(botCaster, i)) { + if (IsCompleteHealSpell(botSpellList[i].spellid) && CheckSpellRecastTimers(botCaster, i)) { result.SpellId = botSpellList[i].spellid; result.SpellIndex = i; result.ManaCost = botSpellList[i].manacost; @@ -1855,12 +1859,12 @@ BotSpell Bot::GetBestBotSpellForRegularSingleTargetHeal(Bot* botCaster) { result.SpellIndex = 0; result.ManaCost = 0; - if(botCaster) { + if (botCaster) { std::list botSpellList = GetBotSpellsForSpellEffect(botCaster, SE_CurrentHP); - for(std::list::iterator botSpellListItr = botSpellList.begin(); botSpellListItr != botSpellList.end(); ++botSpellListItr) { + for (std::list::iterator botSpellListItr = botSpellList.begin(); botSpellListItr != botSpellList.end(); ++botSpellListItr) { // Assuming all the spells have been loaded into this list by level and in descending order - if(IsRegularSingleTargetHealSpell(botSpellListItr->SpellId) && CheckSpellRecastTimers(botCaster, botSpellListItr->SpellIndex)) { + if (IsRegularSingleTargetHealSpell(botSpellListItr->SpellId) && CheckSpellRecastTimers(botCaster, botSpellListItr->SpellIndex)) { result.SpellId = botSpellListItr->SpellId; result.SpellIndex = botSpellListItr->SpellIndex; result.ManaCost = botSpellListItr->ManaCost; @@ -1880,12 +1884,12 @@ BotSpell Bot::GetFirstBotSpellForSingleTargetHeal(Bot* botCaster) { result.SpellIndex = 0; result.ManaCost = 0; - if(botCaster) { + if (botCaster) { std::list botSpellList = GetBotSpellsForSpellEffect(botCaster, SE_CurrentHP); - for(std::list::iterator botSpellListItr = botSpellList.begin(); botSpellListItr != botSpellList.end(); ++botSpellListItr) { + for (std::list::iterator botSpellListItr = botSpellList.begin(); botSpellListItr != botSpellList.end(); ++botSpellListItr) { // Assuming all the spells have been loaded into this list by level and in descending order - if((IsRegularSingleTargetHealSpell(botSpellListItr->SpellId) || IsFastHealSpell(botSpellListItr->SpellId)) && CheckSpellRecastTimers(botCaster, botSpellListItr->SpellIndex)) { + if ((IsRegularSingleTargetHealSpell(botSpellListItr->SpellId) || IsFastHealSpell(botSpellListItr->SpellId)) && CheckSpellRecastTimers(botCaster, botSpellListItr->SpellIndex)) { result.SpellId = botSpellListItr->SpellId; result.SpellIndex = botSpellListItr->SpellIndex; result.ManaCost = botSpellListItr->ManaCost; @@ -1905,12 +1909,12 @@ BotSpell Bot::GetBestBotSpellForGroupHeal(Bot* botCaster) { result.SpellIndex = 0; result.ManaCost = 0; - if(botCaster) { + if (botCaster) { std::list botSpellList = GetBotSpellsForSpellEffect(botCaster, SE_CurrentHP); - for(std::list::iterator botSpellListItr = botSpellList.begin(); botSpellListItr != botSpellList.end(); ++botSpellListItr) { + for (std::list::iterator botSpellListItr = botSpellList.begin(); botSpellListItr != botSpellList.end(); ++botSpellListItr) { // Assuming all the spells have been loaded into this list by level and in descending order - if(IsRegularGroupHealSpell(botSpellListItr->SpellId) && CheckSpellRecastTimers(botCaster, botSpellListItr->SpellIndex)) { + if (IsRegularGroupHealSpell(botSpellListItr->SpellId) && CheckSpellRecastTimers(botCaster, botSpellListItr->SpellIndex)) { result.SpellId = botSpellListItr->SpellId; result.SpellIndex = botSpellListItr->SpellIndex; result.ManaCost = botSpellListItr->ManaCost; @@ -1930,13 +1934,13 @@ BotSpell Bot::GetBestBotSpellForGroupHealOverTime(Bot* botCaster) { result.SpellIndex = 0; result.ManaCost = 0; - if(botCaster) { + if (botCaster) { std::list botHoTSpellList = GetBotSpellsForSpellEffect(botCaster, SE_HealOverTime); std::vector botSpellList = botCaster->GetBotSpells(); - for(std::list::iterator botSpellListItr = botHoTSpellList.begin(); botSpellListItr != botHoTSpellList.end(); ++botSpellListItr) { + for (std::list::iterator botSpellListItr = botHoTSpellList.begin(); botSpellListItr != botHoTSpellList.end(); ++botSpellListItr) { // Assuming all the spells have been loaded into this list by level and in descending order - if(IsGroupHealOverTimeSpell(botSpellListItr->SpellId)) { + if (IsGroupHealOverTimeSpell(botSpellListItr->SpellId)) { for (int i = botSpellList.size() - 1; i >= 0; i--) { if (botSpellList[i].spellid <= 0 || botSpellList[i].spellid >= SPDAT_RECORDS) { @@ -1945,7 +1949,7 @@ BotSpell Bot::GetBestBotSpellForGroupHealOverTime(Bot* botCaster) { continue; } - if(botSpellList[i].spellid == botSpellListItr->SpellId && (botSpellList[i].type & SpellType_Heal) && CheckSpellRecastTimers(botCaster, botSpellListItr->SpellIndex)) { + if (botSpellList[i].spellid == botSpellListItr->SpellId && (botSpellList[i].type & SpellType_Heal) && CheckSpellRecastTimers(botCaster, botSpellListItr->SpellIndex)) { result.SpellId = botSpellListItr->SpellId; result.SpellIndex = botSpellListItr->SpellIndex; result.ManaCost = botSpellListItr->ManaCost; @@ -1967,12 +1971,12 @@ BotSpell Bot::GetBestBotSpellForGroupCompleteHeal(Bot* botCaster) { result.SpellIndex = 0; result.ManaCost = 0; - if(botCaster) { + if (botCaster) { std::list botSpellList = GetBotSpellsForSpellEffect(botCaster, SE_CompleteHeal); - for(std::list::iterator botSpellListItr = botSpellList.begin(); botSpellListItr != botSpellList.end(); ++botSpellListItr) { + for (std::list::iterator botSpellListItr = botSpellList.begin(); botSpellListItr != botSpellList.end(); ++botSpellListItr) { // Assuming all the spells have been loaded into this list by level and in descending order - if(IsGroupCompleteHealSpell(botSpellListItr->SpellId) && CheckSpellRecastTimers(botCaster, botSpellListItr->SpellIndex)) { + if (IsGroupCompleteHealSpell(botSpellListItr->SpellId) && CheckSpellRecastTimers(botCaster, botSpellListItr->SpellIndex)) { result.SpellId = botSpellListItr->SpellId; result.SpellIndex = botSpellListItr->SpellIndex; result.ManaCost = botSpellListItr->ManaCost; @@ -1992,12 +1996,12 @@ BotSpell Bot::GetBestBotSpellForMez(Bot* botCaster) { result.SpellIndex = 0; result.ManaCost = 0; - if(botCaster) { + if (botCaster) { std::list botSpellList = GetBotSpellsForSpellEffect(botCaster, SE_Mez); - for(std::list::iterator botSpellListItr = botSpellList.begin(); botSpellListItr != botSpellList.end(); ++botSpellListItr) { + for (std::list::iterator botSpellListItr = botSpellList.begin(); botSpellListItr != botSpellList.end(); ++botSpellListItr) { // Assuming all the spells have been loaded into this list by level and in descending order - if(IsMezSpell(botSpellListItr->SpellId) && CheckSpellRecastTimers(botCaster, botSpellListItr->SpellIndex)) { + if (IsMezSpell(botSpellListItr->SpellId) && CheckSpellRecastTimers(botCaster, botSpellListItr->SpellIndex)) { result.SpellId = botSpellListItr->SpellId; result.SpellIndex = botSpellListItr->SpellIndex; result.ManaCost = botSpellListItr->ManaCost; @@ -2017,7 +2021,7 @@ BotSpell Bot::GetBestBotSpellForMagicBasedSlow(Bot* botCaster) { result.SpellIndex = 0; result.ManaCost = 0; - if(botCaster) { + if (botCaster) { std::list botSpellList = GetBotSpellsForSpellEffect(botCaster, SE_AttackSpeed); for (std::list::iterator botSpellListItr = botSpellList.begin(); botSpellListItr != botSpellList.end(); ++botSpellListItr) { @@ -2042,12 +2046,12 @@ BotSpell Bot::GetBestBotSpellForDiseaseBasedSlow(Bot* botCaster) { result.SpellIndex = 0; result.ManaCost = 0; - if(botCaster) { + if (botCaster) { std::list botSpellList = GetBotSpellsForSpellEffect(botCaster, SE_AttackSpeed); - for(std::list::iterator botSpellListItr = botSpellList.begin(); botSpellListItr != botSpellList.end(); ++botSpellListItr) { + for (std::list::iterator botSpellListItr = botSpellList.begin(); botSpellListItr != botSpellList.end(); ++botSpellListItr) { // Assuming all the spells have been loaded into this list by level and in descending order - if(IsSlowSpell(botSpellListItr->SpellId) && spells[botSpellListItr->SpellId].resist_type == RESIST_DISEASE && CheckSpellRecastTimers(botCaster, botSpellListItr->SpellIndex)) { + if (IsSlowSpell(botSpellListItr->SpellId) && spells[botSpellListItr->SpellId].resist_type == RESIST_DISEASE && CheckSpellRecastTimers(botCaster, botSpellListItr->SpellIndex)) { result.SpellId = botSpellListItr->SpellId; result.SpellIndex = botSpellListItr->SpellIndex; result.ManaCost = botSpellListItr->ManaCost; @@ -2063,22 +2067,22 @@ BotSpell Bot::GetBestBotSpellForDiseaseBasedSlow(Bot* botCaster) { Mob* Bot::GetFirstIncomingMobToMez(Bot* botCaster, BotSpell botSpell) { Mob* result = 0; - if(botCaster && IsMezSpell(botSpell.SpellId)) { + if (botCaster && IsMezSpell(botSpell.SpellId)) { std::list npc_list; entity_list.GetNPCList(npc_list); - for(std::list::iterator itr = npc_list.begin(); itr != npc_list.end(); ++itr) { + for (std::list::iterator itr = npc_list.begin(); itr != npc_list.end(); ++itr) { NPC* npc = *itr; - if(DistanceSquaredNoZ(npc->GetPosition(), botCaster->GetPosition()) <= botCaster->GetActSpellRange(botSpell.SpellId, spells[botSpell.SpellId].range)) { - if(!npc->IsMezzed()) { - if(botCaster->HasGroup()) { + if (DistanceSquaredNoZ(npc->GetPosition(), botCaster->GetPosition()) <= botCaster->GetActSpellRange(botSpell.SpellId, spells[botSpell.SpellId].range)) { + if (!npc->IsMezzed()) { + if (botCaster->HasGroup()) { Group* g = botCaster->GetGroup(); - if(g) { - for(int counter = 0; counter < g->GroupCount(); counter++) { - if(npc->IsOnHatelist(g->members[counter]) && g->members[counter]->GetTarget() != npc && g->members[counter]->IsEngaged()) { + if (g) { + for (int counter = 0; counter < g->GroupCount(); counter++) { + if (npc->IsOnHatelist(g->members[counter]) && g->members[counter]->GetTarget() != npc && g->members[counter]->IsEngaged()) { result = npc; break; } @@ -2088,7 +2092,7 @@ Mob* Bot::GetFirstIncomingMobToMez(Bot* botCaster, BotSpell botSpell) { } } - if(result) + if (result) break; } } @@ -2096,22 +2100,22 @@ Mob* Bot::GetFirstIncomingMobToMez(Bot* botCaster, BotSpell botSpell) { return result; } -BotSpell Bot::GetBestBotMagicianPetSpell(Bot *botCaster) { +BotSpell Bot::GetBestBotMagicianPetSpell(Bot* botCaster) { BotSpell result; result.SpellId = 0; result.SpellIndex = 0; result.ManaCost = 0; - if(botCaster) { + if (botCaster) { std::list botSpellList = GetBotSpellsForSpellEffect(botCaster, SE_SummonPet); std::string petType = GetBotMagicianPetType(botCaster); - for(std::list::iterator botSpellListItr = botSpellList.begin(); botSpellListItr != botSpellList.end(); ++botSpellListItr) { + for (std::list::iterator botSpellListItr = botSpellList.begin(); botSpellListItr != botSpellList.end(); ++botSpellListItr) { // Assuming all the spells have been loaded into this list by level and in descending order - if(IsSummonPetSpell(botSpellListItr->SpellId) && CheckSpellRecastTimers(botCaster, botSpellListItr->SpellIndex)) { - if(!strncmp(spells[botSpellListItr->SpellId].teleport_zone, petType.c_str(), petType.length())) { + if (IsSummonPetSpell(botSpellListItr->SpellId) && CheckSpellRecastTimers(botCaster, botSpellListItr->SpellIndex)) { + if (!strncmp(spells[botSpellListItr->SpellId].teleport_zone, petType.c_str(), petType.length())) { result.SpellId = botSpellListItr->SpellId; result.SpellIndex = botSpellListItr->SpellIndex; result.ManaCost = botSpellListItr->ManaCost; @@ -2128,41 +2132,41 @@ BotSpell Bot::GetBestBotMagicianPetSpell(Bot *botCaster) { std::string Bot::GetBotMagicianPetType(Bot* botCaster) { std::string result; - if(botCaster) { - if(botCaster->IsPetChooser()) { - switch(botCaster->GetPetChooserID()) { - case 0: - result = std::string("SumWater"); - break; - case 1: - result = std::string("SumFire"); - break; - case 2: - result = std::string("SumAir"); - break; - case 3: - result = std::string("SumEarth"); - break; - default: - result = std::string("MonsterSum"); - break; + if (botCaster) { + if (botCaster->IsPetChooser()) { + switch (botCaster->GetPetChooserID()) { + case 0: + result = std::string("SumWater"); + break; + case 1: + result = std::string("SumFire"); + break; + case 2: + result = std::string("SumAir"); + break; + case 3: + result = std::string("SumEarth"); + break; + default: + result = std::string("MonsterSum"); + break; } } else { - if(botCaster->GetLevel() == 2) + if (botCaster->GetLevel() == 2) result = std::string("SumWater"); - else if(botCaster->GetLevel() == 3) + else if (botCaster->GetLevel() == 3) result = std::string("SumFire"); - else if(botCaster->GetLevel() == 4) + else if (botCaster->GetLevel() == 4) result = std::string("SumAir"); - else if(botCaster->GetLevel() == 5) + else if (botCaster->GetLevel() == 5) result = std::string("SumEarth"); - else if(botCaster->GetLevel() < 30) { + else if (botCaster->GetLevel() < 30) { // Under level 30 int counter = zone->random.Int(0, 3); - switch(counter) { - case 0: + switch (counter) { + case 0: result = std::string("SumWater"); break; case 1: @@ -2183,8 +2187,8 @@ std::string Bot::GetBotMagicianPetType(Bot* botCaster) { // Over level 30 int counter = zone->random.Int(0, 4); - switch(counter) { - case 0: + switch (counter) { + case 0: result = std::string("SumWater"); break; case 1: @@ -2214,12 +2218,12 @@ BotSpell Bot::GetBestBotSpellForNukeByTargetType(Bot* botCaster, SpellTargetType result.SpellIndex = 0; result.ManaCost = 0; - if(botCaster) { + if (botCaster) { std::list botSpellList = GetBotSpellsForSpellEffectAndTargetType(botCaster, SE_CurrentHP, targetType); - for(std::list::iterator botSpellListItr = botSpellList.begin(); botSpellListItr != botSpellList.end(); ++botSpellListItr) { + for (std::list::iterator botSpellListItr = botSpellList.begin(); botSpellListItr != botSpellList.end(); ++botSpellListItr) { // Assuming all the spells have been loaded into this list by level and in descending order - if(IsPureNukeSpell(botSpellListItr->SpellId) && IsDamageSpell(botSpellListItr->SpellId) && CheckSpellRecastTimers(botCaster, botSpellListItr->SpellIndex)) { + if (IsPureNukeSpell(botSpellListItr->SpellId) && IsDamageSpell(botSpellListItr->SpellId) && CheckSpellRecastTimers(botCaster, botSpellListItr->SpellIndex)) { result.SpellId = botSpellListItr->SpellId; result.SpellIndex = botSpellListItr->SpellIndex; result.ManaCost = botSpellListItr->ManaCost; @@ -2240,14 +2244,14 @@ BotSpell Bot::GetBestBotSpellForStunByTargetType(Bot* botCaster, SpellTargetType result.SpellIndex = 0; result.ManaCost = 0; - if(botCaster) + if (botCaster) { std::list botSpellList = GetBotSpellsForSpellEffectAndTargetType(botCaster, SE_Stun, targetType); - for(std::list::iterator botSpellListItr = botSpellList.begin(); botSpellListItr != botSpellList.end(); ++botSpellListItr) + for (std::list::iterator botSpellListItr = botSpellList.begin(); botSpellListItr != botSpellList.end(); ++botSpellListItr) { // Assuming all the spells have been loaded into this list by level and in descending order - if(IsStunSpell(botSpellListItr->SpellId) && CheckSpellRecastTimers(botCaster, botSpellListItr->SpellIndex)) + if (IsStunSpell(botSpellListItr->SpellId) && CheckSpellRecastTimers(botCaster, botSpellListItr->SpellIndex)) { result.SpellId = botSpellListItr->SpellId; result.SpellIndex = botSpellListItr->SpellIndex; @@ -2267,12 +2271,12 @@ BotSpell Bot::GetBestBotWizardNukeSpellByTargetResists(Bot* botCaster, Mob* targ result.SpellIndex = 0; result.ManaCost = 0; - if(botCaster && target) { + if (botCaster && target) { const int lureResisValue = -100; const int maxTargetResistValue = 300; bool selectLureNuke = false; - if((target->GetMR() > maxTargetResistValue) && (target->GetCR() > maxTargetResistValue) && (target->GetFR() > maxTargetResistValue)) + if ((target->GetMR() > maxTargetResistValue) && (target->GetCR() > maxTargetResistValue) && (target->GetFR() > maxTargetResistValue)) selectLureNuke = true; @@ -2283,31 +2287,31 @@ BotSpell Bot::GetBestBotWizardNukeSpellByTargetResists(Bot* botCaster, Mob* targ firstWizardMagicNukeSpellFound.SpellIndex = 0; firstWizardMagicNukeSpellFound.ManaCost = 0; - for(std::list::iterator botSpellListItr = botSpellList.begin(); botSpellListItr != botSpellList.end(); ++botSpellListItr) { + for (std::list::iterator botSpellListItr = botSpellList.begin(); botSpellListItr != botSpellList.end(); ++botSpellListItr) { // Assuming all the spells have been loaded into this list by level and in descending order bool spellSelected = false; - if(CheckSpellRecastTimers(botCaster, botSpellListItr->SpellIndex)) { - if(selectLureNuke && (spells[botSpellListItr->SpellId].resist_difficulty < lureResisValue)) { + if (CheckSpellRecastTimers(botCaster, botSpellListItr->SpellIndex)) { + if (selectLureNuke && (spells[botSpellListItr->SpellId].resist_difficulty < lureResisValue)) { spellSelected = true; } - else if(IsPureNukeSpell(botSpellListItr->SpellId)) { - if(((target->GetMR() < target->GetCR()) || (target->GetMR() < target->GetFR())) && (GetSpellResistType(botSpellListItr->SpellId) == RESIST_MAGIC) + else if (IsPureNukeSpell(botSpellListItr->SpellId)) { + if (((target->GetMR() < target->GetCR()) || (target->GetMR() < target->GetFR())) && (GetSpellResistType(botSpellListItr->SpellId) == RESIST_MAGIC) && (spells[botSpellListItr->SpellId].resist_difficulty > lureResisValue)) { spellSelected = true; } - else if(((target->GetCR() < target->GetMR()) || (target->GetCR() < target->GetFR())) && (GetSpellResistType(botSpellListItr->SpellId) == RESIST_COLD) + else if (((target->GetCR() < target->GetMR()) || (target->GetCR() < target->GetFR())) && (GetSpellResistType(botSpellListItr->SpellId) == RESIST_COLD) && (spells[botSpellListItr->SpellId].resist_difficulty > lureResisValue)) { spellSelected = true; } - else if(((target->GetFR() < target->GetCR()) || (target->GetFR() < target->GetMR())) && (GetSpellResistType(botSpellListItr->SpellId) == RESIST_FIRE) + else if (((target->GetFR() < target->GetCR()) || (target->GetFR() < target->GetMR())) && (GetSpellResistType(botSpellListItr->SpellId) == RESIST_FIRE) && (spells[botSpellListItr->SpellId].resist_difficulty > lureResisValue)) { spellSelected = true; } - else if((GetSpellResistType(botSpellListItr->SpellId) == RESIST_MAGIC) && (spells[botSpellListItr->SpellId].resist_difficulty > lureResisValue) && !IsStunSpell(botSpellListItr->SpellId)) { + else if ((GetSpellResistType(botSpellListItr->SpellId) == RESIST_MAGIC) && (spells[botSpellListItr->SpellId].resist_difficulty > lureResisValue) && !IsStunSpell(botSpellListItr->SpellId)) { firstWizardMagicNukeSpellFound.SpellId = botSpellListItr->SpellId; firstWizardMagicNukeSpellFound.SpellIndex = botSpellListItr->SpellIndex; firstWizardMagicNukeSpellFound.ManaCost = botSpellListItr->ManaCost; @@ -2315,7 +2319,7 @@ BotSpell Bot::GetBestBotWizardNukeSpellByTargetResists(Bot* botCaster, Mob* targ } } - if(spellSelected) { + if (spellSelected) { result.SpellId = botSpellListItr->SpellId; result.SpellIndex = botSpellListItr->SpellIndex; result.ManaCost = botSpellListItr->ManaCost; @@ -2324,7 +2328,7 @@ BotSpell Bot::GetBestBotWizardNukeSpellByTargetResists(Bot* botCaster, Mob* targ } } - if(result.SpellId == 0) { + if (result.SpellId == 0) { result = firstWizardMagicNukeSpellFound; } } @@ -2332,17 +2336,17 @@ BotSpell Bot::GetBestBotWizardNukeSpellByTargetResists(Bot* botCaster, Mob* targ return result; } -BotSpell Bot::GetDebuffBotSpell(Bot* botCaster, Mob *tar) { +BotSpell Bot::GetDebuffBotSpell(Bot* botCaster, Mob* tar) { BotSpell result; result.SpellId = 0; result.SpellIndex = 0; result.ManaCost = 0; - if(!tar || !botCaster) + if (!tar || !botCaster) return result; - if(botCaster && botCaster->AI_HasSpells()) { + if (botCaster && botCaster->AI_HasSpells()) { std::vector botSpellList = botCaster->GetBotSpells(); for (int i = botSpellList.size() - 1; i >= 0; i--) { @@ -2352,9 +2356,9 @@ BotSpell Bot::GetDebuffBotSpell(Bot* botCaster, Mob *tar) { continue; } - if(((botSpellList[i].type & SpellType_Debuff) || IsDebuffSpell(botSpellList[i].spellid)) + if (((botSpellList[i].type & SpellType_Debuff) || IsDebuffSpell(botSpellList[i].spellid)) && (!tar->IsImmuneToSpell(botSpellList[i].spellid, botCaster) - && tar->CanBuffStack(botSpellList[i].spellid, botCaster->GetLevel(), true) >= 0) + && tar->CanBuffStack(botSpellList[i].spellid, botCaster->GetLevel(), true) >= 0) && CheckSpellRecastTimers(botCaster, i)) { result.SpellId = botSpellList[i].spellid; result.SpellIndex = i; @@ -2368,28 +2372,28 @@ BotSpell Bot::GetDebuffBotSpell(Bot* botCaster, Mob *tar) { return result; } -BotSpell Bot::GetBestBotSpellForResistDebuff(Bot* botCaster, Mob *tar) { +BotSpell Bot::GetBestBotSpellForResistDebuff(Bot* botCaster, Mob* tar) { BotSpell result; result.SpellId = 0; result.SpellIndex = 0; result.ManaCost = 0; - if(!tar) + if (!tar) return result; - int level_mod = (tar->GetLevel() - botCaster->GetLevel())* (tar->GetLevel() - botCaster->GetLevel()) / 2; - if(tar->GetLevel() - botCaster->GetLevel() < 0) + int level_mod = (tar->GetLevel() - botCaster->GetLevel()) * (tar->GetLevel() - botCaster->GetLevel()) / 2; + if (tar->GetLevel() - botCaster->GetLevel() < 0) { level_mod = -level_mod; } - bool needsMagicResistDebuff = (tar->GetMR() + level_mod) > 100 ? true: false; - bool needsColdResistDebuff = (tar->GetCR() + level_mod) > 100 ? true: false; - bool needsFireResistDebuff = (tar->GetFR() + level_mod) > 100 ? true: false; - bool needsPoisonResistDebuff = (tar->GetPR() + level_mod) > 100 ? true: false; - bool needsDiseaseResistDebuff = (tar->GetDR() + level_mod) > 100 ? true: false; + bool needsMagicResistDebuff = (tar->GetMR() + level_mod) > 100 ? true : false; + bool needsColdResistDebuff = (tar->GetCR() + level_mod) > 100 ? true : false; + bool needsFireResistDebuff = (tar->GetFR() + level_mod) > 100 ? true : false; + bool needsPoisonResistDebuff = (tar->GetPR() + level_mod) > 100 ? true : false; + bool needsDiseaseResistDebuff = (tar->GetDR() + level_mod) > 100 ? true : false; - if(botCaster && botCaster->AI_HasSpells()) { + if (botCaster && botCaster->AI_HasSpells()) { std::vector botSpellList = botCaster->GetBotSpells(); for (int i = botSpellList.size() - 1; i >= 0; i--) { @@ -2399,14 +2403,14 @@ BotSpell Bot::GetBestBotSpellForResistDebuff(Bot* botCaster, Mob *tar) { continue; } - if(((botSpellList[i].type & SpellType_Debuff) || IsResistDebuffSpell(botSpellList[i].spellid)) + if (((botSpellList[i].type & SpellType_Debuff) || IsResistDebuffSpell(botSpellList[i].spellid)) && ((needsMagicResistDebuff && (IsEffectInSpell(botSpellList[i].spellid, SE_ResistMagic)) || IsEffectInSpell(botSpellList[i].spellid, SE_ResistAll)) - || (needsColdResistDebuff && (IsEffectInSpell(botSpellList[i].spellid, SE_ResistCold)) || IsEffectInSpell(botSpellList[i].spellid, SE_ResistAll)) - || (needsFireResistDebuff && (IsEffectInSpell(botSpellList[i].spellid, SE_ResistFire)) || IsEffectInSpell(botSpellList[i].spellid, SE_ResistAll)) - || (needsPoisonResistDebuff && (IsEffectInSpell(botSpellList[i].spellid, SE_ResistPoison)) || IsEffectInSpell(botSpellList[i].spellid, SE_ResistAll)) - || (needsDiseaseResistDebuff && (IsEffectInSpell(botSpellList[i].spellid, SE_ResistDisease)) || IsEffectInSpell(botSpellList[i].spellid, SE_ResistAll))) + || (needsColdResistDebuff && (IsEffectInSpell(botSpellList[i].spellid, SE_ResistCold)) || IsEffectInSpell(botSpellList[i].spellid, SE_ResistAll)) + || (needsFireResistDebuff && (IsEffectInSpell(botSpellList[i].spellid, SE_ResistFire)) || IsEffectInSpell(botSpellList[i].spellid, SE_ResistAll)) + || (needsPoisonResistDebuff && (IsEffectInSpell(botSpellList[i].spellid, SE_ResistPoison)) || IsEffectInSpell(botSpellList[i].spellid, SE_ResistAll)) + || (needsDiseaseResistDebuff && (IsEffectInSpell(botSpellList[i].spellid, SE_ResistDisease)) || IsEffectInSpell(botSpellList[i].spellid, SE_ResistAll))) && (!tar->IsImmuneToSpell(botSpellList[i].spellid, botCaster) - && tar->CanBuffStack(botSpellList[i].spellid, botCaster->GetLevel(), true) >= 0) + && tar->CanBuffStack(botSpellList[i].spellid, botCaster->GetLevel(), true) >= 0) && CheckSpellRecastTimers(botCaster, i)) { result.SpellId = botSpellList[i].spellid; result.SpellIndex = i; @@ -2420,7 +2424,7 @@ BotSpell Bot::GetBestBotSpellForResistDebuff(Bot* botCaster, Mob *tar) { return result; } -BotSpell Bot::GetBestBotSpellForCure(Bot* botCaster, Mob *tar) { +BotSpell Bot::GetBestBotSpellForCure(Bot* botCaster, Mob* tar) { BotSpell_wPriority result; bool spellSelected = false; @@ -2428,7 +2432,7 @@ BotSpell Bot::GetBestBotSpellForCure(Bot* botCaster, Mob *tar) { result.SpellIndex = 0; result.ManaCost = 0; - if(!tar) + if (!tar) return result; int countNeedsCured = 0; @@ -2437,16 +2441,16 @@ BotSpell Bot::GetBestBotSpellForCure(Bot* botCaster, Mob *tar) { bool isCursed = tar->FindType(SE_CurseCounter); bool isCorrupted = tar->FindType(SE_CorruptionCounter); - if(botCaster && botCaster->AI_HasSpells()) { + if (botCaster && botCaster->AI_HasSpells()) { std::list cureList = GetPrioritizedBotSpellsBySpellType(botCaster, SpellType_Cure); - if(tar->HasGroup()) { - Group *g = tar->GetGroup(); + if (tar->HasGroup()) { + Group* g = tar->GetGroup(); - if(g) { - for( int i = 0; imembers[i] && !g->members[i]->qglobal) { - if(botCaster->GetNeedsCured(g->members[i])) + if (g) { + for (int i = 0; i < MAX_GROUP_MEMBERS; i++) { + if (g->members[i] && !g->members[i]->qglobal) { + if (botCaster->GetNeedsCured(g->members[i])) countNeedsCured++; } } @@ -2454,31 +2458,31 @@ BotSpell Bot::GetBestBotSpellForCure(Bot* botCaster, Mob *tar) { } //Check for group cure first - if(countNeedsCured > 2) { + if (countNeedsCured > 2) { for (std::list::iterator itr = cureList.begin(); itr != cureList.end(); ++itr) { BotSpell selectedBotSpell = *itr; - if(IsGroupSpell(itr->SpellId) && CheckSpellRecastTimers(botCaster, itr->SpellIndex)) { - if(selectedBotSpell.SpellId == 0) + if (IsGroupSpell(itr->SpellId) && CheckSpellRecastTimers(botCaster, itr->SpellIndex)) { + if (selectedBotSpell.SpellId == 0) continue; - if(isPoisoned && IsEffectInSpell(itr->SpellId, SE_PoisonCounter)) { + if (isPoisoned && IsEffectInSpell(itr->SpellId, SE_PoisonCounter)) { spellSelected = true; } - else if(isDiseased && IsEffectInSpell(itr->SpellId, SE_DiseaseCounter)) { + else if (isDiseased && IsEffectInSpell(itr->SpellId, SE_DiseaseCounter)) { spellSelected = true; } - else if(isCursed && IsEffectInSpell(itr->SpellId, SE_CurseCounter)) { + else if (isCursed && IsEffectInSpell(itr->SpellId, SE_CurseCounter)) { spellSelected = true; } - else if(isCorrupted && IsEffectInSpell(itr->SpellId, SE_CorruptionCounter)) { + else if (isCorrupted && IsEffectInSpell(itr->SpellId, SE_CorruptionCounter)) { spellSelected = true; } - else if(IsEffectInSpell(itr->SpellId, SE_DispelDetrimental)) { + else if (IsEffectInSpell(itr->SpellId, SE_DispelDetrimental)) { spellSelected = true; } - if(spellSelected) + if (spellSelected) { result.SpellId = itr->SpellId; result.SpellIndex = itr->SpellIndex; @@ -2491,31 +2495,31 @@ BotSpell Bot::GetBestBotSpellForCure(Bot* botCaster, Mob *tar) { } //no group cure for target- try to find single target spell - if(!spellSelected) { - for(std::list::iterator itr = cureList.begin(); itr != cureList.end(); ++itr) { + if (!spellSelected) { + for (std::list::iterator itr = cureList.begin(); itr != cureList.end(); ++itr) { BotSpell selectedBotSpell = *itr; - if(CheckSpellRecastTimers(botCaster, itr->SpellIndex)) { - if(selectedBotSpell.SpellId == 0) + if (CheckSpellRecastTimers(botCaster, itr->SpellIndex)) { + if (selectedBotSpell.SpellId == 0) continue; - if(isPoisoned && IsEffectInSpell(itr->SpellId, SE_PoisonCounter)) { + if (isPoisoned && IsEffectInSpell(itr->SpellId, SE_PoisonCounter)) { spellSelected = true; } - else if(isDiseased && IsEffectInSpell(itr->SpellId, SE_DiseaseCounter)) { + else if (isDiseased && IsEffectInSpell(itr->SpellId, SE_DiseaseCounter)) { spellSelected = true; } - else if(isCursed && IsEffectInSpell(itr->SpellId, SE_CurseCounter)) { + else if (isCursed && IsEffectInSpell(itr->SpellId, SE_CurseCounter)) { spellSelected = true; } - else if(isCorrupted && IsEffectInSpell(itr->SpellId, SE_CorruptionCounter)) { + else if (isCorrupted && IsEffectInSpell(itr->SpellId, SE_CorruptionCounter)) { spellSelected = true; } - else if(IsEffectInSpell(itr->SpellId, SE_DispelDetrimental)) { + else if (IsEffectInSpell(itr->SpellId, SE_DispelDetrimental)) { spellSelected = true; } - if(spellSelected) + if (spellSelected) { result.SpellId = itr->SpellId; result.SpellIndex = itr->SpellIndex; @@ -2532,25 +2536,25 @@ BotSpell Bot::GetBestBotSpellForCure(Bot* botCaster, Mob *tar) { } void Bot::SetSpellRecastTimer(int timer_index, int32 recast_delay) { - if(timer_index > 0 && timer_index <= MaxSpellTimer) { + if (timer_index > 0 && timer_index <= MaxSpellTimer) { timers[timer_index - 1] = Timer::GetCurrentTime() + recast_delay; } } -int32 Bot::GetSpellRecastTimer(Bot *caster, int timer_index) { +int32 Bot::GetSpellRecastTimer(Bot* caster, int timer_index) { int32 result = 0; - if(caster) { - if(timer_index > 0 && timer_index <= MaxSpellTimer) { + if (caster) { + if (timer_index > 0 && timer_index <= MaxSpellTimer) { result = caster->timers[timer_index - 1]; } } return result; } -bool Bot::CheckSpellRecastTimers(Bot *caster, int SpellIndex) { - if(caster) { - if(caster->AIspells[SpellIndex].time_cancast < Timer::GetCurrentTime()) { //checks spell recast - if(GetSpellRecastTimer(caster, spells[caster->AIspells[SpellIndex].spellid].timer_id) < Timer::GetCurrentTime()) { //checks for spells on the same timer +bool Bot::CheckSpellRecastTimers(Bot* caster, int SpellIndex) { + if (caster) { + if (caster->AIspells[SpellIndex].time_cancast < Timer::GetCurrentTime()) { //checks spell recast + if (GetSpellRecastTimer(caster, spells[caster->AIspells[SpellIndex].spellid].timer_id) < Timer::GetCurrentTime()) { //checks for spells on the same timer return true; //can cast spell } } @@ -2559,35 +2563,35 @@ bool Bot::CheckSpellRecastTimers(Bot *caster, int SpellIndex) { } void Bot::SetDisciplineRecastTimer(int timer_index, int32 recast_delay) { - if(timer_index > 0 && timer_index <= MaxDisciplineTimer) { + if (timer_index > 0 && timer_index <= MaxDisciplineTimer) { timers[DisciplineReuseStart + timer_index - 1] = Timer::GetCurrentTime() + recast_delay; } } -int32 Bot::GetDisciplineRecastTimer(Bot *caster, int timer_index) { +int32 Bot::GetDisciplineRecastTimer(Bot* caster, int timer_index) { int32 result = 0; - if(caster) { - if(timer_index > 0 && timer_index <= MaxDisciplineTimer) { + if (caster) { + if (timer_index > 0 && timer_index <= MaxDisciplineTimer) { result = caster->timers[DisciplineReuseStart + timer_index - 1]; } } return result; } -uint32 Bot::GetDisciplineRemainingTime(Bot *caster, int timer_index) { +uint32 Bot::GetDisciplineRemainingTime(Bot* caster, int timer_index) { int32 result = 0; - if(caster) { - if(timer_index > 0 && timer_index <= MaxDisciplineTimer) { - if(GetDisciplineRecastTimer(caster, timer_index) > Timer::GetCurrentTime()) + if (caster) { + if (timer_index > 0 && timer_index <= MaxDisciplineTimer) { + if (GetDisciplineRecastTimer(caster, timer_index) > Timer::GetCurrentTime()) result = GetDisciplineRecastTimer(caster, timer_index) - Timer::GetCurrentTime(); } } return result; } -bool Bot::CheckDisciplineRecastTimers(Bot *caster, int timer_index) { - if(caster) { - if(GetDisciplineRecastTimer(caster, timer_index) < Timer::GetCurrentTime()) { //checks for spells on the same timer +bool Bot::CheckDisciplineRecastTimers(Bot* caster, int timer_index) { + if (caster) { + if (GetDisciplineRecastTimer(caster, timer_index) < Timer::GetCurrentTime()) { //checks for spells on the same timer return true; //can cast spell } } @@ -2702,204 +2706,189 @@ uint8 Bot::GetChanceToCastBySpellType(uint32 spellType) // ElixirAIDetermineSpellToCast is called during AI bot logics // It determines by class which spell to cast bool Bot::ElixirAIDetermineSpellToCast() { - BotSpell selectedBotSpell; - int8 spellAIResult; - Group *grp = GetGroup(); + int8 spellAIResult; + Group* grp = GetGroup(); + + ElixirSpellCacheRefresh(); - if (GetClass() == WARRIOR || GetClass() == SHADOWKNIGHT || GetClass() == PALADIN) { - - /*if(CheckAETaunt()) { - selectedBotSpell = GetBestBotSpellForAETaunt(this); - if (selectedBotSpell.SpellId > 0 && ElixirAITryCastSpell(selectedBotSpell)) { - Log(Logs::General, Logs::Botenaries, "%s AE Taunting.", GetName()); - return true; - } - } + BotSpell botSpell{}; + for (int i = 0; i < 15; i++) { + if (elixirCacheSpells[i] == -1) continue; + + if (ElixirAITryCastSpell(elixirCacheSpells[i], true)) { + return true; + } + } + return false; +} + +void Bot::ElixirSpellCacheRefresh() { + if (isElixirSpellCacheBuilt) return; + isElixirSpellCacheBuilt = true; + for (int i = 0; i < 15; i++) { + elixirCacheSpells[i] = -1; + } + + + // 0 is group heal all classes + // 1 ae nukes all classes + // 2 evade spells + // 3 slows all classes, hot for dru/clr/shm + // + // 4 shm/clr/dru/pal single target heal + // 5 nukes all classes + // 6 all non-priests single target heal + // 7 hot for everyone + // 10 hp buffs + // 11 ac buffs + // 12 haste buffs + // 13 + + + for (int spellID = 1; spellID < SPDAT_RECORDS; spellID++) { + int spellSlot = -1; + if (GetSpellLevel(spellID, GetClass()) <= 0) continue; + if (GetSpellLevel(spellID, GetClass()) > GetLevel()) continue; + + if (spellID == 13) { + if (true) { - if(CheckTaunt()) { - selectedBotSpell = GetBestBotSpellForTaunt(this); - if (selectedBotSpell.SpellId > 0 && ElixirAITryCastSpell(selectedBotSpell)) { - return true; - } } - */ + } + if (spells[spellID].target_type == ST_Target && IsEffectInSpell(spellID, SE_CurrentHP) && spellSlot == -1 && spells[spellID].base_value > 0) { + if (GetClass() == CLERIC || GetClass() == DRUID || GetClass() == SHAMAN || GetClass() == PALADIN) spellSlot = 4; + else spellSlot = 6; } - switch (GetClass()) { - case CLERIC: - case PALADIN: - case RANGER: - selectedBotSpell = GetBestBotSpellForGroupHeal(this); - if (ElixirAITryCastSpell(selectedBotSpell, true)) { - return true; - } - - selectedBotSpell = GetBestBotSpellForHealOverTime(this); - if (ElixirAITryCastSpell(selectedBotSpell, true)) { - return true; - } - - selectedBotSpell = GetBestBotSpellForFastHeal(this); - if (ElixirAITryCastSpell(selectedBotSpell, true)) { - return true; - } - - selectedBotSpell = GetBestBotSpellForRegularSingleTargetHeal(this); - if (ElixirAITryCastSpell(selectedBotSpell, true)) { - return true; - } - - for (int i = 0; i < MAX_GROUP_MEMBERS; i++) { - if (!grp) break; - if (!grp->members[i]) continue; - if (!grp->members[i]->qglobal) continue; - if(!GetNeedsCured(grp->members[i])) continue; - if (grp->members[i]->DontCureMeBefore() > Timer::GetCurrentTime()) continue; - selectedBotSpell = GetBestBotSpellForCure(this, grp->members[i]); - if (ElixirAITryCastSpell(selectedBotSpell, true)) { - return true; - } - } - - if (GetManaRatio() > 50) { // healers only offensive or buff at > 50% mana - selectedBotSpell = GetBestBotSpellForNukeByTargetType(this, ST_Target); - if (ElixirAITryCastSpell(selectedBotSpell)) { - return true; - } - - auto buffSpells = GetBotSpellsBySpellType(this, SpellType_Buff); - for (auto buffSpell : buffSpells) { - if (!ElixirAITryCastSpell(selectedBotSpell)) continue; - return true; - } - } - return false; - // Pets class will first cast their pet, then buffs - case DRUID: - case MAGICIAN: - case SHADOWKNIGHT: - case SHAMAN: - case NECROMANCER: - case ENCHANTER: - case BEASTLORD: - selectedBotSpell = GetBestBotSpellForGroupHeal(this); - if (ElixirAITryCastSpell(selectedBotSpell, true)) { - return true; - } - - selectedBotSpell = GetBestBotSpellForHealOverTime(this); - if (ElixirAITryCastSpell(selectedBotSpell, true)) { - return true; - } - - selectedBotSpell = GetBestBotSpellForFastHeal(this); - if (ElixirAITryCastSpell(selectedBotSpell, true)) { - return true; - } - - selectedBotSpell = GetBestBotSpellForRegularSingleTargetHeal(this); - if (ElixirAITryCastSpell(selectedBotSpell, true)) { - return true; - } - - for (int i = 0; i < MAX_GROUP_MEMBERS; i++) { - if (!grp) break; - if (!grp->members[i]) continue; - if (!grp->members[i]->qglobal) continue; - if(!GetNeedsCured(grp->members[i])) continue; - if (grp->members[i]->DontCureMeBefore() > Timer::GetCurrentTime()) continue; - selectedBotSpell = GetBestBotSpellForCure(this, grp->members[i]); - if (ElixirAITryCastSpell(selectedBotSpell, true)) { - return true; - } - } - - if (GetManaRatio() > 50) { // healers only offensive or buff at > 50% mana - selectedBotSpell = GetBestBotSpellForNukeByTargetType(this, ST_Target); - if (ElixirAITryCastSpell(selectedBotSpell)) { - return true; - } - - auto buffSpells = GetBotSpellsBySpellType(this, SpellType_Buff); - for (auto buffSpell : buffSpells) { - if (!ElixirAITryCastSpell(selectedBotSpell)) continue; - return true; - } - } - return false; - case WIZARD: // This can eventually be move into the BEASTLORD case handler once pre-combat is fully implemented - if (GetTarget() && HasOrMayGetAggro()) { - selectedBotSpell = GetFirstBotSpellBySpellType(this, SpellType_Escape); - if (selectedBotSpell.SpellId > 0 && ElixirAITryCastSpell(selectedBotSpell)) { - return true; - } - } - - selectedBotSpell = GetFirstBotSpellBySpellType(this, SpellType_Nuke); - if (selectedBotSpell.SpellId > 0 && ElixirAITryCastSpell(selectedBotSpell)) { - return true; - } - return false; - case BARD: - if (GetTarget() && HasOrMayGetAggro()) { - selectedBotSpell = GetFirstBotSpellBySpellType(this, SpellType_PreCombatBuffSong); - if (selectedBotSpell.SpellId > 0 && ElixirAITryCastSpell(selectedBotSpell)) { - return true; - } - } - - selectedBotSpell = GetFirstBotSpellBySpellType(this, SpellType_InCombatBuffSong); - if (selectedBotSpell.SpellId > 0 && ElixirAITryCastSpell(selectedBotSpell)) { - return true; - } - return false; - default: - if (GetTarget() && HasOrMayGetAggro()) { - selectedBotSpell = GetFirstBotSpellBySpellType(this, SpellType_Escape); - if (selectedBotSpell.SpellId > 0 && ElixirAITryCastSpell(selectedBotSpell)) { - return true; - } - } - - selectedBotSpell = GetFirstBotSpellBySpellType(this, SpellType_Nuke); - if (selectedBotSpell.SpellId > 0 && ElixirAITryCastSpell(selectedBotSpell)) { - return true; - } - - selectedBotSpell = GetFirstBotSpellBySpellType(this, SpellType_InCombatBuff); - if (selectedBotSpell.SpellId > 0 && ElixirAITryCastSpell(selectedBotSpell)) { - return true; - } - return false; + if (IsEffectInSpell(spellID, SE_HealOverTime) && spellSlot == -1) { + if (GetClass() == CLERIC || GetClass() == DRUID || GetClass() == SHAMAN || GetClass() == PALADIN) spellSlot = 3; + else spellSlot = 7; } - return false; + + if (IsRegularGroupHealSpell(spellID) && spellSlot == -1) { + if (GetClass() == CLERIC || GetClass() == DRUID || GetClass() == SHAMAN || GetClass() == PALADIN) spellSlot = 0; + else spellSlot = 0; + } + + if (IsAENukeSpell(spellID) && spellSlot == -1) { + spellSlot = 1; + } + + if (IsSlowSpell(spellID) && spellSlot == -1) { + spellSlot = 3; + } + + if (IsPureNukeSpell(spellID) && spellSlot == -1) { + if (GetClass() == CLERIC || GetClass() == DRUID || GetClass() == SHAMAN || GetClass() == PALADIN) { + if (GetManaRatio() > 90) { + spellSlot = 5; + } + } + else { + spellSlot = 5; + } + } + /* + //TODO: escape spell slot 2 + if (GetTarget() && HasOrMayGetAggro()) { + selectedBotSpell = GetFirstBotSpellBySpellType(this, SpellType_Escape); + if (selectedBotSpell.SpellId > 0 && ElixirAITryCastSpell(selectedBotSpell)) { + return true; + } + } + */ + + if (IsBuffSpell(spellID) && spellSlot == -1) { + spellSlot = 10; + } + if (IsHasteSpell(spellID) && spellSlot == -1) { + spellSlot = 12; + } + if (spellSlot == -1) continue; + + if (elixirCacheSpells[spellSlot] == -1) { + elixirCacheSpells[spellSlot] = spellID; + continue; + } + + if (GetSpellLevel(spellID, GetClass()) < GetSpellLevel(elixirCacheSpells[spellSlot], GetClass())) { + continue; + } + elixirCacheSpells[spellSlot] = spellID; + } } // ElixirAITryCastSpell takes a provided spell id and does a spell check to determine if the spell is valid // Once valid, it will cast on returned mob candidate -bool Bot::ElixirAITryCastSpell(BotSpell botSpell, bool isHeal) { - auto spellID = botSpell.SpellId; +bool Bot::ElixirAITryCastSpell(uint16 spellID, bool isHeal) { if (spellID == 0) return false; - Mob* outMob; - auto spellAIResult = ElixirCastSpellCheck(spellID, outMob); + Mob* outMob = nullptr; + auto spellAIResult = ElixirCastSpellCheck(spellID, &outMob); if (spellAIResult < 0) return false; if (spellAIResult == 0) { - AIDoSpellCast(botSpell.SpellIndex, GetTarget(), -1); + + if (outMob == nullptr && GetTarget() != nullptr) outMob = GetTarget(); + if (outMob == nullptr) outMob = this; + AIElixirDoSpellCast(spellID, outMob, -1); if (GetTarget() == this) return true; - if (isHeal) BotGroupSay(this, "Casting %s on %s.", spells[spellID].name, GetTarget()->GetCleanName()); + BotGroupSay(this, "Casting %s on %s.", spells[spellID].name, outMob->GetCleanName()); return true; } - + if (outMob == nullptr) { - return false; + return false; } - AIDoSpellCast(botSpell.SpellIndex, outMob, -1); + AIElixirDoSpellCast(spellID, outMob, -1); if (outMob == this) return true; - if (isHeal) BotGroupSay(this, "Casting %s on %s.", spells[spellID].name, outMob->GetCleanName()); + BotGroupSay(this, "Casting %s on %s.", spells[spellID].name, outMob->GetCleanName()); return true; } + +bool Bot::AIElixirDoSpellCast(uint16 spellID, Mob* tar, int32 mana_cost) { + // manacost has special values, -1 is no mana cost, -2 is instant cast (no mana) + int32 manaCost = mana_cost; + + if (manaCost == -1) + manaCost = spells[spellID].mana; + else if (manaCost == -2) + manaCost = 0; + + int32 extraMana = 0; + int32 hasMana = GetMana(); + + Log(Logs::General, Logs::Mercenaries, "Attempting to cast %s on %s", spells[spellID].name, tar == nullptr ? "no target" : tar->GetCleanName()); + + // Allow bots to cast buff spells even if they are out of mana + if (RuleB(Bots, FinishBuffing)) { + if (manaCost > hasMana) { + //TODO: fix FinishBuffing no mana cost system + if (false) { + extraMana = manaCost - hasMana; + SetMana(manaCost); + } + } + } + + bool result = NPC::CastSpell(spellID, tar->GetID(), EQ::spells::CastingSlot::Gem2, spells[spellID].mana == -2 ? 0 : -1, mana_cost, 0, -1, -1, 0, 0); + if (IsCasting() && IsSitting()) Stand(); + + // if the spell wasn't casted, then take back any extra mana that was given to the bot to cast that spell + if (!result) { + SetMana(hasMana); + extraMana = false; + return result; + } + + //AIspells[i].time_cancast = Timer::GetCurrentTime() + spells[AIspells[i].spellid].recast_time; + if (spells[spellID].timer_id > 0) { + SetSpellRecastTimer(spells[spellID].timer_id, spells[spellID].recast_time); + } + + return result; +} + #endif diff --git a/zone/command.cpp b/zone/command.cpp index c7f6b3b3a..0e5edf1b6 100755 --- a/zone/command.cpp +++ b/zone/command.cpp @@ -80,6 +80,7 @@ #include "../common/shared_tasks.h" #include "gm_commands/door_manipulation.h" #include "../common/languages.h" +#include "elixir.h" extern QueryServ* QServ; extern WorldServer worldserver; @@ -209,6 +210,7 @@ int command_init(void) command_add("dz", "Manage expeditions and dynamic zone instances", 80, command_dz) || command_add("dzkickplayers", "Removes all players from current expedition. (/kickplayers alternative for pre-RoF clients)", 0, command_dzkickplayers) || command_add("editmassrespawn", "[name-search] [second-value] - Mass (Zone wide) NPC respawn timer editing command", 100, command_editmassrespawn) || + command_add("elixircheck", "[spellid] - Check how elixir AI works with provided spell id", 100, command_elixircheck) || command_add("emote", "['name'/'world'/'zone'] [type] [message] - Send an emote message", 80, command_emote) || command_add("emotesearch", "Searches NPC Emotes", 80, command_emotesearch) || command_add("emoteview", "Lists all NPC Emotes", 80, command_emoteview) || @@ -15900,6 +15902,97 @@ void command_emptyinventory(Client *c, const Seperator *sep) } } + +void command_elixircheck(Client* c, const Seperator* sep) +{ + if (sep->arg[1][0] == 0) { + c->Message(Chat::White, "Usage: #elixircheck [spellid]"); + return; + } + + auto spellid = atoi(sep->arg[1]); + if (spellid < 1) { + c->Message(Chat::Red, "Invalid spell id: %d", spellid); + return; + } + Mob* outMob = nullptr; + const SPDat_Spell_Struct& spDat = spells[spellid]; + auto result = c->ElixirCastSpellCheck(spellid, &outMob); + if (result < 0) { + switch (result) { + case ELIXIR_UNHANDLED_SPELL: + c->Message(Chat::Red, "Elixir AI failed to cast %s due to error %d (UNHANDLED_SPELL)", spDat.name, result); + return; + case ELIXIR_CANNOT_CAST_BAD_STATE: + c->Message(Chat::Red, "Elixir AI failed to cast %s due to error %d (CANNOT_CAST_BAD_STATE)", spDat.name, result); + return; + case ELIXIR_NOT_ENOUGH_MANA: + c->Message(Chat::Red, "Elixir AI failed to cast %s due to error %d (NOT_ENOUGH_MANA)", spDat.name, result); + return; + case ELIXIR_LULL_IGNORED: + c->Message(Chat::Red, "Elixir AI failed to cast %s due to error %d (LULL_IGNORED)", spDat.name, result); + return; + case ELIXIR_MEZ_IGNORED: + c->Message(Chat::Red, "Elixir AI failed to cast %s due to error %d (MEZ_IGNORED)", spDat.name, result); + return; + case ELIXIR_CHARM_IGNORED: + c->Message(Chat::Red, "Elixir AI failed to cast %s due to error %d (CHARM_IGNORED)", spDat.name, result); + return; + case ELIXIR_NO_TARGET: + c->Message(Chat::Red, "Elixir AI failed to cast %s due to error %d (NO_TARGET)", spDat.name, result); + return; + case ELIXIR_INVALID_TARGET_BODYTYPE: + c->Message(Chat::Red, "Elixir AI failed to cast %s due to error %d (INVALID_TARGET_BODYTYPE)", spDat.name, result); + return; + case ELIXIR_TRANSPORT_IGNORED: + c->Message(Chat::Red, "Elixir AI failed to cast %s due to error %d (TRANSPORT_IGNORED)", spDat.name, result); + return; + case ELIXIR_NOT_LINE_OF_SIGHT: + c->Message(Chat::Red, "Elixir AI failed to cast %s due to error %d (NOT_LINE_OF_SIGHT)", spDat.name, result); + return; + case ELIXIR_COMPONENT_REQUIRED: + c->Message(Chat::Red, "Elixir AI failed to cast %s due to error %d (COMPONENT_REQUIRED)", spDat.name, result); + return; + case ELIXIR_ALREADY_HAVE_BUFF: + c->Message(Chat::Red, "Elixir AI failed to cast %s due to error %d (ALREADY_HAVE_BUFF)", spDat.name, result); + return; + case ELIXIR_ZONETYPE_FAIL: + c->Message(Chat::Red, "Elixir AI failed to cast %s due to error %d (ZONETYPE_FAIL)", spDat.name, result); + return; + case ELIXIR_CANNOT_USE_IN_COMBAT: + c->Message(Chat::Red, "Elixir AI failed to cast %s due to error %d (CANNOT_USE_IN_COMBAT)", spDat.name, result); + return; + case ELIXIR_NOT_ENOUGH_ENDURANCE: + c->Message(Chat::Red, "Elixir AI failed to cast %s due to error %d (NOT_ENOUGH_ENDURANCE)", spDat.name, result); + return; + case ELIXIR_ALREADY_HAVE_PET: + c->Message(Chat::Red, "Elixir AI failed to cast %s due to error %d (ALREADY_HAVE_PET)", spDat.name, result); + return; + case ELIXIR_OUT_OF_RANGE: + c->Message(Chat::Red, "Elixir AI failed to cast %s due to error %d (OUT_OF_RANGE)", spDat.name, result); + return; + case ELIXIR_NO_PET: + c->Message(Chat::Red, "Elixir AI failed to cast %s due to error %d (NO_PET)", spDat.name, result); + return; + case ELIXIR_NOT_NEEDED: + c->Message(Chat::Red, "Elixir AI failed to cast %s due to error %d (NOT_NEEDED)", spDat.name, result); + return; + default: + c->Message(Chat::Red, "Elixir AI failed to cast %s due to error %d (UNKNOWN)", spDat.name, result); + return; + } + } + + if (result == 0) { + c->Message(Chat::White, "Elixir AI would return OK to cast %s", spDat.name); + return; + } + if (result == 1) { + c->Message(Chat::White, "Elixir AI would return OK if target changes to %s to cast %s", outMob->GetCleanName(), spDat.name); + } +} + + // All new code added to command.cpp should be BEFORE this comment line. Do no append code to this file below the BOTS code block. #ifdef BOTS #include "bot_command.h" diff --git a/zone/command.h b/zone/command.h index b0d5ccc40..6da2bd2d1 100644 --- a/zone/command.h +++ b/zone/command.h @@ -88,6 +88,7 @@ void command_dye(Client *c, const Seperator *sep); void command_dz(Client *c, const Seperator *sep); void command_dzkickplayers(Client *c, const Seperator *sep); void command_editmassrespawn(Client* c, const Seperator* sep); +void command_elixircheck(Client* c, const Seperator* sep); void command_emote(Client *c, const Seperator *sep); void command_emotesearch(Client* c, const Seperator *sep); void command_emoteview(Client* c, const Seperator *sep); diff --git a/zone/elixir.cpp b/zone/elixir.cpp index 7de140d5d..40c07c1f9 100644 --- a/zone/elixir.cpp +++ b/zone/elixir.cpp @@ -13,12 +13,12 @@ extern Zone* zone; // If 0 is returned, spell is valid and no target changing is required // If a negative value is returned, an error occured. See elixir.h ELIXIR_ prefix const error lookup of reasons // If 1 is returned, outMob is set to the suggested mob entity -int8 Mob::ElixirCastSpellCheck(uint16 spellID, Mob *outMob) +int8 Mob::ElixirCastSpellCheck(uint16 spellID, Mob** outMob) { - int manaCurrent = GetMana(); - int manaMax = GetMaxMana(); - int hpCurrent = GetHP(); - int hpMax = GetMaxHP(); + int manaCurrent = GetMana(); + int manaMax = GetMaxMana(); + int hpCurrent = GetHP(); + int hpMax = GetMaxHP(); int endCurrent = GetEndurance(); int endMax = GetMaxEndurance(); @@ -38,33 +38,38 @@ int8 Mob::ElixirCastSpellCheck(uint16 spellID, Mob *outMob) if (aeMinimum < 1) aeMinimum = 1; if (aeMinimum > 99) aeMinimum = 99; - if (IsCorpse()) return ELIXIR_CANNOT_CAST_BAD_STATE; - - bool isHeal = false; + if (IsCorpse()) return ELIXIR_CANNOT_CAST_BAD_STATE; + + bool isHeal = false; bool isDebuff = false; bool isBuff = false; bool isLifetap = false; bool isMana = false; bool isCharm = false; bool isSnare = false; - bool isSow = false; + bool isSow = false; bool isTaunt = false; bool isSingleTargetSpell = false; bool isPetSummon = false; bool isTransport = false; bool isGroupSpell = false; bool isBardSong = false; + bool isBeneficial = false; + bool isStun = false; bool isMez = false; bool isLull = false; long stunDuration = 0; long damageAmount = 0; long healAmount = 0; + bool isGroupHated = false; - int skillID; + int skillID = 0; - bodyType targetBodyType = BT_NoTarget2; - - const SPDat_Spell_Struct &spDat = spells[spellID]; + bodyType targetBodyType = BT_NoTarget2; + + const SPDat_Spell_Struct& spDat = spells[spellID]; + + Log(Logs::General, Logs::Mercenaries, "%s checking %s vs %s", GetName(), spDat.name, target == nullptr ? "no target" : target->GetCleanName()); int spellgroup = spDat.type_description_id; uint32 ticks = spDat.buff_duration; @@ -75,42 +80,42 @@ int8 Mob::ElixirCastSpellCheck(uint16 spellID, Mob *outMob) int category = spDat.spell_category; int subcategory = spDat.effect_description_id; - uint32 buffCount; - Group *grp = GetGroup(); - Raid *raid = GetRaid(); + uint32 buffCount = 0; + Group* grp = GetGroup(); + Raid* raid = GetRaid(); - for (int i = 0; i < EFFECT_COUNT; i++) { - if (IsBlankSpellEffect(spellID, i)) continue; + for (int i = 0; i < EFFECT_COUNT; i++) { + if (IsBlankSpellEffect(spellID, i)) continue; - int attr = spDat.effect_id[i]; - int base = spDat.base_value[i]; - int base2 = spDat.limit_value[i]; - int max = spDat.max_value[i]; - int calc = spDat.formula[i]; + int attr = spDat.effect_id[i]; + int base = spDat.base_value[i]; + int base2 = spDat.limit_value[i]; + int max = spDat.max_value[i]; + int calc = spDat.formula[i]; - if (attr == SE_CurrentHP) { //0 - if (max > 0) { //Heal / HoT - if (ticks < 5 && base > 0) { //regen - isHeal = true; - healAmount = base; - } - if (ticks > 0) { - isBuff = true; - } - if (category == 114) { //taps like touch of zlandicar - isLifetap = true; - } - } - if (base < 0 && damageAmount == 0) { - damageAmount = -base; - } - if (max < 0) { //Nuke / DoT + if (attr == SE_CurrentHP) { //0 + if (max > 0) { //Heal / HoT + if (ticks < 5 && base > 0) { //regen + isHeal = true; + healAmount = base; + } + if (ticks > 0) { + isBuff = true; + } + if (category == 114) { //taps like touch of zlandicar + isLifetap = true; + } + } + if (base < 0 && damageAmount == 0) { + damageAmount = -base; + } + if (max < 0) { //Nuke / DoT damageAmount = -max; } - } + } - if (attr == SE_ArmorClass || // 1 ac - attr == SE_ATK || //2 attack + if (attr == SE_ArmorClass || // 1 ac + attr == SE_ATK || //2 attack attr == SE_STR || //4 str attr == SE_DEX || //5 dex attr == SE_AGI || //6 agi @@ -124,9 +129,9 @@ int8 Mob::ElixirCastSpellCheck(uint16 spellID, Mob *outMob) if (base < 0) { //-stat isDebuff = true; } - } + } - if (attr == SE_MovementSpeed) { //3 + if (attr == SE_MovementSpeed) { //3 if (base > 0) { //+Movement isBuff = true; isSow = true; @@ -137,7 +142,7 @@ int8 Mob::ElixirCastSpellCheck(uint16 spellID, Mob *outMob) } } - if (attr == SE_CHA) { //10 CHA + if (attr == SE_CHA) { //10 CHA if (base > 0 && base < 254) { //+CHA isBuff = true; } @@ -155,7 +160,7 @@ int8 Mob::ElixirCastSpellCheck(uint16 spellID, Mob *outMob) } } - if (attr == SE_CurrentMana) { //15 Mana + if (attr == SE_CurrentMana) { //15 Mana isMana = true; } if (attr == SE_Lull) { // pacify (lull) @@ -175,7 +180,7 @@ int8 Mob::ElixirCastSpellCheck(uint16 spellID, Mob *outMob) isTransport = true; } - if (attr == SE_ChangeFrenzyRad) { //30 frenzy radius reduction (lull) + if (attr == SE_ChangeFrenzyRad) { //30 frenzy radius reduction (lull) isLull = true; } @@ -194,7 +199,7 @@ int8 Mob::ElixirCastSpellCheck(uint16 spellID, Mob *outMob) if (attr == SE_Teleport) { //83 Transport isTransport = true; } - + if (attr == SE_Harmony) { //86 reaction radius reduction (lull) isLull = true; } @@ -202,6 +207,11 @@ int8 Mob::ElixirCastSpellCheck(uint16 spellID, Mob *outMob) isTransport = true; } + + if (attr == SE_HealOverTime) { //100 Heal over times + isHeal = true; + } + if (attr == SE_Familiar) { //108 Summon Familiar isPetSummon = true; } @@ -213,7 +223,7 @@ int8 Mob::ElixirCastSpellCheck(uint16 spellID, Mob *outMob) if (attr == SE_SkillAttack) { //193 skill attack skillID = spDat.skill; } - } + } if (subcategory == 43 && ticks < 10) { //Health isHeal = true; @@ -224,6 +234,8 @@ int8 Mob::ElixirCastSpellCheck(uint16 spellID, Mob *outMob) isLifetap = true; } } + isBeneficial = IsBeneficialSpell(spellID); + isStun = IsStunSpell(spellID); /* //TODO TargetTypes: @@ -243,7 +255,7 @@ int8 Mob::ElixirCastSpellCheck(uint16 spellID, Mob *outMob) if (targettype == ST_GroupTeleport) { //3 Group v1 isGroupSpell = true; } - + if (isGroupSpell && IsBardSong(spellID)) { isBardSong = true; } @@ -304,28 +316,28 @@ int8 Mob::ElixirCastSpellCheck(uint16 spellID, Mob *outMob) if (targetBodyType != BT_Animal) return ELIXIR_INVALID_TARGET_BODYTYPE; } - if (targettype == ST_Undead ) { //10 Undead + if (targettype == ST_Undead) { //10 Undead if (target == nullptr) return ELIXIR_NO_TARGET; if (targetBodyType != BT_Undead) return ELIXIR_INVALID_TARGET_BODYTYPE; } if (targettype == ST_Summoned) { //11 Summoned - if (target == nullptr) return ELIXIR_NO_TARGET; + if (target == nullptr) return ELIXIR_NO_TARGET; if (targetBodyType != BT_Summoned) return ELIXIR_INVALID_TARGET_BODYTYPE; } if (targettype == ST_Plant) { //Plant - if (target == nullptr) return ELIXIR_NO_TARGET; + if (target == nullptr) return ELIXIR_NO_TARGET; if (targetBodyType != BT_Plant) return ELIXIR_INVALID_TARGET_BODYTYPE; } if (isTransport) return ELIXIR_TRANSPORT_IGNORED; - if (spDat.npc_no_los == 0 && target && isSingleTargetSpell && CheckLosFN(target)) return ELIXIR_NOT_LINE_OF_SIGHT; + if (spDat.npc_no_los == 0 && target && isSingleTargetSpell && !isBeneficial && !CheckLosFN(target)) return ELIXIR_NOT_LINE_OF_SIGHT; for (int i = 0; i < 4; i++) { // Reagent check - if (spDat.component[i] == 0) continue; - if (spDat.component_count[i] == -1) continue; + if (spDat.component[i] < 1) continue; + if (spDat.component_count[i] < 1) continue; if (IsMerc()) continue; //mercs don't have inventory nor require reagents #ifdef BOTS if (IsBot()) continue; //bots don't have inventory nor require reagents @@ -340,7 +352,7 @@ int8 Mob::ElixirCastSpellCheck(uint16 spellID, Mob *outMob) if (skillID == EQ::skills::SkillBackstab) { // 8 backstab - if (!target) { + if (target == nullptr) { return ELIXIR_NO_TARGET; } if (!BehindMob(target)) { @@ -351,9 +363,9 @@ int8 Mob::ElixirCastSpellCheck(uint16 spellID, Mob *outMob) } return 0; } - + if (recourseID > 0) { //recourse buff attached - const SPDat_Spell_Struct &spDatRecourse = spells[recourseID]; + const SPDat_Spell_Struct& spDatRecourse = spells[recourseID]; if (spDatRecourse.buff_duration > 0) { buffCount = GetMaxTotalSlots(); for (uint32 i = 0; i < buffCount; i++) { @@ -372,8 +384,8 @@ int8 Mob::ElixirCastSpellCheck(uint16 spellID, Mob *outMob) } } - if (ticks > 0 && !IsBeneficialSpell(spellID) && targettype == ST_Target) { // debuff - if (!target) { + if (ticks > 0 && !isBeneficial && targettype == ST_Target) { // debuff + if (target == nullptr) { return ELIXIR_NO_TARGET; } @@ -397,14 +409,31 @@ int8 Mob::ElixirCastSpellCheck(uint16 spellID, Mob *outMob) return ELIXIR_ZONETYPE_FAIL; } + if (target) { //do aggro check + if (target->GetHateAmount(this) > 0) isGroupHated = true; + if (!isGroupHated) { + for (int i = 0; i < MAX_GROUP_MEMBERS; i++) { + if (!grp) break; + if (!grp->members[i]) continue; + if (target->GetHateAmount(grp->members[i]) == 0) continue; + isGroupHated = true; + break; + } + } + } //TODO: zone_type 2 check (can't cast outdoors indoor only) if (IsEffectInSpell(spellID, SE_Levitate) && !zone->CanLevitate()) { return ELIXIR_ZONETYPE_FAIL; } - + if (!spDat.can_cast_in_combat) { - if (IsEngaged()) return ELIXIR_CANNOT_USE_IN_COMBAT; + if (IsEngaged()) { + return ELIXIR_CANNOT_USE_IN_COMBAT; + } + if (target == nullptr) { + return ELIXIR_NO_TARGET; + } buffCount = target->GetMaxTotalSlots(); for (uint32 i = 0; i < buffCount; i++) { auto buff = target->buffs[i]; @@ -412,7 +441,7 @@ int8 Mob::ElixirCastSpellCheck(uint16 spellID, Mob *outMob) if (IsDetrimentalSpell(buff.spellid) && buff.ticsremaining > 0 && !DetrimentalSpellAllowsRest(buff.spellid)) { return ELIXIR_CANNOT_USE_IN_COMBAT; } - } + } } if (IsDisciplineBuff(spellID)) { @@ -434,7 +463,7 @@ int8 Mob::ElixirCastSpellCheck(uint16 spellID, Mob *outMob) if (isPetSummon && HasPet()) return ELIXIR_ALREADY_HAVE_PET; - + if (targettype == ST_Pet && isHeal) { if (!HasPet()) { return ELIXIR_NO_PET; @@ -445,11 +474,11 @@ int8 Mob::ElixirCastSpellCheck(uint16 spellID, Mob *outMob) return ELIXIR_NOT_NEEDED; } - if (isBuff && targettype == ST_Pet && IsBeneficialSpell(spellID)) { + if (isBuff && targettype == ST_Pet && isBeneficial) { if (!HasPet()) { return ELIXIR_NO_PET; } - + buffCount = GetPet()->GetMaxTotalSlots(); for (uint32 i = 0; i < buffCount; i++) { auto buff = GetPet()->buffs[i]; @@ -471,7 +500,7 @@ int8 Mob::ElixirCastSpellCheck(uint16 spellID, Mob *outMob) } if (isMana && targettype == ST_Self && ticks <= 0 && !isPetSummon) { // self only regen, like harvest, canni - if (stunDuration > 0 && IsEngaged()) { + if (stunDuration > 0 && isGroupHated) { return ELIXIR_CANNOT_USE_IN_COMBAT; } @@ -487,64 +516,22 @@ int8 Mob::ElixirCastSpellCheck(uint16 spellID, Mob *outMob) return ELIXIR_NOT_NEEDED; } - - if (isGroupSpell && isHeal && ticks == 0) { //self/group instant heals + if (isHeal) { //heal logic int groupHealCount = 0; - - float sqDistance = spDat.aoe_range * spDat.aoe_range; - for (int i = 0; i < MAX_GROUP_MEMBERS; i++) { - if (!grp) break; - if (!grp->members[i]) continue; - if (grp->members[i]->GetHPRatio() > healPercent) continue; - if (sqDistance > 0 && DistanceSquaredNoZ(target->GetPosition(), grp->members[i]->GetPosition()) > sqDistance) continue; - groupHealCount++; - } - - if (groupHealCount < aeMinimum) { - return ELIXIR_NOT_NEEDED; - } - return 0; - } - - - if ((targettype == ST_Self || isGroupSpell) && IsBeneficialSpell(spellID)) { //self/group beneficial spell - if (IsEngaged() && !isBardSong) { - return ELIXIR_CANNOT_USE_IN_COMBAT; - } - - if (ticks > 0) { - bool isBuffNeeded = true; - - buffCount = GetMaxTotalSlots(); - for (uint32 i = 0; i < buffCount; i++) { - auto buff = buffs[i]; - if (buff.spellid == SPELL_UNKNOWN) continue; - if (spells[buff.spellid].buff_duration_formula == DF_Permanent) continue; - if (buff.ticsremaining < 2) continue; - if (buff.spellid == spellID) { - isBuffNeeded = false; - break; - } - int stackResult = CheckStackConflict(buff.spellid, buff.casterlevel, spellID, GetLevel(), entity_list.GetMobID(buff.casterid), this, i); - if (stackResult == -1) { - isBuffNeeded = false; - break; - } + int healIDPercent = 100; + // figure out who is lowest HP party member + if (GetHPRatio() <= healPercent) { + if (ticks == 0) { // instant heal, just apply + *outMob = this; + healIDPercent = GetHPRatio(); } - if (isBuffNeeded) return 0; - if (!isGroupSpell) return ELIXIR_NOT_NEEDED; - - isBuffNeeded = true; - for (int i = 0; i < MAX_GROUP_MEMBERS; i++) { - - if (!grp) break; - if (!grp->members[i]) continue; - buffCount = grp->members[i]->GetMaxTotalSlots(); + else { // it's a heal buff, check if player already has it + bool isBuffNeeded = true; + buffCount = GetMaxTotalSlots(); for (uint32 i = 0; i < buffCount; i++) { auto buff = buffs[i]; if (buff.spellid == SPELL_UNKNOWN) continue; if (spells[buff.spellid].buff_duration_formula == DF_Permanent) continue; - if (buff.ticsremaining < 2) continue; if (buff.spellid == spellID) { isBuffNeeded = false; break; @@ -555,90 +542,129 @@ int8 Mob::ElixirCastSpellCheck(uint16 spellID, Mob *outMob) break; } } - if (!isBuffNeeded) continue; - outMob = grp->members[i]; - return 1; + if (isBuffNeeded) { + *outMob = this; + healIDPercent = GetHPRatio(); + } } + } + + for (int i = 0; i < MAX_GROUP_MEMBERS; i++) { + if (!grp) break; + if (!grp->members[i]) continue; + if (grp->members[i]->GetHPRatio() > healPercent) continue; + if (grp->members[i]->GetHPRatio() > healIDPercent) continue; + if (!IsWithinSpellRange(grp->members[i], spDat.range, spellID)) continue; + + groupHealCount++; + if (ticks == 0) { // instant heal, just apply + *outMob = grp->members[i]; + healIDPercent = grp->members[i]->GetHPRatio(); + } + else { // it's a heal buff, check if player already has it + bool isBuffNeeded = true; + buffCount = grp->members[i]->GetMaxTotalSlots(); + for (uint32 j = 0; j < buffCount; j++) { + auto buff = grp->members[i]->buffs[j]; + if (buff.spellid == SPELL_UNKNOWN) continue; + if (spells[buff.spellid].buff_duration_formula == DF_Permanent) continue; + if (buff.spellid == spellID) { + isBuffNeeded = false; + break; + } + int stackResult = CheckStackConflict(buff.spellid, buff.casterlevel, spellID, GetLevel(), entity_list.GetMobID(buff.casterid), this, i); + if (stackResult == -1) { + isBuffNeeded = false; + break; + } + // TODO: Immune Check + } + if (isBuffNeeded) { + *outMob = grp->members[i]; + healIDPercent = GetHPRatio(); + } + } + } + + if (isGroupSpell && groupHealCount < aeMinimum) { return ELIXIR_NOT_NEEDED; } - return 0; + if (!*outMob) { + return ELIXIR_NOT_NEEDED; + } + return 1; } - if (targettype == ST_Target || IsBeneficialSpell(spellID)) { //single target beneficial spell - if (isHeal) { //heal logic - int healIDPercent = 100; - // figure out who is lowest HP party member - if (GetHPRatio() <= healPercent) { - if (ticks == 0) { // instant heal, just apply - outMob = this; - healIDPercent = GetHPRatio(); - } else { // it's a heal buff, check if player already has it - bool isBuffNeeded = true; - for (uint32 i = 0; i < buffCount; i++) { - auto buff = buffs[i]; - if (buff.spellid == SPELL_UNKNOWN) continue; - if (spells[buff.spellid].buff_duration_formula == DF_Permanent) continue; - if (buff.spellid == spellID) { - isBuffNeeded = false; - break; - } - int stackResult = CheckStackConflict(buff.spellid, buff.casterlevel, spellID, GetLevel(), entity_list.GetMobID(buff.casterid), this, i); - if (stackResult == -1) { - isBuffNeeded = false; - break; - } - } - if (isBuffNeeded) { - outMob = this; - healIDPercent = GetHPRatio(); - } + + if ((targettype == ST_Self || isGroupSpell) && isBeneficial) { //self/group beneficial spell + if (isGroupHated && !isBardSong) { + return ELIXIR_CANNOT_USE_IN_COMBAT; + } + + if (ticks <= 4 && GetClass() != BARD) { //don't bother with short duration buffs + return ELIXIR_NOT_NEEDED; + } + + if (ticks == 0) { + return 0; + } + bool isBuffNeeded = true; + + buffCount = GetMaxTotalSlots(); + for (uint32 i = 0; i < buffCount; i++) { + auto buff = buffs[i]; + if (buff.spellid == SPELL_UNKNOWN) continue; + if (spells[buff.spellid].buff_duration_formula == DF_Permanent) continue; + if (buff.ticsremaining < 2) continue; + if (buff.spellid == spellID) { + isBuffNeeded = false; + break; + } + int stackResult = CheckStackConflict(buff.spellid, buff.casterlevel, spellID, GetLevel(), entity_list.GetMobID(buff.casterid), this, i); + if (stackResult == -1) { + isBuffNeeded = false; + break; + } + } + if (isBuffNeeded) return 0; + if (!isGroupSpell) return ELIXIR_NOT_NEEDED; + + isBuffNeeded = true; + for (int i = 0; i < MAX_GROUP_MEMBERS; i++) { + + if (!grp) break; + if (!grp->members[i]) continue; + buffCount = grp->members[i]->GetMaxTotalSlots(); + for (uint32 j = 0; j < buffCount; j++) { + auto buff = grp->members[i]->buffs[j]; + if (buff.spellid == SPELL_UNKNOWN) continue; + if (spells[buff.spellid].buff_duration_formula == DF_Permanent) continue; + if (buff.ticsremaining < 2) continue; + if (buff.spellid == spellID) { + isBuffNeeded = false; + break; + } + int stackResult = CheckStackConflict(buff.spellid, buff.casterlevel, spellID, GetLevel(), entity_list.GetMobID(buff.casterid), this, i); + if (stackResult == -1) { + isBuffNeeded = false; + break; } } - - for (int i = 0; i < MAX_GROUP_MEMBERS; i++) { - if (!grp) break; - if (!grp->members[i]) continue; - if (grp->members[i]->GetHPRatio() > healPercent) continue; - if (grp->members[i]->GetHPRatio() > healIDPercent) continue; - if (!IsWithinSpellRange(grp->members[i], spDat.range, spellID)) continue; - - if (ticks == 0) { // instant heal, just apply - outMob = grp->members[i]; - healIDPercent = grp->members[i]->GetHPRatio(); - } else { // it's a heal buff, check if player already has it - bool isBuffNeeded = true; - for (uint32 i = 0; i < buffCount; i++) { - auto buff = grp->members[i]->buffs[i]; - if (buff.spellid == SPELL_UNKNOWN) continue; - if (spells[buff.spellid].buff_duration_formula == DF_Permanent) continue; - if (buff.spellid == spellID) { - isBuffNeeded = false; - break; - } - int stackResult = CheckStackConflict(buff.spellid, buff.casterlevel, spellID, GetLevel(), entity_list.GetMobID(buff.casterid), this, i); - if (stackResult == -1) { - isBuffNeeded = false; - break; - } - // TODO: Immune Check - } - if (isBuffNeeded) { - outMob = grp->members[i]; - healIDPercent = GetHPRatio(); - } - } - } - if (!outMob) { - return ELIXIR_NOT_NEEDED; - } + if (!isBuffNeeded) continue; + *outMob = grp->members[i]; return 1; } + return ELIXIR_NOT_NEEDED; + + } + + if (targettype == ST_Target && isBeneficial && damageAmount == 0) { //single target beneficial spell // TODO: add exceptions for combat buffs situation bool isCombatBuff = false; - if (IsEngaged() && !isCombatBuff) { + if (isGroupHated && !isCombatBuff) { return ELIXIR_NOT_NEEDED; } @@ -647,9 +673,12 @@ int8 Mob::ElixirCastSpellCheck(uint16 spellID, Mob *outMob) if (ticks == 0) { return ELIXIR_NOT_NEEDED; } - + if (ticks <= 4 && GetClass() != BARD) { //don't bother with short duration buffs + return ELIXIR_NOT_NEEDED; + } // always self buff first bool isBuffNeeded = true; + buffCount = GetMaxBuffSlots(); for (uint32 i = 0; i < buffCount; i++) { auto buff = buffs[i]; if (buff.spellid == SPELL_UNKNOWN) continue; @@ -669,7 +698,7 @@ int8 Mob::ElixirCastSpellCheck(uint16 spellID, Mob *outMob) if (target && target->GetID() == GetID()) { return 0; } - outMob = this; + *outMob = this; return 1; } @@ -677,10 +706,11 @@ int8 Mob::ElixirCastSpellCheck(uint16 spellID, Mob *outMob) if (!grp) break; if (!grp->members[i]) continue; if (!IsWithinSpellRange(grp->members[i], spDat.range, spellID)) continue; - + bool isBuffNeeded = true; - for (uint32 i = 0; i < buffCount; i++) { - auto buff = grp->members[i]->buffs[i]; + buffCount = grp->members[i]->GetMaxTotalSlots(); + for (uint32 j = 0; j < buffCount; j++) { + auto buff = grp->members[i]->buffs[j]; if (buff.spellid == SPELL_UNKNOWN) continue; if (spells[buff.spellid].buff_duration_formula == DF_Permanent) continue; if (buff.spellid == spellID) { @@ -688,7 +718,7 @@ int8 Mob::ElixirCastSpellCheck(uint16 spellID, Mob *outMob) break; } int stackResult = CheckStackConflict(buff.spellid, buff.casterlevel, spellID, GetLevel(), entity_list.GetMobID(buff.casterid), this, i); - if (stackResult == -1) { + if (stackResult == -1) { isBuffNeeded = false; break; } @@ -698,7 +728,7 @@ int8 Mob::ElixirCastSpellCheck(uint16 spellID, Mob *outMob) if (target && target->GetID() == grp->members[i]->GetID()) { return 0; } - outMob = grp->members[i]; + *outMob = grp->members[i]; return 1; } } @@ -706,6 +736,22 @@ int8 Mob::ElixirCastSpellCheck(uint16 spellID, Mob *outMob) return ELIXIR_NOT_NEEDED; } + if (isStun && (targettype == ST_AEClientV1 || targettype == ST_AreaClientOnly || targettype == ST_AECaster)) { // PB AE stun + int targetCount = 0; + float sqDistance = spDat.aoe_range * spDat.aoe_range; + auto hates = GetHateList(); + auto iter = hates.begin(); + for (auto iter : hates) { + if (sqDistance > 0 && DistanceSquaredNoZ(GetPosition(), iter->entity_on_hatelist->GetPosition()) > sqDistance) continue; + if (iter->entity_on_hatelist->IsStunned()) continue; + targetCount++; + } + if (targetCount < aeMinimum) { + return ELIXIR_NOT_NEEDED; + } + return 0; + } + if (damageAmount > 0 && (targettype == ST_AEClientV1 || targettype == ST_AreaClientOnly || targettype == ST_AECaster)) { // PB AE DD int targetCount = 0; float sqDistance = spDat.aoe_range * spDat.aoe_range; @@ -724,13 +770,13 @@ int8 Mob::ElixirCastSpellCheck(uint16 spellID, Mob *outMob) if (damageAmount > 0 && (targettype == ST_TargetAETap || targettype == ST_AETarget)) { // Target AE DD - if (!target) { + if (target == nullptr) { return ELIXIR_NO_TARGET; } if (!IsWithinSpellRange(target, spDat.range, spellID)) { return ELIXIR_OUT_OF_RANGE; } - + int targetCount = 0; float sqDistance = spDat.aoe_range * spDat.aoe_range; auto hates = GetHateList(); @@ -746,17 +792,21 @@ int8 Mob::ElixirCastSpellCheck(uint16 spellID, Mob *outMob) return 0; } - - if (targettype == ST_Target || !IsBeneficialSpell(spellID)) { // single target detrimental spell - if (!hate_list.IsEntOnHateList(target)) { + + if (targettype == ST_Target && !isBeneficial) { // single target detrimental spell + if (target == nullptr) { return ELIXIR_NO_TARGET; } - + + if (!isGroupHated) { + return ELIXIR_NOT_NEEDED; + } + if (target->GetHPRatio() <= 0) { return ELIXIR_NOT_NEEDED; } - if (!IsWithinSpellRange(GetPet(), spDat.range, spellID)) { + if (!IsWithinSpellRange(target, spDat.range, spellID)) { return ELIXIR_OUT_OF_RANGE; } @@ -768,13 +818,17 @@ int8 Mob::ElixirCastSpellCheck(uint16 spellID, Mob *outMob) return ELIXIR_NOT_NEEDED; } - if (ticks == 0) { - if (!target) { - return ELIXIR_NO_TARGET; + if (isStun) { + if (target->IsStunned()) { + return ELIXIR_NOT_NEEDED; } return 0; } - + + if (ticks == 0) { + return 0; + } + buffCount = target->GetMaxTotalSlots(); for (uint32 i = 0; i < buffCount; i++) { auto buff = target->buffs[i]; if (buff.spellid == SPELL_UNKNOWN) continue; @@ -791,7 +845,7 @@ int8 Mob::ElixirCastSpellCheck(uint16 spellID, Mob *outMob) return 0; } - return ELIXIR_UNHANDLED_SPELL; + return ELIXIR_UNHANDLED_SPELL; } /* @@ -801,4 +855,4 @@ int8 Mob::ElixirCastSpellCheck(uint16 spellID, Mob *outMob) if (!raid->members[i].member) continue; //raid->members[i].GroupNumber == gid } -*/ \ No newline at end of file +*/ diff --git a/zone/merc.cpp b/zone/merc.cpp index 8958a5d10..a75882107 100644 --- a/zone/merc.cpp +++ b/zone/merc.cpp @@ -21,15 +21,15 @@ extern volatile bool is_zone_loaded; #if EQDEBUG >= 12 - #define MercAI_DEBUG_Spells 25 +#define MercAI_DEBUG_Spells 25 #elif EQDEBUG >= 9 - #define MercAI_DEBUG_Spells 10 +#define MercAI_DEBUG_Spells 10 #else - #define MercAI_DEBUG_Spells -1 +#define MercAI_DEBUG_Spells -1 #endif Merc::Merc(const NPCType* d, float x, float y, float z, float heading) -: NPC(d, nullptr, glm::vec4(x, y, z, heading), GravityBehavior::Water, false), endupkeep_timer(1000), rest_timer(1), confidence_timer(6000), check_target_timer(2000) + : NPC(d, nullptr, glm::vec4(x, y, z, heading), GravityBehavior::Water, false), endupkeep_timer(1000), rest_timer(1), confidence_timer(6000), check_target_timer(2000) { base_hp = d->max_hp; base_mana = d->Mana; @@ -132,59 +132,59 @@ float Merc::GetDefaultSize() { float MercSize = GetSize(); - switch(this->GetRace()) + switch (this->GetRace()) { - case 1: // Humans - MercSize = 6.0; - break; - case 2: // Barbarian - MercSize = 7.0; - break; - case 3: // Erudite - MercSize = 6.0; - break; - case 4: // Wood Elf - MercSize = 5.0; - break; - case 5: // High Elf - MercSize = 6.0; - break; - case 6: // Dark Elf - MercSize = 5.0; - break; - case 7: // Half Elf - MercSize = 5.5; - break; - case 8: // Dwarf - MercSize = 4.0; - break; - case 9: // Troll - MercSize = 8.0; - break; - case 10: // Ogre - MercSize = 9.0; - break; - case 11: // Halfling - MercSize = 3.5; - break; - case 12: // Gnome - MercSize = 3.0; - break; - case 128: // Iksar - MercSize = 6.0; - break; - case 130: // Vah Shir - MercSize = 7.0; - break; - case 330: // Froglok - MercSize = 5.0; - break; - case 522: // Drakkin - MercSize = 5.0; - break; - default: - MercSize = 6.0; - break; + case 1: // Humans + MercSize = 6.0; + break; + case 2: // Barbarian + MercSize = 7.0; + break; + case 3: // Erudite + MercSize = 6.0; + break; + case 4: // Wood Elf + MercSize = 5.0; + break; + case 5: // High Elf + MercSize = 6.0; + break; + case 6: // Dark Elf + MercSize = 5.0; + break; + case 7: // Half Elf + MercSize = 5.5; + break; + case 8: // Dwarf + MercSize = 4.0; + break; + case 9: // Troll + MercSize = 8.0; + break; + case 10: // Ogre + MercSize = 9.0; + break; + case 11: // Halfling + MercSize = 3.5; + break; + case 12: // Gnome + MercSize = 3.0; + break; + case 128: // Iksar + MercSize = 6.0; + break; + case 130: // Vah Shir + MercSize = 7.0; + break; + case 330: // Froglok + MercSize = 5.0; + break; + case 522: // Drakkin + MercSize = 5.0; + break; + default: + MercSize = 6.0; + break; } return MercSize; @@ -192,19 +192,19 @@ float Merc::GetDefaultSize() { int Merc::CalcRecommendedLevelBonus(uint8 level, uint8 reclevel, int basestat) { - if( (reclevel > 0) && (level < reclevel) ) + if ((reclevel > 0) && (level < reclevel)) { int32 statmod = (level * 10000 / reclevel) * basestat; - if( statmod < 0 ) + if (statmod < 0) { statmod -= 5000; - return (statmod/10000); + return (statmod / 10000); } else { statmod += 5000; - return (statmod/10000); + return (statmod / 10000); } } @@ -222,32 +222,32 @@ void Merc::CalcItemBonuses(StatBonuses* newbon) { continue; if (equipment[i] == 0) continue; - const EQ::ItemData * itm = database.GetItem(equipment[i]); + const EQ::ItemData* itm = database.GetItem(equipment[i]); if (itm) AddItemBonuses(itm, newbon); } // Caps - if(newbon->HPRegen > CalcHPRegenCap()) + if (newbon->HPRegen > CalcHPRegenCap()) newbon->HPRegen = CalcHPRegenCap(); - if(newbon->ManaRegen > CalcManaRegenCap()) + if (newbon->ManaRegen > CalcManaRegenCap()) newbon->ManaRegen = CalcManaRegenCap(); - if(newbon->EnduranceRegen > CalcEnduranceRegenCap()) + if (newbon->EnduranceRegen > CalcEnduranceRegenCap()) newbon->EnduranceRegen = CalcEnduranceRegenCap(); SetAttackTimer(); } -void Merc::AddItemBonuses(const EQ::ItemData *item, StatBonuses* newbon) { +void Merc::AddItemBonuses(const EQ::ItemData* item, StatBonuses* newbon) { - if(GetLevel() < item->ReqLevel) + if (GetLevel() < item->ReqLevel) { return; } - if(GetLevel() >= item->RecLevel) + if (GetLevel() >= item->RecLevel) { newbon->AC += item->AC; newbon->HP += item->HP; @@ -302,214 +302,214 @@ void Merc::AddItemBonuses(const EQ::ItemData *item, StatBonuses* newbon) { int lvl = GetLevel(); int reclvl = item->RecLevel; - newbon->AC += CalcRecommendedLevelBonus( lvl, reclvl, item->AC ); - newbon->HP += CalcRecommendedLevelBonus( lvl, reclvl, item->HP ); - newbon->Mana += CalcRecommendedLevelBonus( lvl, reclvl, item->Mana ); - newbon->Endurance += CalcRecommendedLevelBonus( lvl, reclvl, item->Endur ); - newbon->STR += CalcRecommendedLevelBonus( lvl, reclvl, (item->AStr + item->HeroicStr) ); - newbon->STA += CalcRecommendedLevelBonus( lvl, reclvl, (item->ASta + item->HeroicSta) ); - newbon->DEX += CalcRecommendedLevelBonus( lvl, reclvl, (item->ADex + item->HeroicDex) ); - newbon->AGI += CalcRecommendedLevelBonus( lvl, reclvl, (item->AAgi + item->HeroicAgi) ); - newbon->INT += CalcRecommendedLevelBonus( lvl, reclvl, (item->AInt + item->HeroicInt) ); - newbon->WIS += CalcRecommendedLevelBonus( lvl, reclvl, (item->AWis + item->HeroicWis) ); - newbon->CHA += CalcRecommendedLevelBonus( lvl, reclvl, (item->ACha + item->HeroicCha) ); + newbon->AC += CalcRecommendedLevelBonus(lvl, reclvl, item->AC); + newbon->HP += CalcRecommendedLevelBonus(lvl, reclvl, item->HP); + newbon->Mana += CalcRecommendedLevelBonus(lvl, reclvl, item->Mana); + newbon->Endurance += CalcRecommendedLevelBonus(lvl, reclvl, item->Endur); + newbon->STR += CalcRecommendedLevelBonus(lvl, reclvl, (item->AStr + item->HeroicStr)); + newbon->STA += CalcRecommendedLevelBonus(lvl, reclvl, (item->ASta + item->HeroicSta)); + newbon->DEX += CalcRecommendedLevelBonus(lvl, reclvl, (item->ADex + item->HeroicDex)); + newbon->AGI += CalcRecommendedLevelBonus(lvl, reclvl, (item->AAgi + item->HeroicAgi)); + newbon->INT += CalcRecommendedLevelBonus(lvl, reclvl, (item->AInt + item->HeroicInt)); + newbon->WIS += CalcRecommendedLevelBonus(lvl, reclvl, (item->AWis + item->HeroicWis)); + newbon->CHA += CalcRecommendedLevelBonus(lvl, reclvl, (item->ACha + item->HeroicCha)); - newbon->MR += CalcRecommendedLevelBonus( lvl, reclvl, (item->MR + item->HeroicMR) ); - newbon->FR += CalcRecommendedLevelBonus( lvl, reclvl, (item->FR + item->HeroicFR) ); - newbon->CR += CalcRecommendedLevelBonus( lvl, reclvl, (item->CR + item->HeroicCR) ); - newbon->PR += CalcRecommendedLevelBonus( lvl, reclvl, (item->PR + item->HeroicPR) ); - newbon->DR += CalcRecommendedLevelBonus( lvl, reclvl, (item->DR + item->HeroicDR) ); - newbon->Corrup += CalcRecommendedLevelBonus( lvl, reclvl, (item->SVCorruption + item->HeroicSVCorrup) ); + newbon->MR += CalcRecommendedLevelBonus(lvl, reclvl, (item->MR + item->HeroicMR)); + newbon->FR += CalcRecommendedLevelBonus(lvl, reclvl, (item->FR + item->HeroicFR)); + newbon->CR += CalcRecommendedLevelBonus(lvl, reclvl, (item->CR + item->HeroicCR)); + newbon->PR += CalcRecommendedLevelBonus(lvl, reclvl, (item->PR + item->HeroicPR)); + newbon->DR += CalcRecommendedLevelBonus(lvl, reclvl, (item->DR + item->HeroicDR)); + newbon->Corrup += CalcRecommendedLevelBonus(lvl, reclvl, (item->SVCorruption + item->HeroicSVCorrup)); - newbon->STRCapMod += CalcRecommendedLevelBonus( lvl, reclvl, item->HeroicStr ); - newbon->STACapMod += CalcRecommendedLevelBonus( lvl, reclvl, item->HeroicSta ); - newbon->DEXCapMod += CalcRecommendedLevelBonus( lvl, reclvl, item->HeroicDex ); - newbon->AGICapMod += CalcRecommendedLevelBonus( lvl, reclvl, item->HeroicAgi ); - newbon->INTCapMod += CalcRecommendedLevelBonus( lvl, reclvl, item->HeroicInt ); - newbon->WISCapMod += CalcRecommendedLevelBonus( lvl, reclvl, item->HeroicWis ); - newbon->CHACapMod += CalcRecommendedLevelBonus( lvl, reclvl, item->HeroicCha ); - newbon->MRCapMod += CalcRecommendedLevelBonus( lvl, reclvl, item->HeroicMR ); - newbon->CRCapMod += CalcRecommendedLevelBonus( lvl, reclvl, item->HeroicFR ); - newbon->FRCapMod += CalcRecommendedLevelBonus( lvl, reclvl, item->HeroicCR ); - newbon->PRCapMod += CalcRecommendedLevelBonus( lvl, reclvl, item->HeroicPR ); - newbon->DRCapMod += CalcRecommendedLevelBonus( lvl, reclvl, item->HeroicDR ); - newbon->CorrupCapMod += CalcRecommendedLevelBonus( lvl, reclvl, item->HeroicSVCorrup ); + newbon->STRCapMod += CalcRecommendedLevelBonus(lvl, reclvl, item->HeroicStr); + newbon->STACapMod += CalcRecommendedLevelBonus(lvl, reclvl, item->HeroicSta); + newbon->DEXCapMod += CalcRecommendedLevelBonus(lvl, reclvl, item->HeroicDex); + newbon->AGICapMod += CalcRecommendedLevelBonus(lvl, reclvl, item->HeroicAgi); + newbon->INTCapMod += CalcRecommendedLevelBonus(lvl, reclvl, item->HeroicInt); + newbon->WISCapMod += CalcRecommendedLevelBonus(lvl, reclvl, item->HeroicWis); + newbon->CHACapMod += CalcRecommendedLevelBonus(lvl, reclvl, item->HeroicCha); + newbon->MRCapMod += CalcRecommendedLevelBonus(lvl, reclvl, item->HeroicMR); + newbon->CRCapMod += CalcRecommendedLevelBonus(lvl, reclvl, item->HeroicFR); + newbon->FRCapMod += CalcRecommendedLevelBonus(lvl, reclvl, item->HeroicCR); + newbon->PRCapMod += CalcRecommendedLevelBonus(lvl, reclvl, item->HeroicPR); + newbon->DRCapMod += CalcRecommendedLevelBonus(lvl, reclvl, item->HeroicDR); + newbon->CorrupCapMod += CalcRecommendedLevelBonus(lvl, reclvl, item->HeroicSVCorrup); - newbon->HeroicSTR += CalcRecommendedLevelBonus( lvl, reclvl, item->HeroicStr ); - newbon->HeroicSTA += CalcRecommendedLevelBonus( lvl, reclvl, item->HeroicSta ); - newbon->HeroicDEX += CalcRecommendedLevelBonus( lvl, reclvl, item->HeroicDex ); - newbon->HeroicAGI += CalcRecommendedLevelBonus( lvl, reclvl, item->HeroicAgi ); - newbon->HeroicINT += CalcRecommendedLevelBonus( lvl, reclvl, item->HeroicInt ); - newbon->HeroicWIS += CalcRecommendedLevelBonus( lvl, reclvl, item->HeroicWis ); - newbon->HeroicCHA += CalcRecommendedLevelBonus( lvl, reclvl, item->HeroicCha ); - newbon->HeroicMR += CalcRecommendedLevelBonus( lvl, reclvl, item->HeroicMR ); - newbon->HeroicFR += CalcRecommendedLevelBonus( lvl, reclvl, item->HeroicFR ); - newbon->HeroicCR += CalcRecommendedLevelBonus( lvl, reclvl, item->HeroicCR ); - newbon->HeroicPR += CalcRecommendedLevelBonus( lvl, reclvl, item->HeroicPR ); - newbon->HeroicDR += CalcRecommendedLevelBonus( lvl, reclvl, item->HeroicDR ); - newbon->HeroicCorrup += CalcRecommendedLevelBonus( lvl, reclvl, item->HeroicSVCorrup ); + newbon->HeroicSTR += CalcRecommendedLevelBonus(lvl, reclvl, item->HeroicStr); + newbon->HeroicSTA += CalcRecommendedLevelBonus(lvl, reclvl, item->HeroicSta); + newbon->HeroicDEX += CalcRecommendedLevelBonus(lvl, reclvl, item->HeroicDex); + newbon->HeroicAGI += CalcRecommendedLevelBonus(lvl, reclvl, item->HeroicAgi); + newbon->HeroicINT += CalcRecommendedLevelBonus(lvl, reclvl, item->HeroicInt); + newbon->HeroicWIS += CalcRecommendedLevelBonus(lvl, reclvl, item->HeroicWis); + newbon->HeroicCHA += CalcRecommendedLevelBonus(lvl, reclvl, item->HeroicCha); + newbon->HeroicMR += CalcRecommendedLevelBonus(lvl, reclvl, item->HeroicMR); + newbon->HeroicFR += CalcRecommendedLevelBonus(lvl, reclvl, item->HeroicFR); + newbon->HeroicCR += CalcRecommendedLevelBonus(lvl, reclvl, item->HeroicCR); + newbon->HeroicPR += CalcRecommendedLevelBonus(lvl, reclvl, item->HeroicPR); + newbon->HeroicDR += CalcRecommendedLevelBonus(lvl, reclvl, item->HeroicDR); + newbon->HeroicCorrup += CalcRecommendedLevelBonus(lvl, reclvl, item->HeroicSVCorrup); } //FatherNitwit: New style haste, shields, and regens - if(newbon->haste < (int16)item->Haste) { + if (newbon->haste < (int16)item->Haste) { newbon->haste = item->Haste; } - if(item->Regen > 0) + if (item->Regen > 0) newbon->HPRegen += item->Regen; - if(item->ManaRegen > 0) + if (item->ManaRegen > 0) newbon->ManaRegen += item->ManaRegen; - if(item->EnduranceRegen > 0) + if (item->EnduranceRegen > 0) newbon->EnduranceRegen += item->EnduranceRegen; - if(item->Attack > 0) { + if (item->Attack > 0) { unsigned int cap = RuleI(Character, ItemATKCap); cap += itembonuses.ItemATKCap + spellbonuses.ItemATKCap + aabonuses.ItemATKCap; - if((newbon->ATK + item->Attack) > cap) + if ((newbon->ATK + item->Attack) > cap) newbon->ATK = RuleI(Character, ItemATKCap); else newbon->ATK += item->Attack; } - if(item->DamageShield > 0) { - if((newbon->DamageShield + item->DamageShield) > RuleI(Character, ItemDamageShieldCap)) + if (item->DamageShield > 0) { + if ((newbon->DamageShield + item->DamageShield) > RuleI(Character, ItemDamageShieldCap)) newbon->DamageShield = RuleI(Character, ItemDamageShieldCap); else newbon->DamageShield += item->DamageShield; } - if(item->SpellShield > 0) { - if((newbon->SpellShield + item->SpellShield) > RuleI(Character, ItemSpellShieldingCap)) + if (item->SpellShield > 0) { + if ((newbon->SpellShield + item->SpellShield) > RuleI(Character, ItemSpellShieldingCap)) newbon->SpellShield = RuleI(Character, ItemSpellShieldingCap); else newbon->SpellShield += item->SpellShield; } - if(item->Shielding > 0) { - if((newbon->MeleeMitigation + item->Shielding) > RuleI(Character, ItemShieldingCap)) + if (item->Shielding > 0) { + if ((newbon->MeleeMitigation + item->Shielding) > RuleI(Character, ItemShieldingCap)) newbon->MeleeMitigation = RuleI(Character, ItemShieldingCap); else newbon->MeleeMitigation += item->Shielding; } - if(item->StunResist > 0) { - if((newbon->StunResist + item->StunResist) > RuleI(Character, ItemStunResistCap)) + if (item->StunResist > 0) { + if ((newbon->StunResist + item->StunResist) > RuleI(Character, ItemStunResistCap)) newbon->StunResist = RuleI(Character, ItemStunResistCap); else newbon->StunResist += item->StunResist; } - if(item->StrikeThrough > 0) { - if((newbon->StrikeThrough + item->StrikeThrough) > RuleI(Character, ItemStrikethroughCap)) + if (item->StrikeThrough > 0) { + if ((newbon->StrikeThrough + item->StrikeThrough) > RuleI(Character, ItemStrikethroughCap)) newbon->StrikeThrough = RuleI(Character, ItemStrikethroughCap); else newbon->StrikeThrough += item->StrikeThrough; } - if(item->Avoidance > 0) { - if((newbon->AvoidMeleeChance + item->Avoidance) > RuleI(Character, ItemAvoidanceCap)) + if (item->Avoidance > 0) { + if ((newbon->AvoidMeleeChance + item->Avoidance) > RuleI(Character, ItemAvoidanceCap)) newbon->AvoidMeleeChance = RuleI(Character, ItemAvoidanceCap); else newbon->AvoidMeleeChance += item->Avoidance; } - if(item->Accuracy > 0) { - if((newbon->HitChance + item->Accuracy) > RuleI(Character, ItemAccuracyCap)) + if (item->Accuracy > 0) { + if ((newbon->HitChance + item->Accuracy) > RuleI(Character, ItemAccuracyCap)) newbon->HitChance = RuleI(Character, ItemAccuracyCap); else newbon->HitChance += item->Accuracy; } - if(item->CombatEffects > 0) { - if((newbon->ProcChance + item->CombatEffects) > RuleI(Character, ItemCombatEffectsCap)) + if (item->CombatEffects > 0) { + if ((newbon->ProcChance + item->CombatEffects) > RuleI(Character, ItemCombatEffectsCap)) newbon->ProcChance = RuleI(Character, ItemCombatEffectsCap); else newbon->ProcChance += item->CombatEffects; } - if(item->DotShielding > 0) { - if((newbon->DoTShielding + item->DotShielding) > RuleI(Character, ItemDoTShieldingCap)) + if (item->DotShielding > 0) { + if ((newbon->DoTShielding + item->DotShielding) > RuleI(Character, ItemDoTShieldingCap)) newbon->DoTShielding = RuleI(Character, ItemDoTShieldingCap); else newbon->DoTShielding += item->DotShielding; } - if(item->HealAmt > 0) { - if((newbon->HealAmt + item->HealAmt) > RuleI(Character, ItemHealAmtCap)) + if (item->HealAmt > 0) { + if ((newbon->HealAmt + item->HealAmt) > RuleI(Character, ItemHealAmtCap)) newbon->HealAmt = RuleI(Character, ItemHealAmtCap); else newbon->HealAmt += item->HealAmt; } - if(item->SpellDmg > 0) { - if((newbon->SpellDmg + item->SpellDmg) > RuleI(Character, ItemSpellDmgCap)) + if (item->SpellDmg > 0) { + if ((newbon->SpellDmg + item->SpellDmg) > RuleI(Character, ItemSpellDmgCap)) newbon->SpellDmg = RuleI(Character, ItemSpellDmgCap); else newbon->SpellDmg += item->SpellDmg; } - if(item->Clairvoyance > 0) { - if((newbon->Clairvoyance + item->Clairvoyance) > RuleI(Character, ItemClairvoyanceCap)) + if (item->Clairvoyance > 0) { + if ((newbon->Clairvoyance + item->Clairvoyance) > RuleI(Character, ItemClairvoyanceCap)) newbon->Clairvoyance = RuleI(Character, ItemClairvoyanceCap); else newbon->Clairvoyance += item->Clairvoyance; } - if(item->DSMitigation > 0) { - if((newbon->DSMitigation + item->DSMitigation) > RuleI(Character, ItemDSMitigationCap)) + if (item->DSMitigation > 0) { + if ((newbon->DSMitigation + item->DSMitigation) > RuleI(Character, ItemDSMitigationCap)) newbon->DSMitigation = RuleI(Character, ItemDSMitigationCap); else newbon->DSMitigation += item->DSMitigation; } - if (item->Worn.Effect>0 && (item->Worn.Type == EQ::item::ItemEffectWorn)) { // latent effects + if (item->Worn.Effect > 0 && (item->Worn.Type == EQ::item::ItemEffectWorn)) { // latent effects ApplySpellsBonuses(item->Worn.Effect, item->Worn.Level, newbon, 0, item->Worn.Type); } - if (item->Focus.Effect>0 && (item->Focus.Type == EQ::item::ItemEffectFocus)) { // focus effects + if (item->Focus.Effect > 0 && (item->Focus.Type == EQ::item::ItemEffectFocus)) { // focus effects ApplySpellsBonuses(item->Focus.Effect, item->Focus.Level, newbon, 0); } - switch(item->BardType) + switch (item->BardType) { case 51: /* All (e.g. Singing Short Sword) */ - { - if(item->BardValue > newbon->singingMod) - newbon->singingMod = item->BardValue; - if(item->BardValue > newbon->brassMod) - newbon->brassMod = item->BardValue; - if(item->BardValue > newbon->stringedMod) - newbon->stringedMod = item->BardValue; - if(item->BardValue > newbon->percussionMod) - newbon->percussionMod = item->BardValue; - if(item->BardValue > newbon->windMod) - newbon->windMod = item->BardValue; - break; - } + { + if (item->BardValue > newbon->singingMod) + newbon->singingMod = item->BardValue; + if (item->BardValue > newbon->brassMod) + newbon->brassMod = item->BardValue; + if (item->BardValue > newbon->stringedMod) + newbon->stringedMod = item->BardValue; + if (item->BardValue > newbon->percussionMod) + newbon->percussionMod = item->BardValue; + if (item->BardValue > newbon->windMod) + newbon->windMod = item->BardValue; + break; + } case 50: /* Singing */ - { - if(item->BardValue > newbon->singingMod) - newbon->singingMod = item->BardValue; - break; - } + { + if (item->BardValue > newbon->singingMod) + newbon->singingMod = item->BardValue; + break; + } case 23: /* Wind */ - { - if(item->BardValue > newbon->windMod) - newbon->windMod = item->BardValue; - break; - } + { + if (item->BardValue > newbon->windMod) + newbon->windMod = item->BardValue; + break; + } case 24: /* stringed */ - { - if(item->BardValue > newbon->stringedMod) - newbon->stringedMod = item->BardValue; - break; - } + { + if (item->BardValue > newbon->stringedMod) + newbon->stringedMod = item->BardValue; + break; + } case 25: /* brass */ - { - if(item->BardValue > newbon->brassMod) - newbon->brassMod = item->BardValue; - break; - } + { + if (item->BardValue > newbon->brassMod) + newbon->brassMod = item->BardValue; + break; + } case 26: /* Percussion */ - { - if(item->BardValue > newbon->percussionMod) - newbon->percussionMod = item->BardValue; - break; - } + { + if (item->BardValue > newbon->percussionMod) + newbon->percussionMod = item->BardValue; + break; + } } - if (item->SkillModValue != 0 && item->SkillModType <= EQ::skills::HIGHEST_SKILL){ + if (item->SkillModValue != 0 && item->SkillModType <= EQ::skills::HIGHEST_SKILL) { if ((item->SkillModValue > 0 && newbon->skillmod[item->SkillModType] < item->SkillModValue) || (item->SkillModValue < 0 && newbon->skillmod[item->SkillModType] > item->SkillModValue)) { @@ -564,7 +564,7 @@ void Merc::AddItemBonuses(const EQ::ItemData *item, StatBonuses* newbon) { } if (item->ExtraDmgSkill != 0 && item->ExtraDmgSkill <= EQ::skills::HIGHEST_SKILL) { - if((newbon->SkillDamageAmount[item->ExtraDmgSkill] + item->ExtraDmgAmt) > RuleI(Character, ItemExtraDmgCap)) + if ((newbon->SkillDamageAmount[item->ExtraDmgSkill] + item->ExtraDmgAmt) > RuleI(Character, ItemExtraDmgCap)) newbon->SkillDamageAmount[item->ExtraDmgSkill] = RuleI(Character, ItemExtraDmgCap); else newbon->SkillDamageAmount[item->ExtraDmgSkill] += item->ExtraDmgAmt; @@ -573,12 +573,12 @@ void Merc::AddItemBonuses(const EQ::ItemData *item, StatBonuses* newbon) { int Merc::GroupLeadershipAAHealthEnhancement() { - Group *g = GetGroup(); + Group* g = GetGroup(); - if(!g || (g->GroupCount() < 3)) + if (!g || (g->GroupCount() < 3)) return 0; - switch(g->GetLeadershipAA(groupAAHealthEnhancement)) + switch (g->GetLeadershipAA(groupAAHealthEnhancement)) { case 0: return 0; @@ -595,12 +595,12 @@ int Merc::GroupLeadershipAAHealthEnhancement() int Merc::GroupLeadershipAAManaEnhancement() { - Group *g = GetGroup(); + Group* g = GetGroup(); - if(!g || (g->GroupCount() < 3)) + if (!g || (g->GroupCount() < 3)) return 0; - switch(g->GetLeadershipAA(groupAAManaEnhancement)) + switch (g->GetLeadershipAA(groupAAManaEnhancement)) { case 0: return 0; @@ -617,12 +617,12 @@ int Merc::GroupLeadershipAAManaEnhancement() int Merc::GroupLeadershipAAHealthRegeneration() { - Group *g = GetGroup(); + Group* g = GetGroup(); - if(!g || (g->GroupCount() < 3)) + if (!g || (g->GroupCount() < 3)) return 0; - switch(g->GetLeadershipAA(groupAAHealthRegeneration)) + switch (g->GetLeadershipAA(groupAAHealthRegeneration)) { case 0: return 0; @@ -639,12 +639,12 @@ int Merc::GroupLeadershipAAHealthRegeneration() int Merc::GroupLeadershipAAOffenseEnhancement() { - Group *g = GetGroup(); + Group* g = GetGroup(); - if(!g || (g->GroupCount() < 3)) + if (!g || (g->GroupCount() < 3)) return 0; - switch(g->GetLeadershipAA(groupAAOffenseEnhancement)) + switch (g->GetLeadershipAA(groupAAOffenseEnhancement)) { case 0: return 0; @@ -669,7 +669,7 @@ int32 Merc::CalcSTR() { STR = val + mod; - if(STR < 1) + if (STR < 1) STR = 1; return(STR); @@ -682,7 +682,7 @@ int32 Merc::CalcSTA() { STA = val + mod; - if(STA < 1) + if (STA < 1) STA = 1; return(STA); @@ -696,7 +696,7 @@ int32 Merc::CalcAGI() { AGI = val + mod; - if(AGI < 1) + if (AGI < 1) AGI = 1; return(AGI); @@ -709,7 +709,7 @@ int32 Merc::CalcDEX() { DEX = val + mod; - if(DEX < 1) + if (DEX < 1) DEX = 1; return(DEX); @@ -722,7 +722,7 @@ int32 Merc::CalcINT() { INT = val + mod; - if(INT < 1) + if (INT < 1) INT = 1; return(INT); @@ -735,7 +735,7 @@ int32 Merc::CalcWIS() { WIS = val + mod; - if(WIS < 1) + if (WIS < 1) WIS = 1; return(WIS); @@ -748,7 +748,7 @@ int32 Merc::CalcCHA() { CHA = val + mod; - if(CHA < 1) + if (CHA < 1) CHA = 1; return(CHA); @@ -761,7 +761,7 @@ int32 Merc::CalcMR() { MR = _baseMR + itembonuses.MR + spellbonuses.MR + aabonuses.MR; - if(MR < 1) + if (MR < 1) MR = 1; return(MR); @@ -771,7 +771,7 @@ int32 Merc::CalcFR() { FR = _baseFR + itembonuses.FR + spellbonuses.FR + aabonuses.FR; - if(FR < 1) + if (FR < 1) FR = 1; return(FR); @@ -781,7 +781,7 @@ int32 Merc::CalcDR() { DR = _baseDR + itembonuses.DR + spellbonuses.DR + aabonuses.DR; - if(DR < 1) + if (DR < 1) DR = 1; return(DR); @@ -791,7 +791,7 @@ int32 Merc::CalcPR() { PR = _basePR + itembonuses.PR + spellbonuses.PR + aabonuses.PR; - if(PR < 1) + if (PR < 1) PR = 1; return(PR); @@ -801,7 +801,7 @@ int32 Merc::CalcCR() { CR = _baseCR + itembonuses.CR + spellbonuses.CR + aabonuses.CR; - if(CR < 1) + if (CR < 1) CR = 1; return(CR); @@ -835,7 +835,7 @@ int32 Merc::CalcHPRegen() { int32 Merc::CalcHPRegenCap() { - int cap = RuleI(Character, ItemHealthRegenCap) + itembonuses.HeroicSTA/25; + int cap = RuleI(Character, ItemHealthRegenCap) + itembonuses.HeroicSTA / 25; cap += aabonuses.ItemHPRegenCap + spellbonuses.ItemHPRegenCap + itembonuses.ItemHPRegenCap; @@ -863,7 +863,7 @@ int32 Merc::CalcMaxHP() { current_hp = max_hp; int hp_perc_cap = spellbonuses.HPPercCap[SBIndex::RESOURCE_PERCENT_CAP]; - if(hp_perc_cap) { + if (hp_perc_cap) { int curHP_cap = (max_hp * hp_perc_cap) / 100; if (current_hp > curHP_cap || (spellbonuses.HPPercCap[SBIndex::RESOURCE_AMOUNT_CAP] && current_hp > spellbonuses.HPPercCap[SBIndex::RESOURCE_AMOUNT_CAP])) current_hp = curHP_cap; @@ -879,22 +879,22 @@ int32 Merc::CalcBaseHP() int32 Merc::CalcMaxMana() { - switch(GetCasterClass()) + switch (GetCasterClass()) { case 'I': case 'W': { max_mana = (CalcBaseMana() + itembonuses.Mana + spellbonuses.Mana + GroupLeadershipAAManaEnhancement()); break; - } + } case 'N': { max_mana = 0; break; - } + } default: { LogDebug("Invalid Class [{}] in CalcMaxMana", GetCasterClass()); max_mana = 0; break; - } + } } if (max_mana < 0) { max_mana = 0; @@ -905,9 +905,9 @@ int32 Merc::CalcMaxMana() } int mana_perc_cap = spellbonuses.ManaPercCap[SBIndex::RESOURCE_PERCENT_CAP]; - if(mana_perc_cap) { + if (mana_perc_cap) { int curMana_cap = (max_mana * mana_perc_cap) / 100; - if (current_mana > curMana_cap || (spellbonuses.ManaPercCap[SBIndex::RESOURCE_AMOUNT_CAP] && current_mana > spellbonuses.ManaPercCap[SBIndex::RESOURCE_AMOUNT_CAP])) + if (current_mana > curMana_cap || (spellbonuses.ManaPercCap[SBIndex::RESOURCE_AMOUNT_CAP] && current_mana > spellbonuses.ManaPercCap[SBIndex::RESOURCE_AMOUNT_CAP])) current_mana = curMana_cap; } @@ -958,9 +958,9 @@ int32 Merc::CalcManaRegen() regen = mana_regen + spellbonuses.ManaRegen + itembonuses.ManaRegen; } - if(GetCasterClass() == 'I') + if (GetCasterClass() == 'I') regen += (itembonuses.HeroicINT / 25); - else if(GetCasterClass() == 'W') + else if (GetCasterClass() == 'W') regen += (itembonuses.HeroicWIS / 25); else regen = 0; @@ -974,7 +974,7 @@ int32 Merc::CalcManaRegen() int32 Merc::CalcManaRegenCap() { int32 cap = RuleI(Character, ItemManaRegenCap) + aabonuses.ItemManaRegenCap; - switch(GetCasterClass()) + switch (GetCasterClass()) { case 'I': cap += (itembonuses.HeroicINT / 25); @@ -1000,7 +1000,7 @@ void Merc::CalcMaxEndurance() } int end_perc_cap = spellbonuses.EndPercCap[SBIndex::RESOURCE_PERCENT_CAP]; - if(end_perc_cap) { + if (end_perc_cap) { int curEnd_cap = (max_end * end_perc_cap) / 100; if (cur_end > curEnd_cap || (spellbonuses.EndPercCap[SBIndex::RESOURCE_AMOUNT_CAP] && cur_end > spellbonuses.EndPercCap[SBIndex::RESOURCE_AMOUNT_CAP])) cur_end = curEnd_cap; @@ -1047,11 +1047,11 @@ int32 Merc::CalcBaseEndurance() } else { - Stats = GetSTR()+GetSTA()+GetDEX()+GetAGI(); + Stats = GetSTR() + GetSTA() + GetDEX() + GetAGI(); int LevelBase = GetLevel() * 15; int at_most_800 = Stats; - if(at_most_800 > 800) + if (at_most_800 > 800) at_most_800 = 800; int Bonus400to800 = 0; @@ -1059,14 +1059,14 @@ int32 Merc::CalcBaseEndurance() int Bonus800plus = 0; int HalfBonus800plus = 0; - int BonusUpto800 = int( at_most_800 / 4 ) ; - if(Stats > 400) { - Bonus400to800 = int( (at_most_800 - 400) / 4 ); - HalfBonus400to800 = int( std::max( ( at_most_800 - 400 ), 0 ) / 8 ); + int BonusUpto800 = int(at_most_800 / 4); + if (Stats > 400) { + Bonus400to800 = int((at_most_800 - 400) / 4); + HalfBonus400to800 = int(std::max((at_most_800 - 400), 0) / 8); - if(Stats > 800) { - Bonus800plus = int( (Stats - 800) / 8 ) * 2; - HalfBonus800plus = int( (Stats - 800) / 16 ); + if (Stats > 800) { + Bonus800plus = int((Stats - 800) / 8) * 2; + HalfBonus800plus = int((Stats - 800) / 16); } } int bonus_sum = BonusUpto800 + Bonus400to800 + HalfBonus400to800 + Bonus800plus + HalfBonus800plus; @@ -1074,7 +1074,7 @@ int32 Merc::CalcBaseEndurance() base_end = LevelBase; //take all of the sums from above, then multiply by level*0.075 - base_end += ( bonus_sum * 3 * GetLevel() ) / 40; + base_end += (bonus_sum * 3 * GetLevel()) / 40; } return base_end; } @@ -1087,7 +1087,7 @@ int32 Merc::CalcEnduranceRegen() { } int32 Merc::CalcEnduranceRegenCap() { - int cap = (RuleI(Character, ItemEnduranceRegenCap) + itembonuses.HeroicSTR/25 + itembonuses.HeroicDEX/25 + itembonuses.HeroicAGI/25 + itembonuses.HeroicSTA/25); + int cap = (RuleI(Character, ItemEnduranceRegenCap) + itembonuses.HeroicSTR / 25 + itembonuses.HeroicDEX / 25 + itembonuses.HeroicAGI / 25 + itembonuses.HeroicSTA / 25); return (cap * RuleI(Character, EnduranceRegenMultiplier) / 100); } @@ -1095,9 +1095,9 @@ int32 Merc::CalcEnduranceRegenCap() { void Merc::SetEndurance(int32 newEnd) { /*Endurance can't be less than 0 or greater than max*/ - if(newEnd < 0) + if (newEnd < 0) newEnd = 0; - else if(newEnd > GetMaxEndurance()){ + else if (newEnd > GetMaxEndurance()) { newEnd = GetMaxEndurance(); } @@ -1118,24 +1118,25 @@ void Merc::DoEnduranceUpkeep() { for (buffs_i = 0; buffs_i < buff_count; buffs_i++) { if (buffs[buffs_i].spellid != SPELL_UNKNOWN) { int upkeep = spells[buffs[buffs_i].spellid].endurance_upkeep; - if(upkeep > 0) { + if (upkeep > 0) { has_effect = true; - if(cost_redux > 0) { - if(upkeep <= cost_redux) + if (cost_redux > 0) { + if (upkeep <= cost_redux) continue; //reduced to 0 upkeep -= cost_redux; } - if((upkeep+upkeep_sum) > GetEndurance()) { + if ((upkeep + upkeep_sum) > GetEndurance()) { //they do not have enough to keep this one going. BuffFadeBySlot(buffs_i); - } else { + } + else { upkeep_sum += upkeep; } } } } - if(upkeep_sum != 0) + if (upkeep_sum != 0) SetEndurance(GetEndurance() - upkeep_sum); if (!has_effect) @@ -1148,22 +1149,22 @@ void Merc::CalcRestState() { // The bot must have been out of combat for RuleI(Character, RestRegenTimeToActivate) seconds, // must be sitting down, and must not have any detrimental spells affecting them. // - if(!RuleB(Character, RestRegenEnabled)) + if (!RuleB(Character, RestRegenEnabled)) return; RestRegenHP = RestRegenMana = RestRegenEndurance = 0; - if(IsEngaged() || !IsSitting()) + if (IsEngaged() || !IsSitting()) return; - if(!rest_timer.Check(false)) + if (!rest_timer.Check(false)) return; uint32 buff_count = GetMaxTotalSlots(); for (unsigned int j = 0; j < buff_count; j++) { - if(buffs[j].spellid != SPELL_UNKNOWN) { - if(IsDetrimentalSpell(buffs[j].spellid) && (buffs[j].ticsremaining > 0)) - if(!DetrimentalSpellAllowsRest(buffs[j].spellid)) + if (buffs[j].spellid != SPELL_UNKNOWN) { + if (IsDetrimentalSpell(buffs[j].spellid) && (buffs[j].ticsremaining > 0)) + if (!DetrimentalSpellAllowsRest(buffs[j].spellid)) return; } } @@ -1189,7 +1190,7 @@ uint16 Merc::MaxSkill(EQ::skills::SkillType skillid, uint16 class_, uint16 level } void Merc::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho) { - if(ns) { + if (ns) { Mob::FillSpawnStruct(ns, ForWho); ns->spawn.afk = 0; @@ -1240,7 +1241,7 @@ void Merc::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho) { bool Merc::Process() { - if(IsStunned() && stunned_timer.Check()) + if (IsStunned() && stunned_timer.Check()) Mob::UnStun(); if (GetDepop()) @@ -1250,12 +1251,12 @@ bool Merc::Process() return false; } - if(!GetMercOwner()) { + if (!GetMercOwner()) { //p_depop = true; //this was causing a crash - removed merc from entity list, but not group //return false; //merc can live after client dies, not sure how long } - if(IsSuspended()) + if (IsSuspended()) { return false; } @@ -1266,14 +1267,14 @@ bool Merc::Process() SpellProcess(); - if(tic_timer.Check()) + if (tic_timer.Check()) { //6 seconds, or whatever the rule is set to has passed, send this position to everyone to avoid ghosting - if(!IsMoving() && !IsEngaged()) + if (!IsMoving() && !IsEngaged()) { SentPositionPacket(0.0f, 0.0f, 0.0f, 0.0f, 0); - if(IsSitting()) { - if(!rest_timer.Enabled()) { + if (IsSitting()) { + if (!rest_timer.Enabled()) { rest_timer.Start(RuleI(Character, RestRegenTimeToActivate) * 1000); } } @@ -1283,17 +1284,17 @@ bool Merc::Process() CalcRestState(); - if(GetHP() < GetMaxHP()) + if (GetHP() < GetMaxHP()) SetHP(GetHP() + CalcHPRegen() + RestRegenHP); - if(GetMana() < GetMaxMana()) + if (GetMana() < GetMaxMana()) SetMana(GetMana() + CalcManaRegen() + RestRegenMana); - if(GetEndurance() < GetMaxEndurance()) + if (GetEndurance() < GetMaxEndurance()) SetEndurance(GetEndurance() + CalcEnduranceRegen() + RestRegenEndurance); } - if(confidence_timer.Check()) { + if (confidence_timer.Check()) { _check_confidence = true; } @@ -1301,7 +1302,7 @@ bool Merc::Process() SendHPUpdate(); } - if (endupkeep_timer.Check() && GetHP() > 0){ + if (endupkeep_timer.Check() && GetHP() > 0) { DoEnduranceUpkeep(); } @@ -1314,10 +1315,10 @@ bool Merc::Process() return true; } -bool Merc::IsMercCasterCombatRange(Mob *target) { +bool Merc::IsMercCasterCombatRange(Mob* target) { bool result = false; - if(target) { + if (target) { float range = MercAISpellRange; range *= range; @@ -1327,7 +1328,7 @@ bool Merc::IsMercCasterCombatRange(Mob *target) { float targetDistance = DistanceSquaredNoZ(m_Position, target->GetPosition()); - if(targetDistance > range) + if (targetDistance > range) result = false; else result = true; @@ -1337,22 +1338,22 @@ bool Merc::IsMercCasterCombatRange(Mob *target) { } void Merc::AI_Process() { - if(!IsAIControlled()) + if (!IsAIControlled()) return; - if(IsCasting()) + if (IsCasting()) return; // A merc wont start its AI if not grouped - if(!HasGroup()) { + if (!HasGroup()) { return; } Mob* MercOwner = GetOwner(); - if(GetAppearance() == eaDead) + if (GetAppearance() == eaDead) { - if(!MercOwner) + if (!MercOwner) { Depop(); } @@ -1360,7 +1361,7 @@ void Merc::AI_Process() { } // The merc needs an owner - if(!MercOwner) { + if (!MercOwner) { //SetTarget(0); //SetOwnerID(0); // TODO: Need to wait and try casting rez if merc is a healer with a dead owner @@ -1382,58 +1383,58 @@ void Merc::AI_Process() { } */ - if(check_target_timer.Check()) { + if (check_target_timer.Check()) { CheckHateList(); } - if(IsEngaged()) + if (IsEngaged()) { - if(rest_timer.Enabled()) + if (rest_timer.Enabled()) rest_timer.Disable(); - if(IsRooted()) + if (IsRooted()) SetTarget(hate_list.GetClosestEntOnHateList(this)); else FindTarget(); - if(!GetTarget()) + if (!GetTarget()) return; - if(HasPet()) + if (HasPet()) GetPet()->SetTarget(GetTarget()); - if(!IsSitting()) + if (!IsSitting()) FaceTarget(GetTarget()); - if(DivineAura()) + if (DivineAura()) return; int hateCount = entity_list.GetHatedCount(this, nullptr, false); - if(GetHatedCount() < hateCount) { + if (GetHatedCount() < hateCount) { SetHatedCount(hateCount); - if(!CheckConfidence()) { - if(!confidence_timer.Enabled()) { + if (!CheckConfidence()) { + if (!confidence_timer.Enabled()) { confidence_timer.Start(10000); } } } //Check specific conditions for merc to lose confidence and flee (or regain confidence once fleeing) - if(_check_confidence) { + if (_check_confidence) { //not already running - if(!_lost_confidence) { + if (!_lost_confidence) { //and fail confidence check - if(!CheckConfidence()) { + if (!CheckConfidence()) { _lost_confidence = true; //move to bottom of hate lists? //Iterate though hatelist // SetHate(other, hate, damage) - if(RuleB(Combat, EnableFearPathing)) { + if (RuleB(Combat, EnableFearPathing)) { CalculateNewFearpoint(); - if(currently_fleeing) { + if (currently_fleeing) { return; } } @@ -1443,27 +1444,27 @@ void Merc::AI_Process() { } } else { //are fleeing due to lost confidence - if(CheckConfidence()) { //passed test - regain confidence + if (CheckConfidence()) { //passed test - regain confidence _lost_confidence = false; } } //they are in flee mode - if(_lost_confidence) + if (_lost_confidence) return; } // Let's check if we have a los with our target. // If we don't, our hate_list is wiped. // Else, it was causing the merc to aggro behind wall etc... causing massive trains. - if(GetTarget()->IsMezzed() || !IsAttackAllowed(GetTarget())) { + if (GetTarget()->IsMezzed() || !IsAttackAllowed(GetTarget())) { WipeHateList(); - if(IsMoving()) { + if (IsMoving()) { SetHeading(0); SetRunAnimSpeed(0); - if(moved) { + if (moved) { moved = false; StopNavigation(); } @@ -1485,33 +1486,33 @@ void Merc::AI_Process() { float meleeDistance = GetMaxMeleeRangeToTarget(GetTarget()); - if(GetClass() == SHADOWKNIGHT || GetClass() == PALADIN || GetClass() == WARRIOR) { + if (GetClass() == SHADOWKNIGHT || GetClass() == PALADIN || GetClass() == WARRIOR) { meleeDistance = meleeDistance * .30; } else { meleeDistance *= (float)zone->random.Real(.50, .85); } - if(IsMercCaster() && GetLevel() > 12) { - if(IsMercCasterCombatRange(GetTarget())) + if (IsMercCaster() && GetLevel() > 12) { + if (IsMercCasterCombatRange(GetTarget())) atCombatRange = true; } - else if(DistanceSquared(m_Position, GetTarget()->GetPosition()) <= meleeDistance) { + else if (DistanceSquared(m_Position, GetTarget()->GetPosition()) <= meleeDistance) { atCombatRange = true; } - if(atCombatRange) + if (atCombatRange) { - if(IsMoving()) + if (IsMoving()) { SetHeading(CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY())); SetRunAnimSpeed(0); - if(moved) { + if (moved) { StopNavigation(); } } - if(AI_movement_timer->Check()) { + if (AI_movement_timer->Check()) { if (!IsMoving()) { if (GetClass() == ROGUE) { if (HasTargetReflection() && !GetTarget()->IsFeared() && !GetTarget()->IsStunned()) { @@ -1574,11 +1575,11 @@ void Merc::AI_Process() { // SendPosition(); } - if(!IsMercCaster() && GetTarget() && !IsStunned() && !IsMezzed() && (GetAppearance() != eaDead)) + if (!IsMercCaster() && GetTarget() && !IsStunned() && !IsMezzed() && (GetAppearance() != eaDead)) { // we can't fight if we don't have a target, are stun/mezzed or dead.. // Stop attacking if the target is enraged - if(IsEngaged() && !BehindMob(GetTarget(), GetX(), GetY()) && GetTarget()->IsEnraged()) + if (IsEngaged() && !BehindMob(GetTarget(), GetX(), GetY()) && GetTarget()->IsEnraged()) return; //TODO: Implement Stances. /*if(GetBotStance() == BotStancePassive) @@ -1588,25 +1589,25 @@ void Merc::AI_Process() { DoClassAttacks(GetTarget()); //try main hand first - if(attack_timer.Check()) + if (attack_timer.Check()) { Attack(GetTarget(), EQ::invslot::slotPrimary); bool tripleSuccess = false; - if(GetOwner() && GetTarget() && CanThisClassDoubleAttack()) + if (GetOwner() && GetTarget() && CanThisClassDoubleAttack()) { - if(GetOwner()) { + if (GetOwner()) { Attack(GetTarget(), EQ::invslot::slotPrimary, true); } - if(GetOwner() && GetTarget() && GetSpecialAbility(SPECATK_TRIPLE)) { + if (GetOwner() && GetTarget() && GetSpecialAbility(SPECATK_TRIPLE)) { tripleSuccess = true; Attack(GetTarget(), EQ::invslot::slotPrimary, true); } //quad attack, does this belong here?? - if(GetOwner() && GetTarget() && GetSpecialAbility(SPECATK_QUAD)) { + if (GetOwner() && GetTarget() && GetSpecialAbility(SPECATK_QUAD)) { Attack(GetTarget(), EQ::invslot::slotPrimary, true); } } @@ -1616,7 +1617,7 @@ void Merc::AI_Process() { if (GetTarget() && flurrychance) { - if(zone->random.Roll(flurrychance)) + if (zone->random.Roll(flurrychance)) { MessageString(Chat::NPCFlurry, YOU_FLURRY); Attack(GetTarget(), EQ::invslot::slotPrimary, false); @@ -1627,7 +1628,7 @@ void Merc::AI_Process() { int16 ExtraAttackChanceBonus = spellbonuses.ExtraAttackChance[SBIndex::EXTRA_ATTACK_CHANCE] + itembonuses.ExtraAttackChance[SBIndex::EXTRA_ATTACK_CHANCE] + aabonuses.ExtraAttackChance[SBIndex::EXTRA_ATTACK_CHANCE]; if (GetTarget() && ExtraAttackChanceBonus) { - if(zone->random.Roll(ExtraAttackChanceBonus)) + if (zone->random.Roll(ExtraAttackChanceBonus)) { Attack(GetTarget(), EQ::invslot::slotPrimary, false); } @@ -1647,7 +1648,7 @@ void Merc::AI_Process() { //} //now off hand - if(GetTarget() && attack_dw_timer.Check() && CanThisClassDualWield()) + if (GetTarget() && attack_dw_timer.Check() && CanThisClassDualWield()) { int weapontype = 0; // No weapon type bool bIsFist = true; @@ -1660,15 +1661,15 @@ void Merc::AI_Process() { int16 Ambidexterity = aabonuses.Ambidexterity + spellbonuses.Ambidexterity + itembonuses.Ambidexterity; DualWieldProbability = (GetSkill(EQ::skills::SkillDualWield) + GetLevel() + Ambidexterity) / 400.0f; // 78.0 max int16 DWBonus = spellbonuses.DualWieldChance + itembonuses.DualWieldChance; - DualWieldProbability += DualWieldProbability*float(DWBonus)/ 100.0f; + DualWieldProbability += DualWieldProbability * float(DWBonus) / 100.0f; // Max 78% of DW if (zone->random.Roll(DualWieldProbability)) { Attack(GetTarget(), EQ::invslot::slotSecondary); // Single attack with offhand - if(CanThisClassDoubleAttack()) { - if(GetTarget() && GetTarget()->GetHP() > -10) + if (CanThisClassDoubleAttack()) { + if (GetTarget() && GetTarget()->GetHP() > -10) Attack(GetTarget(), EQ::invslot::slotSecondary); // Single attack with offhand } } @@ -1678,7 +1679,7 @@ void Merc::AI_Process() { } else { - if(GetTarget()->IsFeared() && !spellend_timer.Enabled()) { + if (GetTarget()->IsFeared() && !spellend_timer.Enabled()) { // This is a mob that is fleeing either because it has been feared or is low on hitpoints //TODO: Implement Stances. //if(GetStance() != MercStancePassive) @@ -1687,7 +1688,7 @@ void Merc::AI_Process() { if (AI_movement_timer->Check()) { - if(!IsRooted()) { + if (!IsRooted()) { LogAI("Pursuing [{}] while engaged", GetTarget()->GetCleanName()); RunTo(GetTarget()->GetX(), GetTarget()->GetY(), GetTarget()->GetZ()); return; @@ -1700,16 +1701,16 @@ void Merc::AI_Process() { } } // end not in combat range - if(!IsMoving() && !spellend_timer.Enabled()) + if (!IsMoving() && !spellend_timer.Enabled()) { //TODO: Implement Stances. //if(GetStance() == MercStancePassive) // return; - if(AI_EngagedCastCheck()) { + if (AI_EngagedCastCheck()) { MercMeditate(false); } - else if(GetArchetype() == ARCHETYPE_CASTER) + else if (GetArchetype() == ARCHETYPE_CASTER) MercMeditate(true); } } @@ -1724,22 +1725,22 @@ void Merc::AI_Process() { if (m_PlayerState & static_cast(PlayerState::Aggressive)) SendRemovePlayerState(PlayerState::Aggressive); - if(!check_target_timer.Enabled()) + if (!check_target_timer.Enabled()) check_target_timer.Start(2000, false); - if(!IsMoving() && AI_think_timer->Check() && !spellend_timer.Enabled()) + if (!IsMoving() && AI_think_timer->Check() && !spellend_timer.Enabled()) { //TODO: Implement passive stances. //if(GetStance() != MercStancePassive) { - if(!AI_IdleCastCheck() && !IsCasting()) { - if(GetArchetype() == ARCHETYPE_CASTER) { + if (!AI_IdleCastCheck() && !IsCasting()) { + if (GetArchetype() == ARCHETYPE_CASTER) { MercMeditate(true); } } } - if(AI_movement_timer->Check()) { - if(GetFollowID()) { + if (AI_movement_timer->Check()) { + if (GetFollowID()) { Mob* follow = entity_list.GetMob(GetFollowID()); if (follow) { @@ -1781,7 +1782,8 @@ void Merc::AI_Start(int32 iMoveDelay) { if (merc_spells.empty()) { AIautocastspell_timer->SetTimer(1000); AIautocastspell_timer->Disable(); - } else { + } + else { AIautocastspell_timer->SetTimer(750); AIautocastspell_timer->Start(RandomTimer(0, 2000), false); } @@ -1811,7 +1813,7 @@ bool Merc::AI_EngagedCastCheck() { int8 mercClass = GetClass(); - switch(mercClass) + switch (mercClass) { case TANK: if (!AICastSpell(GetChanceToCastBySpellType(SpellType_Nuke), SpellType_Nuke)) { @@ -1821,8 +1823,8 @@ bool Merc::AI_EngagedCastCheck() { } break; case HEALER: - if(!entity_list.Merc_AICheckCloseBeneficialSpells(this, GetChanceToCastBySpellType(SpellType_Heal), MercAISpellRange, SpellType_Heal)) { - if(!entity_list.Merc_AICheckCloseBeneficialSpells(this, GetChanceToCastBySpellType(SpellType_Buff), MercAISpellRange, SpellType_Buff)) { + if (!entity_list.Merc_AICheckCloseBeneficialSpells(this, GetChanceToCastBySpellType(SpellType_Heal), MercAISpellRange, SpellType_Heal)) { + if (!entity_list.Merc_AICheckCloseBeneficialSpells(this, GetChanceToCastBySpellType(SpellType_Buff), MercAISpellRange, SpellType_Buff)) { failedToCast = true; } } @@ -1845,11 +1847,11 @@ bool Merc::AI_EngagedCastCheck() { break; } - if(!AIautocastspell_timer->Enabled()) { + if (!AIautocastspell_timer->Enabled()) { AIautocastspell_timer->Start(RandomTimer(100, 250), false); } - if(!failedToCast) + if (!failedToCast) result = true; } @@ -1869,16 +1871,16 @@ bool Merc::AI_IdleCastCheck() { //Ok, IdleCastCheck depends of class. int8 mercClass = GetClass(); - switch(mercClass) + switch (mercClass) { case TANK: failedToCast = true; break; case HEALER: - if(!entity_list.Merc_AICheckCloseBeneficialSpells(this, 100, MercAISpellRange, SpellType_Cure)) { - if(!entity_list.Merc_AICheckCloseBeneficialSpells(this, 100, MercAISpellRange, SpellType_Heal)) { - if(!entity_list.Merc_AICheckCloseBeneficialSpells(this, 100, MercAISpellRange, SpellType_Resurrect)) { - if(!entity_list.Merc_AICheckCloseBeneficialSpells(this, 100, MercAISpellRange, SpellType_Buff)) { + if (!entity_list.Merc_AICheckCloseBeneficialSpells(this, 100, MercAISpellRange, SpellType_Cure)) { + if (!entity_list.Merc_AICheckCloseBeneficialSpells(this, 100, MercAISpellRange, SpellType_Heal)) { + if (!entity_list.Merc_AICheckCloseBeneficialSpells(this, 100, MercAISpellRange, SpellType_Resurrect)) { + if (!entity_list.Merc_AICheckCloseBeneficialSpells(this, 100, MercAISpellRange, SpellType_Buff)) { failedToCast = true; } } @@ -1887,7 +1889,7 @@ bool Merc::AI_IdleCastCheck() { result = true; break; case MELEEDPS: - if(!entity_list.Merc_AICheckCloseBeneficialSpells(this, 100, MercAISpellRange, SpellType_Buff)) { + if (!entity_list.Merc_AICheckCloseBeneficialSpells(this, 100, MercAISpellRange, SpellType_Buff)) { failedToCast = true; } break; @@ -1896,10 +1898,10 @@ bool Merc::AI_IdleCastCheck() { break; } - if(!AIautocastspell_timer->Enabled()) + if (!AIautocastspell_timer->Enabled()) AIautocastspell_timer->Start(RandomTimer(500, 1000), false); - if(!failedToCast) + if (!failedToCast) result = true; } @@ -1908,7 +1910,7 @@ bool Merc::AI_IdleCastCheck() { bool EntityList::Merc_AICheckCloseBeneficialSpells(Merc* caster, uint8 iChance, float iRange, uint32 iSpellTypes) { - if((iSpellTypes & SPELL_TYPES_DETRIMENTAL) != 0) { + if ((iSpellTypes & SPELL_TYPES_DETRIMENTAL) != 0) { //according to live, you can buff and heal through walls... //now with PCs, this only applies if you can TARGET the target, but // according to Rogean, Live NPCs will just cast through walls/floors, no problem.. @@ -1918,10 +1920,10 @@ bool EntityList::Merc_AICheckCloseBeneficialSpells(Merc* caster, uint8 iChance, return(false); } - if(!caster) + if (!caster) return false; - if(!caster->AI_HasSpells()) + if (!caster->AI_HasSpells()) return false; if (iChance < 100) { @@ -1932,27 +1934,27 @@ bool EntityList::Merc_AICheckCloseBeneficialSpells(Merc* caster, uint8 iChance, int8 mercCasterClass = caster->GetClass(); - if(caster->HasGroup()) { - if( mercCasterClass == HEALER) { - if( iSpellTypes == SpellType_Heal ) { - if(caster->AICastSpell(100, SpellType_Heal)) + if (caster->HasGroup()) { + if (mercCasterClass == HEALER) { + if (iSpellTypes == SpellType_Heal) { + if (caster->AICastSpell(100, SpellType_Heal)) return true; } - if( iSpellTypes == SpellType_Cure ) { - if(caster->AICastSpell(100, SpellType_Cure)) + if (iSpellTypes == SpellType_Cure) { + if (caster->AICastSpell(100, SpellType_Cure)) return true; } - if( iSpellTypes == SpellType_Resurrect ) { - if(caster->AICastSpell(100, SpellType_Resurrect)) + if (iSpellTypes == SpellType_Resurrect) { + if (caster->AICastSpell(100, SpellType_Resurrect)) return true; } } //Ok for the buffs.. - if( iSpellTypes == SpellType_Buff) { - if(caster->AICastSpell(100, SpellType_Buff)) + if (iSpellTypes == SpellType_Buff) { + if (caster->AICastSpell(100, SpellType_Buff)) return true; } } @@ -1979,15 +1981,16 @@ bool Merc::AIDoSpellCast(uint16 spellid, Mob* tar, int32 mana_cost, uint32* oDon if (mercSpell.type & SpellType_Escape) { dist2 = 0; - } else + } + else dist2 = DistanceSquared(m_Position, tar->GetPosition()); - if (((((spells[spellid].target_type==ST_GroupTeleport && mercSpell.type==SpellType_Heal) - || spells[spellid].target_type==ST_AECaster - || spells[spellid].target_type==ST_Group - || spells[spellid].target_type==ST_AEBard) - && dist2 <= spells[spellid].aoe_range*spells[spellid].aoe_range) - || dist2 <= GetActSpellRange(spellid, spells[spellid].range)*GetActSpellRange(spellid, spells[spellid].range)) && (mana_cost <= GetMana() || GetMana() == GetMaxMana())) + if (((((spells[spellid].target_type == ST_GroupTeleport && mercSpell.type == SpellType_Heal) + || spells[spellid].target_type == ST_AECaster + || spells[spellid].target_type == ST_Group + || spells[spellid].target_type == ST_AEBard) + && dist2 <= spells[spellid].aoe_range * spells[spellid].aoe_range) + || dist2 <= GetActSpellRange(spellid, spells[spellid].range) * GetActSpellRange(spellid, spells[spellid].range)) && (mana_cost <= GetMana() || GetMana() == GetMaxMana())) { SetRunAnimSpeed(0); SentPositionPacket(0.0f, 0.0f, 0.0f, 0.0f, 0); @@ -1995,19 +1998,19 @@ bool Merc::AIDoSpellCast(uint16 spellid, Mob* tar, int32 mana_cost, uint32* oDon result = CastSpell(spellid, tar->GetID(), EQ::spells::CastingSlot::Gem2, -1, mana_cost, oDontDoAgainBefore, -1, -1, 0, 0); - if(IsCasting() && IsSitting()) + if (IsCasting() && IsSitting()) Stand(); } // if the spell wasn't casted, then take back any extra mana that was given to the bot to cast that spell - if(!result) { + if (!result) { SetMana(hasMana); extraMana = false; } else { //handle spell recast and recast timers SetSpellTimeCanCast(mercSpell.spellid, spells[spellid].recast_time); - if(spells[spellid].timer_id > 0) { + if (spells[spellid].timer_id > 0) { SetSpellRecastTimer(spells[spellid].timer_id, spellid, spells[spellid].recast_time); } } @@ -2017,7 +2020,7 @@ bool Merc::AIDoSpellCast(uint16 spellid, Mob* tar, int32 mana_cost, uint32* oDon bool Merc::AICastSpell(int8 iChance, uint32 iSpellTypes) { - if(!AI_HasSpells()) + if (!AI_HasSpells()) return false; if (RuleB(Mercs, IsMercsElixirEnabled)) { @@ -2025,7 +2028,7 @@ bool Merc::AICastSpell(int8 iChance, uint32 iSpellTypes) { } if (iChance < 100) { - if (zone->random.Int(0, 100) > iChance){ + if (zone->random.Int(0, 100) > iChance) { return false; } } @@ -2037,10 +2040,10 @@ bool Merc::AICastSpell(int8 iChance, uint32 iSpellTypes) { bool castedSpell = false; bool isDiscipline = false; - if(HasGroup()) { - Group *g = GetGroup(); + if (HasGroup()) { + Group* g = GetGroup(); - if(g) { + if (g) { MercSpell selectedMercSpell; selectedMercSpell.spellid = 0; selectedMercSpell.stance = 0; @@ -2049,7 +2052,7 @@ bool Merc::AICastSpell(int8 iChance, uint32 iSpellTypes) { selectedMercSpell.proc_chance = 0; selectedMercSpell.time_cancast = 0; - switch(mercClass) + switch (mercClass) { case TANK: case MELEEDPS: @@ -2061,401 +2064,401 @@ bool Merc::AICastSpell(int8 iChance, uint32 iSpellTypes) { } switch (iSpellTypes) { - case SpellType_Heal: { - Mob* tar = nullptr; - int8 numToHeal = g->GetNumberNeedingHealedInGroup(IsEngaged() ? 75 : 95, true); - int8 checkHPR = IsEngaged() ? 95 : 99; - int8 checkPetHPR = IsEngaged() ? 95 : 99; + case SpellType_Heal: { + Mob* tar = nullptr; + int8 numToHeal = g->GetNumberNeedingHealedInGroup(IsEngaged() ? 75 : 95, true); + int8 checkHPR = IsEngaged() ? 95 : 99; + int8 checkPetHPR = IsEngaged() ? 95 : 99; - //todo: check stance to determine healing spell selection + //todo: check stance to determine healing spell selection - for(int i = 0; i < MAX_GROUP_MEMBERS; i++) { - if(g->members[i] && !g->members[i]->qglobal) { - int8 hpr = (int8)g->members[i]->GetHPRatio(); + for (int i = 0; i < MAX_GROUP_MEMBERS; i++) { + if (g->members[i] && !g->members[i]->qglobal) { + int8 hpr = (int8)g->members[i]->GetHPRatio(); - if(g->members[i]->HasPet() && g->members[i]->GetPet()->GetHPRatio() < checkHPR) { - if(!tar || ((g->members[i]->GetPet()->GetHPRatio() + 25) < tar->GetHPRatio())) { - tar = g->members[i]->GetPet(); - checkPetHPR = g->members[i]->GetPet()->GetHPRatio() + 25; - } - } + if (g->members[i]->HasPet() && g->members[i]->GetPet()->GetHPRatio() < checkHPR) { + if (!tar || ((g->members[i]->GetPet()->GetHPRatio() + 25) < tar->GetHPRatio())) { + tar = g->members[i]->GetPet(); + checkPetHPR = g->members[i]->GetPet()->GetHPRatio() + 25; + } + } - if(hpr > checkHPR) { - continue; - } + if (hpr > checkHPR) { + continue; + } - if(IsEngaged() && (g->members[i]->GetClass() == NECROMANCER && hpr >= 50) - || (g->members[i]->GetClass() == SHAMAN && hpr >= 80)) { - //allow necros to lifetap & shaman to canni without wasting mana - continue; - } + if (IsEngaged() && (g->members[i]->GetClass() == NECROMANCER && hpr >= 50) + || (g->members[i]->GetClass() == SHAMAN && hpr >= 80)) { + //allow necros to lifetap & shaman to canni without wasting mana + continue; + } - if(hpr < checkHPR && g->members[i] == GetMercOwner()) { - if(!tar || (hpr < tar->GetHPRatio() || (tar->IsPet() && hpr < checkPetHPR))) - tar = g->members[i]; //check owner first - } - else if(hpr < checkHPR && g->HasRole(g->members[i], RoleTank)){ - if(!tar || (hpr < tar->GetHPRatio() || (tar->IsPet() && hpr < checkPetHPR))) - tar = g->members[i]; - } - else if( hpr < checkHPR && (!tar || (hpr < tar->GetHPRatio() || (tar->IsPet() && hpr < checkPetHPR)))) { - tar = g->members[i]; - } - } + if (hpr < checkHPR && g->members[i] == GetMercOwner()) { + if (!tar || (hpr < tar->GetHPRatio() || (tar->IsPet() && hpr < checkPetHPR))) + tar = g->members[i]; //check owner first + } + else if (hpr < checkHPR && g->HasRole(g->members[i], RoleTank)) { + if (!tar || (hpr < tar->GetHPRatio() || (tar->IsPet() && hpr < checkPetHPR))) + tar = g->members[i]; + } + else if (hpr < checkHPR && (!tar || (hpr < tar->GetHPRatio() || (tar->IsPet() && hpr < checkPetHPR)))) { + tar = g->members[i]; + } + } + } + + if (numToHeal > 2) { + selectedMercSpell = GetBestMercSpellForGroupHeal(this); + } + + if (tar && selectedMercSpell.spellid == 0) { + if (tar->GetHPRatio() < 15) { + //check for very fast heals first (casting time < 1 s) + selectedMercSpell = GetBestMercSpellForVeryFastHeal(this); + + //check for fast heals next (casting time < 2 s) + if (selectedMercSpell.spellid == 0) { + selectedMercSpell = GetBestMercSpellForFastHeal(this); + } + + //get regular heal + if (selectedMercSpell.spellid == 0) { + selectedMercSpell = GetBestMercSpellForRegularSingleTargetHeal(this); + } + } + else if (tar->GetHPRatio() < 35) { + //check for fast heals next (casting time < 2 s) + selectedMercSpell = GetBestMercSpellForFastHeal(this); + + //get regular heal + if (selectedMercSpell.spellid == 0) { + selectedMercSpell = GetBestMercSpellForRegularSingleTargetHeal(this); + } + } + else if (tar->GetHPRatio() < 80) { + selectedMercSpell = GetBestMercSpellForPercentageHeal(this); + + //get regular heal + if (selectedMercSpell.spellid == 0) { + selectedMercSpell = GetBestMercSpellForRegularSingleTargetHeal(this); + } + } + else { + //check for heal over time. if not present, try it first + if (!tar->FindType(SE_HealOverTime)) { + selectedMercSpell = GetBestMercSpellForHealOverTime(this); + + //get regular heal + if (selectedMercSpell.spellid == 0) { + selectedMercSpell = GetBestMercSpellForRegularSingleTargetHeal(this); + } + } + } + } + + if (selectedMercSpell.spellid > 0) { + castedSpell = AIDoSpellCast(selectedMercSpell.spellid, tar, -1); + } + + if (castedSpell) { + if (tar && tar != this) { // [tar] was implicitly valid at this point..this change is to catch any bad logic + //we don't need spam of bots healing themselves + MercGroupSay(this, "Casting %s on %s.", spells[selectedMercSpell.spellid].name, tar->GetCleanName()); + } + } + + break; + } + case SpellType_Root: { + break; + } + case SpellType_Buff: { + + if (GetClass() == HEALER && GetManaRatio() < 50) { + return false; //mercs buff when Mana > 50% + } + + std::list buffSpellList = GetMercSpellsBySpellType(this, SpellType_Buff); + + for (auto itr = buffSpellList.begin(); + itr != buffSpellList.end(); ++itr) { + MercSpell selectedMercSpell = *itr; + + if (!((spells[selectedMercSpell.spellid].target_type == ST_Target || spells[selectedMercSpell.spellid].target_type == ST_Pet || + spells[selectedMercSpell.spellid].target_type == ST_Group || spells[selectedMercSpell.spellid].target_type == ST_GroupTeleport || + spells[selectedMercSpell.spellid].target_type == ST_Self))) { + continue; + } + + if (spells[selectedMercSpell.spellid].target_type == ST_Self) { + if (!this->IsImmuneToSpell(selectedMercSpell.spellid, this) + && (this->CanBuffStack(selectedMercSpell.spellid, mercLevel, true) >= 0)) { + + if (this->GetArchetype() == ARCHETYPE_MELEE && IsEffectInSpell(selectedMercSpell.spellid, SE_IncreaseSpellHaste)) { + continue; + } + + uint32 TempDontBuffMeBeforeTime = this->DontBuffMeBefore(); + + if (selectedMercSpell.spellid > 0) { + if (isDiscipline) { + castedSpell = UseDiscipline(selectedMercSpell.spellid, GetID()); } + else { + castedSpell = AIDoSpellCast(selectedMercSpell.spellid, this, -1, &TempDontBuffMeBeforeTime); - if(numToHeal > 2) { - selectedMercSpell = GetBestMercSpellForGroupHeal(this); + if (TempDontBuffMeBeforeTime != this->DontBuffMeBefore()) + this->SetDontBuffMeBefore(TempDontBuffMeBeforeTime); } + } + } + } + else { + for (int i = 0; i < MAX_GROUP_MEMBERS; i++) { + if (g->members[i]) { + Mob* tar = g->members[i]; - if(tar && selectedMercSpell.spellid == 0) { - if(tar->GetHPRatio() < 15) { - //check for very fast heals first (casting time < 1 s) - selectedMercSpell = GetBestMercSpellForVeryFastHeal(this); + if (!tar->IsImmuneToSpell(selectedMercSpell.spellid, this) + && (tar->CanBuffStack(selectedMercSpell.spellid, mercLevel, true) >= 0)) { - //check for fast heals next (casting time < 2 s) - if(selectedMercSpell.spellid == 0) { - selectedMercSpell = GetBestMercSpellForFastHeal(this); - } - - //get regular heal - if(selectedMercSpell.spellid == 0) { - selectedMercSpell = GetBestMercSpellForRegularSingleTargetHeal(this); - } - } - else if (tar->GetHPRatio() < 35) { - //check for fast heals next (casting time < 2 s) - selectedMercSpell = GetBestMercSpellForFastHeal(this); - - //get regular heal - if(selectedMercSpell.spellid == 0) { - selectedMercSpell = GetBestMercSpellForRegularSingleTargetHeal(this); - } - } - else if (tar->GetHPRatio() < 80) { - selectedMercSpell = GetBestMercSpellForPercentageHeal(this); - - //get regular heal - if(selectedMercSpell.spellid == 0) { - selectedMercSpell = GetBestMercSpellForRegularSingleTargetHeal(this); - } - } - else { - //check for heal over time. if not present, try it first - if(!tar->FindType(SE_HealOverTime)) { - selectedMercSpell = GetBestMercSpellForHealOverTime(this); - - //get regular heal - if(selectedMercSpell.spellid == 0) { - selectedMercSpell = GetBestMercSpellForRegularSingleTargetHeal(this); - } - } - } - } - - if(selectedMercSpell.spellid > 0) { - castedSpell = AIDoSpellCast(selectedMercSpell.spellid, tar, -1); - } - - if(castedSpell) { - if(tar && tar != this) { // [tar] was implicitly valid at this point..this change is to catch any bad logic - //we don't need spam of bots healing themselves - MercGroupSay(this, "Casting %s on %s.", spells[selectedMercSpell.spellid].name, tar->GetCleanName()); - } - } - - break; - } - case SpellType_Root: { - break; - } - case SpellType_Buff: { - - if(GetClass() == HEALER && GetManaRatio() < 50) { - return false; //mercs buff when Mana > 50% - } - - std::list buffSpellList = GetMercSpellsBySpellType(this, SpellType_Buff); - - for (auto itr = buffSpellList.begin(); - itr != buffSpellList.end(); ++itr) { - MercSpell selectedMercSpell = *itr; - - if(!((spells[selectedMercSpell.spellid].target_type == ST_Target || spells[selectedMercSpell.spellid].target_type == ST_Pet || - spells[selectedMercSpell.spellid].target_type == ST_Group || spells[selectedMercSpell.spellid].target_type == ST_GroupTeleport || - spells[selectedMercSpell.spellid].target_type == ST_Self))) { - continue; - } - - if(spells[selectedMercSpell.spellid].target_type == ST_Self) { - if( !this->IsImmuneToSpell(selectedMercSpell.spellid, this) - && (this->CanBuffStack(selectedMercSpell.spellid, mercLevel, true) >= 0)) { - - if( this->GetArchetype() == ARCHETYPE_MELEE && IsEffectInSpell(selectedMercSpell.spellid, SE_IncreaseSpellHaste)) { - continue; - } - - uint32 TempDontBuffMeBeforeTime = this->DontBuffMeBefore(); - - if(selectedMercSpell.spellid > 0) { - if(isDiscipline) { - castedSpell = UseDiscipline(selectedMercSpell.spellid, GetID()); - } - else { - castedSpell = AIDoSpellCast(selectedMercSpell.spellid, this, -1, &TempDontBuffMeBeforeTime); - - if(TempDontBuffMeBeforeTime != this->DontBuffMeBefore()) - this->SetDontBuffMeBefore(TempDontBuffMeBeforeTime); - } - } - } - } - else { - for( int i = 0; i < MAX_GROUP_MEMBERS; i++) { - if(g->members[i]) { - Mob* tar = g->members[i]; - - if( !tar->IsImmuneToSpell(selectedMercSpell.spellid, this) - && (tar->CanBuffStack(selectedMercSpell.spellid, mercLevel, true) >= 0)) { - - if( tar->GetArchetype() == ARCHETYPE_MELEE && IsEffectInSpell(selectedMercSpell.spellid, SE_IncreaseSpellHaste)) { - continue; - } - - uint32 TempDontBuffMeBeforeTime = tar->DontBuffMeBefore(); - - if(selectedMercSpell.spellid > 0) { - if(isDiscipline) { - castedSpell = UseDiscipline(selectedMercSpell.spellid, tar->GetID()); - } - else { - castedSpell = AIDoSpellCast(selectedMercSpell.spellid, tar, -1, &TempDontBuffMeBeforeTime); - - if(TempDontBuffMeBeforeTime != tar->DontBuffMeBefore()) - tar->SetDontBuffMeBefore(TempDontBuffMeBeforeTime); - } - } - } - - if(!castedSpell && tar->GetPet()) { - - //don't cast group spells on pets - if(IsGroupSpell(selectedMercSpell.spellid) - || spells[selectedMercSpell.spellid].target_type == ST_Group - || spells[selectedMercSpell.spellid].target_type == ST_GroupTeleport ) { - continue; - } - - if(!tar->GetPet()->IsImmuneToSpell(selectedMercSpell.spellid, this) - && (tar->GetPet()->CanBuffStack(selectedMercSpell.spellid, mercLevel, true) >= 0)) { - - uint32 TempDontBuffMeBeforeTime = tar->DontBuffMeBefore(); - - if(selectedMercSpell.spellid > 0) { - if(isDiscipline) { - castedSpell = UseDiscipline(selectedMercSpell.spellid, tar->GetPet()->GetID()); - } - else { - castedSpell = AIDoSpellCast(selectedMercSpell.spellid, tar->GetPet(), -1, &TempDontBuffMeBeforeTime); - - if(TempDontBuffMeBeforeTime != tar->GetPet()->DontBuffMeBefore()) - tar->GetPet()->SetDontBuffMeBefore(TempDontBuffMeBeforeTime); - } - } - } - } - } - } - } - } - break; - } - case SpellType_Nuke: { - switch(mercClass) - { - case TANK: - //check for taunt - if(CheckAETaunt()) { - //get AE taunt - selectedMercSpell = GetBestMercSpellForAETaunt(this); - Log(Logs::General, Logs::Mercenaries, "%s AE Taunting.", GetName()); - } - - if(selectedMercSpell.spellid == 0 && CheckTaunt()) { - //get taunt - selectedMercSpell = GetBestMercSpellForTaunt(this); - } - - //get hate disc - if(selectedMercSpell.spellid == 0) { - selectedMercSpell = GetBestMercSpellForHate(this); - } - - break; - case HEALER: - break; - case MELEEDPS: - break; - case CASTERDPS: - Mob* tar = GetTarget(); - - selectedMercSpell = GetBestMercSpellForAENuke(this, tar); - - if(selectedMercSpell.spellid == 0 && !tar->GetSpecialAbility(UNSTUNABLE) && !tar->IsStunned()) { - uint8 stunChance = 15; - if(zone->random.Roll(stunChance)) { - selectedMercSpell = GetBestMercSpellForStun(this); - } - } - - if(selectedMercSpell.spellid == 0) { - uint8 lureChance = 25; - if(zone->random.Roll(lureChance)) { - selectedMercSpell = GetBestMercSpellForNukeByTargetResists(this, tar); - } - } - - if(selectedMercSpell.spellid == 0) { - selectedMercSpell = GetBestMercSpellForNuke(this); - } - - break; - } - - if(selectedMercSpell.spellid > 0) { - if(isDiscipline) { - castedSpell = UseDiscipline(selectedMercSpell.spellid, GetTarget()->GetID()); - } - else { - castedSpell = AIDoSpellCast(selectedMercSpell.spellid, GetTarget(), -1); - } - } - - break; - } - case SpellType_InCombatBuff: { - std::list buffSpellList = GetMercSpellsBySpellType(this, SpellType_InCombatBuff); - Mob* tar = this; - - for (auto itr = buffSpellList.begin(); - itr != buffSpellList.end(); ++itr) { - MercSpell selectedMercSpell = *itr; - - if(!(spells[selectedMercSpell.spellid].target_type == ST_Self)) { + if (tar->GetArchetype() == ARCHETYPE_MELEE && IsEffectInSpell(selectedMercSpell.spellid, SE_IncreaseSpellHaste)) { continue; } - if (spells[selectedMercSpell.spellid].skill == EQ::skills::SkillBackstab && spells[selectedMercSpell.spellid].target_type == ST_Self) { - if(!hidden) { - continue; - } - } + uint32 TempDontBuffMeBeforeTime = tar->DontBuffMeBefore(); - if( !tar->IsImmuneToSpell(selectedMercSpell.spellid, this) - && (tar->CanBuffStack(selectedMercSpell.spellid, mercLevel, true) >= 0)) { - - uint32 TempDontBuffMeBeforeTime = tar->DontBuffMeBefore(); - - if(selectedMercSpell.spellid > 0) { - if(isDiscipline) { - castedSpell = UseDiscipline(selectedMercSpell.spellid, GetID()); - } - else { - castedSpell = AIDoSpellCast(selectedMercSpell.spellid, this, -1); - } - } - } - } - break; - } - case SpellType_Cure: { - Mob* tar = nullptr; - for(int i = 0; i < MAX_GROUP_MEMBERS; i++) { - if(g->members[i] && !g->members[i]->qglobal) { - if(GetNeedsCured(g->members[i]) && (g->members[i]->DontCureMeBefore() < Timer::GetCurrentTime())) { - tar = g->members[i]; - } - } - } - - if(tar && !(g->GetNumberNeedingHealedInGroup(IsEngaged() ? 25 : 40, false) > 0) && !(g->GetNumberNeedingHealedInGroup(IsEngaged() ? 40 : 60, false) > 2)) - { - selectedMercSpell = GetBestMercSpellForCure(this, tar); - - if(selectedMercSpell.spellid == 0) - break; - - uint32 TempDontCureMeBeforeTime = tar->DontCureMeBefore(); - - castedSpell = AIDoSpellCast(selectedMercSpell.spellid, tar, spells[selectedMercSpell.spellid].mana, &TempDontCureMeBeforeTime); - - if(castedSpell) { - if(IsGroupSpell(selectedMercSpell.spellid)){ - - if(this->HasGroup()) { - Group *g = this->GetGroup(); - - if(g) { - for( int i = 0; imembers[i] && !g->members[i]->qglobal) { - if(TempDontCureMeBeforeTime != tar->DontCureMeBefore()) - g->members[i]->SetDontCureMeBefore(Timer::GetCurrentTime() + 4000); - } - } - } - } - } - else { - if(TempDontCureMeBeforeTime != tar->DontCureMeBefore()) - tar->SetDontCureMeBefore(Timer::GetCurrentTime() + 4000); - } - } - } - break; - } - case SpellType_Resurrect: { - Corpse *corpse = GetGroupMemberCorpse(); - - if(corpse) { - selectedMercSpell = GetFirstMercSpellBySpellType(this, SpellType_Resurrect); - - if(selectedMercSpell.spellid == 0) - break; - - uint32 TempDontRootMeBeforeTime = corpse->DontRootMeBefore(); - - castedSpell = AIDoSpellCast(selectedMercSpell.spellid, corpse, spells[selectedMercSpell.spellid].mana, &TempDontRootMeBeforeTime); - - //CastSpell(selectedMercSpell.spellid, corpse->GetID(), 1, -1, -1, &TempDontRootMeBeforeTime); - corpse->SetDontRootMeBefore(TempDontRootMeBeforeTime); - } - - break; - } - case SpellType_Escape: { - Mob* tar = GetTarget(); - uint8 hpr = (uint8)GetHPRatio(); - bool mayGetAggro = false; - - if(tar && (mercClass == CASTERDPS) || (mercClass == MELEEDPS)) { - mayGetAggro = HasOrMayGetAggro(); //classes have hate reducing spells - - if (mayGetAggro) { - selectedMercSpell = GetFirstMercSpellBySpellType(this, SpellType_Escape); - - if(selectedMercSpell.spellid == 0) - break; - - if(isDiscipline) { + if (selectedMercSpell.spellid > 0) { + if (isDiscipline) { castedSpell = UseDiscipline(selectedMercSpell.spellid, tar->GetID()); } else { - castedSpell = AIDoSpellCast(selectedMercSpell.spellid, tar, -1); + castedSpell = AIDoSpellCast(selectedMercSpell.spellid, tar, -1, &TempDontBuffMeBeforeTime); + + if (TempDontBuffMeBeforeTime != tar->DontBuffMeBefore()) + tar->SetDontBuffMeBefore(TempDontBuffMeBeforeTime); } } } - break; - } + + if (!castedSpell && tar->GetPet()) { + + //don't cast group spells on pets + if (IsGroupSpell(selectedMercSpell.spellid) + || spells[selectedMercSpell.spellid].target_type == ST_Group + || spells[selectedMercSpell.spellid].target_type == ST_GroupTeleport) { + continue; + } + + if (!tar->GetPet()->IsImmuneToSpell(selectedMercSpell.spellid, this) + && (tar->GetPet()->CanBuffStack(selectedMercSpell.spellid, mercLevel, true) >= 0)) { + + uint32 TempDontBuffMeBeforeTime = tar->DontBuffMeBefore(); + + if (selectedMercSpell.spellid > 0) { + if (isDiscipline) { + castedSpell = UseDiscipline(selectedMercSpell.spellid, tar->GetPet()->GetID()); + } + else { + castedSpell = AIDoSpellCast(selectedMercSpell.spellid, tar->GetPet(), -1, &TempDontBuffMeBeforeTime); + + if (TempDontBuffMeBeforeTime != tar->GetPet()->DontBuffMeBefore()) + tar->GetPet()->SetDontBuffMeBefore(TempDontBuffMeBeforeTime); + } + } + } + } + } + } + } + } + break; + } + case SpellType_Nuke: { + switch (mercClass) + { + case TANK: + //check for taunt + if (CheckAETaunt()) { + //get AE taunt + selectedMercSpell = GetBestMercSpellForAETaunt(this); + Log(Logs::General, Logs::Mercenaries, "%s AE Taunting.", GetName()); + } + + if (selectedMercSpell.spellid == 0 && CheckTaunt()) { + //get taunt + selectedMercSpell = GetBestMercSpellForTaunt(this); + } + + //get hate disc + if (selectedMercSpell.spellid == 0) { + selectedMercSpell = GetBestMercSpellForHate(this); + } + + break; + case HEALER: + break; + case MELEEDPS: + break; + case CASTERDPS: + Mob* tar = GetTarget(); + + selectedMercSpell = GetBestMercSpellForAENuke(this, tar); + + if (selectedMercSpell.spellid == 0 && !tar->GetSpecialAbility(UNSTUNABLE) && !tar->IsStunned()) { + uint8 stunChance = 15; + if (zone->random.Roll(stunChance)) { + selectedMercSpell = GetBestMercSpellForStun(this); + } + } + + if (selectedMercSpell.spellid == 0) { + uint8 lureChance = 25; + if (zone->random.Roll(lureChance)) { + selectedMercSpell = GetBestMercSpellForNukeByTargetResists(this, tar); + } + } + + if (selectedMercSpell.spellid == 0) { + selectedMercSpell = GetBestMercSpellForNuke(this); + } + + break; + } + + if (selectedMercSpell.spellid > 0) { + if (isDiscipline) { + castedSpell = UseDiscipline(selectedMercSpell.spellid, GetTarget()->GetID()); + } + else { + castedSpell = AIDoSpellCast(selectedMercSpell.spellid, GetTarget(), -1); + } + } + + break; + } + case SpellType_InCombatBuff: { + std::list buffSpellList = GetMercSpellsBySpellType(this, SpellType_InCombatBuff); + Mob* tar = this; + + for (auto itr = buffSpellList.begin(); + itr != buffSpellList.end(); ++itr) { + MercSpell selectedMercSpell = *itr; + + if (!(spells[selectedMercSpell.spellid].target_type == ST_Self)) { + continue; + } + + if (spells[selectedMercSpell.spellid].skill == EQ::skills::SkillBackstab && spells[selectedMercSpell.spellid].target_type == ST_Self) { + if (!hidden) { + continue; + } + } + + if (!tar->IsImmuneToSpell(selectedMercSpell.spellid, this) + && (tar->CanBuffStack(selectedMercSpell.spellid, mercLevel, true) >= 0)) { + + uint32 TempDontBuffMeBeforeTime = tar->DontBuffMeBefore(); + + if (selectedMercSpell.spellid > 0) { + if (isDiscipline) { + castedSpell = UseDiscipline(selectedMercSpell.spellid, GetID()); + } + else { + castedSpell = AIDoSpellCast(selectedMercSpell.spellid, this, -1); + } + } + } + } + break; + } + case SpellType_Cure: { + Mob* tar = nullptr; + for (int i = 0; i < MAX_GROUP_MEMBERS; i++) { + if (g->members[i] && !g->members[i]->qglobal) { + if (GetNeedsCured(g->members[i]) && (g->members[i]->DontCureMeBefore() < Timer::GetCurrentTime())) { + tar = g->members[i]; + } + } + } + + if (tar && !(g->GetNumberNeedingHealedInGroup(IsEngaged() ? 25 : 40, false) > 0) && !(g->GetNumberNeedingHealedInGroup(IsEngaged() ? 40 : 60, false) > 2)) + { + selectedMercSpell = GetBestMercSpellForCure(this, tar); + + if (selectedMercSpell.spellid == 0) + break; + + uint32 TempDontCureMeBeforeTime = tar->DontCureMeBefore(); + + castedSpell = AIDoSpellCast(selectedMercSpell.spellid, tar, spells[selectedMercSpell.spellid].mana, &TempDontCureMeBeforeTime); + + if (castedSpell) { + if (IsGroupSpell(selectedMercSpell.spellid)) { + + if (this->HasGroup()) { + Group* g = this->GetGroup(); + + if (g) { + for (int i = 0; i < MAX_GROUP_MEMBERS; i++) { + if (g->members[i] && !g->members[i]->qglobal) { + if (TempDontCureMeBeforeTime != tar->DontCureMeBefore()) + g->members[i]->SetDontCureMeBefore(Timer::GetCurrentTime() + 4000); + } + } + } + } + } + else { + if (TempDontCureMeBeforeTime != tar->DontCureMeBefore()) + tar->SetDontCureMeBefore(Timer::GetCurrentTime() + 4000); + } + } + } + break; + } + case SpellType_Resurrect: { + Corpse* corpse = GetGroupMemberCorpse(); + + if (corpse) { + selectedMercSpell = GetFirstMercSpellBySpellType(this, SpellType_Resurrect); + + if (selectedMercSpell.spellid == 0) + break; + + uint32 TempDontRootMeBeforeTime = corpse->DontRootMeBefore(); + + castedSpell = AIDoSpellCast(selectedMercSpell.spellid, corpse, spells[selectedMercSpell.spellid].mana, &TempDontRootMeBeforeTime); + + //CastSpell(selectedMercSpell.spellid, corpse->GetID(), 1, -1, -1, &TempDontRootMeBeforeTime); + corpse->SetDontRootMeBefore(TempDontRootMeBeforeTime); + } + + break; + } + case SpellType_Escape: { + Mob* tar = GetTarget(); + uint8 hpr = (uint8)GetHPRatio(); + bool mayGetAggro = false; + + if (tar && (mercClass == CASTERDPS) || (mercClass == MELEEDPS)) { + mayGetAggro = HasOrMayGetAggro(); //classes have hate reducing spells + + if (mayGetAggro) { + selectedMercSpell = GetFirstMercSpellBySpellType(this, SpellType_Escape); + + if (selectedMercSpell.spellid == 0) + break; + + if (isDiscipline) { + castedSpell = UseDiscipline(selectedMercSpell.spellid, tar->GetID()); + } + else { + castedSpell = AIDoSpellCast(selectedMercSpell.spellid, tar, -1); + } + } + } + break; + } } } } @@ -2464,18 +2467,18 @@ bool Merc::AICastSpell(int8 iChance, uint32 iSpellTypes) { } void Merc::CheckHateList() { - if(check_target_timer.Enabled()) + if (check_target_timer.Enabled()) check_target_timer.Disable(); - if(!IsEngaged()) { - if(GetFollowID()) { + if (!IsEngaged()) { + if (GetFollowID()) { Group* g = GetGroup(); - if(g) { + if (g) { Mob* MercOwner = GetOwner(); - if(MercOwner && MercOwner->GetTarget() && MercOwner->GetTarget()->IsNPC() && (MercOwner->GetTarget()->GetHateAmount(MercOwner) || MercOwner->CastToClient()->AutoAttackEnabled()) && IsAttackAllowed(MercOwner->GetTarget())) { + if (MercOwner && MercOwner->GetTarget() && MercOwner->GetTarget()->IsNPC() && (MercOwner->GetTarget()->GetHateAmount(MercOwner) || MercOwner->CastToClient()->AutoAttackEnabled()) && IsAttackAllowed(MercOwner->GetTarget())) { float range = g->HasRole(MercOwner, RolePuller) ? RuleI(Mercs, AggroRadiusPuller) : RuleI(Mercs, AggroRadius); range = range * range; - if(DistanceSquaredNoZ(m_Position, MercOwner->GetTarget()->GetPosition()) < range) { + if (DistanceSquaredNoZ(m_Position, MercOwner->GetTarget()->GetPosition()) < range) { AddToHateList(MercOwner->GetTarget(), 1); } } @@ -2488,16 +2491,16 @@ void Merc::CheckHateList() { float dist = DistanceSquaredNoZ(m_Position, npc->GetPosition()); int radius = RuleI(Mercs, AggroRadius); radius *= radius; - if(dist <= radius) { + if (dist <= radius) { - for(int counter = 0; counter < g->GroupCount(); counter++) { + for (int counter = 0; counter < g->GroupCount(); counter++) { Mob* groupMember = g->members[counter]; - if(groupMember) { - if(npc->IsOnHatelist(groupMember)) { - if(!hate_list.IsEntOnHateList(npc)) { + if (groupMember) { + if (npc->IsOnHatelist(groupMember)) { + if (!hate_list.IsEntOnHateList(npc)) { float range = g->HasRole(groupMember, RolePuller) ? RuleI(Mercs, AggroRadiusPuller) : RuleI(Mercs, AggroRadius); range *= range; - if(DistanceSquaredNoZ(m_Position, npc->GetPosition()) < range) { + if (DistanceSquaredNoZ(m_Position, npc->GetPosition()) < range) { hate_list.AddEntToHateList(npc, 1); } } @@ -2515,16 +2518,16 @@ void Merc::CheckHateList() { bool Merc::HasOrMayGetAggro() { bool mayGetAggro = false; - if(GetTarget() && GetTarget()->GetHateTop()) { - Mob *topHate = GetTarget()->GetHateTop(); + if (GetTarget() && GetTarget()->GetHateTop()) { + Mob* topHate = GetTarget()->GetHateTop(); - if(topHate == this) + if (topHate == this) mayGetAggro = true; //I currently have aggro else { uint32 myHateAmt = GetTarget()->GetHateAmount(this); uint32 topHateAmt = GetTarget()->GetHateAmount(topHate); - if(myHateAmt > 0 && topHateAmt > 0 && (uint8)((myHateAmt/topHateAmt)*100) > 90) //I have 90% as much hate as top, next action may give me aggro + if (myHateAmt > 0 && topHateAmt > 0 && (uint8)((myHateAmt / topHateAmt) * 100) > 90) //I have 90% as much hate as top, next action may give me aggro mayGetAggro = true; } } @@ -2532,15 +2535,15 @@ bool Merc::HasOrMayGetAggro() { return mayGetAggro; } -bool Merc::CheckAENuke(Merc* caster, Mob* tar, uint16 spell_id, uint8 &numTargets) { +bool Merc::CheckAENuke(Merc* caster, Mob* tar, uint16 spell_id, uint8& numTargets) { std::list npc_list; entity_list.GetNPCList(npc_list); for (auto itr = npc_list.begin(); itr != npc_list.end(); ++itr) { NPC* npc = *itr; - if(DistanceSquaredNoZ(npc->GetPosition(), tar->GetPosition()) <= spells[spell_id].aoe_range * spells[spell_id].aoe_range) { - if(!npc->IsMezzed()) { + if (DistanceSquaredNoZ(npc->GetPosition(), tar->GetPosition()) <= spells[spell_id].aoe_range * spells[spell_id].aoe_range) { + if (!npc->IsMezzed()) { numTargets++; } else { @@ -2550,7 +2553,7 @@ bool Merc::CheckAENuke(Merc* caster, Mob* tar, uint16 spell_id, uint8 &numTarget } } - if(numTargets > 1) + if (numTargets > 1) return true; return false; @@ -2565,14 +2568,14 @@ int32 Merc::GetFocusEffect(focusType type, uint16 spell_id) { //Improved Healing, Damage & Mana Reduction are handled differently in that some are random percentages //In these cases we need to find the most powerful effect, so that each piece of gear wont get its own chance - if((type == focusManaCost || type == focusImprovedHeal || type == focusImprovedDamage) + if ((type == focusManaCost || type == focusImprovedHeal || type == focusImprovedDamage) && RuleB(Spells, LiveLikeFocusEffects)) { rand_effectiveness = true; } //Check if item focus effect exists for the client. - if (itembonuses.FocusEffects[type]){ + if (itembonuses.FocusEffects[type]) { const EQ::ItemData* TempItem = nullptr; const EQ::ItemData* UsedItem = nullptr; @@ -2589,13 +2592,14 @@ int32 Merc::GetFocusEffect(focusType type, uint16 spell_id) { continue; TempItem = database.GetItem(equipment[x]); if (TempItem && TempItem->Focus.Effect > 0 && TempItem->Focus.Effect != SPELL_UNKNOWN) { - if(rand_effectiveness) { + if (rand_effectiveness) { focus_max = CalcFocusEffect(type, TempItem->Focus.Effect, spell_id, true); if (focus_max > 0 && focus_max_real >= 0 && focus_max > focus_max_real) { focus_max_real = focus_max; UsedItem = TempItem; UsedFocusID = TempItem->Focus.Effect; - } else if (focus_max < 0 && focus_max < focus_max_real) { + } + else if (focus_max < 0 && focus_max < focus_max_real) { focus_max_real = focus_max; UsedItem = TempItem; UsedFocusID = TempItem->Focus.Effect; @@ -2607,7 +2611,8 @@ int32 Merc::GetFocusEffect(focusType type, uint16 spell_id) { realTotal = Total; UsedItem = TempItem; UsedFocusID = TempItem->Focus.Effect; - } else if (Total < 0 && Total < realTotal) { + } + else if (Total < 0 && Total < realTotal) { realTotal = Total; UsedItem = TempItem; UsedFocusID = TempItem->Focus.Effect; @@ -2616,7 +2621,7 @@ int32 Merc::GetFocusEffect(focusType type, uint16 spell_id) { } } - if(UsedItem && rand_effectiveness && focus_max_real != 0) + if (UsedItem && rand_effectiveness && focus_max_real != 0) realTotal = CalcFocusEffect(type, UsedFocusID, spell_id); if (realTotal != 0 && UsedItem) @@ -2624,7 +2629,7 @@ int32 Merc::GetFocusEffect(focusType type, uint16 spell_id) { } //Check if spell focus effect exists for the client. - if (spellbonuses.FocusEffects[type]){ + if (spellbonuses.FocusEffects[type]) { //Spell Focus int32 Total2 = 0; @@ -2641,13 +2646,14 @@ int32 Merc::GetFocusEffect(focusType type, uint16 spell_id) { if (focusspellid == 0 || focusspellid >= SPDAT_RECORDS) continue; - if(rand_effectiveness) { + if (rand_effectiveness) { focus_max2 = CalcFocusEffect(type, focusspellid, spell_id, true); if (focus_max2 > 0 && focus_max_real2 >= 0 && focus_max2 > focus_max_real2) { focus_max_real2 = focus_max2; buff_tracker = buff_slot; focusspell_tracker = focusspellid; - } else if (focus_max2 < 0 && focus_max2 < focus_max_real2) { + } + else if (focus_max2 < 0 && focus_max2 < focus_max_real2) { focus_max_real2 = focus_max2; buff_tracker = buff_slot; focusspell_tracker = focusspellid; @@ -2659,7 +2665,8 @@ int32 Merc::GetFocusEffect(focusType type, uint16 spell_id) { realTotal2 = Total2; buff_tracker = buff_slot; focusspell_tracker = focusspellid; - } else if (Total2 < 0 && Total2 < realTotal2) { + } + else if (Total2 < 0 && Total2 < realTotal2) { realTotal2 = Total2; buff_tracker = buff_slot; focusspell_tracker = focusspellid; @@ -2667,11 +2674,11 @@ int32 Merc::GetFocusEffect(focusType type, uint16 spell_id) { } } - if(focusspell_tracker && rand_effectiveness && focus_max_real2 != 0) + if (focusspell_tracker && rand_effectiveness && focus_max_real2 != 0) realTotal2 = CalcFocusEffect(type, focusspell_tracker, spell_id); // For effects like gift of mana that only fire once, save the spellid into an array that consists of all available buff slots. - if(buff_tracker >= 0 && buffs[buff_tracker].hit_number > 0) { + if (buff_tracker >= 0 && buffs[buff_tracker].hit_number > 0) { m_spellHitsLeft[buff_tracker] = focusspell_tracker; } } @@ -2702,10 +2709,10 @@ int32 Merc::GetFocusEffect(focusType type, uint16 spell_id) { } }*/ - if(type == focusReagentCost && IsSummonPetSpell(spell_id) && GetAA(aaElementalPact)) + if (type == focusReagentCost && IsSummonPetSpell(spell_id) && GetAA(aaElementalPact)) return 100; - if(type == focusReagentCost && (IsEffectInSpell(spell_id, SE_SummonItem) || IsSacrificeSpell(spell_id))) + if (type == focusReagentCost && (IsEffectInSpell(spell_id, SE_SummonItem) || IsSacrificeSpell(spell_id))) return 0; //Summon Spells that require reagents are typically imbue type spells, enchant metal, sacrifice and shouldn't be affected //by reagent conservation for obvious reasons. @@ -2716,11 +2723,11 @@ int32 Merc::GetFocusEffect(focusType type, uint16 spell_id) { int32 Merc::GetActSpellCost(uint16 spell_id, int32 cost) { // Formula = Unknown exact, based off a random percent chance up to mana cost(after focuses) of the cast spell - if(this->itembonuses.Clairvoyance && spells[spell_id].classes[(GetClass()%17) - 1] >= GetLevel() - 5) + if (this->itembonuses.Clairvoyance && spells[spell_id].classes[(GetClass() % 17) - 1] >= GetLevel() - 5) { int16 mana_back = this->itembonuses.Clairvoyance * zone->random.Int(1, 100) / 100; // Doesnt generate mana, so best case is a free spell - if(mana_back > cost) + if (mana_back > cost) mana_back = cost; cost -= mana_back; @@ -2733,7 +2740,7 @@ int32 Merc::GetActSpellCost(uint16 spell_id, int32 cost) int16 focus_redux = GetFocusEffect(focusManaCost, spell_id); - if(focus_redux > 0) + if (focus_redux > 0) { PercentManaReduction += zone->random.Real(1, (double)focus_redux); } @@ -2741,20 +2748,20 @@ int32 Merc::GetActSpellCost(uint16 spell_id, int32 cost) cost -= (cost * (PercentManaReduction / 100)); // Gift of Mana - reduces spell cost to 1 mana - if(focus_redux >= 100) { + if (focus_redux >= 100) { uint32 buff_max = GetMaxTotalSlots(); for (int buffSlot = 0; buffSlot < buff_max; buffSlot++) { if (buffs[buffSlot].spellid == 0 || buffs[buffSlot].spellid >= SPDAT_RECORDS) continue; - if(IsEffectInSpell(buffs[buffSlot].spellid, SE_ReduceManaCost)) { - if(CalcFocusEffect(focusManaCost, buffs[buffSlot].spellid, spell_id) == 100) + if (IsEffectInSpell(buffs[buffSlot].spellid, SE_ReduceManaCost)) { + if (CalcFocusEffect(focusManaCost, buffs[buffSlot].spellid, spell_id) == 100) cost = 1; } } } - if(cost < 0) + if (cost < 0) cost = 0; return cost; @@ -2766,126 +2773,126 @@ int8 Merc::GetChanceToCastBySpellType(uint32 spellType) { int8 chance = 0; switch (spellType) { - case SpellType_Nuke: { - switch(mercClass) - { - case TANK: { - chance = 100; - break; - } - case HEALER:{ - break; - } - case MELEEDPS:{ - chance = 100; - break; - } - case CASTERDPS:{ - chance = 100; - break; - } - } - break; - } - case SpellType_Heal: { - switch(mercClass) - { - case TANK: { - break; - } - case HEALER:{ - chance = 100; - break; - } - case MELEEDPS:{ - break; - } - case CASTERDPS:{ - break; - } - } - break; - } - case SpellType_Root: { - switch(mercClass) - { - case TANK: { - break; - } - case HEALER:{ - break; - } - case MELEEDPS:{ - break; - } - case CASTERDPS:{ - break; - } - } - break; - } - case SpellType_Buff: { - switch(mercClass) - { - case TANK: { - break; - } - case HEALER:{ - chance = IsEngaged() ? 0 : 100; - break; - } - case MELEEDPS:{ - break; - } - case CASTERDPS:{ - break; - } - } - break; - } - case SpellType_InCombatBuff: { - switch(mercClass) - { - case TANK: { - chance = 50; - break; - } - case HEALER:{ - break; - } - case MELEEDPS:{ - chance = 50; - break; - } - case CASTERDPS:{ - break; - } - } - break; - } - case SpellType_Escape: { - switch(mercClass) - { - case TANK: { - break; - } - case HEALER:{ - break; - } - case MELEEDPS:{ - chance = 100; - break; - } - case CASTERDPS:{ - chance = 100; - break; - } - } - break; - } - default: - chance = 0; - break; + case SpellType_Nuke: { + switch (mercClass) + { + case TANK: { + chance = 100; + break; + } + case HEALER: { + break; + } + case MELEEDPS: { + chance = 100; + break; + } + case CASTERDPS: { + chance = 100; + break; + } + } + break; + } + case SpellType_Heal: { + switch (mercClass) + { + case TANK: { + break; + } + case HEALER: { + chance = 100; + break; + } + case MELEEDPS: { + break; + } + case CASTERDPS: { + break; + } + } + break; + } + case SpellType_Root: { + switch (mercClass) + { + case TANK: { + break; + } + case HEALER: { + break; + } + case MELEEDPS: { + break; + } + case CASTERDPS: { + break; + } + } + break; + } + case SpellType_Buff: { + switch (mercClass) + { + case TANK: { + break; + } + case HEALER: { + chance = IsEngaged() ? 0 : 100; + break; + } + case MELEEDPS: { + break; + } + case CASTERDPS: { + break; + } + } + break; + } + case SpellType_InCombatBuff: { + switch (mercClass) + { + case TANK: { + chance = 50; + break; + } + case HEALER: { + break; + } + case MELEEDPS: { + chance = 50; + break; + } + case CASTERDPS: { + break; + } + } + break; + } + case SpellType_Escape: { + switch (mercClass) + { + case TANK: { + break; + } + case HEALER: { + break; + } + case MELEEDPS: { + chance = 100; + break; + } + case CASTERDPS: { + chance = 100; + break; + } + } + break; + } + default: + chance = 0; + break; } return chance; @@ -2896,7 +2903,7 @@ bool Merc::CheckStance(int16 stance) { //checks of current stance matches stances listed as valid for spell in database //stance = 0 for all stances, stance # for only that stance & -stance# for all but that stance if (stance == 0 || (stance > 0 && stance == GetStance()) || (stance < 0 && std::abs(stance) != GetStance())) { - return true; + return true; } return false; @@ -2905,7 +2912,7 @@ bool Merc::CheckStance(int16 stance) { std::list Merc::GetMercSpellsBySpellType(Merc* caster, uint32 spellType) { std::list result; - if(caster && caster->AI_HasSpells()) { + if (caster && caster->AI_HasSpells()) { std::vector mercSpellList = caster->GetMercSpells(); for (int i = mercSpellList.size() - 1; i >= 0; i--) { @@ -2915,7 +2922,7 @@ std::list Merc::GetMercSpellsBySpellType(Merc* caster, uint32 spellTy continue; } - if((mercSpellList[i].type & spellType) && caster->CheckStance(mercSpellList[i].stance)) { + if ((mercSpellList[i].type & spellType) && caster->CheckStance(mercSpellList[i].stance)) { MercSpell mercSpell; mercSpell.spellid = mercSpellList[i].spellid; mercSpell.stance = mercSpellList[i].stance; @@ -2942,7 +2949,7 @@ MercSpell Merc::GetFirstMercSpellBySpellType(Merc* caster, uint32 spellType) { result.proc_chance = 0; result.time_cancast = 0; - if(caster && caster->AI_HasSpells()) { + if (caster && caster->AI_HasSpells()) { std::vector mercSpellList = caster->GetMercSpells(); for (int i = mercSpellList.size() - 1; i >= 0; i--) { @@ -2952,17 +2959,17 @@ MercSpell Merc::GetFirstMercSpellBySpellType(Merc* caster, uint32 spellType) { continue; } - if((mercSpellList[i].type & spellType) + if ((mercSpellList[i].type & spellType) && caster->CheckStance(mercSpellList[i].stance) && CheckSpellRecastTimers(caster, mercSpellList[i].spellid)) { - result.spellid = mercSpellList[i].spellid; - result.stance = mercSpellList[i].stance; - result.type = mercSpellList[i].type; - result.slot = mercSpellList[i].slot; - result.proc_chance = mercSpellList[i].proc_chance; - result.time_cancast = mercSpellList[i].time_cancast; + result.spellid = mercSpellList[i].spellid; + result.stance = mercSpellList[i].stance; + result.type = mercSpellList[i].type; + result.slot = mercSpellList[i].slot; + result.proc_chance = mercSpellList[i].proc_chance; + result.time_cancast = mercSpellList[i].time_cancast; - break; + break; } } } @@ -2980,7 +2987,7 @@ MercSpell Merc::GetMercSpellBySpellID(Merc* caster, uint16 spellid) { result.proc_chance = 0; result.time_cancast = 0; - if(caster && caster->AI_HasSpells()) { + if (caster && caster->AI_HasSpells()) { std::vector mercSpellList = caster->GetMercSpells(); for (int i = mercSpellList.size() - 1; i >= 0; i--) { @@ -2990,16 +2997,16 @@ MercSpell Merc::GetMercSpellBySpellID(Merc* caster, uint16 spellid) { continue; } - if((mercSpellList[i].spellid == spellid) + if ((mercSpellList[i].spellid == spellid) && caster->CheckStance(mercSpellList[i].stance)) { - result.spellid = mercSpellList[i].spellid; - result.stance = mercSpellList[i].stance; - result.type = mercSpellList[i].type; - result.slot = mercSpellList[i].slot; - result.proc_chance = mercSpellList[i].proc_chance; - result.time_cancast = mercSpellList[i].time_cancast; + result.spellid = mercSpellList[i].spellid; + result.stance = mercSpellList[i].stance; + result.type = mercSpellList[i].type; + result.slot = mercSpellList[i].slot; + result.proc_chance = mercSpellList[i].proc_chance; + result.time_cancast = mercSpellList[i].time_cancast; - break; + break; } } } @@ -3010,7 +3017,7 @@ MercSpell Merc::GetMercSpellBySpellID(Merc* caster, uint16 spellid) { std::list Merc::GetMercSpellsForSpellEffect(Merc* caster, int spellEffect) { std::list result; - if(caster && caster->AI_HasSpells()) { + if (caster && caster->AI_HasSpells()) { std::vector mercSpellList = caster->GetMercSpells(); for (int i = mercSpellList.size() - 1; i >= 0; i--) { @@ -3020,7 +3027,7 @@ std::list Merc::GetMercSpellsForSpellEffect(Merc* caster, int spellEf continue; } - if(IsEffectInSpell(mercSpellList[i].spellid, spellEffect) && caster->CheckStance(mercSpellList[i].stance)) { + if (IsEffectInSpell(mercSpellList[i].spellid, spellEffect) && caster->CheckStance(mercSpellList[i].stance)) { MercSpell MercSpell; MercSpell.spellid = mercSpellList[i].spellid; MercSpell.stance = mercSpellList[i].stance; @@ -3040,7 +3047,7 @@ std::list Merc::GetMercSpellsForSpellEffect(Merc* caster, int spellEf std::list Merc::GetMercSpellsForSpellEffectAndTargetType(Merc* caster, int spellEffect, SpellTargetType targetType) { std::list result; - if(caster && caster->AI_HasSpells()) { + if (caster && caster->AI_HasSpells()) { std::vector mercSpellList = caster->GetMercSpells(); for (int i = mercSpellList.size() - 1; i >= 0; i--) { @@ -3050,8 +3057,8 @@ std::list Merc::GetMercSpellsForSpellEffectAndTargetType(Merc* caster continue; } - if(IsEffectInSpell(mercSpellList[i].spellid, spellEffect) && caster->CheckStance(mercSpellList[i].stance)) { - if(spells[mercSpellList[i].spellid].target_type == targetType) { + if (IsEffectInSpell(mercSpellList[i].spellid, spellEffect) && caster->CheckStance(mercSpellList[i].stance)) { + if (spells[mercSpellList[i].spellid].target_type == targetType) { MercSpell MercSpell; MercSpell.spellid = mercSpellList[i].spellid; MercSpell.stance = mercSpellList[i].stance; @@ -3079,22 +3086,22 @@ MercSpell Merc::GetBestMercSpellForVeryFastHeal(Merc* caster) { result.proc_chance = 0; result.time_cancast = 0; - if(caster) { + if (caster) { std::list mercSpellList = GetMercSpellsForSpellEffect(caster, SE_CurrentHP); for (auto mercSpellListItr = mercSpellList.begin(); mercSpellListItr != mercSpellList.end(); - ++mercSpellListItr) { + ++mercSpellListItr) { // Assuming all the spells have been loaded into this list by level and in descending order - if(IsVeryFastHealSpell(mercSpellListItr->spellid) + if (IsVeryFastHealSpell(mercSpellListItr->spellid) && CheckSpellRecastTimers(caster, mercSpellListItr->spellid)) { - result.spellid = mercSpellListItr->spellid; - result.stance = mercSpellListItr->stance; - result.type = mercSpellListItr->type; - result.slot = mercSpellListItr->slot; - result.proc_chance = mercSpellListItr->proc_chance; - result.time_cancast = mercSpellListItr->time_cancast; + result.spellid = mercSpellListItr->spellid; + result.stance = mercSpellListItr->stance; + result.type = mercSpellListItr->type; + result.slot = mercSpellListItr->slot; + result.proc_chance = mercSpellListItr->proc_chance; + result.time_cancast = mercSpellListItr->time_cancast; - break; + break; } } } @@ -3112,22 +3119,22 @@ MercSpell Merc::GetBestMercSpellForFastHeal(Merc* caster) { result.proc_chance = 0; result.time_cancast = 0; - if(caster) { + if (caster) { std::list mercSpellList = GetMercSpellsForSpellEffect(caster, SE_CurrentHP); for (auto mercSpellListItr = mercSpellList.begin(); mercSpellListItr != mercSpellList.end(); - ++mercSpellListItr) { + ++mercSpellListItr) { // Assuming all the spells have been loaded into this list by level and in descending order - if(IsFastHealSpell(mercSpellListItr->spellid) + if (IsFastHealSpell(mercSpellListItr->spellid) && CheckSpellRecastTimers(caster, mercSpellListItr->spellid)) { - result.spellid = mercSpellListItr->spellid; - result.stance = mercSpellListItr->stance; - result.type = mercSpellListItr->type; - result.slot = mercSpellListItr->slot; - result.proc_chance = mercSpellListItr->proc_chance; - result.time_cancast = mercSpellListItr->time_cancast; + result.spellid = mercSpellListItr->spellid; + result.stance = mercSpellListItr->stance; + result.type = mercSpellListItr->type; + result.slot = mercSpellListItr->slot; + result.proc_chance = mercSpellListItr->proc_chance; + result.time_cancast = mercSpellListItr->time_cancast; - break; + break; } } } @@ -3145,13 +3152,13 @@ MercSpell Merc::GetBestMercSpellForHealOverTime(Merc* caster) { result.proc_chance = 0; result.time_cancast = 0; - if(caster) { + if (caster) { std::list mercHoTSpellList = GetMercSpellsForSpellEffect(caster, SE_HealOverTime); for (auto mercSpellListItr = mercHoTSpellList.begin(); mercSpellListItr != mercHoTSpellList.end(); - ++mercSpellListItr) { + ++mercSpellListItr) { // Assuming all the spells have been loaded into this list by level and in descending order - if(IsHealOverTimeSpell(mercSpellListItr->spellid)) { + if (IsHealOverTimeSpell(mercSpellListItr->spellid)) { if (mercSpellListItr->spellid <= 0 || mercSpellListItr->spellid >= SPDAT_RECORDS) { // this is both to quit early to save cpu and to avoid casting bad spells @@ -3159,7 +3166,7 @@ MercSpell Merc::GetBestMercSpellForHealOverTime(Merc* caster) { continue; } - if(CheckSpellRecastTimers(caster, mercSpellListItr->spellid)) { + if (CheckSpellRecastTimers(caster, mercSpellListItr->spellid)) { result.spellid = mercSpellListItr->spellid; result.stance = mercSpellListItr->stance; result.type = mercSpellListItr->type; @@ -3186,22 +3193,22 @@ MercSpell Merc::GetBestMercSpellForPercentageHeal(Merc* caster) { result.proc_chance = 0; result.time_cancast = 0; - if(caster && caster->AI_HasSpells()) { + if (caster && caster->AI_HasSpells()) { std::list mercSpellList = GetMercSpellsForSpellEffect(caster, SE_CurrentHP); for (auto mercSpellListItr = mercSpellList.begin(); mercSpellListItr != mercSpellList.end(); - ++mercSpellListItr) { + ++mercSpellListItr) { // Assuming all the spells have been loaded into this list by level and in descending order - if(IsCompleteHealSpell(mercSpellListItr->spellid) + if (IsCompleteHealSpell(mercSpellListItr->spellid) && CheckSpellRecastTimers(caster, mercSpellListItr->spellid)) { - result.spellid = mercSpellListItr->spellid; - result.stance = mercSpellListItr->stance; - result.type = mercSpellListItr->type; - result.slot = mercSpellListItr->slot; - result.proc_chance = mercSpellListItr->proc_chance; - result.time_cancast = mercSpellListItr->time_cancast; + result.spellid = mercSpellListItr->spellid; + result.stance = mercSpellListItr->stance; + result.type = mercSpellListItr->type; + result.slot = mercSpellListItr->slot; + result.proc_chance = mercSpellListItr->proc_chance; + result.time_cancast = mercSpellListItr->time_cancast; - break; + break; } } } @@ -3219,22 +3226,22 @@ MercSpell Merc::GetBestMercSpellForRegularSingleTargetHeal(Merc* caster) { result.proc_chance = 0; result.time_cancast = 0; - if(caster) { + if (caster) { std::list mercSpellList = GetMercSpellsForSpellEffect(caster, SE_CurrentHP); for (auto mercSpellListItr = mercSpellList.begin(); mercSpellListItr != mercSpellList.end(); - ++mercSpellListItr) { + ++mercSpellListItr) { // Assuming all the spells have been loaded into this list by level and in descending order - if(IsRegularSingleTargetHealSpell(mercSpellListItr->spellid) + if (IsRegularSingleTargetHealSpell(mercSpellListItr->spellid) && CheckSpellRecastTimers(caster, mercSpellListItr->spellid)) { - result.spellid = mercSpellListItr->spellid; - result.stance = mercSpellListItr->stance; - result.type = mercSpellListItr->type; - result.slot = mercSpellListItr->slot; - result.proc_chance = mercSpellListItr->proc_chance; - result.time_cancast = mercSpellListItr->time_cancast; + result.spellid = mercSpellListItr->spellid; + result.stance = mercSpellListItr->stance; + result.type = mercSpellListItr->type; + result.slot = mercSpellListItr->slot; + result.proc_chance = mercSpellListItr->proc_chance; + result.time_cancast = mercSpellListItr->time_cancast; - break; + break; } } } @@ -3252,23 +3259,23 @@ MercSpell Merc::GetFirstMercSpellForSingleTargetHeal(Merc* caster) { result.proc_chance = 0; result.time_cancast = 0; - if(caster) { + if (caster) { std::list mercSpellList = GetMercSpellsForSpellEffect(caster, SE_CurrentHP); for (auto mercSpellListItr = mercSpellList.begin(); mercSpellListItr != mercSpellList.end(); - ++mercSpellListItr) { + ++mercSpellListItr) { // Assuming all the spells have been loaded into this list by level and in descending order - if((IsRegularSingleTargetHealSpell(mercSpellListItr->spellid) + if ((IsRegularSingleTargetHealSpell(mercSpellListItr->spellid) || IsFastHealSpell(mercSpellListItr->spellid)) && CheckSpellRecastTimers(caster, mercSpellListItr->spellid)) { - result.spellid = mercSpellListItr->spellid; - result.stance = mercSpellListItr->stance; - result.type = mercSpellListItr->type; - result.slot = mercSpellListItr->slot; - result.proc_chance = mercSpellListItr->proc_chance; - result.time_cancast = mercSpellListItr->time_cancast; + result.spellid = mercSpellListItr->spellid; + result.stance = mercSpellListItr->stance; + result.type = mercSpellListItr->type; + result.slot = mercSpellListItr->slot; + result.proc_chance = mercSpellListItr->proc_chance; + result.time_cancast = mercSpellListItr->time_cancast; - break; + break; } } } @@ -3286,22 +3293,22 @@ MercSpell Merc::GetBestMercSpellForGroupHeal(Merc* caster) { result.proc_chance = 0; result.time_cancast = 0; - if(caster) { + if (caster) { std::list mercSpellList = GetMercSpellsForSpellEffect(caster, SE_CurrentHP); for (auto mercSpellListItr = mercSpellList.begin(); mercSpellListItr != mercSpellList.end(); - ++mercSpellListItr) { + ++mercSpellListItr) { // Assuming all the spells have been loaded into this list by level and in descending order - if(IsRegularGroupHealSpell(mercSpellListItr->spellid) + if (IsRegularGroupHealSpell(mercSpellListItr->spellid) && CheckSpellRecastTimers(caster, mercSpellListItr->spellid)) { - result.spellid = mercSpellListItr->spellid; - result.stance = mercSpellListItr->stance; - result.type = mercSpellListItr->type; - result.slot = mercSpellListItr->slot; - result.proc_chance = mercSpellListItr->proc_chance; - result.time_cancast = mercSpellListItr->time_cancast; + result.spellid = mercSpellListItr->spellid; + result.stance = mercSpellListItr->stance; + result.type = mercSpellListItr->type; + result.slot = mercSpellListItr->slot; + result.proc_chance = mercSpellListItr->proc_chance; + result.time_cancast = mercSpellListItr->time_cancast; - break; + break; } } } @@ -3319,13 +3326,13 @@ MercSpell Merc::GetBestMercSpellForGroupHealOverTime(Merc* caster) { result.proc_chance = 0; result.time_cancast = 0; - if(caster) { + if (caster) { std::list mercHoTSpellList = GetMercSpellsForSpellEffect(caster, SE_HealOverTime); for (auto mercSpellListItr = mercHoTSpellList.begin(); mercSpellListItr != mercHoTSpellList.end(); - ++mercSpellListItr) { + ++mercSpellListItr) { // Assuming all the spells have been loaded into this list by level and in descending order - if(IsGroupHealOverTimeSpell(mercSpellListItr->spellid)) { + if (IsGroupHealOverTimeSpell(mercSpellListItr->spellid)) { if (mercSpellListItr->spellid <= 0 || mercSpellListItr->spellid >= SPDAT_RECORDS) { // this is both to quit early to save cpu and to avoid casting bad spells @@ -3333,7 +3340,7 @@ MercSpell Merc::GetBestMercSpellForGroupHealOverTime(Merc* caster) { continue; } - if(CheckSpellRecastTimers(caster, mercSpellListItr->spellid)) { + if (CheckSpellRecastTimers(caster, mercSpellListItr->spellid)) { result.spellid = mercSpellListItr->spellid; result.stance = mercSpellListItr->stance; result.type = mercSpellListItr->type; @@ -3360,22 +3367,22 @@ MercSpell Merc::GetBestMercSpellForGroupCompleteHeal(Merc* caster) { result.proc_chance = 0; result.time_cancast = 0; - if(caster) { + if (caster) { std::list mercSpellList = GetMercSpellsForSpellEffect(caster, SE_CompleteHeal); for (auto mercSpellListItr = mercSpellList.begin(); mercSpellListItr != mercSpellList.end(); - ++mercSpellListItr) { + ++mercSpellListItr) { // Assuming all the spells have been loaded into this list by level and in descending order - if(IsGroupCompleteHealSpell(mercSpellListItr->spellid) + if (IsGroupCompleteHealSpell(mercSpellListItr->spellid) && CheckSpellRecastTimers(caster, mercSpellListItr->spellid)) { - result.spellid = mercSpellListItr->spellid; - result.stance = mercSpellListItr->stance; - result.type = mercSpellListItr->type; - result.slot = mercSpellListItr->slot; - result.proc_chance = mercSpellListItr->proc_chance; - result.time_cancast = mercSpellListItr->time_cancast; + result.spellid = mercSpellListItr->spellid; + result.stance = mercSpellListItr->stance; + result.type = mercSpellListItr->type; + result.slot = mercSpellListItr->slot; + result.proc_chance = mercSpellListItr->proc_chance; + result.time_cancast = mercSpellListItr->time_cancast; - break; + break; } } } @@ -3393,24 +3400,24 @@ MercSpell Merc::GetBestMercSpellForAETaunt(Merc* caster) { result.proc_chance = 0; result.time_cancast = 0; - if(caster) { + if (caster) { std::list mercSpellList = GetMercSpellsForSpellEffect(caster, SE_Taunt); for (auto mercSpellListItr = mercSpellList.begin(); mercSpellListItr != mercSpellList.end(); - ++mercSpellListItr) { + ++mercSpellListItr) { // Assuming all the spells have been loaded into this list by level and in descending order - if((spells[mercSpellListItr->spellid].target_type == ST_AECaster + if ((spells[mercSpellListItr->spellid].target_type == ST_AECaster || spells[mercSpellListItr->spellid].target_type == ST_AETarget || spells[mercSpellListItr->spellid].target_type == ST_UndeadAE) && CheckSpellRecastTimers(caster, mercSpellListItr->spellid)) { - result.spellid = mercSpellListItr->spellid; - result.stance = mercSpellListItr->stance; - result.type = mercSpellListItr->type; - result.slot = mercSpellListItr->slot; - result.proc_chance = mercSpellListItr->proc_chance; - result.time_cancast = mercSpellListItr->time_cancast; + result.spellid = mercSpellListItr->spellid; + result.stance = mercSpellListItr->stance; + result.type = mercSpellListItr->type; + result.slot = mercSpellListItr->slot; + result.proc_chance = mercSpellListItr->proc_chance; + result.time_cancast = mercSpellListItr->time_cancast; - break; + break; } } } @@ -3428,22 +3435,22 @@ MercSpell Merc::GetBestMercSpellForTaunt(Merc* caster) { result.proc_chance = 0; result.time_cancast = 0; - if(caster) { + if (caster) { std::list mercSpellList = GetMercSpellsForSpellEffect(caster, SE_Taunt); for (auto mercSpellListItr = mercSpellList.begin(); mercSpellListItr != mercSpellList.end(); - ++mercSpellListItr) { + ++mercSpellListItr) { // Assuming all the spells have been loaded into this list by level and in descending order - if((spells[mercSpellListItr->spellid].target_type == ST_Target) + if ((spells[mercSpellListItr->spellid].target_type == ST_Target) && CheckSpellRecastTimers(caster, mercSpellListItr->spellid)) { - result.spellid = mercSpellListItr->spellid; - result.stance = mercSpellListItr->stance; - result.type = mercSpellListItr->type; - result.slot = mercSpellListItr->slot; - result.proc_chance = mercSpellListItr->proc_chance; - result.time_cancast = mercSpellListItr->time_cancast; + result.spellid = mercSpellListItr->spellid; + result.stance = mercSpellListItr->stance; + result.type = mercSpellListItr->type; + result.slot = mercSpellListItr->slot; + result.proc_chance = mercSpellListItr->proc_chance; + result.time_cancast = mercSpellListItr->time_cancast; - break; + break; } } } @@ -3461,13 +3468,13 @@ MercSpell Merc::GetBestMercSpellForHate(Merc* caster) { result.proc_chance = 0; result.time_cancast = 0; - if(caster) { + if (caster) { std::list mercSpellList = GetMercSpellsForSpellEffect(caster, SE_InstantHate); for (auto mercSpellListItr = mercSpellList.begin(); mercSpellListItr != mercSpellList.end(); - ++mercSpellListItr) { + ++mercSpellListItr) { // Assuming all the spells have been loaded into this list by level and in descending order - if(CheckSpellRecastTimers(caster, mercSpellListItr->spellid)) { + if (CheckSpellRecastTimers(caster, mercSpellListItr->spellid)) { result.spellid = mercSpellListItr->spellid; result.stance = mercSpellListItr->stance; result.type = mercSpellListItr->type; @@ -3483,7 +3490,7 @@ MercSpell Merc::GetBestMercSpellForHate(Merc* caster) { return result; } -MercSpell Merc::GetBestMercSpellForCure(Merc* caster, Mob *tar) { +MercSpell Merc::GetBestMercSpellForCure(Merc* caster, Mob* tar) { MercSpell result; bool spellSelected = false; @@ -3494,7 +3501,7 @@ MercSpell Merc::GetBestMercSpellForCure(Merc* caster, Mob *tar) { result.proc_chance = 0; result.time_cancast = 0; - if(!tar) + if (!tar) return result; int countNeedsCured = 0; @@ -3503,16 +3510,16 @@ MercSpell Merc::GetBestMercSpellForCure(Merc* caster, Mob *tar) { bool isCursed = tar->FindType(SE_CurseCounter); bool isCorrupted = tar->FindType(SE_CorruptionCounter); - if(caster && caster->AI_HasSpells()) { + if (caster && caster->AI_HasSpells()) { std::list cureList = GetMercSpellsBySpellType(caster, SpellType_Cure); - if(tar->HasGroup()) { - Group *g = tar->GetGroup(); + if (tar->HasGroup()) { + Group* g = tar->GetGroup(); - if(g) { - for( int i = 0; imembers[i] && !g->members[i]->qglobal) { - if(caster->GetNeedsCured(g->members[i])) + if (g) { + for (int i = 0; i < MAX_GROUP_MEMBERS; i++) { + if (g->members[i] && !g->members[i]->qglobal) { + if (caster->GetNeedsCured(g->members[i])) countNeedsCured++; } } @@ -3520,31 +3527,31 @@ MercSpell Merc::GetBestMercSpellForCure(Merc* caster, Mob *tar) { } //Check for group cure first - if(countNeedsCured > 2) { + if (countNeedsCured > 2) { for (auto itr = cureList.begin(); itr != cureList.end(); ++itr) { MercSpell selectedMercSpell = *itr; - if(IsGroupSpell(itr->spellid) && CheckSpellRecastTimers(caster, itr->spellid)) { - if(selectedMercSpell.spellid == 0) + if (IsGroupSpell(itr->spellid) && CheckSpellRecastTimers(caster, itr->spellid)) { + if (selectedMercSpell.spellid == 0) continue; - if(isPoisoned && IsEffectInSpell(itr->spellid, SE_PoisonCounter)) { + if (isPoisoned && IsEffectInSpell(itr->spellid, SE_PoisonCounter)) { spellSelected = true; } - else if(isDiseased && IsEffectInSpell(itr->spellid, SE_DiseaseCounter)) { + else if (isDiseased && IsEffectInSpell(itr->spellid, SE_DiseaseCounter)) { spellSelected = true; } - else if(isCursed && IsEffectInSpell(itr->spellid, SE_CurseCounter)) { + else if (isCursed && IsEffectInSpell(itr->spellid, SE_CurseCounter)) { spellSelected = true; } - else if(isCorrupted && IsEffectInSpell(itr->spellid, SE_CorruptionCounter)) { + else if (isCorrupted && IsEffectInSpell(itr->spellid, SE_CorruptionCounter)) { spellSelected = true; } - else if(IsEffectInSpell(itr->spellid, SE_DispelDetrimental)) { + else if (IsEffectInSpell(itr->spellid, SE_DispelDetrimental)) { spellSelected = true; } - if(spellSelected) + if (spellSelected) { result.spellid = itr->spellid; result.stance = itr->stance; @@ -3560,31 +3567,31 @@ MercSpell Merc::GetBestMercSpellForCure(Merc* caster, Mob *tar) { } //no group cure for target- try to find single target spell - if(!spellSelected) { + if (!spellSelected) { for (auto itr = cureList.begin(); itr != cureList.end(); ++itr) { MercSpell selectedMercSpell = *itr; - if(CheckSpellRecastTimers(caster, itr->spellid)) { - if(selectedMercSpell.spellid == 0) + if (CheckSpellRecastTimers(caster, itr->spellid)) { + if (selectedMercSpell.spellid == 0) continue; - if(isPoisoned && IsEffectInSpell(itr->spellid, SE_PoisonCounter)) { + if (isPoisoned && IsEffectInSpell(itr->spellid, SE_PoisonCounter)) { spellSelected = true; } - else if(isDiseased && IsEffectInSpell(itr->spellid, SE_DiseaseCounter)) { + else if (isDiseased && IsEffectInSpell(itr->spellid, SE_DiseaseCounter)) { spellSelected = true; } - else if(isCursed && IsEffectInSpell(itr->spellid, SE_CurseCounter)) { + else if (isCursed && IsEffectInSpell(itr->spellid, SE_CurseCounter)) { spellSelected = true; } - else if(isCorrupted && IsEffectInSpell(itr->spellid, SE_CorruptionCounter)) { + else if (isCorrupted && IsEffectInSpell(itr->spellid, SE_CorruptionCounter)) { spellSelected = true; } - else if(IsEffectInSpell(itr->spellid, SE_DispelDetrimental)) { + else if (IsEffectInSpell(itr->spellid, SE_DispelDetrimental)) { spellSelected = true; } - if(spellSelected) + if (spellSelected) { result.spellid = itr->spellid; result.stance = itr->stance; @@ -3614,13 +3621,13 @@ MercSpell Merc::GetBestMercSpellForStun(Merc* caster) { result.proc_chance = 0; result.time_cancast = 0; - if(caster) { + if (caster) { std::list mercSpellList = GetMercSpellsForSpellEffect(caster, SE_Stun); for (auto mercSpellListItr = mercSpellList.begin(); mercSpellListItr != mercSpellList.end(); - ++mercSpellListItr) { + ++mercSpellListItr) { // Assuming all the spells have been loaded into this list by level and in descending order - if(CheckSpellRecastTimers(caster, mercSpellListItr->spellid)) { + if (CheckSpellRecastTimers(caster, mercSpellListItr->spellid)) { result.spellid = mercSpellListItr->spellid; result.stance = mercSpellListItr->stance; result.type = mercSpellListItr->type; @@ -3647,11 +3654,11 @@ MercSpell Merc::GetBestMercSpellForAENuke(Merc* caster, Mob* tar) { result.proc_chance = 0; result.time_cancast = 0; - if(caster) { + if (caster) { uint8 initialCastChance = 0; uint8 castChanceFalloff = 75; - switch(caster->GetStance()) + switch (caster->GetStance()) { case EQ::constants::stanceBurnAE: initialCastChance = 50; @@ -3665,17 +3672,17 @@ MercSpell Merc::GetBestMercSpellForAENuke(Merc* caster, Mob* tar) { } //check of we even want to cast an AE nuke - if(zone->random.Roll(initialCastChance)) { + if (zone->random.Roll(initialCastChance)) { result = GetBestMercSpellForAERainNuke(caster, tar); //check if we have a spell & allow for other AE nuke types - if(result.spellid == 0 && zone->random.Roll(castChanceFalloff)) { + if (result.spellid == 0 && zone->random.Roll(castChanceFalloff)) { result = GetBestMercSpellForPBAENuke(caster, tar); //check if we have a spell & allow for other AE nuke types - if(result.spellid == 0 && zone->random.Roll(castChanceFalloff)) { + if (result.spellid == 0 && zone->random.Roll(castChanceFalloff)) { result = GetBestMercSpellForTargetedAENuke(caster, tar); } @@ -3699,7 +3706,7 @@ MercSpell Merc::GetBestMercSpellForTargetedAENuke(Merc* caster, Mob* tar) { result.proc_chance = 0; result.time_cancast = 0; - switch(caster->GetStance()) + switch (caster->GetStance()) { case EQ::constants::stanceBurnAE: numTargetsCheck = 1; @@ -3710,27 +3717,27 @@ MercSpell Merc::GetBestMercSpellForTargetedAENuke(Merc* caster, Mob* tar) { break; } - if(caster) { + if (caster) { std::list mercSpellList = GetMercSpellsBySpellType(caster, SpellType_Nuke); for (auto mercSpellListItr = mercSpellList.begin(); mercSpellListItr != mercSpellList.end(); - ++mercSpellListItr) { + ++mercSpellListItr) { // Assuming all the spells have been loaded into this list by level and in descending order - if(IsAENukeSpell(mercSpellListItr->spellid) && !IsAERainNukeSpell(mercSpellListItr->spellid) + if (IsAENukeSpell(mercSpellListItr->spellid) && !IsAERainNukeSpell(mercSpellListItr->spellid) && !IsPBAENukeSpell(mercSpellListItr->spellid) && CheckSpellRecastTimers(caster, mercSpellListItr->spellid)) { - uint8 numTargets = 0; - if(CheckAENuke(caster, tar, mercSpellListItr->spellid, numTargets)) { - if(numTargets >= numTargetsCheck && zone->random.Roll(castChance)) { - result.spellid = mercSpellListItr->spellid; - result.stance = mercSpellListItr->stance; - result.type = mercSpellListItr->type; - result.slot = mercSpellListItr->slot; - result.proc_chance = mercSpellListItr->proc_chance; - result.time_cancast = mercSpellListItr->time_cancast; - } + uint8 numTargets = 0; + if (CheckAENuke(caster, tar, mercSpellListItr->spellid, numTargets)) { + if (numTargets >= numTargetsCheck && zone->random.Roll(castChance)) { + result.spellid = mercSpellListItr->spellid; + result.stance = mercSpellListItr->stance; + result.type = mercSpellListItr->type; + result.slot = mercSpellListItr->slot; + result.proc_chance = mercSpellListItr->proc_chance; + result.time_cancast = mercSpellListItr->time_cancast; } + } - break; + break; } } } @@ -3751,7 +3758,7 @@ MercSpell Merc::GetBestMercSpellForPBAENuke(Merc* caster, Mob* tar) { result.proc_chance = 0; result.time_cancast = 0; - switch(caster->GetStance()) + switch (caster->GetStance()) { case EQ::constants::stanceBurnAE: numTargetsCheck = 2; @@ -3762,16 +3769,16 @@ MercSpell Merc::GetBestMercSpellForPBAENuke(Merc* caster, Mob* tar) { break; } - if(caster) { + if (caster) { std::list mercSpellList = GetMercSpellsBySpellType(caster, SpellType_Nuke); for (auto mercSpellListItr = mercSpellList.begin(); mercSpellListItr != mercSpellList.end(); - ++mercSpellListItr) { + ++mercSpellListItr) { // Assuming all the spells have been loaded into this list by level and in descending order - if(IsPBAENukeSpell(mercSpellListItr->spellid) && CheckSpellRecastTimers(caster, mercSpellListItr->spellid)) { + if (IsPBAENukeSpell(mercSpellListItr->spellid) && CheckSpellRecastTimers(caster, mercSpellListItr->spellid)) { uint8 numTargets = 0; - if(CheckAENuke(caster, caster, mercSpellListItr->spellid, numTargets)) { - if(numTargets >= numTargetsCheck && zone->random.Roll(castChance)) { + if (CheckAENuke(caster, caster, mercSpellListItr->spellid, numTargets)) { + if (numTargets >= numTargetsCheck && zone->random.Roll(castChance)) { result.spellid = mercSpellListItr->spellid; result.stance = mercSpellListItr->stance; result.type = mercSpellListItr->type; @@ -3802,7 +3809,7 @@ MercSpell Merc::GetBestMercSpellForAERainNuke(Merc* caster, Mob* tar) { result.proc_chance = 0; result.time_cancast = 0; - switch(caster->GetStance()) + switch (caster->GetStance()) { case EQ::constants::stanceBurnAE: numTargetsCheck = 1; @@ -3813,16 +3820,16 @@ MercSpell Merc::GetBestMercSpellForAERainNuke(Merc* caster, Mob* tar) { break; } - if(caster) { + if (caster) { std::list mercSpellList = GetMercSpellsBySpellType(caster, SpellType_Nuke); for (auto mercSpellListItr = mercSpellList.begin(); mercSpellListItr != mercSpellList.end(); - ++mercSpellListItr) { + ++mercSpellListItr) { // Assuming all the spells have been loaded into this list by level and in descending order - if(IsAERainNukeSpell(mercSpellListItr->spellid) && zone->random.Roll(castChance) && CheckSpellRecastTimers(caster, mercSpellListItr->spellid)) { + if (IsAERainNukeSpell(mercSpellListItr->spellid) && zone->random.Roll(castChance) && CheckSpellRecastTimers(caster, mercSpellListItr->spellid)) { uint8 numTargets = 0; - if(CheckAENuke(caster, tar, mercSpellListItr->spellid, numTargets)) { - if(numTargets >= numTargetsCheck) { + if (CheckAENuke(caster, tar, mercSpellListItr->spellid, numTargets)) { + if (numTargets >= numTargetsCheck) { result.spellid = mercSpellListItr->spellid; result.stance = mercSpellListItr->stance; result.type = mercSpellListItr->type; @@ -3852,22 +3859,22 @@ MercSpell Merc::GetBestMercSpellForNuke(Merc* caster) { result.proc_chance = 0; result.time_cancast = 0; - if(caster) { + if (caster) { std::list mercSpellList = GetMercSpellsBySpellType(caster, SpellType_Nuke); for (auto mercSpellListItr = mercSpellList.begin(); mercSpellListItr != mercSpellList.end(); - ++mercSpellListItr) { + ++mercSpellListItr) { // Assuming all the spells have been loaded into this list by level and in descending order - if(IsPureNukeSpell(mercSpellListItr->spellid) && !IsAENukeSpell(mercSpellListItr->spellid) + if (IsPureNukeSpell(mercSpellListItr->spellid) && !IsAENukeSpell(mercSpellListItr->spellid) && zone->random.Roll(castChance) && CheckSpellRecastTimers(caster, mercSpellListItr->spellid)) { - result.spellid = mercSpellListItr->spellid; - result.stance = mercSpellListItr->stance; - result.type = mercSpellListItr->type; - result.slot = mercSpellListItr->slot; - result.proc_chance = mercSpellListItr->proc_chance; - result.time_cancast = mercSpellListItr->time_cancast; + result.spellid = mercSpellListItr->spellid; + result.stance = mercSpellListItr->stance; + result.type = mercSpellListItr->type; + result.slot = mercSpellListItr->slot; + result.proc_chance = mercSpellListItr->proc_chance; + result.time_cancast = mercSpellListItr->time_cancast; - break; + break; } } } @@ -3886,39 +3893,39 @@ MercSpell Merc::GetBestMercSpellForNukeByTargetResists(Merc* caster, Mob* target result.proc_chance = 0; result.time_cancast = 0; - if(!target) + if (!target) return result; - if(caster) { + if (caster) { const int lureResisValue = -100; const int maxTargetResistValue = 300; bool selectLureNuke = false; - if((target->GetMR() > maxTargetResistValue) && (target->GetCR() > maxTargetResistValue) && (target->GetFR() > maxTargetResistValue)) + if ((target->GetMR() > maxTargetResistValue) && (target->GetCR() > maxTargetResistValue) && (target->GetFR() > maxTargetResistValue)) selectLureNuke = true; std::list mercSpellList = GetMercSpellsBySpellType(caster, SpellType_Nuke); for (auto mercSpellListItr = mercSpellList.begin(); mercSpellListItr != mercSpellList.end(); - ++mercSpellListItr) { + ++mercSpellListItr) { // Assuming all the spells have been loaded into this list by level and in descending order - if(IsPureNukeSpell(mercSpellListItr->spellid) && !IsAENukeSpell(mercSpellListItr->spellid) && CheckSpellRecastTimers(caster, mercSpellListItr->spellid)) { - if(selectLureNuke && (spells[mercSpellListItr->spellid].resist_difficulty < lureResisValue)) { + if (IsPureNukeSpell(mercSpellListItr->spellid) && !IsAENukeSpell(mercSpellListItr->spellid) && CheckSpellRecastTimers(caster, mercSpellListItr->spellid)) { + if (selectLureNuke && (spells[mercSpellListItr->spellid].resist_difficulty < lureResisValue)) { spellSelected = true; } else { - if(((target->GetMR() < target->GetCR()) || (target->GetMR() < target->GetFR())) && (GetSpellResistType(mercSpellListItr->spellid) == RESIST_MAGIC) + if (((target->GetMR() < target->GetCR()) || (target->GetMR() < target->GetFR())) && (GetSpellResistType(mercSpellListItr->spellid) == RESIST_MAGIC) && (spells[mercSpellListItr->spellid].resist_difficulty > lureResisValue)) { spellSelected = true; } - else if(((target->GetCR() < target->GetMR()) || (target->GetCR() < target->GetFR())) && (GetSpellResistType(mercSpellListItr->spellid) == RESIST_COLD) + else if (((target->GetCR() < target->GetMR()) || (target->GetCR() < target->GetFR())) && (GetSpellResistType(mercSpellListItr->spellid) == RESIST_COLD) && (spells[mercSpellListItr->spellid].resist_difficulty > lureResisValue)) { spellSelected = true; } - else if(((target->GetFR() < target->GetCR()) || (target->GetFR() < target->GetMR())) && (GetSpellResistType(mercSpellListItr->spellid) == RESIST_FIRE) + else if (((target->GetFR() < target->GetCR()) || (target->GetFR() < target->GetMR())) && (GetSpellResistType(mercSpellListItr->spellid) == RESIST_FIRE) && (spells[mercSpellListItr->spellid].resist_difficulty > lureResisValue)) { spellSelected = true; @@ -3926,7 +3933,7 @@ MercSpell Merc::GetBestMercSpellForNukeByTargetResists(Merc* caster, Mob* target } } - if(spellSelected) { + if (spellSelected) { result.spellid = mercSpellListItr->spellid; result.stance = mercSpellListItr->stance; result.type = mercSpellListItr->type; @@ -3942,21 +3949,21 @@ MercSpell Merc::GetBestMercSpellForNukeByTargetResists(Merc* caster, Mob* target return result; } -bool Merc::GetNeedsCured(Mob *tar) { +bool Merc::GetNeedsCured(Mob* tar) { bool needCured = false; - if(tar) { - if(tar->FindType(SE_PoisonCounter) || tar->FindType(SE_DiseaseCounter) || tar->FindType(SE_CurseCounter) || tar->FindType(SE_CorruptionCounter)) { + if (tar) { + if (tar->FindType(SE_PoisonCounter) || tar->FindType(SE_DiseaseCounter) || tar->FindType(SE_CurseCounter) || tar->FindType(SE_CorruptionCounter)) { uint32 buff_count = tar->GetMaxTotalSlots(); int buffsWithCounters = 0; needCured = true; for (unsigned int j = 0; j < buff_count; j++) { - if(tar->GetBuffs()[j].spellid != SPELL_UNKNOWN) { - if(CalculateCounters(tar->GetBuffs()[j].spellid) > 0) { + if (tar->GetBuffs()[j].spellid != SPELL_UNKNOWN) { + if (CalculateCounters(tar->GetBuffs()[j].spellid) > 0) { buffsWithCounters++; - if(buffsWithCounters == 1 && (tar->GetBuffs()[j].ticsremaining < 2 || (int32)((tar->GetBuffs()[j].ticsremaining * 6) / tar->GetBuffs()[j].counters) < 2)) { + if (buffsWithCounters == 1 && (tar->GetBuffs()[j].ticsremaining < 2 || (int32)((tar->GetBuffs()[j].ticsremaining * 6) / tar->GetBuffs()[j].counters) < 2)) { // Spell has ticks remaining but may have too many counters to cure in the time remaining; // We should try to just wait it out. Could spend entire time trying to cure spell instead of healing, buffing, etc. // Since this is the first buff with counters, don't try to cure. Cure spell will be wasted, as cure will try to @@ -3973,7 +3980,7 @@ bool Merc::GetNeedsCured(Mob *tar) { return needCured; } -void Merc::MercGroupSay(Mob *speaker, const char *msg, ...) +void Merc::MercGroupSay(Mob* speaker, const char* msg, ...) { char buf[1000]; @@ -3983,10 +3990,10 @@ void Merc::MercGroupSay(Mob *speaker, const char *msg, ...) vsnprintf(buf, 1000, msg, ap); va_end(ap); - if(speaker->HasGroup()) { - Group *g = speaker->GetGroup(); + if (speaker->HasGroup()) { + Group* g = speaker->GetGroup(); - if(g) + if (g) g->GroupMessage(speaker->CastToMob(), 0, 100, buf); } } @@ -3999,16 +4006,16 @@ bool Merc::UseDiscipline(int32 spell_id, int32 target) { } //make sure we can use it.. - if(!IsValidSpell(spell_id)) { + if (!IsValidSpell(spell_id)) { return(false); } - const SPDat_Spell_Struct &spell = spells[spell_id]; + const SPDat_Spell_Struct& spell = spells[spell_id]; - if(spell.recast_time > 0) + if (spell.recast_time > 0) { - if(CheckDisciplineRecastTimers(this, spell_id, spells[spell_id].timer_id)) { - if(spells[spell_id].timer_id > 0) { + if (CheckDisciplineRecastTimers(this, spell_id, spells[spell_id].timer_id)) { + if (spells[spell_id].timer_id > 0) { SetDisciplineRecastTimer(spells[spell_id].timer_id, spell_id, spell.recast_time); } @@ -4019,14 +4026,15 @@ bool Merc::UseDiscipline(int32 spell_id, int32 target) { } } - if(GetEndurance() > spell.endurance_cost) { + if (GetEndurance() > spell.endurance_cost) { SetEndurance(GetEndurance() - spell.endurance_cost); - } else { + } + else { //too fatigued to use this skill right now. return(false); } - if(IsCasting()) + if (IsCasting()) InterruptSpell(); CastSpell(spell_id, target, EQ::spells::CastingSlot::Discipline); @@ -4035,7 +4043,7 @@ bool Merc::UseDiscipline(int32 spell_id, int32 target) { } void Merc::SetSpellRecastTimer(uint16 timer_id, uint16 spellid, uint32 recast_delay) { - if(timer_id > 0) { + if (timer_id > 0) { MercTimer timer; timer.timerid = timer_id; timer.timertype = 1; @@ -4045,21 +4053,21 @@ void Merc::SetSpellRecastTimer(uint16 timer_id, uint16 spellid, uint32 recast_de } } -int32 Merc::GetSpellRecastTimer(Merc *caster, uint16 timer_id) { +int32 Merc::GetSpellRecastTimer(Merc* caster, uint16 timer_id) { int32 result = 0; - if(caster && timer_id > 0) { - if(caster->timers.find(timer_id) != caster->timers.end()) { + if (caster && timer_id > 0) { + if (caster->timers.find(timer_id) != caster->timers.end()) { result = caster->timers[timer_id].time_cancast; } } return result; } -bool Merc::CheckSpellRecastTimers(Merc *caster, uint16 spell_id) { - if(caster) { +bool Merc::CheckSpellRecastTimers(Merc* caster, uint16 spell_id) { + if (caster) { MercSpell mercSpell = GetMercSpellBySpellID(caster, spell_id); - if(mercSpell.spellid > 0 && mercSpell.time_cancast < Timer::GetCurrentTime()) { //checks spell recast - if(GetSpellRecastTimer(caster, spells[spell_id].timer_id) < Timer::GetCurrentTime()) { //checks for spells on the same timer + if (mercSpell.spellid > 0 && mercSpell.time_cancast < Timer::GetCurrentTime()) { //checks spell recast + if (GetSpellRecastTimer(caster, spells[spell_id].timer_id) < Timer::GetCurrentTime()) { //checks for spells on the same timer return true; //can cast spell } } @@ -4068,7 +4076,7 @@ bool Merc::CheckSpellRecastTimers(Merc *caster, uint16 spell_id) { } void Merc::SetDisciplineRecastTimer(uint16 timer_id, uint16 spellid, uint32 recast_delay) { - if(timer_id > 0) { + if (timer_id > 0) { MercTimer timer; timer.timerid = timer_id; timer.timertype = 2; @@ -4078,31 +4086,31 @@ void Merc::SetDisciplineRecastTimer(uint16 timer_id, uint16 spellid, uint32 reca } } -int32 Merc::GetDisciplineRecastTimer(Merc *caster, uint16 timer_id) { +int32 Merc::GetDisciplineRecastTimer(Merc* caster, uint16 timer_id) { int32 result = 0; - if(caster && timer_id > 0) { - if(caster->timers.find(timer_id) != caster->timers.end()) { + if (caster && timer_id > 0) { + if (caster->timers.find(timer_id) != caster->timers.end()) { result = caster->timers[timer_id].time_cancast; } } return result; } -int32 Merc::GetDisciplineRemainingTime(Merc *caster, uint16 timer_id) { +int32 Merc::GetDisciplineRemainingTime(Merc* caster, uint16 timer_id) { int32 result = 0; - if(caster && timer_id > 0) { + if (caster && timer_id > 0) { int32 time_cancast = GetDisciplineRecastTimer(caster, timer_id); - if(time_cancast > Timer::GetCurrentTime()) + if (time_cancast > Timer::GetCurrentTime()) result = time_cancast - Timer::GetCurrentTime(); } return result; } -bool Merc::CheckDisciplineRecastTimers(Merc *caster, uint16 spell_id, uint16 timer_id) { - if(caster) { +bool Merc::CheckDisciplineRecastTimers(Merc* caster, uint16 spell_id, uint16 timer_id) { + if (caster) { MercSpell mercSpell = GetMercSpellBySpellID(caster, spell_id); - if(mercSpell.spellid > 0 && mercSpell.time_cancast < Timer::GetCurrentTime()) { //checks spell recast - if(timer_id > 0 && !(GetDisciplineRecastTimer(caster, timer_id) < Timer::GetCurrentTime())) { //checks for spells on the same timer + if (mercSpell.spellid > 0 && mercSpell.time_cancast < Timer::GetCurrentTime()) { //checks spell recast + if (timer_id > 0 && !(GetDisciplineRecastTimer(caster, timer_id) < Timer::GetCurrentTime())) { //checks for spells on the same timer return false; //can't cast spell } return true; @@ -4113,7 +4121,7 @@ bool Merc::CheckDisciplineRecastTimers(Merc *caster, uint16 spell_id, uint16 tim void Merc::SetSpellTimeCanCast(uint16 spellid, uint32 recast_delay) { for (int i = 0; i < merc_spells.size(); i++) { - if(merc_spells[i].spellid == spellid) { + if (merc_spells[i].spellid == spellid) { merc_spells[i].time_cancast = Timer::GetCurrentTime() + recast_delay; } } @@ -4123,7 +4131,7 @@ bool Merc::CheckTaunt() { Mob* tar = GetTarget(); //Only taunt if we are not top on target's hate list //This ensures we have taunt available to regain aggro if needed - if(tar && tar->GetHateTop() && tar->GetHateTop() != this) { + if (tar && tar->GetHateTop() && tar->GetHateTop() != this) { return true; } return false; @@ -4134,7 +4142,7 @@ bool Merc::CheckAETaunt() { MercSpell mercSpell = GetBestMercSpellForAETaunt(this); uint8 result = 0; - if(mercSpell.spellid != 0) { + if (mercSpell.spellid != 0) { std::list npc_list; entity_list.GetNPCList(npc_list); @@ -4145,15 +4153,15 @@ bool Merc::CheckAETaunt() { int range = GetActSpellRange(mercSpell.spellid, spells[mercSpell.spellid].range); range *= range; - if(dist <= range) { - if(!npc->IsMezzed()) { - if(HasGroup()) { + if (dist <= range) { + if (!npc->IsMezzed()) { + if (HasGroup()) { Group* g = GetGroup(); - if(g) { - for(int i = 0; i < g->GroupCount(); i++) { + if (g) { + for (int i = 0; i < g->GroupCount(); i++) { //if(npc->IsOnHatelist(g->members[i]) && g->members[i]->GetTarget() != npc && g->members[i]->IsEngaged()) { - if(GetTarget() != npc && g->members[i] && g->members[i]->GetTarget() != npc && npc->IsOnHatelist(g->members[i])) { + if (GetTarget() != npc && g->members[i] && g->members[i]->GetTarget() != npc && npc->IsOnHatelist(g->members[i])) { result++; } } @@ -4163,7 +4171,7 @@ bool Merc::CheckAETaunt() { } } - if(result >= 1) { + if (result >= 1) { Log(Logs::General, Logs::Mercenaries, "%s: Attempting AE Taunt", GetCleanName()); return true; } @@ -4174,15 +4182,15 @@ bool Merc::CheckAETaunt() { Corpse* Merc::GetGroupMemberCorpse() { Corpse* corpse = nullptr; - if(HasGroup()) { + if (HasGroup()) { Group* g = GetGroup(); - if(g) { - for(int i = 0; i < g->GroupCount(); i++) { - if(g->members[i] && g->members[i]->IsClient()) { + if (g) { + for (int i = 0; i < g->GroupCount(); i++) { + if (g->members[i] && g->members[i]->IsClient()) { corpse = entity_list.GetCorpseByOwnerWithinRange(g->members[i]->CastToClient(), this, RuleI(Mercs, ResurrectRadius)); - if(corpse && !corpse->IsRezzed()) { + if (corpse && !corpse->IsRezzed()) { return corpse; } } @@ -4193,12 +4201,12 @@ Corpse* Merc::GetGroupMemberCorpse() { } bool Merc::TryHide() { - if(GetClass() != MELEEDPS) { + if (GetClass() != MELEEDPS) { return false; } //don't hide if already hidden - if(hidden == true) { + if (hidden == true) { return false; } @@ -4229,13 +4237,13 @@ bool Merc::CheckConfidence() { float ConRating = 1.0; int CurrentCon = 0; - if(!mob) continue; + if (!mob) continue; - if(!mob->IsEngaged()) continue; + if (!mob->IsEngaged()) continue; - if(mob->IsFeared() || mob->IsMezzed() || mob->IsStunned() || mob->IsRooted() || mob->IsCharmed()) continue; + if (mob->IsFeared() || mob->IsMezzed() || mob->IsStunned() || mob->IsRooted() || mob->IsCharmed()) continue; - if(!mob->CheckAggro(this)) continue; + if (!mob->CheckAggro(this)) continue; float AggroRange = mob->GetAggroRange(); @@ -4243,61 +4251,61 @@ bool Merc::CheckConfidence() { AggroRange = AggroRange * AggroRange; - if(DistanceSquared(m_Position, mob->GetPosition()) > AggroRange) continue; + if (DistanceSquared(m_Position, mob->GetPosition()) > AggroRange) continue; CurrentCon = this->GetLevelCon(mob->GetLevel()); - switch(CurrentCon) { + switch (CurrentCon) { - case CON_GRAY: { - ConRating = 0; - break; - } + case CON_GRAY: { + ConRating = 0; + break; + } - case CON_GREEN: { - ConRating = 0.1; - break; - } + case CON_GREEN: { + ConRating = 0.1; + break; + } - case CON_LIGHTBLUE: { - ConRating = 0.2; - break; - } + case CON_LIGHTBLUE: { + ConRating = 0.2; + break; + } - case CON_BLUE: { - ConRating = 0.6; - break; - } + case CON_BLUE: { + ConRating = 0.6; + break; + } - case CON_WHITE: { - ConRating = 1.0; - break; - } + case CON_WHITE: { + ConRating = 1.0; + break; + } - case CON_YELLOW: { - ConRating = 1.2; - break; - } + case CON_YELLOW: { + ConRating = 1.2; + break; + } - case CON_RED: { - ConRating = 1.5; - break; - } + case CON_RED: { + ConRating = 1.5; + break; + } - default: { - ConRating = 0; - break; - } + default: { + ConRating = 0; + break; + } } ConfidenceCheck += ConRating; } - if(ConfidenceRating < ConfidenceCheck) { - ConfidenceLossChance = 25 - ( 5 * (GetTierID() - 1)); + if (ConfidenceRating < ConfidenceCheck) { + ConfidenceLossChance = 25 - (5 * (GetTierID() - 1)); } - if(zone->random.Roll(ConfidenceLossChance)) { + if (zone->random.Roll(ConfidenceLossChance)) { result = false; } @@ -4310,27 +4318,27 @@ void Merc::MercMeditate(bool isSitting) { { return; } - if(isSitting) { + if (isSitting) { // If the merc is a caster and has less than 99% mana while its not engaged, he needs to sit to meditate - if(GetManaRatio() < 99.0f) + if (GetManaRatio() < 99.0f) { - if(!IsSitting()) + if (!IsSitting()) Sit(); } else { - if(IsSitting()) + if (IsSitting()) Stand(); } } else { - if(IsSitting()) + if (IsSitting()) Stand(); } - if(IsSitting()) { - if(!rest_timer.Enabled()) { + if (IsSitting()) { + if (!rest_timer.Enabled()) { rest_timer.Start(RuleI(Character, RestRegenTimeToActivate) * 1000); } } @@ -4341,7 +4349,7 @@ void Merc::MercMeditate(bool isSitting) { void Merc::Sit() { - if(IsMoving()) { + if (IsMoving()) { moved = false; // SetHeading(CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY())); SentPositionPacket(0.0f, 0.0f, 0.0f, 0.0f, 0); @@ -4358,7 +4366,7 @@ void Merc::Stand() { bool Merc::IsSitting() { bool result = false; - if(GetAppearance() == eaSitting && !IsMoving()) + if (GetAppearance() == eaSitting && !IsMoving()) result = true; return result; @@ -4367,7 +4375,7 @@ bool Merc::IsSitting() { bool Merc::IsStanding() { bool result = false; - if(GetAppearance() == eaStanding) + if (GetAppearance() == eaStanding) result = true; return result; @@ -4376,16 +4384,16 @@ bool Merc::IsStanding() { float Merc::GetMaxMeleeRangeToTarget(Mob* target) { float result = 0; - if(target) { + if (target) { float size_mod = GetSize(); float other_size_mod = target->GetSize(); - if(GetRace() == 49 || GetRace() == 158 || GetRace() == 196) //For races with a fixed size + if (GetRace() == 49 || GetRace() == 158 || GetRace() == 196) //For races with a fixed size size_mod = 60.0f; else if (size_mod < 6.0) size_mod = 8.0f; - if(target->GetRace() == 49 || target->GetRace() == 158 || target->GetRace() == 196) //For races with a fixed size + if (target->GetRace() == 49 || target->GetRace() == 158 || target->GetRace() == 196) //For races with a fixed size other_size_mod = 60.0f; else if (other_size_mod < 6.0) other_size_mod = 8.0f; @@ -4413,17 +4421,17 @@ float Merc::GetMaxMeleeRangeToTarget(Mob* target) { return result; } -void Merc::DoClassAttacks(Mob *target) { - if(target == nullptr) +void Merc::DoClassAttacks(Mob* target) { + if (target == nullptr) return; //gotta have a target for all these bool ca_time = classattack_timer.Check(false); //only check attack allowed if we are going to do something - if(ca_time && !IsAttackAllowed(target)) + if (ca_time && !IsAttackAllowed(target)) return; - if(!ca_time) + if (!ca_time) return; float HasteModifier = GetHaste() * 0.01f; @@ -4432,49 +4440,49 @@ void Merc::DoClassAttacks(Mob *target) { int reuse = TauntReuseTime * 1000; //make this very long since if they dont use it once, they prolly never will bool did_attack = false; //class specific stuff... - switch(GetClass()) { - case MELEEDPS: - if(level >= 10) { - reuse = BackstabReuseTime * 1000; - TryBackstab(target, reuse); - did_attack = true; - } - break; - case TANK:{ - if(level >= RuleI(Combat, NPCBashKickLevel)){ - if(zone->random.Int(0, 100) > 25) //tested on live, warrior mobs both kick and bash, kick about 75% of the time, casting doesn't seem to make a difference. - { - DoAnim(animKick, 0, false); - int32 dmg = GetBaseSkillDamage(EQ::skills::SkillKick); + switch (GetClass()) { + case MELEEDPS: + if (level >= 10) { + reuse = BackstabReuseTime * 1000; + TryBackstab(target, reuse); + did_attack = true; + } + break; + case TANK: { + if (level >= RuleI(Combat, NPCBashKickLevel)) { + if (zone->random.Int(0, 100) > 25) //tested on live, warrior mobs both kick and bash, kick about 75% of the time, casting doesn't seem to make a difference. + { + DoAnim(animKick, 0, false); + int32 dmg = GetBaseSkillDamage(EQ::skills::SkillKick); - if (GetWeaponDamage(target, (const EQ::ItemData*)nullptr) <= 0) - dmg = DMG_INVULNERABLE; + if (GetWeaponDamage(target, (const EQ::ItemData*)nullptr) <= 0) + dmg = DMG_INVULNERABLE; - reuse = KickReuseTime * 1000; - DoSpecialAttackDamage(target, EQ::skills::SkillKick, dmg, 1, -1, reuse); - did_attack = true; - } - else - { - DoAnim(animTailRake, 0, false); - int32 dmg = GetBaseSkillDamage(EQ::skills::SkillBash); + reuse = KickReuseTime * 1000; + DoSpecialAttackDamage(target, EQ::skills::SkillKick, dmg, 1, -1, reuse); + did_attack = true; + } + else + { + DoAnim(animTailRake, 0, false); + int32 dmg = GetBaseSkillDamage(EQ::skills::SkillBash); - if (GetWeaponDamage(target, (const EQ::ItemData*)nullptr) <= 0) - dmg = DMG_INVULNERABLE; + if (GetWeaponDamage(target, (const EQ::ItemData*)nullptr) <= 0) + dmg = DMG_INVULNERABLE; - reuse = BashReuseTime * 1000; - DoSpecialAttackDamage(target, EQ::skills::SkillBash, dmg, 1, -1, reuse); - did_attack = true; - } - } - break; - } + reuse = BashReuseTime * 1000; + DoSpecialAttackDamage(target, EQ::skills::SkillBash, dmg, 1, -1, reuse); + did_attack = true; + } + } + break; + } } classattack_timer.Start(reuse / HasteModifier); } -bool Merc::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, bool IsFromSpell, ExtraAttackOptions *opts) +bool Merc::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, bool IsFromSpell, ExtraAttackOptions* opts) { if (!other) { SetTarget(nullptr); @@ -4487,10 +4495,10 @@ bool Merc::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, boo void Merc::Damage(Mob* other, int32 damage, uint16 spell_id, EQ::skills::SkillType attack_skill, bool avoidable, int8 buffslot, bool iBuffTic, eSpecialAttacks special) { - if(IsDead() || IsCorpse()) + if (IsDead() || IsCorpse()) return; - if(spell_id==0) + if (spell_id == 0) spell_id = SPELL_UNKNOWN; NPC::Damage(other, damage, spell_id, attack_skill, avoidable, buffslot, iBuffTic, special); @@ -4503,7 +4511,7 @@ bool Merc::FindTarget() { bool found = false; Mob* target = GetHateTop(); - if(target) { + if (target) { found = true; SetTarget(target); } @@ -4518,7 +4526,7 @@ void Merc::SetTarget(Mob* mob) { Mob* Merc::GetOwnerOrSelf() { Mob* Result = nullptr; - if(this->GetMercOwner()) + if (this->GetMercOwner()) Result = GetMercOwner(); else Result = this; @@ -4528,7 +4536,7 @@ Mob* Merc::GetOwnerOrSelf() { bool Merc::Death(Mob* killerMob, int32 damage, uint16 spell, EQ::skills::SkillType attack_skill) { - if(!NPC::Death(killerMob, damage, spell, attack_skill)) + if (!NPC::Death(killerMob, damage, spell, attack_skill)) { return false; } @@ -4553,9 +4561,9 @@ bool Merc::Death(Mob* killerMob, int32 damage, uint16 spell, EQ::skills::SkillTy Client* Merc::GetMercOwner() { Client* mercOwner = nullptr; - if(GetOwner()) + if (GetOwner()) { - if(GetOwner()->IsClient()) + if (GetOwner()->IsClient()) { mercOwner = GetOwner()->CastToClient(); } @@ -4569,93 +4577,93 @@ Mob* Merc::GetOwner() { Result = entity_list.GetMob(GetOwnerID()); - if(!Result) { + if (!Result) { this->SetOwnerID(0); } return Result->CastToMob(); } -const char* Merc::GetRandomName(){ +const char* Merc::GetRandomName() { // creates up to a 10 char name static char name[17]; - char vowels[18]="aeiouyaeiouaeioe"; - char cons[48]="bcdfghjklmnpqrstvwxzybcdgklmnprstvwbcdgkpstrkd"; - char rndname[17]="\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; - char paircons[33]="ngrkndstshthphsktrdrbrgrfrclcr"; + char vowels[18] = "aeiouyaeiouaeioe"; + char cons[48] = "bcdfghjklmnpqrstvwxzybcdgklmnprstvwbcdgkpstrkd"; + char rndname[17] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; + char paircons[33] = "ngrkndstshthphsktrdrbrgrfrclcr"; bool valid = false; - while(!valid) { - int rndnum=zone->random.Int(0, 75),n=1; - bool dlc=false; - bool vwl=false; - bool dbl=false; - if (rndnum>63) + while (!valid) { + int rndnum = zone->random.Int(0, 75), n = 1; + bool dlc = false; + bool vwl = false; + bool dbl = false; + if (rndnum > 63) { // rndnum is 0 - 75 where 64-75 is cons pair, 17-63 is cons, 0-16 is vowel - rndnum=(rndnum-61)*2; // name can't start with "ng" "nd" or "rk" - rndname[0]=paircons[rndnum]; - rndname[1]=paircons[rndnum+1]; - n=2; + rndnum = (rndnum - 61) * 2; // name can't start with "ng" "nd" or "rk" + rndname[0] = paircons[rndnum]; + rndname[1] = paircons[rndnum + 1]; + n = 2; } - else if (rndnum>16) + else if (rndnum > 16) { - rndnum-=17; - rndname[0]=cons[rndnum]; + rndnum -= 17; + rndname[0] = cons[rndnum]; } else { - rndname[0]=vowels[rndnum]; - vwl=true; + rndname[0] = vowels[rndnum]; + vwl = true; } - int namlen=zone->random.Int(5, 10); - for (int i=n;irandom.Int(5, 10); + for (int i = n; i < namlen; i++) { - dlc=false; + dlc = false; if (vwl) //last char was a vowel { // so pick a cons or cons pair - rndnum=zone->random.Int(0, 62); - if (rndnum>46) + rndnum = zone->random.Int(0, 62); + if (rndnum > 46) { // pick a cons pair - if (i>namlen-3) // last 2 chars in name? + if (i > namlen - 3) // last 2 chars in name? { // name can only end in cons pair "rk" "st" "sh" "th" "ph" "sk" "nd" or "ng" - rndnum=zone->random.Int(0, 7)*2; + rndnum = zone->random.Int(0, 7) * 2; } else { // pick any from the set - rndnum=(rndnum-47)*2; + rndnum = (rndnum - 47) * 2; } - rndname[i]=paircons[rndnum]; - rndname[i+1]=paircons[rndnum+1]; - dlc=true; // flag keeps second letter from being doubled below - i+=1; + rndname[i] = paircons[rndnum]; + rndname[i + 1] = paircons[rndnum + 1]; + dlc = true; // flag keeps second letter from being doubled below + i += 1; } else { // select a single cons - rndname[i]=cons[rndnum]; + rndname[i] = cons[rndnum]; } } else { // select a vowel - rndname[i]=vowels[zone->random.Int(0, 16)]; + rndname[i] = vowels[zone->random.Int(0, 16)]; } - vwl=!vwl; + vwl = !vwl; if (!dbl && !dlc) { // one chance at double letters in name - if (!zone->random.Int(0, i+9)) // chances decrease towards end of name + if (!zone->random.Int(0, i + 9)) // chances decrease towards end of name { - rndname[i+1]=rndname[i]; - dbl=true; - i+=1; + rndname[i + 1] = rndname[i]; + dbl = true; + i += 1; } } } - rndname[0]=toupper(rndname[0]); + rndname[0] = toupper(rndname[0]); - if(!database.CheckNameFilter(rndname)) { + if (!database.CheckNameFilter(rndname)) { valid = false; } - else if(rndname[0] < 'A' && rndname[0] > 'Z') { + else if (rndname[0] < 'A' && rndname[0] > 'Z') { //name must begin with an upper-case letter. valid = false; } @@ -4700,7 +4708,7 @@ bool Merc::LoadMercSpells() { merc_spells.push_back(mercSpell); - if(mercSpellEntryItr->proc_chance > 0) + if (mercSpellEntryItr->proc_chance > 0) AddProcToWeapon(mercSpellEntryItr->spellid, true, mercSpellEntryItr->proc_chance); } } @@ -4720,37 +4728,37 @@ bool Merc::LoadMercSpells() { bool Merc::Save() { - if(database.SaveMerc(this)){ + if (database.SaveMerc(this)) { return true; } return false; } -Merc* Merc::LoadMerc(Client *c, MercTemplate* merc_template, uint32 merchant_id, bool updateFromDB) { +Merc* Merc::LoadMerc(Client* c, MercTemplate* merc_template, uint32 merchant_id, bool updateFromDB) { - if(c) + if (c) { - if(c->GetMercID()) + if (c->GetMercID()) { merc_template = zone->GetMercTemplate(c->GetMercInfo().MercTemplateID); } } //get mercenary data - if(merc_template) + if (merc_template) { //TODO: Maybe add a way of updating client merc stats in a seperate function? like, for example, on leveling up. const NPCType* npc_type_to_copy = content_db.GetMercType(merc_template->MercNPCID, merc_template->RaceID, c->GetLevel()); - if(npc_type_to_copy != nullptr) + if (npc_type_to_copy != nullptr) { //This is actually a very terrible method of assigning stats, and should be changed at some point. See the comment in merc's deconstructor. auto npc_type = new NPCType; memset(npc_type, 0, sizeof(NPCType)); memcpy(npc_type, npc_type_to_copy, sizeof(NPCType)); - if(c && !updateFromDB) + if (c && !updateFromDB) { - if(c->GetMercInfo().merc_name[0] == 0) + if (c->GetMercInfo().merc_name[0] == 0) { snprintf(c->GetMercInfo().merc_name, 64, "%s", GetRandomName()); //sanity check. } @@ -4762,10 +4770,10 @@ Merc* Merc::LoadMerc(Client *c, MercTemplate* merc_template, uint32 merchant_id, // Use the Gender and Size of the Merchant if possible uint8 tmpgender = 0; float tmpsize = 6.0f; - if(merchant_id > 0) + if (merchant_id > 0) { NPC* tar = entity_list.GetNPCByID(merchant_id); - if(tar) + if (tar) { tmpgender = tar->GetGender(); tmpsize = tar->GetSize(); @@ -4799,13 +4807,13 @@ Merc* Merc::LoadMerc(Client *c, MercTemplate* merc_template, uint32 merchant_id, auto merc = new Merc(npc_type, c->GetX(), c->GetY(), c->GetZ(), 0); merc->GiveNPCTypeData(npc_type); // for clean up, works a bit like pets - if(merc) + if (merc) { - merc->SetMercData( merc_template->MercTemplateID ); + merc->SetMercData(merc_template->MercTemplateID); database.LoadMercEquipment(merc); merc->UpdateMercStats(c, true); - if(updateFromDB) + if (updateFromDB) { database.LoadCurrentMerc(c); @@ -4834,7 +4842,7 @@ Merc* Merc::LoadMerc(Client *c, MercTemplate* merc_template, uint32 merchant_id, merc->RandomizeFeatures(false, true); } - if(merc->GetMercID()) { + if (merc->GetMercID()) { database.LoadMercBuffs(merc); } @@ -4849,7 +4857,7 @@ Merc* Merc::LoadMerc(Client *c, MercTemplate* merc_template, uint32 merchant_id, return 0; } -void Merc::UpdateMercInfo(Client *c) { +void Merc::UpdateMercInfo(Client* c) { snprintf(c->GetMercInfo().merc_name, 64, "%s", name); c->GetMercInfo().mercid = GetMercID(); c->GetMercInfo().IsSuspended = IsSuspended(); @@ -4870,13 +4878,13 @@ void Merc::UpdateMercInfo(Client *c) { c->GetMercInfo().drakkinDetails = drakkin_details; } -void Merc::UpdateMercStats(Client *c, bool setmax) +void Merc::UpdateMercStats(Client* c, bool setmax) { if (c->GetMercInfo().MercTemplateID > 0) { Log(Logs::General, Logs::Mercenaries, "Updating Mercenary Stats for %s (%s).", GetName(), c->GetName()); - const NPCType *npc_type = content_db.GetMercType( - zone->GetMercTemplate(c->GetMercInfo().MercTemplateID)->MercNPCID, GetRace(), c->GetLevel()); + const NPCType* npc_type = content_db.GetMercType( + zone->GetMercTemplate(c->GetMercInfo().MercTemplateID)->MercNPCID, GetRace(), c->GetLevel()); if (npc_type) { max_hp = npc_type->max_hp; base_hp = npc_type->max_hp; @@ -5054,7 +5062,7 @@ void Merc::UpdateMercAppearance() { uint8 materialFromSlot = EQ::textures::materialInvalid; for (int i = EQ::invslot::EQUIPMENT_BEGIN; i <= EQ::invslot::EQUIPMENT_END; ++i) { itemID = equipment[i]; - if(itemID != 0) { + if (itemID != 0) { materialFromSlot = EQ::InventoryProfile::CalcMaterialFromSlot(i); if (materialFromSlot != EQ::textures::materialInvalid) this->SendWearChange(materialFromSlot); @@ -5105,14 +5113,14 @@ void Merc::AddItem(uint8 slot, uint32 item_id) { UpdateEquipmentLight(); } -bool Merc::Spawn(Client *owner) { +bool Merc::Spawn(Client* owner) { - if(!owner) + if (!owner) return false; MercTemplate* merc_template = zone->GetMercTemplate(GetMercTemplateID()); - if(!merc_template) + if (!merc_template) return false; entity_list.AddMerc(this, true, true); @@ -5271,17 +5279,17 @@ void Client::SendMercResponsePackets(uint32 ResponseType) void Client::UpdateMercTimer() { - Merc *merc = GetMerc(); + Merc* merc = GetMerc(); - if(merc && !merc->IsSuspended()) + if (merc && !merc->IsSuspended()) { - if(GetMercTimer()->Check()) + if (GetMercTimer()->Check()) { uint32 upkeep = merc->CalcUpkeepCost(merc->GetMercTemplateID(), GetLevel()); - if(CheckCanRetainMerc(upkeep)) + if (CheckCanRetainMerc(upkeep)) { - if(RuleB(Mercs, ChargeMercUpkeepCost)) + if (RuleB(Mercs, ChargeMercUpkeepCost)) { TakeMoneyFromPP((upkeep * 100), true); } @@ -5328,33 +5336,33 @@ bool Client::CheckCanHireMerc(Mob* merchant, uint32 template_id) { MercTemplate* mercTemplate = zone->GetMercTemplate(template_id); //check for suspended merc - if(GetMercInfo().mercid != 0 && GetMercInfo().IsSuspended) { + if (GetMercInfo().mercid != 0 && GetMercInfo().IsSuspended) { SendMercResponsePackets(6); return false; } // Check if max number of mercs is already reached - if(GetNumMercs() >= MAXMERCS) { + if (GetNumMercs() >= MAXMERCS) { SendMercResponsePackets(6); return false; } //check for valid merchant - if(!merchant) { + if (!merchant) { SendMercResponsePackets(17); return false; } //check for merchant too far away - if(DistanceSquared(m_Position, merchant->GetPosition()) > USE_NPC_RANGE2) { + if (DistanceSquared(m_Position, merchant->GetPosition()) > USE_NPC_RANGE2) { SendMercResponsePackets(18); return false; } //check for sufficient funds and remove them last - if(RuleB(Mercs, ChargeMercPurchaseCost)) { + if (RuleB(Mercs, ChargeMercPurchaseCost)) { uint32 cost = Merc::CalcPurchaseCost(template_id, GetLevel()) * 100; // Cost is in gold - if(cost > 0 && !HasMoney(cost)) { + if (cost > 0 && !HasMoney(cost)) { SendMercResponsePackets(1); return false; } @@ -5369,9 +5377,9 @@ bool Client::CheckCanRetainMerc(uint32 upkeep) { Merc* merc = GetMerc(); //check for sufficient funds - if(RuleB(Mercs, ChargeMercPurchaseCost)) { - if(merc) { - if(upkeep > 0 && !HasMoney(upkeep * 100)) { + if (RuleB(Mercs, ChargeMercPurchaseCost)) { + if (merc) { + if (upkeep > 0 && !HasMoney(upkeep * 100)) { SendMercResponsePackets(14); return false; } @@ -5384,13 +5392,13 @@ bool Client::CheckCanRetainMerc(uint32 upkeep) { bool Client::CheckCanSpawnMerc(uint32 template_id) { // Check if mercs are enabled globally - if(!RuleB(Mercs, AllowMercs)) + if (!RuleB(Mercs, AllowMercs)) { return false; } // Check if zone allows mercs - if(!zone->AllowMercs()) + if (!zone->AllowMercs()) { SendMercResponsePackets(3); return false; @@ -5399,35 +5407,35 @@ bool Client::CheckCanSpawnMerc(uint32 template_id) { MercTemplate* mercTemplate = zone->GetMercTemplate(template_id); // Invalid merc data - if(!mercTemplate) + if (!mercTemplate) { SendMercResponsePackets(11); return false; } // Check client version - if(static_cast(ClientVersion()) < mercTemplate->ClientVersion) + if (static_cast(ClientVersion()) < mercTemplate->ClientVersion) { SendMercResponsePackets(3); return false; } // Check for raid - if(HasRaid()) + if (HasRaid()) { SendMercResponsePackets(4); return false; } // Check group size - if(GetGroup() && GetGroup()->GroupCount() >= MAX_GROUP_MEMBERS) // database.GroupCount(GetGroup()->GetID()) + if (GetGroup() && GetGroup()->GroupCount() >= MAX_GROUP_MEMBERS) // database.GroupCount(GetGroup()->GetID()) { SendMercResponsePackets(8); return false; } // Check in combat - if(GetAggroCount() > 0) + if (GetAggroCount() > 0) { SendMercResponsePackets(9); return false; @@ -5447,7 +5455,7 @@ bool Client::CheckCanUnsuspendMerc() { MercTemplate* mercTemplate = zone->GetMercTemplate(GetMercInfo().MercTemplateID); - if(!GetPTimers().Expired(&database, pTimerMercSuspend, false)) + if (!GetPTimers().Expired(&database, pTimerMercSuspend, false)) { SendMercResponsePackets(10); //TODO: find this packet response and tell them properly. @@ -5462,7 +5470,7 @@ bool Client::CheckCanUnsuspendMerc() { void Client::CheckMercSuspendTimer() { - if(GetMercInfo().SuspendedTime != 0) + if (GetMercInfo().SuspendedTime != 0) { //if(time(nullptr) >= GetMercInfo().SuspendedTime) if (p_timers.Expired(&database, pTimerMercSuspend, false)) @@ -5477,11 +5485,11 @@ void Client::CheckMercSuspendTimer() { void Client::SuspendMercCommand() { - if(GetMercInfo().MercTemplateID != 0) + if (GetMercInfo().MercTemplateID != 0) { - if(GetMercInfo().IsSuspended) + if (GetMercInfo().IsSuspended) { - if(!CheckCanUnsuspendMerc()) + if (!CheckCanUnsuspendMerc()) { Log(Logs::General, Logs::Mercenaries, "SuspendMercCommand Unable to Unsuspend Merc for %s.", GetName()); @@ -5490,7 +5498,7 @@ void Client::SuspendMercCommand() { // Get merc, assign it to client & spawn Merc* merc = Merc::LoadMerc(this, &zone->merc_templates[GetMercInfo().MercTemplateID], 0, true); - if(merc) + if (merc) { SpawnMerc(merc, false); Log(Logs::General, Logs::Mercenaries, "SuspendMercCommand Successful Unsuspend for %s.", GetName()); @@ -5515,7 +5523,7 @@ void Client::SuspendMercCommand() { } } - if(CurrentMerc && GetMercID()) + if (CurrentMerc && GetMercID()) { CurrentMerc->Suspend(); Log(Logs::General, Logs::Mercenaries, "SuspendMercCommand Successful Suspend for %s.", GetName()); @@ -5545,7 +5553,7 @@ void Client::SuspendMercCommand() { // Handles all client zone change event void Merc::ProcessClientZoneChange(Client* mercOwner) { - if(mercOwner) + if (mercOwner) { Zone(); } @@ -5553,20 +5561,20 @@ void Merc::ProcessClientZoneChange(Client* mercOwner) { void Client::SpawnMercOnZone() { - if(!RuleB(Mercs, AllowMercs)) + if (!RuleB(Mercs, AllowMercs)) return; if (GetMerc()) return; - if(database.LoadMercInfo(this)) + if (database.LoadMercInfo(this)) { - if(!GetMercInfo().IsSuspended) + if (!GetMercInfo().IsSuspended) { GetMercInfo().SuspendedTime = 0; // Get merc, assign it to client & spawn Merc* merc = Merc::LoadMerc(this, &zone->merc_templates[GetMercInfo().MercTemplateID], 0, true); - if(merc) + if (merc) { SpawnMerc(merc, false); } @@ -5650,7 +5658,7 @@ bool Merc::Suspend() { Client* mercOwner = GetMercOwner(); - if(!mercOwner) + if (!mercOwner) return false; SetSuspended(true); @@ -5697,14 +5705,14 @@ bool Merc::Unsuspend(bool setMaxStats) { Client* mercOwner = nullptr; - if(GetMercOwner()) { + if (GetMercOwner()) { mercOwner = GetMercOwner(); } - if(!mercOwner) + if (!mercOwner) return false; - if(GetID()) + if (GetID()) { // Set time remaining to max on unsuspend - there is a charge for unsuspending as well SetSuspended(false); @@ -5720,12 +5728,12 @@ bool Merc::Unsuspend(bool setMaxStats) { mercOwner->GetMercTimer()->Start(RuleI(Mercs, UpkeepIntervalMS)); //mercOwner->GetMercTimer()->SetTimer(mercOwner->GetMercInfo().MercTimerRemaining); mercOwner->SendMercTimer(this); - if(!mercOwner->GetPTimers().Expired(&database, pTimerMercSuspend, false)) + if (!mercOwner->GetPTimers().Expired(&database, pTimerMercSuspend, false)) mercOwner->GetPTimers().Clear(&database, pTimerMercSuspend); if (MercJoinClientGroup()) { - if(setMaxStats) + if (setMaxStats) { SetHP(GetMaxHP()); SetMana(GetMaxMana()); @@ -5733,10 +5741,10 @@ bool Merc::Unsuspend(bool setMaxStats) { } //check for sufficient funds and remove them last - if(RuleB(Mercs, ChargeMercUpkeepCost)) + if (RuleB(Mercs, ChargeMercUpkeepCost)) { uint32 cost = CalcUpkeepCost(GetMercTemplateID(), GetLevel()) * 100; // Cost is in gold - if(cost > 0 && !mercOwner->HasMoney(cost)) + if (cost > 0 && !mercOwner->HasMoney(cost)) { mercOwner->SendMercResponsePackets(1); Suspend(); @@ -5783,21 +5791,21 @@ void Merc::Depop() { WipeHateList(); - if(IsCasting()) + if (IsCasting()) { InterruptSpell(); } entity_list.RemoveFromHateLists(this); - if(GetGroup()) + if (GetGroup()) { RemoveMercFromGroup(this, GetGroup()); } entity_list.RemoveMerc(this->GetID()); - if(HasPet()) + if (HasPet()) { GetPet()->Depop(); } @@ -5811,12 +5819,12 @@ bool Merc::RemoveMercFromGroup(Merc* merc, Group* group) { bool Result = false; - if(merc && group) + if (merc && group) { uint32 groupID = group->GetID(); - if(merc->HasGroup()) + if (merc->HasGroup()) { - if(!group->IsLeader(merc)) + if (!group->IsLeader(merc)) { merc->SetFollowID(0); @@ -5824,9 +5832,9 @@ bool Merc::RemoveMercFromGroup(Merc* merc, Group* group) { { group->DisbandGroup(); } - else if(group->DelMember(merc, true)) + else if (group->DelMember(merc, true)) { - if(merc->GetMercCharacterID() != 0) + if (merc->GetMercCharacterID() != 0) { database.SetGroupID(merc->GetName(), 0, merc->GetMercCharacterID(), true); } @@ -5835,15 +5843,15 @@ bool Merc::RemoveMercFromGroup(Merc* merc, Group* group) { else { // A merc is group leader - Disband and re-group each member with their mercs - for(int i = 0; i < MAX_GROUP_MEMBERS; i++) + for (int i = 0; i < MAX_GROUP_MEMBERS; i++) { - if(!group->members[i]) + if (!group->members[i]) continue; - if(!group->members[i]->IsClient()) + if (!group->members[i]->IsClient()) continue; - Client *groupMember = group->members[i]->CastToClient(); + Client* groupMember = group->members[i]->CastToClient(); groupMember->LeaveGroup(); if (groupMember->GetMerc()) { @@ -5851,7 +5859,7 @@ bool Merc::RemoveMercFromGroup(Merc* merc, Group* group) { } } // Group should be removed by now, but just in case: - Group *oldGroup = entity_list.GetGroupByID(groupID); + Group* oldGroup = entity_list.GetGroupByID(groupID); if (oldGroup != nullptr) { oldGroup->DisbandGroup(); @@ -5869,18 +5877,18 @@ bool Merc::MercJoinClientGroup() { Client* mercOwner = nullptr; - if(GetMercOwner()) + if (GetMercOwner()) { mercOwner = GetMercOwner(); } - if(!mercOwner) + if (!mercOwner) { Suspend(); return false; } - if(GetID()) + if (GetID()) { if (HasGroup()) { @@ -5890,11 +5898,11 @@ bool Merc::MercJoinClientGroup() { Group* g = entity_list.GetGroupByClient(mercOwner); //nobody from our group is here... start a new group - if(!g) + if (!g) { g = new Group(mercOwner); - if(!g) + if (!g) { delete g; g = nullptr; @@ -5903,7 +5911,7 @@ bool Merc::MercJoinClientGroup() { entity_list.AddGroup(g); - if(g->GetID() == 0) + if (g->GetID() == 0) { delete g; @@ -5948,11 +5956,11 @@ bool Merc::MercJoinClientGroup() { bool Merc::AddMercToGroup(Merc* merc, Group* group) { bool Result = false; - if(merc && group) { + if (merc && group) { // Remove merc from current group if it's not the destination group - if(merc->HasGroup()) + if (merc->HasGroup()) { - if(merc->GetGroup() == group && merc->GetMercOwner()) + if (merc->GetGroup() == group && merc->GetMercOwner()) { // Merc is already in the destination group merc->SetFollowID(merc->GetMercOwner()->GetID()); @@ -5961,7 +5969,7 @@ bool Merc::AddMercToGroup(Merc* merc, Group* group) { merc->RemoveMercFromGroup(merc, merc->GetGroup()); } //Try and add the member, followed by checking if the merc owner exists. - if(group->AddMember(merc) && merc->GetMercOwner()) + if (group->AddMember(merc) && merc->GetMercOwner()) { merc->SetFollowID(merc->GetMercOwner()->GetID()); Result = true; @@ -5978,7 +5986,7 @@ bool Merc::AddMercToGroup(Merc* merc, Group* group) { void Client::InitializeMercInfo() { - for(int i=0; iGetOwnerID() != GetID()) + if (tmp->GetOwnerID() != GetID()) { SetMercID(0); Log(Logs::Detail, Logs::Mercenaries, "GetMerc Owner Mismatch - OwnerID: %d, ClientID: %d, Client: %s.", tmp->GetOwnerID(), GetID(), GetName()); @@ -6015,9 +6023,9 @@ uint8 Client::GetNumMercs() { uint8 numMercs = 0; - for(int i=0; iGetMercTemplate(template_id); - SetMercTemplateID( merc_template->MercTemplateID ); - SetMercType( merc_template->MercType ); - SetMercSubType( merc_template->MercSubType ); - SetProficiencyID( merc_template->ProficiencyID ); - SetTierID( merc_template->TierID ); - SetCostFormula( merc_template->CostFormula ); - SetMercNameType( merc_template->MercNameType ); + SetMercTemplateID(merc_template->MercTemplateID); + SetMercType(merc_template->MercType); + SetMercSubType(merc_template->MercSubType); + SetProficiencyID(merc_template->ProficiencyID); + SetTierID(merc_template->TierID); + SetCostFormula(merc_template->CostFormula); + SetMercNameType(merc_template->MercNameType); } -MercTemplate* Zone::GetMercTemplate( uint32 template_id ) { +MercTemplate* Zone::GetMercTemplate(uint32 template_id) { return &merc_templates[template_id]; } @@ -6229,7 +6237,7 @@ int NPC::GetNumMercTypes(uint32 clientVersion) { std::list mercTypeList = GetMercTypesList(); for (auto mercTypeListItr = mercTypeList.begin(); mercTypeListItr != mercTypeList.end(); ++mercTypeListItr) { - if(mercTypeListItr->ClientVersion <= clientVersion) + if (mercTypeListItr->ClientVersion <= clientVersion) count++; } @@ -6242,7 +6250,7 @@ int NPC::GetNumMercs(uint32 clientVersion) { std::list mercDataList = GetMercsList(); for (auto mercListItr = mercDataList.begin(); mercListItr != mercDataList.end(); ++mercListItr) { - if(mercListItr->ClientVersion <= clientVersion) + if (mercListItr->ClientVersion <= clientVersion) count++; } @@ -6253,11 +6261,11 @@ std::list NPC::GetMercTypesList(uint32 clientVersion) { std::list result; - if(GetNumMercTypes() > 0) + if (GetNumMercTypes() > 0) { for (auto mercTypeListItr = mercTypeList.begin(); mercTypeListItr != mercTypeList.end(); - ++mercTypeListItr) { - if(mercTypeListItr->ClientVersion <= clientVersion) + ++mercTypeListItr) { + if (mercTypeListItr->ClientVersion <= clientVersion) { MercType mercType; mercType.Type = mercTypeListItr->Type; @@ -6274,14 +6282,14 @@ std::list NPC::GetMercsList(uint32 clientVersion) { std::list result; - if(GetNumMercs() > 0) + if (GetNumMercs() > 0) { for (auto mercListItr = mercDataList.begin(); mercListItr != mercDataList.end(); ++mercListItr) { - if(mercListItr->ClientVersion <= clientVersion) + if (mercListItr->ClientVersion <= clientVersion) { - MercTemplate *merc_template = zone->GetMercTemplate(mercListItr->MercTemplateID); + MercTemplate* merc_template = zone->GetMercTemplate(mercListItr->MercTemplateID); - if(merc_template) + if (merc_template) { MercData mercData; mercData.MercTemplateID = mercListItr->MercTemplateID; @@ -6299,16 +6307,16 @@ std::list NPC::GetMercsList(uint32 clientVersion) { return result; } -uint32 Merc::CalcPurchaseCost(uint32 templateID , uint8 level, uint8 currency_type) { +uint32 Merc::CalcPurchaseCost(uint32 templateID, uint8 level, uint8 currency_type) { uint32 cost = 0; - MercTemplate *mercData = zone->GetMercTemplate(templateID); + MercTemplate* mercData = zone->GetMercTemplate(templateID); - if(mercData) + if (mercData) { //calculate cost in coin - cost in gold - if(currency_type == 0) + if (currency_type == 0) { int levels_above_cutoff; switch (mercData->CostFormula) @@ -6323,7 +6331,7 @@ uint32 Merc::CalcPurchaseCost(uint32 templateID , uint8 level, uint8 currency_ty break; } } - else if(currency_type == 19) + else if (currency_type == 19) { // cost in Bayle Marks cost = 1; @@ -6333,16 +6341,16 @@ uint32 Merc::CalcPurchaseCost(uint32 templateID , uint8 level, uint8 currency_ty return cost; } -uint32 Merc::CalcUpkeepCost(uint32 templateID , uint8 level, uint8 currency_type) { +uint32 Merc::CalcUpkeepCost(uint32 templateID, uint8 level, uint8 currency_type) { uint32 cost = 0; - MercTemplate *mercData = zone->GetMercTemplate(templateID); + MercTemplate* mercData = zone->GetMercTemplate(templateID); - if(mercData) + if (mercData) { //calculate cost in coin - cost in gold - if(currency_type == 0) + if (currency_type == 0) { int levels_above_cutoff; switch (mercData->CostFormula) @@ -6357,7 +6365,7 @@ uint32 Merc::CalcUpkeepCost(uint32 templateID , uint8 level, uint8 currency_type break; } } - else if(currency_type == 19) + else if (currency_type == 19) { // cost in Bayle Marks cost = 1; @@ -6371,125 +6379,125 @@ uint32 Merc::CalcUpkeepCost(uint32 templateID , uint8 level, uint8 currency_type // ElixirAIDetermineSpellToCast is called during Merc::AICastSpell and overrides normal logic // It determines by class which spell to cast bool Merc::ElixirAIDetermineSpellToCast() { - MercSpell selectedMercSpell; - int8 spellAIResult; - Group *grp = GetGroup(); + MercSpell selectedMercSpell; + int8 spellAIResult; + Group* grp = GetGroup(); - switch (GetClass()) { - case HEALER: - selectedMercSpell = GetBestMercSpellForGroupHeal(this); + switch (GetClass()) { + case HEALER: + selectedMercSpell = GetBestMercSpellForGroupHeal(this); + if (ElixirAITryCastSpell(selectedMercSpell, true)) { + return true; + } + + selectedMercSpell = GetBestMercSpellForHealOverTime(this); + if (ElixirAITryCastSpell(selectedMercSpell, true)) { + return true; + } + + selectedMercSpell = GetBestMercSpellForFastHeal(this); + if (ElixirAITryCastSpell(selectedMercSpell, true)) { + return true; + } + + selectedMercSpell = GetBestMercSpellForRegularSingleTargetHeal(this); + if (ElixirAITryCastSpell(selectedMercSpell, true)) { + return true; + } + + for (int i = 0; i < MAX_GROUP_MEMBERS; i++) { + if (!grp) break; + if (!grp->members[i]) continue; + if (!grp->members[i]->qglobal) continue; + if (!GetNeedsCured(grp->members[i])) continue; + if (grp->members[i]->DontCureMeBefore() > Timer::GetCurrentTime()) continue; + selectedMercSpell = GetBestMercSpellForCure(this, grp->members[i]); if (ElixirAITryCastSpell(selectedMercSpell, true)) { return true; } + } - selectedMercSpell = GetBestMercSpellForHealOverTime(this); - if (ElixirAITryCastSpell(selectedMercSpell, true)) { - return true; - } - - selectedMercSpell = GetBestMercSpellForFastHeal(this); - if (ElixirAITryCastSpell(selectedMercSpell, true)) { - return true; - } - - selectedMercSpell = GetBestMercSpellForRegularSingleTargetHeal(this); - if (ElixirAITryCastSpell(selectedMercSpell, true)) { - return true; - } - - for (int i = 0; i < MAX_GROUP_MEMBERS; i++) { - if (!grp) break; - if (!grp->members[i]) continue; - if (!grp->members[i]->qglobal) continue; - if(!GetNeedsCured(grp->members[i])) continue; - if (grp->members[i]->DontCureMeBefore() > Timer::GetCurrentTime()) continue; - selectedMercSpell = GetBestMercSpellForCure(this, grp->members[i]); - if (ElixirAITryCastSpell(selectedMercSpell, true)) { - return true; - } - } - - if (GetManaRatio() > 50) { // healers only offensive or buff at > 50% mana - selectedMercSpell = GetBestMercSpellForStun(this); - if (ElixirAITryCastSpell(selectedMercSpell)) { - return true; - } - - selectedMercSpell = GetBestMercSpellForNuke(this); - if (ElixirAITryCastSpell(selectedMercSpell)) { - return true; - } - - auto buffSpells = GetMercSpellsBySpellType(this, SpellType_Buff); - for (auto buffSpell : buffSpells) { - if (!ElixirAITryCastSpell(selectedMercSpell)) continue; - return true; - } - } - return false; - case MELEEDPS: - if (GetTarget() && HasOrMayGetAggro()) { - selectedMercSpell = GetFirstMercSpellBySpellType(this, SpellType_Escape); - if (selectedMercSpell.spellid > 0 && ElixirAITryCastSpell(selectedMercSpell)) { - return true; - } - } - - selectedMercSpell = GetFirstMercSpellBySpellType(this, SpellType_Nuke); - if (selectedMercSpell.spellid > 0 && ElixirAITryCastSpell(selectedMercSpell)) { + if (GetManaRatio() > 50) { // healers only offensive or buff at > 50% mana + selectedMercSpell = GetBestMercSpellForStun(this); + if (ElixirAITryCastSpell(selectedMercSpell)) { return true; } - selectedMercSpell = GetFirstMercSpellBySpellType(this, SpellType_InCombatBuff); - if (selectedMercSpell.spellid > 0 && ElixirAITryCastSpell(selectedMercSpell)) { - return true; - } - return false; - case TANK: - if(CheckAETaunt()) { - selectedMercSpell = GetBestMercSpellForAETaunt(this); - if (selectedMercSpell.spellid > 0 && ElixirAITryCastSpell(selectedMercSpell)) { - Log(Logs::General, Logs::Mercenaries, "%s AE Taunting.", GetName()); - return true; - } - } - - if(CheckTaunt()) { - selectedMercSpell = GetBestMercSpellForTaunt(this); - if (selectedMercSpell.spellid > 0 && ElixirAITryCastSpell(selectedMercSpell)) { - return true; - } - } - - selectedMercSpell = GetBestMercSpellForHate(this); - if (selectedMercSpell.spellid > 0 && ElixirAITryCastSpell(selectedMercSpell)) { + selectedMercSpell = GetBestMercSpellForNuke(this); + if (ElixirAITryCastSpell(selectedMercSpell)) { return true; } - selectedMercSpell = GetFirstMercSpellBySpellType(this, SpellType_Nuke); - if (selectedMercSpell.spellid > 0 && ElixirAITryCastSpell(selectedMercSpell)) { - return true; - } - - selectedMercSpell = GetFirstMercSpellBySpellType(this, SpellType_InCombatBuff); - if (selectedMercSpell.spellid > 0 && ElixirAITryCastSpell(selectedMercSpell)) { - return true; - } - return false; - case CASTERDPS: - if (GetTarget() && HasOrMayGetAggro()) { - selectedMercSpell = GetFirstMercSpellBySpellType(this, SpellType_Escape); - if (selectedMercSpell.spellid > 0 && ElixirAITryCastSpell(selectedMercSpell)) { - return true; - } - } - - selectedMercSpell = GetFirstMercSpellBySpellType(this, SpellType_Nuke); - if (selectedMercSpell.spellid > 0 && ElixirAITryCastSpell(selectedMercSpell)) { + auto buffSpells = GetMercSpellsBySpellType(this, SpellType_Buff); + for (auto buffSpell : buffSpells) { + if (!ElixirAITryCastSpell(selectedMercSpell)) continue; return true; } } return false; + case MELEEDPS: + if (GetTarget() && HasOrMayGetAggro()) { + selectedMercSpell = GetFirstMercSpellBySpellType(this, SpellType_Escape); + if (selectedMercSpell.spellid > 0 && ElixirAITryCastSpell(selectedMercSpell)) { + return true; + } + } + + selectedMercSpell = GetFirstMercSpellBySpellType(this, SpellType_Nuke); + if (selectedMercSpell.spellid > 0 && ElixirAITryCastSpell(selectedMercSpell)) { + return true; + } + + selectedMercSpell = GetFirstMercSpellBySpellType(this, SpellType_InCombatBuff); + if (selectedMercSpell.spellid > 0 && ElixirAITryCastSpell(selectedMercSpell)) { + return true; + } + return false; + case TANK: + if (CheckAETaunt()) { + selectedMercSpell = GetBestMercSpellForAETaunt(this); + if (selectedMercSpell.spellid > 0 && ElixirAITryCastSpell(selectedMercSpell)) { + Log(Logs::General, Logs::Mercenaries, "%s AE Taunting.", GetName()); + return true; + } + } + + if (CheckTaunt()) { + selectedMercSpell = GetBestMercSpellForTaunt(this); + if (selectedMercSpell.spellid > 0 && ElixirAITryCastSpell(selectedMercSpell)) { + return true; + } + } + + selectedMercSpell = GetBestMercSpellForHate(this); + if (selectedMercSpell.spellid > 0 && ElixirAITryCastSpell(selectedMercSpell)) { + return true; + } + + selectedMercSpell = GetFirstMercSpellBySpellType(this, SpellType_Nuke); + if (selectedMercSpell.spellid > 0 && ElixirAITryCastSpell(selectedMercSpell)) { + return true; + } + + selectedMercSpell = GetFirstMercSpellBySpellType(this, SpellType_InCombatBuff); + if (selectedMercSpell.spellid > 0 && ElixirAITryCastSpell(selectedMercSpell)) { + return true; + } + return false; + case CASTERDPS: + if (GetTarget() && HasOrMayGetAggro()) { + selectedMercSpell = GetFirstMercSpellBySpellType(this, SpellType_Escape); + if (selectedMercSpell.spellid > 0 && ElixirAITryCastSpell(selectedMercSpell)) { + return true; + } + } + + selectedMercSpell = GetFirstMercSpellBySpellType(this, SpellType_Nuke); + if (selectedMercSpell.spellid > 0 && ElixirAITryCastSpell(selectedMercSpell)) { + return true; + } + } + return false; } // ElixirAITryCastSpell takes a provided spell id and does a spell check to determine if the spell is valid @@ -6498,8 +6506,8 @@ bool Merc::ElixirAITryCastSpell(MercSpell mercSpell, bool isHeal) { auto spellID = mercSpell.spellid; if (spellID == 0) return false; - Mob* outMob; - auto spellAIResult = ElixirCastSpellCheck(spellID, outMob); + Mob* outMob = nullptr; + auto spellAIResult = ElixirCastSpellCheck(spellID, &outMob); if (spellAIResult < 0) return false; @@ -6509,7 +6517,7 @@ bool Merc::ElixirAITryCastSpell(MercSpell mercSpell, bool isHeal) { if (isHeal) MercGroupSay(this, "Casting %s on %s.", spells[spellID].name, GetTarget()->GetCleanName()); return true; } - + if (outMob == nullptr) { return false; } @@ -6517,4 +6525,4 @@ bool Merc::ElixirAITryCastSpell(MercSpell mercSpell, bool isHeal) { if (outMob == this) return true; if (isHeal) MercGroupSay(this, "Casting %s on %s.", spells[spellID].name, outMob->GetCleanName()); return true; -} \ No newline at end of file +} diff --git a/zone/mob.h b/zone/mob.h index 1f534524c..3baa827e2 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -855,7 +855,7 @@ public: inline bool HasBaseEffectFocus() const { return (spellbonuses.FocusEffects[focusFcBaseEffects] || aabonuses.FocusEffects[focusFcBaseEffects] || itembonuses.FocusEffects[focusFcBaseEffects]); } int32 GetDualWieldingSameDelayWeapons() const { return dw_same_delay; } inline void SetDualWieldingSameDelayWeapons(int32 val) { dw_same_delay = val; } - int8 ElixirCastSpellCheck(uint16 spellID, Mob* outMob); + int8 ElixirCastSpellCheck(uint16 spellID, Mob** outMob); bool TryDoubleMeleeRoundEffect(); bool GetUseDoubleMeleeRoundDmgBonus() const { return use_double_melee_round_dmg_bonus; } inline void SetUseDoubleMeleeRoundDmgBonus(bool val) { use_double_melee_round_dmg_bonus = val; }