added custom AI for dungeonhelper bot

This commit is contained in:
Nico committed 2026-09-20 20:04:35 +02:00
1 parent 1a9cd340b7
commit 816d506867
4 files changed
+199 -2

No files matched your search

+13
View File
@@ -344,6 +344,19 @@ void LFGMgr::Update(uint32 diff)
TC_LOG_DEBUG("lfg", "Low-population solo LFG group %s expired after %u seconds outside the dungeon.",
gguid.ToString().c_str(), uint32(lowPopulationOutsideTimeout));
// LOWPOP_TIMEOUT_CLEANUP
// Mirror the clean client-side state produced by voluntary LeaveParty().
// Group::Disband()/RemoveGroupData() resets player state/group linkage,
// but the RideTicket must be cleared explicitly.
GuidSet const& lowPopulationPlayers = GetPlayers(gguid);
if (lowPopulationPlayers.size() == 1)
{
ObjectGuid const pguid = *lowPopulationPlayers.begin();
ClearTicket(pguid);
SendLfgUpdateStatus(pguid, LfgUpdateData(LFG_UPDATETYPE_REMOVED_FROM_QUEUE), true);
SendLfgUpdateStatus(pguid, LfgUpdateData(LFG_UPDATETYPE_REMOVED_FROM_QUEUE), false);
}
LeaveLfg(gguid);
group->Disband();
}
@@ -18,8 +18,12 @@
// This is where scripts' loading functions should be declared:
// VIANO_ADVENTURERS
void AddSC_viano_adventurers();
// The name of this function should match:
// void Add${NameOfDirectory}Scripts()
void AddCustomScripts()
{
AddSC_viano_adventurers();
}
@@ -0,0 +1,180 @@
/*
* Viano custom dungeon adventurers
* Initial melee companion implementation.
*/
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "ObjectAccessor.h"
#include "Player.h"
#include "TemporarySummon.h"
#include "MotionMaster.h"
namespace VianoAdventurers
{
static constexpr float FOLLOW_DISTANCE = 2.5f;
static constexpr float FOLLOW_ANGLE = 3.14159265f;
static constexpr float TELEPORT_DISTANCE = 45.0f;
static constexpr uint32 UPDATE_INTERVAL = 500;
class npc_horde_adventurer_melee : public CreatureScript
{
public:
npc_horde_adventurer_melee() : CreatureScript("npc_horde_adventurer_melee") { }
struct npc_horde_adventurer_meleeAI : public ScriptedAI
{
npc_horde_adventurer_meleeAI(Creature* creature) : ScriptedAI(creature) { }
ObjectGuid ownerGuid;
uint32 updateTimer = 0;
Player* GetOwnerPlayer() const
{
if (!ownerGuid)
return nullptr;
return ObjectAccessor::GetPlayer(*me, ownerGuid);
}
void FollowOwner(Player* owner)
{
if (!owner)
return;
me->GetMotionMaster()->MoveFollow(owner, FOLLOW_DISTANCE, FOLLOW_ANGLE);
}
void InitializeAI() override
{
ScriptedAI::InitializeAI();
TempSummon* summon = me->ToTempSummon();
if (!summon)
{
me->DespawnOrUnsummon();
return;
}
Unit* summoner = summon->GetSummoner();
Player* owner = summoner ? summoner->ToPlayer() : nullptr;
if (!owner)
{
me->DespawnOrUnsummon();
return;
}
ownerGuid = owner->GetGUID();
me->SetOwnerGUID(ownerGuid);
me->SetFaction(owner->GetFaction());
me->SetLevel(owner->getLevel());
me->UpdateLevelDependantStats();
me->SetReactState(REACT_PASSIVE);
FollowOwner(owner);
}
void Reset() override
{
if (Player* owner = GetOwnerPlayer())
FollowOwner(owner);
}
void MoveInLineOfSight(Unit* /*who*/) override
{
}
Unit* SelectAssistTarget(Player* owner)
{
if (!owner)
return nullptr;
if (Unit* target = owner->GetVictim())
if (target->IsAlive() && me->IsValidAttackTarget(target))
return target;
for (Unit* attacker : owner->getAttackers())
if (attacker && attacker->IsAlive() && me->IsValidAttackTarget(attacker))
return attacker;
return nullptr;
}
void UpdateAI(uint32 diff) override
{
if (updateTimer > diff)
{
updateTimer -= diff;
if (UpdateVictim())
DoMeleeAttackIfReady();
return;
}
updateTimer = UPDATE_INTERVAL;
Player* owner = GetOwnerPlayer();
if (!owner || !owner->IsInWorld() || !me->IsInMap(owner))
{
me->DespawnOrUnsummon();
return;
}
if (me->getLevel() != owner->getLevel())
{
me->SetLevel(owner->getLevel());
me->UpdateLevelDependantStats();
}
if (me->GetDistance(owner) > TELEPORT_DISTANCE)
{
me->CombatStop(true);
me->GetMotionMaster()->Clear();
me->NearTeleportTo(
owner->GetPositionX() + 1.5f,
owner->GetPositionY(),
owner->GetPositionZ(),
owner->GetOrientation()
);
FollowOwner(owner);
return;
}
Unit* desiredTarget = SelectAssistTarget(owner);
if (desiredTarget)
{
if (me->GetVictim() != desiredTarget)
AttackStart(desiredTarget);
}
else if (me->IsInCombat())
{
me->CombatStop(true);
FollowOwner(owner);
}
else if (!me->GetVictim())
{
FollowOwner(owner);
}
if (UpdateVictim())
DoMeleeAttackIfReady();
}
};
CreatureAI* GetAI(Creature* creature) const override
{
return new npc_horde_adventurer_meleeAI(creature);
}
};
}
void AddSC_viano_adventurers()
{
using namespace VianoAdventurers;
new npc_horde_adventurer_melee();
}
+2 -2
View File
@@ -419,7 +419,7 @@ class item_generic_limit_chance_above_60 : public ItemScript
enum HordeAdventurerHorn
{
NPC_ORGRIMMAR_GRUNT = 3296
NPC_HORDE_ADVENTURER = 900001
};
class item_horde_adventurer_horn : public ItemScript
@@ -445,7 +445,7 @@ public:
}
player->SummonCreature(
NPC_ORGRIMMAR_GRUNT,
NPC_HORDE_ADVENTURER,
player->GetPositionX() + 2.0f,
player->GetPositionY(),
player->GetPositionZ(),