mirror of
https://github.com/mod-playerbots/mod-playerbots.git
synced 2026-02-08 05:01:09 +00:00
# Pull Request
- Applies the clean and corrected singletons, Meyer pattern. (cherry
picked from @SmashingQuasar )
Testing by just playing the game in various ways. Been tested by myself
@Celandriel and @SmashingQuasar
---
## 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**)
---
## 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: Nicolas Lebacq <nicolas.cordier@outlook.com>
Co-authored-by: Keleborn <22352763+Celandriel@users.noreply.github.com>
149 lines
4.4 KiB
C++
149 lines
4.4 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 "MoveToRpgTargetAction.h"
|
|
|
|
#include "ChatHelper.h"
|
|
#include "ChooseRpgTargetAction.h"
|
|
#include "Event.h"
|
|
#include "LastMovementValue.h"
|
|
#include "Playerbots.h"
|
|
|
|
bool MoveToRpgTargetAction::Execute(Event event)
|
|
{
|
|
GuidPosition guidP = AI_VALUE(GuidPosition, "rpg target");
|
|
Unit* unit = botAI->GetUnit(guidP);
|
|
if (unit && !unit->IsInWorld())
|
|
{
|
|
return false;
|
|
}
|
|
GameObject* go = botAI->GetGameObject(guidP);
|
|
if (go && !go->IsInWorld())
|
|
{
|
|
return false;
|
|
}
|
|
Player* player = guidP.GetPlayer();
|
|
|
|
WorldObject* wo = nullptr;
|
|
if (unit)
|
|
wo = unit;
|
|
else if (go)
|
|
wo = go;
|
|
else
|
|
return false;
|
|
|
|
if (botAI->HasStrategy("debug rpg", BOT_STATE_NON_COMBAT) && guidP.GetWorldObject())
|
|
{
|
|
std::ostringstream out;
|
|
out << "Heading to: ";
|
|
out << chat->FormatWorldobject(guidP.GetWorldObject());
|
|
botAI->TellMasterNoFacing(out);
|
|
}
|
|
|
|
if (guidP.IsPlayer())
|
|
{
|
|
Player* player = guidP.GetPlayer();
|
|
|
|
if (player && GET_PLAYERBOT_AI(player))
|
|
{
|
|
GuidPosition guidPP = PAI_VALUE(GuidPosition, "rpg target");
|
|
|
|
if (guidPP.IsPlayer())
|
|
{
|
|
AI_VALUE(GuidSet&, "ignore rpg target").insert(AI_VALUE(GuidPosition, "rpg target"));
|
|
|
|
RESET_AI_VALUE(GuidPosition, "rpg target");
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((unit && unit->isMoving() && !urand(0, 20)) || !ChooseRpgTargetAction::isFollowValid(bot, wo) ||
|
|
guidP.distance(bot) > sPlayerbotAIConfig.reactDistance * 2 || !urand(0, 50))
|
|
{
|
|
AI_VALUE(GuidSet&, "ignore rpg target").insert(AI_VALUE(GuidPosition, "rpg target"));
|
|
RESET_AI_VALUE(GuidPosition, "rpg target");
|
|
return false;
|
|
}
|
|
|
|
float x = wo->GetPositionX();
|
|
float y = wo->GetPositionY();
|
|
float z = wo->GetPositionZ();
|
|
float mapId = wo->GetMapId();
|
|
|
|
if (sPlayerbotAIConfig.randombotsWalkingRPG)
|
|
if (!bot->IsOutdoors())
|
|
bot->m_movementInfo.AddMovementFlag(MOVEMENTFLAG_WALKING);
|
|
|
|
float angle = 0.f;
|
|
float distance = 1.0f;
|
|
if (bot->IsWithinLOS(x, y, z))
|
|
{
|
|
if (!unit || !unit->isMoving())
|
|
angle = wo->GetAngle(bot) + (M_PI * irand(-25, 25) / 100.0); // Closest 45 degrees towards the target
|
|
else
|
|
angle = wo->GetOrientation() +
|
|
(M_PI * irand(-25, 25) / 100.0); // 45 degrees infront of target (leading it's movement)
|
|
|
|
distance = frand(0.5f, 1.f);
|
|
}
|
|
else
|
|
angle = 2 * M_PI * urand(0, 100) / 100.0; // A circle around the target.
|
|
|
|
x += cos(angle) * INTERACTION_DISTANCE * distance;
|
|
y += sin(angle) * INTERACTION_DISTANCE * distance;
|
|
bool exact = true;
|
|
if (!wo->GetMap()->CheckCollisionAndGetValidCoords(wo, wo->GetPositionX(), wo->GetPositionY(), wo->GetPositionZ(),
|
|
x, y, z))
|
|
{
|
|
x = wo->GetPositionX();
|
|
y = wo->GetPositionY();
|
|
z = wo->GetPositionZ();
|
|
exact = false;
|
|
}
|
|
// WaitForReach(distance);
|
|
|
|
bool couldMove = false;
|
|
|
|
// if (bot->IsWithinLOS(x, y, z))
|
|
// couldMove = MoveNear(mapId, x, y, z, 0);
|
|
// else
|
|
couldMove = MoveTo(mapId, x, y, z, false, false, false, exact);
|
|
|
|
if (!couldMove && WorldPosition(mapId, x, y, z).distance(bot) > INTERACTION_DISTANCE)
|
|
{
|
|
AI_VALUE(GuidSet&, "ignore rpg target").insert(AI_VALUE(GuidPosition, "rpg target"));
|
|
RESET_AI_VALUE(GuidPosition, "rpg target");
|
|
}
|
|
|
|
return couldMove;
|
|
}
|
|
|
|
bool MoveToRpgTargetAction::isUseful()
|
|
{
|
|
GuidPosition guidP = AI_VALUE(GuidPosition, "rpg target");
|
|
if (!guidP)
|
|
return false;
|
|
|
|
WorldObject* wo = guidP.GetWorldObject();
|
|
if (!wo)
|
|
return false;
|
|
|
|
TravelTarget* travelTarget = AI_VALUE(TravelTarget*, "travel target");
|
|
if (travelTarget->isTraveling() && ChooseRpgTargetAction::isFollowValid(bot, *travelTarget->getPosition()))
|
|
return false;
|
|
|
|
if (guidP.distance(bot) < INTERACTION_DISTANCE)
|
|
return false;
|
|
|
|
if (!ChooseRpgTargetAction::isFollowValid(bot, wo))
|
|
return false;
|
|
|
|
if (!AI_VALUE(bool, "can move around"))
|
|
return false;
|
|
|
|
return true;
|
|
}
|