diff --git a/playerbot/ChatHelper.h b/playerbot/ChatHelper.h index 8cf03b0ad..4070f8d9d 100644 --- a/playerbot/ChatHelper.h +++ b/playerbot/ChatHelper.h @@ -34,6 +34,7 @@ namespace ai static uint32 parseSlot(string text); static string formatSpell(SpellEntry const *sInfo); + static string formatSpell(uint32 spellId) {const SpellEntry* const spellInfo = sSpellTemplate.LookupEntry(spellId); if (!spellInfo) return ""; return formatSpell(spellInfo);}; uint32 parseSpell(string& text); static string formatGameobject(GameObject* go); diff --git a/playerbot/strategy/ItemVisitors.h b/playerbot/strategy/ItemVisitors.h index fdd6c8124..63347fa9f 100644 --- a/playerbot/strategy/ItemVisitors.h +++ b/playerbot/strategy/ItemVisitors.h @@ -332,6 +332,9 @@ namespace ai { for (int j = 0; j < MAX_ITEM_PROTO_SPELLS; j++) { + if (proto->Spells[j].SpellId == 26656) + return true; + const SpellEntry* const spellInfo = sServerFacade.LookupSpellInfo(proto->Spells[j].SpellId); if (!spellInfo) return false; diff --git a/playerbot/strategy/actions/CastCustomSpellAction.cpp b/playerbot/strategy/actions/CastCustomSpellAction.cpp index 58a678df5..95a36d8fa 100644 --- a/playerbot/strategy/actions/CastCustomSpellAction.cpp +++ b/playerbot/strategy/actions/CastCustomSpellAction.cpp @@ -126,7 +126,7 @@ bool CastCustomSpellAction::Execute(Event& event) ai->StopMoving(); } - if (CheckMountStateAction::CurrentMountSpeed(bot)) + if (AI_VALUE2(uint32, "current mount speed", "self target")) { if (bot->IsFlying() && WorldPosition(bot).currentHeight() > 10.0f) return false; diff --git a/playerbot/strategy/actions/CheckMountStateAction.cpp b/playerbot/strategy/actions/CheckMountStateAction.cpp index d82cd61a2..170bf7505 100644 --- a/playerbot/strategy/actions/CheckMountStateAction.cpp +++ b/playerbot/strategy/actions/CheckMountStateAction.cpp @@ -3,6 +3,7 @@ #include "CheckMountStateAction.h" #include "../values/PositionValue.h" #include "../../ServerFacade.h" +#include "../values/MountValues.h" #include "BattleGroundWS.h" #include "../../TravelMgr.h" @@ -37,6 +38,9 @@ bool CheckMountStateAction::Execute(Event& event) farFromTarget = sServerFacade.IsDistanceGreaterThan(distToTarget, 40.0f); } + bool IsMounted = AI_VALUE2(uint32, "current mount speed", "self target"); + bool IsLeaderMounted = groupMaster && AI_VALUE2(uint32, "current mount speed", "master target"); + //Mount up in battle grounds if (bot->InBattleGround()) { @@ -46,7 +50,7 @@ bool CheckMountStateAction::Execute(Event& event) { if (CanMountInBg()) { - if (ai->HasStrategy("debug mount", BotState::BOT_STATE_NON_COMBAT) && !CurrentMountSpeed(bot)) + if (ai->HasStrategy("debug mount", BotState::BOT_STATE_NON_COMBAT) && !IsMounted) ai->TellMasterNoFacing("Mount in bg. No attackers or far from target and not in combat."); return Mount(); @@ -58,7 +62,7 @@ bool CheckMountStateAction::Execute(Event& event) //Unmounted when able to attack target if (canAttackTarget) { - if (ai->HasStrategy("debug mount", BotState::BOT_STATE_NON_COMBAT) && CurrentMountSpeed(bot)) + if (ai->HasStrategy("debug mount", BotState::BOT_STATE_NON_COMBAT) && IsMounted) ai->TellMasterNoFacing("Unmount. Able to attack target."); return UnMount(); } @@ -70,15 +74,15 @@ bool CheckMountStateAction::Execute(Event& event) //Chase to current target. if (!canAttackTarget && (farFromTarget || shouldChaseTarget)) { - if (ai->HasStrategy("debug mount", BotState::BOT_STATE_NON_COMBAT) && !CurrentMountSpeed(bot)) + if (ai->HasStrategy("debug mount", BotState::BOT_STATE_NON_COMBAT) && !IsMounted) ai->TellMasterNoFacing("Mount. Unable to attack target and target is far or chasable."); return Mount(); } //Following master and close to master that is unmounted. - if (ai->HasStrategy("follow", BotState::BOT_STATE_NON_COMBAT) && groupMaster && groupMaster != bot && !farFromMaster && !CurrentMountSpeed(groupMaster)) + if (ai->HasStrategy("follow", BotState::BOT_STATE_NON_COMBAT) && groupMaster && groupMaster != bot && !farFromMaster && !IsLeaderMounted) { - if (ai->HasStrategy("debug mount", BotState::BOT_STATE_NON_COMBAT) && CurrentMountSpeed(bot)) + if (ai->HasStrategy("debug mount", BotState::BOT_STATE_NON_COMBAT) && IsMounted) ai->TellMasterNoFacing("Unmount. Near umounted group master."); return UnMount(); } @@ -93,7 +97,7 @@ bool CheckMountStateAction::Execute(Event& event) if (guardPosition.isSet() && distance < ai->GetRange("follow")) { - if (ai->HasStrategy("debug mount", BotState::BOT_STATE_NON_COMBAT) && CurrentMountSpeed(bot)) + if (ai->HasStrategy("debug mount", BotState::BOT_STATE_NON_COMBAT) && IsMounted) ai->TellMasterNoFacing("Unmount. Near umounted guard position."); return UnMount(); } @@ -109,7 +113,7 @@ bool CheckMountStateAction::Execute(Event& event) if (stayPosition.isSet() && distance < ai->GetRange("follow")) { - if (ai->HasStrategy("debug mount", BotState::BOT_STATE_NON_COMBAT) && CurrentMountSpeed(bot)) + if (ai->HasStrategy("debug mount", BotState::BOT_STATE_NON_COMBAT) && IsMounted) ai->TellMasterNoFacing("Unmount. Near stay location."); return UnMount(); } @@ -118,7 +122,7 @@ bool CheckMountStateAction::Execute(Event& event) //Doing stuff nearby. if (travelTarget->isWorking()) { - if (ai->HasStrategy("debug mount", BotState::BOT_STATE_NON_COMBAT) && CurrentMountSpeed(bot)) + if (ai->HasStrategy("debug mount", BotState::BOT_STATE_NON_COMBAT) && IsMounted) ai->TellMasterNoFacing("Unmount. Near travel target."); return UnMount(); } @@ -126,7 +130,7 @@ bool CheckMountStateAction::Execute(Event& event) //Rping nearby. if (AI_VALUE(GuidPosition, "rpg target") && sServerFacade.IsDistanceLessThan(AI_VALUE2(float, "distance", "rpg target"), sPlayerbotAIConfig.farDistance)) { - if (ai->HasStrategy("debug mount", BotState::BOT_STATE_NON_COMBAT) && CurrentMountSpeed(bot)) + if (ai->HasStrategy("debug mount", BotState::BOT_STATE_NON_COMBAT) && IsMounted) ai->TellMasterNoFacing("Unmount. Near rpg target."); return UnMount(); } @@ -134,9 +138,9 @@ bool CheckMountStateAction::Execute(Event& event) if (ai->HasStrategy("follow", BotState::BOT_STATE_NON_COMBAT) && groupMaster) { //Mounting with master. - if (CurrentMountSpeed(groupMaster) && !hasAttackers) + if (IsLeaderMounted && !hasAttackers) { - if (ai->HasStrategy("debug mount", BotState::BOT_STATE_NON_COMBAT) && !CurrentMountSpeed(bot)) + if (ai->HasStrategy("debug mount", BotState::BOT_STATE_NON_COMBAT) && !IsMounted) ai->TellMasterNoFacing("Mount. Group master mounted and no attackers."); return Mount(); } @@ -144,7 +148,7 @@ bool CheckMountStateAction::Execute(Event& event) //Mounting to move to master. if (farFromMaster && !bot->IsInCombat()) { - if (ai->HasStrategy("debug mount", BotState::BOT_STATE_NON_COMBAT) && !CurrentMountSpeed(bot)) + if (ai->HasStrategy("debug mount", BotState::BOT_STATE_NON_COMBAT) && !IsMounted) ai->TellMasterNoFacing("Mount. Far from group master and not in combat."); return Mount(); } @@ -155,7 +159,7 @@ bool CheckMountStateAction::Execute(Event& event) //Mounting to travel. if (travelTarget->isTraveling() && AI_VALUE(bool, "can move around")) { - if (ai->HasStrategy("debug mount", BotState::BOT_STATE_NON_COMBAT) && !CurrentMountSpeed(bot)) + if (ai->HasStrategy("debug mount", BotState::BOT_STATE_NON_COMBAT) && !IsMounted) ai->TellMasterNoFacing("Mount. Traveling some place."); return Mount(); } @@ -164,7 +168,7 @@ bool CheckMountStateAction::Execute(Event& event) //Mounting to move to rpg target. if (AI_VALUE(GuidPosition, "rpg target") && sServerFacade.IsDistanceGreaterThan(AI_VALUE2(float, "distance", "rpg target"), sPlayerbotAIConfig.sightDistance)) { - if (ai->HasStrategy("debug mount", BotState::BOT_STATE_NON_COMBAT) && !CurrentMountSpeed(bot)) + if (ai->HasStrategy("debug mount", BotState::BOT_STATE_NON_COMBAT) && !IsMounted) ai->TellMasterNoFacing("Mount. Rpg target far away."); return Mount(); } @@ -172,7 +176,7 @@ bool CheckMountStateAction::Execute(Event& event) //Mounting in safe place. if (!ai->HasStrategy("guard", ai->GetState()) && !ai->HasStrategy("stay", ai->GetState()) && !AI_VALUE(list, "possible rpg targets").empty() && urand(0, 100) > 50) { - if (ai->HasStrategy("debug mount", BotState::BOT_STATE_NON_COMBAT) && !CurrentMountSpeed(bot)) + if (ai->HasStrategy("debug mount", BotState::BOT_STATE_NON_COMBAT) && !IsMounted) ai->TellMasterNoFacing("Mount. Near rpg targets."); return Mount(); } @@ -188,7 +192,7 @@ bool CheckMountStateAction::Execute(Event& event) if (guardPosition.isSet() && distance > 40.0f) { - if (ai->HasStrategy("debug mount", BotState::BOT_STATE_NON_COMBAT) && !CurrentMountSpeed(bot)) + if (ai->HasStrategy("debug mount", BotState::BOT_STATE_NON_COMBAT) && !IsMounted) ai->TellMasterNoFacing("Mount. Move to guard."); return Mount(); } @@ -204,7 +208,7 @@ bool CheckMountStateAction::Execute(Event& event) if (guardPosition.isSet() && distance > 40.0f) { - if (ai->HasStrategy("debug mount", BotState::BOT_STATE_NON_COMBAT) && !CurrentMountSpeed(bot)) + if (ai->HasStrategy("debug mount", BotState::BOT_STATE_NON_COMBAT) && !IsMounted) ai->TellMasterNoFacing("Mount. Move to stay."); return Mount(); } @@ -275,10 +279,10 @@ bool CheckMountStateAction::isUseful() } } - if (!bot->GetMap()->IsMountAllowed()) + if (!bot->GetMap()->IsMountAllowed() && bot->GetMapId() != 531) return false; - if (GetBestMountSpells(false).empty() && GetBestMounts(false).empty() && GetBestMountSpells(true).empty() && GetBestMounts(true).empty()) + if (AI_VALUE(vector, "mount list").empty()) return false; return true; @@ -304,10 +308,11 @@ bool CheckMountStateAction::CanFly() const return false; #endif - if (GetBestMountSpells(true).empty() && GetBestMounts(true).empty()) - return false; + for (auto& mount : AI_VALUE(vector, "mount list")) + if (mount.GetSpeed(true)) + return true; - return true; + return false; } bool CheckMountStateAction::CanMountInBg() const @@ -361,269 +366,110 @@ float CheckMountStateAction::GetAttackDistance() const return 35.0f; } -uint32 CheckMountStateAction::MountSpeed(const SpellEntry* const spellInfo, const bool canFly) +bool CheckMountStateAction::Mount() { - bool isMount = false; + bool canFly = CanFly(); -#ifdef MANGOSBOT_ZERO - uint32 effect = SPELL_AURA_MOD_INCREASE_MOUNTED_SPEED; -#else - uint32 effect = canFly ? SPELL_AURA_MOD_FLIGHT_SPEED_MOUNTED : SPELL_AURA_MOD_INCREASE_MOUNTED_SPEED; //If we can fly only look at flight speed. Normal mounts then don't get any speed. -#endif + uint32 currentSpeed = AI_VALUE2(uint32, "current mount speed", "self target"); - if (!spellInfo) - return 0; + vector mountList = AI_VALUE(vector, "mount list"); - switch (spellInfo->Id) //Aura's hard coded in spell.cpp - { - case 783: //travel form - case 2645: //ghost wolf - if (!canFly) - return 39; - break; - case 33943: //flight form - if (canFly) - return 59; - break; - case 40120: //swift flight form - if (canFly) - return 279; - break; - } + std::shuffle(mountList.begin(), mountList.end(), *GetRandomGenerator()); + std::sort(mountList.begin(), mountList.end(), [canFly](MountValue i, MountValue j) {return i.GetSpeed(canFly) > j.GetSpeed(canFly); }); - for (int i = 0; i < 3; i++) + for (auto& mount : mountList) { - if (spellInfo->EffectApplyAuraName[i] == SPELL_AURA_MOUNTED) - { - isMount = true; - break; - } - } + if (ai->HasStrategy("debug mount", BotState::BOT_STATE_NON_COMBAT)) + ai->TellMasterNoFacing("Try to mount with " + chat->formatSpell(mount.GetSpellId())); -#ifndef MANGOSBOT_ZERO - //This part stops bots from mounting flying mounts when they can't fly. This should be tweaked if bots ever are able to normally ride flying mounts in the old-world. - if(isMount && !canFly) - { - for (int i = 0; i < 3; i++) + if (currentSpeed >= mount.GetSpeed(canFly)) { - if (spellInfo->EffectApplyAuraName[i] == SPELL_AURA_MOD_FLIGHT_SPEED_MOUNTED) - { - return 0; - } + if (ai->HasStrategy("debug mount", BotState::BOT_STATE_NON_COMBAT)) + ai->TellMasterNoFacing("Speed not faster than current."); + + return false; } - } -#endif - if (isMount) - { - for (int i = 0; i < 3; i++) + if (currentSpeed) //Already mounted { - if (spellInfo->EffectApplyAuraName[i] == effect) - { - return spellInfo->EffectBasePoints[i]; - } + if (ai->HasStrategy("debug mount", BotState::BOT_STATE_NON_COMBAT)) + ai->TellMasterNoFacing("Mounted, unmount to mount faster next time."); + return UnMount(); } - } - - return 0; -} - -uint32 CheckMountStateAction::MountSpeed(const ItemPrototype* proto, const bool canFly) -{ - if (!proto) - return 0; - - uint32 speed = 0; - for (int j = 0; j < MAX_ITEM_PROTO_SPELLS; j++) - { - const SpellEntry* const spellInfo = sServerFacade.LookupSpellInfo(proto->Spells[j].SpellId); - speed = MountSpeed(spellInfo, canFly); - - if (speed) - return speed; - } - - return 0; -} - -vector CheckMountStateAction::GetBestMountSpells(const bool canFly) const -{ - uint32 bestMountSpeed = 1; - vector spells; - for (PlayerSpellMap::iterator itr = bot->GetSpellMap().begin(); itr != bot->GetSpellMap().end(); ++itr) - { - uint32 spellId = itr->first; - if (itr->second.state == PLAYERSPELL_REMOVED || itr->second.disabled || IsPassiveSpell(spellId)) - continue; - - const SpellEntry* spellInfo = sServerFacade.LookupSpellInfo(spellId); - - uint32 mountSpeed = MountSpeed(spellInfo, canFly); - - if (mountSpeed < bestMountSpeed) - continue; - - if (mountSpeed > bestMountSpeed) - spells.clear(); - - spells.push_back(spellId); - } - - return spells; -} - -vector CheckMountStateAction::GetBestMounts(const bool canFly) const -{ - list items = AI_VALUE2(list, "inventory items", "mount"); - - uint32 bestMountSpeed = 1; - vector mounts; - - for (auto& item : items) - { - uint32 mountSpeed = MountSpeed(item->GetProto(), canFly); - - if (mountSpeed < bestMountSpeed) - continue; - - if (mountSpeed > bestMountSpeed) - mounts.clear(); - - mounts.push_back(item); - } - - return mounts; -} - -uint32 CheckMountStateAction::GetBestMountSpeed(const bool canFly) const -{ - vector mountSpells = GetBestMountSpells(canFly); - vector mounts = GetBestMounts(canFly); - - if (mountSpells.empty() && mounts.empty()) - return 0; - SpellEntry const* mountSpell = nullptr; - ItemPrototype const* mountItemProto = nullptr; - - if (!mountSpells.empty()) - mountSpell = sServerFacade.LookupSpellInfo(mountSpells.front()); - - if (!mounts.empty()) - mountItemProto = mounts.front()->GetProto(); - - return std::max(MountSpeed(mountSpell, canFly), MountSpeed(mountItemProto, canFly)); -} + ai->RemoveShapeshift(); -uint32 CheckMountStateAction::CurrentMountSpeed(const Unit* unit) -{ - uint32 mountSpeed = 0; + if (!bot->IsStopped()) + { + ai->StopMoving(); + } - for (uint32 auraType = SPELL_AURA_BIND_SIGHT; auraType < TOTAL_AURAS; auraType++) - { - Unit::AuraList const& auras = unit->GetAurasByType((AuraType)auraType); + bool didMount = false; - if (auras.empty()) + if (!mount.IsValidLocation()) + { + if (ai->HasStrategy("debug mount", BotState::BOT_STATE_NON_COMBAT)) + ai->TellMasterNoFacing("Bot can not use this mount here.", PlayerbotSecurityLevel::PLAYERBOT_SECURITY_ALLOW_ALL, true, false); continue; + } - for (Unit::AuraList::const_iterator i = auras.begin(); i != auras.end(); i++) + if (mount.IsItem()) { - Aura* aura = *i; - if (!aura) + if (!mount.GetItem()) + { + if (ai->HasStrategy("debug mount", BotState::BOT_STATE_NON_COMBAT)) + ai->TellMasterNoFacing("Bot does not have this mount.", PlayerbotSecurityLevel::PLAYERBOT_SECURITY_ALLOW_ALL, true, false); continue; + } - SpellEntry const* auraSpell = aura->GetSpellProto(); - - uint32 auraSpeed = std::max(MountSpeed(auraSpell, false), MountSpeed(auraSpell, true)); - - if (auraSpeed < mountSpeed) + if (UseItemAuto(mount.GetItem())) + { + SetDuration(3000U); // 3s + didMount = true; + } + else + { + if (ai->HasStrategy("debug mount", BotState::BOT_STATE_NON_COMBAT)) + ai->TellMasterNoFacing("Mounting failed.", PlayerbotSecurityLevel::PLAYERBOT_SECURITY_ALLOW_ALL, true, false); + } + } + else + { + if (!ai->HasSpell(mount.GetSpellId())) + { + if (ai->HasStrategy("debug mount", BotState::BOT_STATE_NON_COMBAT)) + ai->TellMasterNoFacing("Bot does not have this mount spell.", PlayerbotSecurityLevel::PLAYERBOT_SECURITY_ALLOW_ALL, true, false); continue; + } - mountSpeed = auraSpeed; + if (ai->CastSpell(mount.GetSpellId(), bot)) + { + sPlayerbotAIConfig.logEvent(ai, "CheckMountStateAction", sServerFacade.LookupSpellInfo(mount.GetSpellId())->SpellName[0], to_string(mount.GetSpeed(canFly))); + SetDuration(GetSpellRecoveryTime(sServerFacade.LookupSpellInfo(mount.GetSpellId()))); + didMount = true; + } + else + { + if (ai->HasStrategy("debug mount", BotState::BOT_STATE_NON_COMBAT)) + ai->TellMasterNoFacing("Mountingspell failed.", PlayerbotSecurityLevel::PLAYERBOT_SECURITY_ALLOW_ALL, true, false); + } } - } - - return mountSpeed; -} - -bool CheckMountStateAction::MountWithBestMount(const bool canFly) -{ - vector mountSpells = GetBestMountSpells(canFly); - vector mounts = GetBestMounts(canFly); - if (mountSpells.empty() && mounts.empty()) - return false; - - SpellEntry const* mountSpell; - Item* mountItem; - - if (!mountSpells.empty()) - mountSpell = sServerFacade.LookupSpellInfo(mountSpells.front()); - - if (!mounts.empty()) - mountItem = mounts.front(); - - if (!bot->IsStopped()) - { - ai->StopMoving(); - } - - if (mounts.empty() || (!mountSpells.empty() && MountSpeed(mountSpell, canFly) > MountSpeed(mountItem->GetProto(), canFly))) - { - uint32 spellId = mountSpells[urand(0, mountSpells.size() - 1)]; - if (ai->CastSpell(spellId, bot)) + if (didMount) { - sPlayerbotAIConfig.logEvent(ai, "CheckMountStateAction", sServerFacade.LookupSpellInfo(mountSpells.front())->SpellName[0], to_string(GetBestMountSpeed(canFly))); - SetDuration(GetSpellRecoveryTime(sServerFacade.LookupSpellInfo(mountSpells.front()))); - return true; - } - return false; - } - else - { - Item* mount = mounts[urand(0, mounts.size() - 1)]; - if (UseItemAuto(mount)) - { - sPlayerbotAIConfig.logEvent(ai, "CheckMountStateAction", mount->GetProto()->Name1, to_string(GetBestMountSpeed(canFly))); - SetDuration(3000U); // 3s - return true; + if (ai->HasStrategy("debug mount", BotState::BOT_STATE_NON_COMBAT)) + ai->TellMasterNoFacing("Mounting."); + + return didMount; } } return false; } -bool CheckMountStateAction::Mount() -{ - uint32 currentSpeed = CurrentMountSpeed(bot); - - if (currentSpeed) //Already mounted - { - if (CurrentMountSpeed(bot) < GetBestMountSpeed(CanFly())) //Dismount to speed up. - return UnMount(); - else - return false; - } - - Player* master = GetMaster(); - ai->RemoveShapeshift(); - - bool didMount = false; - - if (CanFly()) - { - didMount = MountWithBestMount(true); - } - - if (!didMount) - didMount = MountWithBestMount(); - - return didMount; -} - bool CheckMountStateAction::UnMount() const { - if (!CurrentMountSpeed(bot)) + if (!AI_VALUE2(uint32, "current mount speed", "self target")) return false; if (bot->IsFlying() && WorldPosition(bot).currentHeight() > 10.0f) diff --git a/playerbot/strategy/actions/CheckMountStateAction.h b/playerbot/strategy/actions/CheckMountStateAction.h index dbf41f1da..701144964 100644 --- a/playerbot/strategy/actions/CheckMountStateAction.h +++ b/playerbot/strategy/actions/CheckMountStateAction.h @@ -19,18 +19,7 @@ namespace ai virtual bool CanFly() const; bool CanMountInBg() const; float GetAttackDistance() const; - - static uint32 MountSpeed(const SpellEntry* const spellInfo, const bool canFly = false); - static uint32 MountSpeed(const ItemPrototype* proto, const bool canFly = false); - - vector GetBestMountSpells(const bool canFly) const; - vector GetBestMounts(const bool canFly) const; - public: - uint32 GetBestMountSpeed(const bool canFly = false) const; - static uint32 CurrentMountSpeed(const Unit* unit); private: - bool MountWithBestMount(const bool canFly = false); - bool Mount(); bool UnMount() const; }; diff --git a/playerbot/strategy/actions/UseItemAction.cpp b/playerbot/strategy/actions/UseItemAction.cpp index 401921150..ce01702e7 100644 --- a/playerbot/strategy/actions/UseItemAction.cpp +++ b/playerbot/strategy/actions/UseItemAction.cpp @@ -926,7 +926,7 @@ bool UseHearthStoneAction::Execute(Event& event) ai->StopMoving(); } - if (CheckMountStateAction::CurrentMountSpeed(bot)) + if (AI_VALUE2(uint32, "current mount speed", "self target")) { if (bot->IsFlying() && WorldPosition(bot).currentHeight() > 10.0f) diff --git a/playerbot/strategy/values/MountValues.cpp b/playerbot/strategy/values/MountValues.cpp new file mode 100644 index 000000000..c81a331c6 --- /dev/null +++ b/playerbot/strategy/values/MountValues.cpp @@ -0,0 +1,228 @@ +#include "botpch.h" +#include "MountValues.h" + +using namespace ai; + +uint32 MountValue::GetSpeed(uint32 spellId, bool canFly) +{ +#ifdef MANGOSBOT_ZERO + if (canFly) + return 0; +#endif + + const SpellEntry* const spellInfo = sSpellTemplate.LookupEntry(spellId); + + if (!spellInfo) + return 0; + + switch (spellInfo->Id) //Aura's hard coded in spell.cpp + { + case 783: //travel form + case 2645: //ghost wolf + if(!canFly) + return 39; + break; + case 33943: //flight form + if (canFly) + return 59; + break; + case 40120: //swift flight form + if (canFly) + return 279; + break; + case 26656: //Black AQ mount + if (!canFly) + return 99; + } + + bool isMount = false; + for (int i = 0; i < 3; i++) + { + if (spellInfo->EffectApplyAuraName[i] == SPELL_AURA_MOUNTED) + { + isMount = true; + break; + } + } + + if(!isMount) + return 0; + +#ifndef MANGOSBOT_ZERO + //This part stops bots from mounting flying mounts when they can't fly. This should be tweaked if bots ever are able to normally ride flying mounts in the old-world. + if (isMount && !canFly) + { + for (int i = 0; i < 3; i++) + { + if (spellInfo->EffectApplyAuraName[i] == SPELL_AURA_MOD_FLIGHT_SPEED_MOUNTED) + { + return 0; + } + } + } +#endif + +#ifdef MANGOSBOT_ZERO + uint32 effect = SPELL_AURA_MOD_INCREASE_MOUNTED_SPEED; +#else + uint32 effect = canFly ? SPELL_AURA_MOD_FLIGHT_SPEED_MOUNTED : SPELL_AURA_MOD_INCREASE_MOUNTED_SPEED; //If we can fly only look at flight speed. Normal mounts then don't get any speed. +#endif + + if (isMount) + { + for (int i = 0; i < 3; i++) + { + if (spellInfo->EffectApplyAuraName[i] == effect) + { + return spellInfo->EffectBasePoints[i]; + } + } + } + + return 0; +} + +uint32 MountValue::GetMountSpell(uint32 itemId) +{ + const ItemPrototype* proto = sObjectMgr.GetItemPrototype(itemId); + + if (!proto) + return 0; + + uint32 speed = 0; + for (int j = 0; j < MAX_ITEM_PROTO_SPELLS; j++) + { + if (GetSpeed(proto->Spells[j].SpellId)) + return proto->Spells[j].SpellId; + + if (GetSpeed(proto->Spells[j].SpellId, true)) + return proto->Spells[j].SpellId; + } + + return 0; +} + +bool MountValue::IsValidLocation() +{ + if (GetSpeed(true)) //Flying mount + { + if (bot->GetMapId() != 530 && bot->GetMapId() != 571) + return false; + +#ifdef MANGOSBOT_ONE + uint32 zone, area; + bot->GetZoneAndAreaId(zone, area); + uint32 v_map = GetVirtualMapForMapAndZone(bot->GetMapId(), zone); + MapEntry const* mapEntry = sMapStore.LookupEntry(v_map); + if (!mapEntry || mapEntry->addon < 1 || !mapEntry->IsContinent()) + return false; +#endif +#ifdef MANGOSBOT_TWO + uint32 zone, area; + bot->GetZoneAndAreaId(zone, area); + if (!bot->CanStartFlyInArea(bot->GetMapId(), zone, area, false)) + return false; +#endif + } + + const SpellEntry* const spellInfo = sSpellTemplate.LookupEntry(spellId); + + bool isAQ40Mounted = false; + + switch (spellInfo->Id) + { + case 25863: // spell used by ingame item for Black Qiraji mount (legendary reward) + case 26655: // spells also related to Black Qiraji mount but use/trigger unknown + case 26656: + case 31700: + if (bot->GetMapId() == 531) + isAQ40Mounted = true; + break; + case 25953: // spells of the 4 regular AQ40 mounts + case 26054: + case 26055: + case 26056: + if (bot->GetMapId() == 531) + { + isAQ40Mounted = true; + break; + } + else + return false; //SPELL_FAILED_NOT_HERE; + default: + break; + } + + // Ignore map check if spell have AreaId. AreaId already checked and this prevent special mount spells + if (bot->GetTypeId() == TYPEID_PLAYER && + !isAQ40Mounted && // [-ZERO] && !m_spellInfo->AreaId) + (bot->GetMap() && !bot->GetMap()->IsMountAllowed())) + { + return false; //SPELL_FAILED_NO_MOUNTS_ALLOWED; + } + + if (bot->GetAreaId() == 35) + return false; //SPELL_FAILED_NO_MOUNTS_ALLOWED; + + return true; +} + +uint32 CurrentMountSpeedValue::Calculate() +{ + Unit* unit = AI_VALUE(Unit*, getQualifier()); + + uint32 mountSpeed = 0; + + for (uint32 auraType = SPELL_AURA_BIND_SIGHT; auraType < TOTAL_AURAS; auraType++) + { + Unit::AuraList const& auras = unit->GetAurasByType((AuraType)auraType); + + if (auras.empty()) + continue; + + for (Unit::AuraList::const_iterator i = auras.begin(); i != auras.end(); i++) + { + Aura* aura = *i; + if (!aura) + continue; + + SpellEntry const* auraSpell = aura->GetSpellProto(); + + uint32 auraSpeed = MountValue::GetSpeed(auraSpell->Id); + + if (auraSpeed < mountSpeed) + continue; + + mountSpeed = auraSpeed; + } + } + + return mountSpeed; +} + +vector MountListValue::Calculate() +{ + vector mounts; + + for (auto& mount : AI_VALUE2(list, "inventory items", "mount")) + mounts.push_back(MountValue(ai, mount)); + + for (PlayerSpellMap::iterator itr = bot->GetSpellMap().begin(); itr != bot->GetSpellMap().end(); ++itr) + if (itr->second.state != PLAYERSPELL_REMOVED && !itr->second.disabled && !IsPassiveSpell(itr->first)) + if(MountValue::IsMountSpell(itr->first)) + mounts.push_back(MountValue(ai, itr->first)); + + return mounts; +} + +string MountListValue::Format() +{ + ostringstream out; out << "{"; + for (auto& mount : this->Calculate()) + { + string speed = to_string(mount.GetSpeed(false) + 1) + "%" + (mount.GetSpeed(true) ? ("/" + (to_string(mount.GetSpeed(true) + 1) + "%")) : ""); + out << (mount.IsItem() ? "(item)" : "(spell)") << chat->formatSpell(mount.GetSpellId()) << "(" << speed.c_str() << "),"; + } + out << "}"; + return out.str(); +} \ No newline at end of file diff --git a/playerbot/strategy/values/MountValues.h b/playerbot/strategy/values/MountValues.h new file mode 100644 index 000000000..8e920298b --- /dev/null +++ b/playerbot/strategy/values/MountValues.h @@ -0,0 +1,44 @@ +#pragma once +#include "../Value.h" + +namespace ai +{ + class MountValue : AiObject + { + public: + MountValue(PlayerbotAI* ai, uint32 spellId) : AiObject(ai), spellId(spellId) {}; + MountValue(PlayerbotAI* ai, Item* item) : AiObject(ai), itemGuid(item->GetObjectGuid()) { spellId = GetMountSpell(item->GetProto()->ItemId); }; + + bool IsItem() { return itemGuid; } + Item* GetItem() { return bot->GetItemByGuid(itemGuid); } + uint32 GetSpellId() { return spellId; } + + uint32 GetSpeed(bool canFly) {return GetSpeed(spellId, canFly);} + + static uint32 IsMountSpell(uint32 spellId) { return GetSpeed(spellId, false) || GetSpeed(spellId, true); } + static uint32 GetSpeed(uint32 spellId, bool canFly); + static uint32 GetSpeed(uint32 spellId) { return std::max(GetSpeed(spellId, false), GetSpeed(spellId, true)); }; + static uint32 GetMountSpell(uint32 itemId); + bool IsValidLocation(); + private: + ObjectGuid itemGuid = ObjectGuid(); + uint32 spellId = 0; + }; + + class CurrentMountSpeedValue : public Uint32CalculatedValue, public Qualified + { + public: + CurrentMountSpeedValue(PlayerbotAI* ai) : Uint32CalculatedValue(ai, "current mount speed", 1) {} + public: + virtual uint32 Calculate(); + }; + + class MountListValue : public CalculatedValue> + { + public: + MountListValue(PlayerbotAI* ai) : CalculatedValue>(ai, "mount list", 10) {} + public: + virtual vector Calculate(); + virtual string Format(); + }; +} diff --git a/playerbot/strategy/values/StatsValues.cpp b/playerbot/strategy/values/StatsValues.cpp index f802b8cea..8098c224b 100644 --- a/playerbot/strategy/values/StatsValues.cpp +++ b/playerbot/strategy/values/StatsValues.cpp @@ -112,7 +112,7 @@ bool IsMountedValue::Calculate() if (target->IsMounted()) return true; - if (CheckMountStateAction::CurrentMountSpeed(target)) + if (AI_VALUE2(uint32, "current mount speed", getQualifier())) return true; return false; diff --git a/playerbot/strategy/values/ValueContext.h b/playerbot/strategy/values/ValueContext.h index d97d200fe..6265bf921 100644 --- a/playerbot/strategy/values/ValueContext.h +++ b/playerbot/strategy/values/ValueContext.h @@ -95,6 +95,7 @@ #include "HazardsValue.h" #include "FocusTargetValue.h" #include "TalentSpecValue.h" +#include "MountValues.h" namespace ai { @@ -350,6 +351,8 @@ namespace ai creators["RTSC saved location"] = &ValueContext::RTSC_saved_location; creators["trainable class spells"] = &ValueContext::trainable_class_spells; + creators["mount list"] = &ValueContext::mount_list; + creators["current mount speed"] = &ValueContext::current_mount_speed; creators["has area debuff"] = &ValueContext::has_area_debuff; creators["combat start time"] = &ValueContext::combat_start_time; @@ -615,6 +618,8 @@ namespace ai static UntypedValue* RTSC_saved_location(PlayerbotAI* ai) { return new RTSCSavedLocationValue(ai); } static UntypedValue* trainable_class_spells(PlayerbotAI* ai) { return new TrainableClassSpells(ai); } + static UntypedValue* mount_list(PlayerbotAI* ai) { return new MountListValue(ai); } + static UntypedValue* current_mount_speed(PlayerbotAI* ai) { return new CurrentMountSpeedValue(ai); } static UntypedValue* has_area_debuff(PlayerbotAI* ai) { return new HasAreaDebuffValue(ai); } static UntypedValue* combat_start_time(PlayerbotAI* ai) { return new CombatStartTimeValue(ai); }