[Bots] Add Basic Bot Raiding Functionality (#2782)

* Fix for GENERIC_9_STRINGS

* Add Bot Heal Message Display

Creates a new rule to display Bot heal messages to the Bot Owner

* 2021-03-25 11L04pm

Spell and Heal Rule added to allow for Bot spell and heal damage to be sent to the Bot Owner's Group.  Also added a check to remove duplicate message for #damage on self.

* Update .gitignore

* BOT work

Added BOT logging damage/heals to owner
Added BOT message to owner for harmony fails
Made var Critical global to remove duplicate crit messages
Added a NULL check to Mob:GetCleanname()

* Bot Group Work

Fixed botid=charid spawn on zone issue
Added a group_list update on zone to refresh from database to fix a dangling pointer to a Bot object that was camped but was previously in a group within the zone being entered.
Modified Bot::ProcessBotGroupInvite to use the client of the bot when doing the Bot initialization so that a leader can invite another owner's Bot

* Jan 4

Basic structure in place for Raid::AddBot though not working

* Basement Jan 5

* End of day Jan 5
Working Raid Invite to a Bot.

* Update to Client::QueuePacket to not attempt to send a packet to a BoT.  Not clean, but a broad solution.

* Updated Raid::VerifyRaid

* Some Bot Raid working

* Before VS Crash

* Use Case 1, 2, 3,4,7 working.
Need to fix 5, 6, 8

* Work on usecase 5

* A few more use cases working

* New work on Raid invite with a invitor having a group

* Bot Raid inviting working for all use cases

* A few changes

* end of day jan 10

* Jan 11

* end of day Jan 11

* Bot Invite/Accept cleanup

* Start of moving raid bot functions to their own methods

* More bot raid changes

* More raid spell work

* end of day Jan 16

* spawn work

* Spawn on login working

* End of Day Jan 18

* Raid leader and mana/hp updates fixed

* Spell Tracking

* Issue with Bot Death in raid when casted upon.  1741 raid.cpp

* Bot Death fixed and few other crashes

* Working on botgroup removal

* Bot Disbanding Work 90%

* Looks like BOTs are working

* Fixed a bot crash

* bug tracing on entity list mismatch

* safe_delete resoves problem.  No to track down leak

* seems to be working

* Memory corruption found - sending packets to BoTs using Client class

* added Raid::IsRaidMemberBot()

* Update p_raid_instance

* g3

* Final - Bot Raid Working

* Fixed IsRaidMemberBot to remove memory leak
Fixed altcombat crash though RaidMainAssist (428) needs fixing

* add RaidMember.IsBot

* Repaired IsBot function to be more preformant.  Now works on standard performance machine

* Fixed Bard AE Target Spells
Removed assert for buffs

* updated based on Feb 2022 master updates

* Added bot_db_updates and version increment

* Cleanup of bot raid work and inclusion of bot_raid in cmake

* Delete .gitignore

* Revert "Delete .gitignore"

This reverts commit 8523658d3b.

* Fixed a packet issue

* Merged upstream/master

Merged upstream/master and removed ifdef BOTS as per recent dev approach for BOTS.  Functionality is there, compiles and tests ok.  A few problems to be resolved though this is a good baseline.

* Added sql update for raid_members to add isbot

* Updated Bot Follow Function

Bot will now follow the Group Leader if IsClient, otherwise follows the Bot Owner

* Updates to Bot Raid System

When camping a client, remove them from the raid.  If they are leader, place leadership to the next client.
Update a few crash checks in bot_raid.cpp

* [BOTS] Added RuleB Enabled checks and updated base repo for raid_members

Updated several RuleB(Bots, Enabled) checks
Updated the base repo to be autogenerated.
Raid functionality should work with a non-bots enabled database.

* Few quick updates

* Updates

Corrected a number of comments.  Compiled and tested against bot and non-bot database though requires the isbot column in raid_members for both.
Moved the db update out of the bot stream to make bot check code easier.

* Formatting and other small updates

* A few more RuleB(Bots, Enabled) additions

* Fix issue with conflict of bot ID versus character ID.

* Delete CMakeSettings.json

* Comment Updates and other

Several updates including
- fixed comments from PR
- added id to raid_members and unique index on name to avoid botid and charid conflicts
- updated a few raid functions for iterators
- reordered several raid operations to ensure send leader packet to be the last item to ensure proper updating on the client
- update sql to use Replace instead of Insert for botid conflicting with charid

* Exploit fix for Raid Bots

Added item from @Nite to disallow spawning or camping bots if Raid is engaged.  Avoids abusive situations.

* Initial Commit

* fix Raid Window after zoning

The raid window was not fully updating for clients not in the zone.

* Cleanup

* Update

Fixed comments

* Resolve crash for MOTD

Fixed a crash situation sending a raid MOTD to BOTS.

* Update ruletypes.h

* Updated to resolve a few recent comments

Fixed some comments within attack.cpp

* fix sql query

* update repository

* prevent duplicate entries in raid after group invite, and cleanup

* fixes for botgroups not following, and add already in raid messages.

* fix messagestring

* fixes

* Cleanup, and resolving issues with disbanding

* refactoring

* more cleanup/fixing.

* fixes for removing from ground in raid

* Refactoring/fixing multiple clients

* fix for compiling

* Bugs from refactoring fixed

* Testing completed, cleaning up unwanted items/duplicate code.

* Cleaned up AICastSpell

* fix typos

* Refactoring

* Adding Raid checks to AI_Process/cleanup

* Fix a typo

Was getting a SQL error on BOT spawn.  Fixed typo.

* fix for crash

* Fixed crash when inviting player, more refactoring

* AI_Process Refactoring work

* More Refactoring/fixes for follow

* Finish Refactoring AI_Process

* cleanup

* cleanup

* cleanup

* cleanup

* fix melee attack loop

* fix for leashowner.

* fix for leashowner.

* Bots persist in raid after client death/LD/Camp

* Fix Bot Groups when zoning after death.

* Fix Bots in group following after client death

* remove unnecessary query

* Allow Raid members to invite Bots if owner is in raid. cleanup

* optimization of raid verification

* remove this

* Code Cleanup

* formatting

* formatting

* formatting

* fix for macro

* add return for TryClassAttacks

* fix query

* fix for crash

* restrict camping/spawn in combat.

* Fix other crash issue.

* update learnmembers to use Strings::To, cleanup magic numbers

* fix for merge.

---------

Co-authored-by: Kinglykrab <kinglykrab@gmail.com>
Co-authored-by: Alex King <89047260+Kinglykrab@users.noreply.github.com>
Co-authored-by: Aeadoin <109764533+Aeadoin@users.noreply.github.com>
This commit is contained in:
Mitch Freeman
2023-03-17 12:19:59 -03:00
committed by GitHub
parent e778041198
commit 45da8cab61
35 changed files with 5429 additions and 5050 deletions
+173 -110
View File
@@ -33,6 +33,7 @@
#include "../common/global_define.h"
#include "guild_mgr.h"
#include "worldserver.h"
#include "raids.h"
#include <sstream>
@@ -42,9 +43,6 @@ constexpr uint32 BOT_FOLLOW_DISTANCE_WALK = 1000; // as DSq value (~31.623 units
constexpr uint32 BOT_KEEP_ALIVE_INTERVAL = 5000; // 5 seconds
//constexpr uint32 BOT_COMBAT_JITTER_INTERVAL_MIN = 5000; // 5 seconds
//constexpr uint32 BOT_COMBAT_JITTER_INTERVAL_MAX = 20000; // 20 seconds
extern WorldServer worldserver;
constexpr int BotAISpellRange = 100; // TODO: Write a method that calcs what the bot's spell range is based on spell, equipment, AA, whatever and replace this
@@ -53,8 +51,6 @@ constexpr int MaxDisciplineTimer = 10;
constexpr int DisciplineReuseStart = MaxSpellTimer + 1;
constexpr int MaxTimer = MaxSpellTimer + MaxDisciplineTimer;
// nHSND negative Healer/Slower/Nuker/Doter
// pH positive Healer
// pS positive Slower
@@ -141,13 +137,13 @@ public:
void Damage(Mob* from, int64 damage, uint16 spell_id, EQ::skills::SkillType attack_skill, bool avoidable = true, int8 buffslot = -1,
bool iBuffTic = false, eSpecialAttacks special = eSpecialAttacks::None) override;
bool HasRaid() final { return (GetRaid() ? true : false); }
bool HasGroup() final { return (GetGroup() ? true : false); }
Raid* GetRaid() final { return entity_list.GetRaidByMob(this); }
bool HasRaid() final { return GetRaid() != nullptr; }
bool HasGroup() final { return GetGroup() != nullptr; }
Raid* GetRaid() final { return entity_list.GetRaidByBot(this); }
Group* GetGroup() final { return entity_list.GetGroupByMob(this); }
// Common, but informal "interfaces" with Client object
uint32 CharacterID() { return GetBotID(); } // Just returns the Bot Id
uint32 CharacterID() const { return GetBotID(); }
inline bool IsInAGuild() const { return (_guildId != GUILD_NONE && _guildId != 0); }
inline bool IsInGuild(uint32 in_gid) const { return (in_gid == _guildId && IsInAGuild()); }
inline uint32 GuildID() const { return _guildId; }
@@ -173,20 +169,19 @@ public:
int GetHandToHandDamage(void) override;
bool TryFinishingBlow(Mob *defender, int64 &damage) override;
void DoRiposte(Mob* defender) override;
inline int32 GetATK() const override { return ATK + itembonuses.ATK + spellbonuses.ATK + ((GetSTR() + GetSkill(EQ::skills::SkillOffense)) * 9 / 10); }
inline int32 GetATK() { return ATK + itembonuses.ATK + spellbonuses.ATK + ((GetSTR() + GetSkill(EQ::skills::SkillOffense)) * 9 / 10); }
inline int32 GetATKBonus() const override { return itembonuses.ATK + spellbonuses.ATK; }
uint32 GetTotalATK();
uint32 GetATKRating();
uint16 GetPrimarySkillValue();
uint16 MaxSkill(EQ::skills::SkillType skillid, uint16 class_, uint16 level) const;
inline uint16 MaxSkill(EQ::skills::SkillType skillid) const { return MaxSkill(skillid, GetClass(), GetLevel()); }
inline uint16 MaxSkill(EQ::skills::SkillType skillid) { return MaxSkill(skillid, GetClass(), GetLevel()); }
int GetBaseSkillDamage(EQ::skills::SkillType skill, Mob *target = nullptr) override;
void DoSpecialAttackDamage(Mob *who, EQ::skills::SkillType skill, int32 max_damage, int32 min_damage = 1, int32 hate_override = -1, int ReuseTime = 10, bool HitChance = false);
void TryBackstab(Mob *other,int ReuseTime = 10) override;
void RogueBackstab(Mob* other, bool min_damage = false, int ReuseTime = 10) override;
void RogueAssassinate(Mob* other) override;
void DoClassAttacks(Mob *target, bool IsRiposte=false);
bool CanDoSpecialAttack(Mob *other);
void CalcBonuses() override;
void CalcItemBonuses(StatBonuses* newbon);
void AddItemBonuses(const EQ::ItemInstance *inst, StatBonuses* newbon, bool isAug = false, bool isTribute = false, int rec_override = 0);
@@ -197,7 +192,7 @@ public:
bool IsNPC() const override { return false; }
Mob* GetOwner() override;
Mob* GetOwnerOrSelf() override;
inline bool HasOwner() override { return (GetBotOwner() ? true : false); }
inline bool HasOwner() override { return GetBotOwner() != nullptr; }
int64 CalcMaxMana() override;
void SetAttackTimer() override;
uint64 GetClassHPFactor();
@@ -215,36 +210,35 @@ public:
void Stand();
bool IsSitting() const override;
bool IsStanding();
int GetWalkspeed() const override { return (int)((float)_GetWalkSpeed() * 1.785714285f); } // 1.25 / 0.7 = 1.7857142857142857142857142857143
int GetRunspeed() const override { return (int)((float)_GetRunSpeed() * 1.785714285f); }
int GetWalkspeed() { return (int)((float)_GetWalkSpeed() * 1.785714285f); } // 1.25 / 0.7 = 1.7857142857142857142857142857143
int GetRunspeed() { return (int)((float)_GetRunSpeed() * 1.785714285f); }
void WalkTo(float x, float y, float z) override;
void RunTo(float x, float y, float z) override;
void StopMoving() override;
void StopMoving(float new_heading) override;
//bool GetCombatJitterFlag() { return m_combat_jitter_flag; }
bool GetGuardFlag() { return m_guard_flag; }
bool GetGuardFlag() const { return m_guard_flag; }
void SetGuardFlag(bool flag = true) { m_guard_flag = flag; }
bool GetHoldFlag() { return m_hold_flag; }
bool GetHoldFlag() const { return m_hold_flag; }
void SetHoldFlag(bool flag = true) { m_hold_flag = flag; }
bool GetAttackFlag() { return m_attack_flag; }
bool GetAttackFlag() const { return m_attack_flag; }
void SetAttackFlag(bool flag = true) { m_attack_flag = flag; }
bool GetAttackingFlag() { return m_attacking_flag; }
bool GetPullFlag() { return m_pull_flag; }
bool GetAttackingFlag() const { return m_attacking_flag; }
bool GetPullFlag() const { return m_pull_flag; }
void SetPullFlag(bool flag = true) { m_pull_flag = flag; }
bool GetPullingFlag() { return m_pulling_flag; }
bool GetReturningFlag() { return m_returning_flag; }
bool GetPullingFlag() const { return m_pulling_flag; }
bool GetReturningFlag() const { return m_returning_flag; }
bool UseDiscipline(uint32 spell_id, uint32 target);
uint8 GetNumberNeedingHealedInGroup(uint8 hpr, bool includePets);
uint8 GetNumberNeedingHealedInGroup(uint8 hpr, bool includePets, Raid* raid);
uint8 GetNumberNeedingHealedInRaidGroup(uint8& need_healed, uint8 hpr, bool includePets, Raid* raid);
bool GetNeedsCured(Mob *tar);
bool GetNeedsHateRedux(Mob *tar);
bool HasOrMayGetAggro();
void SetDefaultBotStance();
void SetSurname(std::string bot_surname);
void SetTitle(std::string bot_title);
void SetSuffix(std::string bot_suffix);
std::string GetSurname() { return _surname; }
std::string GetTitle() { return _title; }
std::string GetSuffix() { return _suffix; }
void SetSurname(std::string_view bot_surname);
void SetTitle(std::string_view bot_title);
void SetSuffix(std::string_view bot_suffix);
std::string GetSurname() const { return _surname; }
std::string GetTitle() const { return _title; }
std::string GetSuffix() const { return _suffix; }
inline virtual int32 GetMaxStat();
inline virtual int32 GetMaxResist();
inline virtual int32 GetMaxSTR();
@@ -282,19 +276,18 @@ public:
uint32 CalcCurrentWeight();
int GroupLeadershipAAHealthEnhancement();
int GroupLeadershipAAManaEnhancement();
int GroupLeadershipAAHealthRegeneration();
int GroupLeadershipAAHealthRegeneration();
int GroupLeadershipAAOffenseEnhancement();
void CalcRestState();
int64 CalcMaxEndurance(); //This calculates the maximum endurance we can have
int64 CalcBaseEndurance(); //Calculates Base End
int64 CalcEnduranceRegen(); //Calculates endurance regen used in DoEnduranceRegen()
int64 GetEndurance() const {return cur_end;} //This gets our current endurance
int64 GetMaxEndurance() const {return max_end;} //This gets our endurance from the last CalcMaxEndurance() call
int64 CalcEnduranceRegenCap();
inline uint8 GetEndurancePercent() { return (uint8)((float)cur_end / (float)max_end * 100.0f); }
void SetEndurance(int32 newEnd); //This sets the current endurance to the new value
void DoEnduranceRegen(); //This Regenerates endurance
void DoEnduranceUpkeep(); //does the endurance upkeep
int64 CalcMaxEndurance();
int64 CalcBaseEndurance();
int64 CalcEnduranceRegen();
int64 GetEndurance() const override {return cur_end;}
int64 GetMaxEndurance() const override {return max_end;}
int64 CalcEnduranceRegenCap();
inline uint8 GetEndurancePercent() override { return (uint8)((float)cur_end / (float)max_end * 100.0f); }
void SetEndurance(int32 newEnd) override;
void DoEnduranceUpkeep();
bool AI_AddBotSpells(uint32 bot_spell_id);
void AddSpellToBotList(
@@ -330,19 +323,20 @@ public:
);
void AI_Bot_Event_SpellCastFinished(bool iCastSucceeded, uint16 slot);
// AI Methods
bool AICastSpell(Mob* tar, uint8 iChance, uint32 iSpellTypes);
bool AI_EngagedCastCheck() override;
bool AI_PursueCastCheck() override;
bool AI_IdleCastCheck() override;
bool AIHealRotation(Mob* tar, bool useFastHeals);
bool GetPauseAI() { return _pauseAI; }
bool GetPauseAI() const { return _pauseAI; }
void SetPauseAI(bool pause_flag) { _pauseAI = pause_flag; }
uint8 GetStopMeleeLevel() { return _stopMeleeLevel; }
uint8 GetStopMeleeLevel() const { return _stopMeleeLevel; }
void SetStopMeleeLevel(uint8 level);
void SetGuardMode();
void SetHoldMode();
uint32 GetBotCasterRange() { return m_bot_caster_range; }
uint32 GetBotCasterRange() const { return m_bot_caster_range; }
bool IsValidSpellRange(uint16 spell_id, Mob const* tar);
// Bot AI Methods
@@ -375,7 +369,7 @@ public:
bool IsImmuneToSpell(uint16 spell_id, Mob *caster) override;
virtual bool DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_center, CastAction_type &CastAction, EQ::spells::CastingSlot slot);
virtual bool DoCastSpell(uint16 spell_id, uint16 target_id, EQ::spells::CastingSlot slot = EQ::spells::CastingSlot::Item, int32 casttime = -1, int32 mana_cost = -1,
uint32* oSpellWillFinish = 0, uint32 item_slot = 0xFFFFFFFF, uint32 aa_id = 0);
uint32* oSpellWillFinish = nullptr, uint32 item_slot = 0xFFFFFFFF, uint32 aa_id = 0);
inline int64 GetFocusEffect(focusType type, uint16 spell_id, Mob *caster = nullptr, bool from_buff_tic = false) override
{ return Mob::GetFocusEffect(type, spell_id, caster, from_buff_tic); }
inline bool Attack(Mob* other, int Hand = EQ::invslot::slotPrimary, bool FromRiposte = false, bool IsStrikethrough = false,
@@ -389,40 +383,51 @@ public:
bool GetBotOwnerDataBuckets();
bool GetBotDataBuckets();
bool CheckDataBucket(std::string bucket_name, std::string bucket_value, uint8 bucket_comparison);
bool CheckDataBucket(const std::string& bucket_name, const std::string& bucket_value, uint8 bucket_comparison);
// Bot Equipment & Inventory Class Methods
void BotTradeAddItem(const EQ::ItemInstance* inst, uint16 slot_id, std::string* error_message, bool save_to_database = true);
void EquipBot(std::string* error_message);
bool CheckLoreConflict(const EQ::ItemData* item);
void UpdateEquipmentLight() override { m_Light.Type[EQ::lightsource::LightEquipment] = m_inv.FindBrightestLightType(); m_Light.Level[EQ::lightsource::LightEquipment] = EQ::lightsource::TypeToLevel(m_Light.Type[EQ::lightsource::LightEquipment]); }
inline EQ::InventoryProfile& GetInv() { return m_inv; }
void UpdateEquipmentLight() override
{
m_Light.Type[EQ::lightsource::LightEquipment] = m_inv.FindBrightestLightType();
m_Light.Level[EQ::lightsource::LightEquipment] = EQ::lightsource::TypeToLevel(m_Light.Type[EQ::lightsource::LightEquipment]);
}
inline EQ::InventoryProfile& GetInv() override { return m_inv; }
// Static Class Methods
//static void DestroyBotRaidObjects(Client* client); // Can be removed after bot raids are dumped
static Bot* LoadBot(uint32 botID);
static uint32 SpawnedBotCount(const uint32 owner_id, uint8 class_id = NO_CLASS);
static void LevelBotWithClient(Client* client, uint8 level, bool sendlvlapp);
//static bool SetBotOwnerCharacterID(uint32 botID, uint32 botOwnerCharacterID, std::string* error_message);
static bool IsBotAttackAllowed(Mob* attacker, Mob* target, bool& hasRuleDefined);
static Bot* GetBotByBotClientOwnerAndBotName(Client* c, std::string botName);
static void ProcessBotGroupInvite(Client* c, std::string botName);
static void ProcessBotGroupDisband(Client* c, std::string botName);
static Bot* GetBotByBotClientOwnerAndBotName(Client* c, const std::string& botName);
static void ProcessBotGroupInvite(Client* c, std::string const& botName);
static void ProcessBotGroupDisband(Client* c, const std::string& botName);
static void BotOrderCampAll(Client* c, uint8 class_id = NO_CLASS);
static void ProcessBotInspectionRequest(Bot* inspectedBot, Client* client);
static void LoadAndSpawnAllZonedBots(Client* bot_owner);
static bool GroupHasBot(Group* group);
static Bot* GetFirstBotInGroup(Group* group);
static void ProcessClientZoneChange(Client* botOwner);
static void ProcessBotOwnerRefDelete(Mob* botOwner); // Removes a Client* reference when the Client object is destroyed
static void ProcessGuildInvite(Client* guildOfficer, Bot* botToGuild); // Processes a client's request to guild a bot
static bool ProcessGuildRemoval(Client* guildOfficer, std::string botName); // Processes a client's request to deguild a bot
static void ProcessBotOwnerRefDelete(Mob* botOwner); // Removes a Client* reference when the Client object is destroyed
static int32 GetSpellRecastTimer(Bot *caster, int timer_index);
static bool CheckSpellRecastTimers(Bot *caster, int SpellIndex);
static int32 GetDisciplineRecastTimer(Bot *caster, int timer_index);
static bool CheckDisciplineRecastTimers(Bot *caster, int timer_index);
static uint32 GetDisciplineRemainingTime(Bot *caster, int timer_index);
//Raid methods
static void ProcessRaidInvite(Mob* invitee, Client* invitor, bool group_invite = false);
static void RemoveBotFromRaid(Bot* bot);
inline void SetDirtyAutoHaters() { m_dirtyautohaters = true; }
static void CreateBotRaid(Mob* invitee, Client* invitor, bool group_invite, Raid* raid);
static void
ProcessBotGroupAdd(Group* group, Raid* raid, Client* client = nullptr, bool new_raid = false, bool initial = false);
static std::list<BotSpell> GetBotSpellsForSpellEffect(Bot* botCaster, int spellEffect);
static std::list<BotSpell> GetBotSpellsForSpellEffectAndTargetType(Bot* botCaster, int spellEffect, SpellTargetType targetType);
static std::list<BotSpell> GetBotSpellsBySpellType(Bot* botCaster, uint32 spellType);
@@ -452,8 +457,8 @@ public:
static BotSpell GetBestBotSpellForResistDebuff(Bot* botCaster, Mob* target);
static NPCType *CreateDefaultNPCTypeStructForBot(
std::string botName,
std::string botLastName,
const std::string& botName,
const std::string& botLastName,
uint8 botLevel,
uint16 botRace,
uint8 botClass,
@@ -467,8 +472,8 @@ public:
// "GET" Class Methods
uint32 GetBotID() const { return _botID; }
uint32 GetBotOwnerCharacterID() { return _botOwnerCharacterID; }
uint32 GetBotSpellID() { return npc_spells_id; }
uint32 GetBotOwnerCharacterID() const { return _botOwnerCharacterID; }
uint32 GetBotSpellID() const { return npc_spells_id; }
Mob* GetBotOwner() { return this->_botOwner; }
uint32 GetBotArcheryRange();
EQ::ItemInstance* GetBotItem(uint16 slot_id);
@@ -486,18 +491,12 @@ public:
uint8 GetChanceToCastBySpellType(uint32 spellType);
bool GetBotEnforceSpellSetting() { return m_enforce_spell_settings; }
float GetBotCasterMaxRange(float melee_distance_max);
bool IsGroupHealer() { return m_CastingRoles.GroupHealer; }
bool IsGroupSlower() { return m_CastingRoles.GroupSlower; }
bool IsGroupNuker() { return m_CastingRoles.GroupNuker; }
bool IsGroupDoter() { return m_CastingRoles.GroupDoter; }
bool IsGroupHealer() const { return m_CastingRoles.GroupHealer; }
bool IsGroupSlower() const { return m_CastingRoles.GroupSlower; }
bool IsGroupNuker() const { return m_CastingRoles.GroupNuker; }
bool IsGroupDoter() const { return m_CastingRoles.GroupDoter; }
static void UpdateGroupCastingRoles(const Group* group, bool disband = false);
//bool IsRaidHealer() { return m_CastingRoles.RaidHealer; }
//bool IsRaidSlower() { return m_CastingRoles.RaidSlower; }
//bool IsRaidNuker() { return m_CastingRoles.RaidNuker; }
//bool IsRaidDoter() { return m_CastingRoles.RaidDoter; }
//static void UpdateRaidCastingRoles(const Raid* raid, bool disband = false);
bool IsBotCaster() { return IsCasterClass(GetClass()); }
bool IsBotHybrid() { return IsHybridClass(GetClass()); }
bool IsBotINTCaster() { return IsINTCasterClass(GetClass()); }
@@ -506,7 +505,6 @@ public:
bool IsBotFighter() { return IsFighterClass(GetClass()); }
bool IsBotNonSpellFighter() { return IsNonSpellFighterClass(GetClass()); }
uint8 GetBotClass() { return GetClass(); }
bool CanHeal();
int GetRawACNoShield(int &shield_ac);
// new heal rotation code
@@ -532,8 +530,8 @@ public:
std::shared_ptr<HealRotation>* MemberOfHealRotation() { return &m_member_of_heal_rotation; }
bool GetAltOutOfCombatBehavior() { return _altoutofcombatbehavior;}
bool GetShowHelm() { return _showhelm; }
bool GetAltOutOfCombatBehavior() const { return _altoutofcombatbehavior;}
bool GetShowHelm() const { return _showhelm; }
inline int32 GetSTR() const override { return STR; }
inline int32 GetSTA() const override { return STA; }
inline int32 GetDEX() const override { return DEX; }
@@ -609,7 +607,6 @@ public:
void SetBotCharmer(bool c) { _botCharmer = c; }
void SetPetChooser(bool p) { _petChooser = p; }
void SetBotOwner(Mob* botOwner) { this->_botOwner = botOwner; }
// void SetBotOwnerCharacterID(uint32 botOwnerCharacterID) { _botOwnerCharacterID = botOwnerCharacterID; }
void SetRangerAutoWeaponSelect(bool enable) { GetClass() == RANGER ? _rangerAutoWeaponSelect = enable : _rangerAutoWeaponSelect = false; }
void SetBotStance(EQ::constants::StanceType botStance) {
if (botStance >= EQ::constants::stancePassive && botStance <= EQ::constants::stanceBurnAE)
@@ -650,7 +647,7 @@ public:
void SetBotEnforceSpellSetting(bool enforcespellsettings, bool save = false);
bool GetBotEnforceSpellSetting() const { return m_enforce_spell_settings; }
static void SpawnBotGroupByName(Client* c, std::string botgroup_name, uint32 leader_id);
static void SpawnBotGroupByName(Client* c, const std::string& botgroup_name, uint32 leader_id);
std::string CreateSayLink(Client* botOwner, const char* message, const char* name);
@@ -663,8 +660,8 @@ public:
// Publicized private functions
static NPCType *FillNPCTypeStruct(
uint32 botSpellsID,
std::string botName,
std::string botLastName,
const std::string& botName,
const std::string& botLastName,
uint8 botLevel,
uint16 botRace,
uint8 botClass,
@@ -722,43 +719,116 @@ public:
// New accessors for BotDatabase access
bool DeleteBot();
uint32* GetTimers() { return timers; }
uint32 GetLastZoneID() { return _lastZoneId; }
int32 GetBaseAC() { return _baseAC; }
int32 GetBaseATK() { return _baseATK; }
int32 GetBaseSTR() { return _baseSTR; }
int32 GetBaseSTA() { return _baseSTA; }
int32 GetBaseCHA() { return _baseCHA; }
int32 GetBaseDEX() { return _baseDEX; }
int32 GetBaseINT() { return _baseINT; }
int32 GetBaseAGI() { return _baseAGI; }
int32 GetBaseWIS() { return _baseWIS; }
int32 GetBaseFR() { return _baseFR; }
int32 GetBaseCR() { return _baseCR; }
int32 GetBaseMR() { return _baseMR; }
int32 GetBasePR() { return _basePR; }
int32 GetBaseDR() { return _baseDR; }
int32 GetBaseCorrup() { return _baseCorrup; }
uint32 GetLastZoneID() const { return _lastZoneId; }
int32 GetBaseAC() const { return _baseAC; }
int32 GetBaseATK() const { return _baseATK; }
int32 GetBaseSTR() const { return _baseSTR; }
int32 GetBaseSTA() const { return _baseSTA; }
int32 GetBaseCHA() const { return _baseCHA; }
int32 GetBaseDEX() const { return _baseDEX; }
int32 GetBaseINT() const { return _baseINT; }
int32 GetBaseAGI() const { return _baseAGI; }
int32 GetBaseWIS() const { return _baseWIS; }
int32 GetBaseFR() const { return _baseFR; }
int32 GetBaseCR() const { return _baseCR; }
int32 GetBaseMR() const { return _baseMR; }
int32 GetBasePR() const { return _basePR; }
int32 GetBaseDR() const { return _baseDR; }
int32 GetBaseCorrup() const { return _baseCorrup; }
void Signal(int signal_id);
void SendPayload(int payload_id, std::string payload_value = std::string());
void OwnerMessage(std::string message);
void OwnerMessage(const std::string& message);
//Raid additions
Raid* p_raid_instance;
static uint8 spell_casting_chances[SPELL_TYPE_COUNT][PLAYER_CLASS_COUNT][EQ::constants::STANCE_TYPE_COUNT][cntHSND];
bool BotCastMez(Mob* tar, uint8 botLevel, bool checked_los, BotSpell& botSpell, Raid* raid);
bool BotCastHeal(Mob* tar, uint8 botLevel, uint8 botClass, BotSpell& botSpell, Raid* raid);
bool BotCastRoot(Mob* tar, uint8 botLevel, uint32 iSpellTypes, BotSpell& botSpell, const bool& checked_los);
bool BotCastBuff(Mob* tar, uint8 botLevel, uint8 botClass);
bool BotCastEscape(Mob*& tar, uint8 botClass, BotSpell& botSpell, uint32 iSpellTypes);
bool BotCastNuke(Mob* tar, uint8 botLevel, uint8 botClass, BotSpell& botSpell, const bool& checked_los);
bool BotCastDispel(Mob* tar, BotSpell& botSpell, uint32 iSpellTypes, const bool& checked_los);
bool BotCastPet(Mob* tar, uint8 botClass, BotSpell& botSpell);
bool BotCastCombatBuff(Mob* tar, uint8 botLevel, uint8 botClass);
bool BotCastLifetap(Mob* tar, uint8 botLevel, BotSpell& botSpell, const bool& checked_los, uint32 iSpellTypes);
bool BotCastSnare(Mob* tar, uint8 botLevel, BotSpell& botSpell, const bool& checked_los, uint32 iSpellTypes);
bool BotCastDOT(Mob* tar, uint8 botLevel, const BotSpell& botSpell, const bool& checked_los);
bool BotCastSlow(Mob* tar, uint8 botLevel, uint8 botClass, BotSpell& botSpell, const bool& checked_los, Raid* raid);
bool BotCastDebuff(Mob* tar, uint8 botLevel, BotSpell& botSpell, bool checked_los);
bool BotCastCure(Mob* tar, uint8 botClass, BotSpell& botSpell, Raid* raid);
bool BotCastHateReduction(Mob* tar, uint8 botLevel, const BotSpell& botSpell);
bool BotCastCombatSong(Mob* tar, uint8 botLevel);
bool BotCastSong(Mob* tar, uint8 botLevel);
bool CheckIfIncapacitated();
bool IsAIProcessValid(const Client* bot_owner, const Group* bot_group, const Raid* raid);
Client* SetLeashOwner(Client* bot_owner, Group* bot_group, Raid* raid, uint32 r_group) const;
Mob* SetFollowMob(Client* leash_owner);
Mob* GetBotTarget(Client* bot_owner);
void AcquireBotTarget(Group* bot_group, Raid* raid, Client* leash_owner, float leash_distance);
void SetBotTarget(Client* bot_owner, Raid* raid, Group* bot_group, Client* leash_owner, float lo_distance, float leash_distance, bool bo_alt_combat);
void SetLeashOwnerTarget(Client* leash_owner, Client* bot_owner, float lo_distance, float leash_distance);
void SetOwnerTarget(Client* bot_owner);
void SetBotGroupTarget(const Client* bot_owner, Client* leash_owner, float lo_distance, float leash_distance, Mob* const& bg_member, Mob* bgm_target);
bool IsValidTarget(Client* bot_owner, Client* leash_owner, float lo_distance, float leash_distance, bool bo_alt_combat, Mob* tar, float tar_distance);
bool PullingFlagChecks(Client* bot_owner);
bool ReturningFlagChecks(Client* bot_owner, float fm_distance);
void BotPullerProcess(Client* bot_owner, Raid* raid);
// Movement Methods
void CalcMeleeDistances(
const Mob* tar,
const EQ::ItemInstance* const& p_item,
const EQ::ItemInstance* const& s_item,
bool behind_mob,
bool backstab_weapon,
float& melee_distance_max,
float& melee_distance
) const;
// Combat Checks
void SetBerserkState();
bool CheckIfCasting(float fm_distance);
void HealRotationChecks();
void CheckCombatRange(Mob* tar, float tar_distance, bool& atCombatRange, const EQ::ItemInstance*& p_item, const EQ::ItemInstance*& s_item);
// Try Combat Methods
bool TryEvade(Mob* tar);
bool TryFacingTarget(Mob* tar);
bool TryRangedAttack(Mob* tar);
bool TryClassAttacks(Mob* tar);
bool TryPrimaryWeaponAttacks(Mob* tar, const EQ::ItemInstance* p_item);
bool TrySecondaryWeaponAttacks(Mob* tar, const EQ::ItemInstance* s_item);
bool TryPursueTarget(float leash_distance, glm::vec3& Goal);
bool TryMeditate();
bool TryAutoDefend(Client* bot_owner, float leash_distance);
bool TryIdleChecks(float fm_distance);
bool TryNonCombatMovementChecks(Client* bot_owner, const Mob* follow_mob, glm::vec3& Goal);
bool TryBardMovementCasts();
void SetRangerCombatWeapon(bool atArcheryRange);
// Public "Refactor" Methods
static bool CheckSpawnConditions(Client* c);
protected:
void PetAIProcess();
void BotMeditate(bool isSitting);
bool CheckBotDoubleAttack(bool Triple = false);
void PerformTradeWithClient(int16 begin_slot_id, int16 end_slot_id, Client* client);
bool AIDoSpellCast(uint8 i, Mob* tar, int32 mana_cost, uint32* oDontDoAgainBefore = 0) override;
bool AIDoSpellCast(int32 i, Mob* tar, int32 mana_cost, uint32* oDontDoAgainBefore = nullptr) override;
BotCastingRoles& GetCastingRoles() { return m_CastingRoles; }
void SetGroupHealer(bool flag = true) { m_CastingRoles.GroupHealer = flag; }
void SetGroupSlower(bool flag = true) { m_CastingRoles.GroupSlower = flag; }
void SetGroupNuker(bool flag = true) { m_CastingRoles.GroupNuker = flag; }
void SetGroupDoter(bool flag = true) { m_CastingRoles.GroupDoter = flag; }
//void SetRaidHealer(bool flag = true) { m_CastingRoles.RaidHealer = flag; }
//void SetRaidSlower(bool flag = true) { m_CastingRoles.RaidSlower = flag; }
//void SetRaidNuker(bool flag = true) { m_CastingRoles.RaidNuker = flag; }
//void SetRaidDoter(bool flag = true) { m_CastingRoles.RaidDoter = flag; }
std::deque<int> bot_signal_q;
std::vector<BotSpells_Struct> AIBot_spells;
@@ -801,8 +871,7 @@ private:
Timer m_evade_timer; // can be moved to pTimers at some point
Timer m_alt_combat_hate_timer;
Timer m_auto_defend_timer;
//Timer m_combat_jitter_timer;
//bool m_combat_jitter_flag;
bool m_dirtyautohaters;
bool m_guard_flag;
bool m_hold_flag;
bool m_attack_flag;
@@ -849,15 +918,12 @@ private:
// Class Methods
void LoadAAs();
int32 acmod();
void GenerateBaseStats();
void GenerateAppearance();
void GenerateArmorClass();
int32 GenerateBaseHitPoints();
int32 GenerateBaseManaPoints();
void GenerateSpecialAttacks();
void SetBotID(uint32 botID);
//void SetCombatJitterFlag(bool flag = true) { m_combat_jitter_flag = flag; }
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; }
@@ -870,9 +936,6 @@ private:
bool LoadPet(); // Load and spawn bot pet if there is one
bool SavePet(); // Save and depop bot pet if there is one
bool DeletePet();
public:
static uint8 spell_casting_chances[SPELL_TYPE_COUNT][PLAYER_CLASS_COUNT][EQ::constants::STANCE_TYPE_COUNT][cntHSND];
};
bool IsSpellInBotList(DBbotspells_Struct* spell_list, uint16 iSpellID);