mod-playerbots/src/Ai/Base/Actions/ChooseTargetActions.cpp
Keleborn 441f9f7552
Warnings PR 1: Event warnings and headers (#2106)
# Pull Request

This is the first in a series of PRs intended to eliminate warnings in
the module. The design intent is to eliminate the calling event when not
needed in the body of the function. Based off of SmashingQuasars work.

---

## How to Test the Changes

- Step-by-step instructions to test the change
- Any required setup (e.g. multiple players, bots, specific
configuration)
- Expected behavior and how to verify it

## Complexity & Impact

- Does this change add new decision branches?
    - [x] No
    - [ ] Yes (**explain below**)

- Does this change increase per-bot or per-tick processing?
    - [x] No
    - [ ] Yes (**describe and justify impact**)

- Could this logic scale poorly under load?
    - [x] No
    - [ ] Yes (**explain why**)

---

## Defaults & Configuration

- Does this change modify default bot behavior?
    - [x] No
    - [ ] Yes (**explain why**)

If this introduces more advanced or AI-heavy logic:

- [ ] Lightweight mode remains the default
- [ ] More complex behavior is optional and thereby configurable

---

## AI Assistance

- Was AI assistance (e.g. ChatGPT or similar tools) used while working
on this change?
    - [x] No
    - [ ] Yes (**explain below**)

---

## Final Checklist

- [x] Stability is not compromised
- [x] Performance impact is understood, tested, and acceptable
- [x] Added logic complexity is justified and explained
- [x] Documentation updated if needed

---

## Notes for Reviewers

Anything that significantly improves realism at the cost of stability or
performance should be carefully discussed
before merging.

---------

Co-authored-by: bashermens <31279994+hermensbas@users.noreply.github.com>
2026-02-14 20:55:10 +01:00

184 lines
5.6 KiB
C++

/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
* and/or modify it under version 3 of the License, or (at your option), any later version.
*/
#include "ChooseTargetActions.h"
#include "ChooseRpgTargetAction.h"
#include "Event.h"
#include "LootObjectStack.h"
#include "NewRpgStrategy.h"
#include "Playerbots.h"
#include "RtiTargetValue.h"
#include "PossibleRpgTargetsValue.h"
#include "PvpTriggers.h"
#include "ServerFacade.h"
bool AttackEnemyPlayerAction::isUseful()
{
if (PlayerHasFlag::IsCapturingFlag(bot))
return false;
return !sPlayerbotAIConfig.IsPvpProhibited(bot->GetZoneId(), bot->GetAreaId());
}
bool AttackEnemyFlagCarrierAction::isUseful()
{
Unit* target = context->GetValue<Unit*>("enemy flag carrier")->Get();
return target && ServerFacade::instance().IsDistanceLessOrEqualThan(ServerFacade::instance().GetDistance2d(bot, target), 100.0f) &&
PlayerHasFlag::IsCapturingFlag(bot);
}
bool DropTargetAction::Execute(Event /*event*/)
{
Unit* target = context->GetValue<Unit*>("current target")->Get();
if (target && target->isDead())
{
ObjectGuid guid = target->GetGUID();
if (guid)
context->GetValue<LootObjectStack*>("available loot")->Get()->Add(guid);
}
// ObjectGuid pullTarget = context->GetValue<ObjectGuid>("pull target")->Get();
// GuidVector possible = botAI->GetAiObjectContext()->GetValue<GuidVector>("possible targets no los")->Get();
// if (pullTarget && find(possible.begin(), possible.end(), pullTarget) == possible.end())
// {
// context->GetValue<ObjectGuid>("pull target")->Set(ObjectGuid::Empty);
// }
context->GetValue<Unit*>("current target")->Set(nullptr);
bot->SetTarget(ObjectGuid::Empty);
bot->SetSelection(ObjectGuid());
botAI->ChangeEngine(BOT_STATE_NON_COMBAT);
if (bot->getClass() == CLASS_HUNTER) // Check for Hunter Class
{
Spell const* spell = bot->GetCurrentSpell(CURRENT_AUTOREPEAT_SPELL); // Get the current spell being cast by the bot
if (spell && spell->m_spellInfo->Id == 75) //Check spell is not nullptr before accessing m_spellInfo
bot->InterruptSpell(CURRENT_AUTOREPEAT_SPELL); // Interrupt Auto Shot
}
bot->AttackStop();
// if (Pet* pet = bot->GetPet())
// {
// if (CreatureAI* creatureAI = ((Creature*)pet)->AI())
// {
// pet->SetReactState(REACT_PASSIVE);
// pet->GetCharmInfo()->SetCommandState(COMMAND_FOLLOW);
// pet->GetCharmInfo()->SetIsCommandFollow(true);
// pet->AttackStop();
// pet->GetCharmInfo()->IsReturning();
// pet->GetMotionMaster()->MoveFollow(bot, PET_FOLLOW_DIST, pet->GetFollowAngle());
// }
// }
return true;
}
bool AttackAnythingAction::Execute(Event event)
{
bool result = AttackAction::Execute(event);
if (result)
{
if (Unit* grindTarget = GetTarget())
{
if (char const* grindName = grindTarget->GetName().c_str())
{
context->GetValue<ObjectGuid>("pull target")->Set(grindTarget->GetGUID());
bot->GetMotionMaster()->Clear();
// bot->StopMoving();
}
}
}
return result;
}
bool AttackAnythingAction::isUseful()
{
if (!bot || !botAI) // Prevents invalid accesses
return false;
if (!botAI->AllowActivity(GRIND_ACTIVITY)) // Bot cannot be active
return false;
if (botAI->HasStrategy("stay", BOT_STATE_NON_COMBAT))
return false;
if (bot->IsInCombat())
return false;
Unit* target = GetTarget();
if (!target || !target->IsInWorld()) // Checks if the target is valid and in the world
return false;
std::string const name = std::string(target->GetName());
if (!name.empty() &&
(name.find("Dummy") != std::string::npos ||
name.find("Charge Target") != std::string::npos ||
name.find("Melee Target") != std::string::npos ||
name.find("Ranged Target") != std::string::npos))
{
return false;
}
return true;
}
bool AttackAnythingAction::isPossible() { return GetTarget() && AttackAction::isPossible(); }
bool DpsAssistAction::isUseful()
{
if (PlayerHasFlag::IsCapturingFlag(bot))
return false;
return true;
}
bool AttackRtiTargetAction::Execute(Event /*event*/)
{
Unit* rtiTarget = AI_VALUE(Unit*, "rti target");
// Fallback: if the "rti target" value did not resolve a valid unit yet,
// try to resolve the raid icon directly from the group.
if (!rtiTarget)
{
if (Group* group = bot->GetGroup())
{
std::string const rti = AI_VALUE(std::string, "rti");
int32 const index = RtiTargetValue::GetRtiIndex(rti);
if (index >= 0)
{
ObjectGuid const guid = group->GetTargetIcon(index);
if (!guid.IsEmpty())
rtiTarget = botAI->GetUnit(guid);
}
}
}
if (rtiTarget && rtiTarget->IsInWorld() && rtiTarget->GetMapId() == bot->GetMapId())
{
botAI->GetAiObjectContext()->GetValue<GuidVector>("prioritized targets")->Set({rtiTarget->GetGUID()});
bool result = Attack(botAI->GetUnit(rtiTarget->GetGUID()));
if (result)
{
context->GetValue<ObjectGuid>("pull target")->Set(rtiTarget->GetGUID());
return true;
}
}
else
botAI->TellError("I dont see my rti attack target");
return false;
}
bool AttackRtiTargetAction::isUseful()
{
if (botAI->ContainsStrategy(STRATEGY_TYPE_HEAL))
return false;
return true;
}