Files
mod-playerbots/src/Ai/Base/Actions/RtscAction.cpp
Alex Dcnh 17b8d7f68b Stage1 refactor world position method names (#2126)
# Pull Request

This change replaces the non‑standard
WorldPosition::getX/getY/getZ/getO/getMapId wrappers with the core
getters (GetPositionX/Y/Z, GetOrientation, GetMapId) and removes the
redundant wrappers.
Goal: align the module with AzerothCore conventions, reduce local
adapters, and improve long‑term maintainability.

---

## Design Philosophy

This is a structural cleanup only (coordinate access) and does not alter
any AI behavior or decision logic.
It follows the stability/performance-first philosophy and does not add
branches or extra runtime work.

Before submitting: yes, this change aligns with the principles of
stability, performance, and predictability.

Principles:

- **Stability before intelligence**  
  A stable system is always preferred over a smarter one.

- **Performance is a shared resource**  
  Any increase in bot cost affects all players and all bots.

- **Simple logic scales better than smart logic**  
Predictable behavior under load is more valuable than perfect decisions.

- **Complexity must justify itself**  
  If a feature cannot clearly explain its cost, it should not exist.

- **Defaults must be cheap**  
  Expensive behavior must always be optional and clearly communicated.

- **Bots should look reasonable, not perfect**  
  The goal is believable behavior, not human simulation.

Before submitting, confirm that this change aligns with those
principles.

---

## Feature Evaluation

Please answer the following:

- Minimum logic required: use core getters (GetPositionX/Y/Z, GetMapId,
GetOrientation) wherever coordinates are needed.
- Cheapest implementation: direct call replacement and removal of
redundant wrappers.
- Runtime cost: negligible (same data access, no additional logic).

---

## How to Test the Changes

- No functional testing required (behavior‑neutral refactor).
- Recommended: compile the module and run a normal server startup as
validation.

## Complexity & Impact

Does this change add new decision branches?
- - [x] No
- - [x] 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:
- - [x] Lightweight mode remains the default
- - [x] 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?
- - [ ] No
- - [x] Yes (**explain below**)

If yes, please specify:

- AI tool or model used: Copilot
- Purpose of usage: Translate this PR text from french to English

---

## 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

This is a core-friendly cleanup only, with no behavioral change.
No additional logic or CPU cost is introduced.
2026-02-13 09:24:42 -08:00

158 lines
4.8 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 "RtscAction.h"
#include "Playerbots.h"
#include "RTSCValues.h"
bool RTSCAction::Execute(Event event)
{
std::string const command = event.getParam();
Player* master = botAI->GetMaster();
if (!master)
return false;
if (command != "reset" && !master->HasSpell(RTSC_MOVE_SPELL))
{
master->learnSpell(RTSC_MOVE_SPELL, false);
botAI->TellMasterNoFacing("RTS control enabled.");
botAI->TellMasterNoFacing("Aedm (Awesome energetic do move) spell trained.");
}
else if (command == "reset")
{
if (master->HasSpell(RTSC_MOVE_SPELL))
{
master->removeSpell(RTSC_MOVE_SPELL, SPEC_MASK_ALL, false);
botAI->TellMasterNoFacing("RTS control spell removed.");
}
RESET_AI_VALUE(bool, "RTSC selected");
RESET_AI_VALUE(std::string, "RTSC next spell action");
for (auto value : botAI->GetAiObjectContext()->GetValues())
if (value.find("RTSC saved location::") != std::string::npos)
RESET_AI_VALUE(WorldPosition, value.c_str());
return true;
}
bool selected = AI_VALUE(bool, "RTSC selected");
if (command == "select" && !selected)
{
SET_AI_VALUE(bool, "RTSC selected", true);
master->SendPlaySpellVisual(bot->GetGUID(), 5036);
return true;
}
else if (command == "cancel")
{
RESET_AI_VALUE(bool, "RTSC selected");
RESET_AI_VALUE(std::string, "RTSC next spell action");
if (selected)
master->SendPlaySpellVisual(bot->GetGUID(), 6372);
return true;
}
else if (command == "toggle")
{
if (!selected)
{
SET_AI_VALUE(bool, "RTSC selected", true);
master->SendPlaySpellVisual(bot->GetGUID(), 5036);
}
else
{
SET_AI_VALUE(bool, "RTSC selected", false);
master->SendPlaySpellVisual(bot->GetGUID(), 6372);
}
return true;
}
else if (command.find("save here ") != std::string::npos)
{
std::string const locationName = command.substr(10);
WorldPosition spellPosition(bot);
SET_AI_VALUE2(WorldPosition, "RTSC saved location", locationName, spellPosition);
Creature* wpCreature =
bot->SummonCreature(15631, spellPosition.GetPositionX(), spellPosition.GetPositionY(),
spellPosition.GetPositionZ(), spellPosition.GetOrientation(), TEMPSUMMON_TIMED_DESPAWN,
2000.0f);
wpCreature->SetObjectScale(0.5f);
return true;
}
else if (command.find("unsave ") != std::string::npos)
{
std::string const locationName = command.substr(7);
RESET_AI_VALUE2(WorldPosition, "RTSC saved location", locationName);
return true;
}
if (command.find("save ") != std::string::npos || command == "move")
{
SET_AI_VALUE(std::string, "RTSC next spell action", command);
return true;
}
if (command.find("show ") != std::string::npos)
{
std::string const locationName = command.substr(5);
WorldPosition spellPosition = AI_VALUE2(WorldPosition, "RTSC saved location", locationName);
if (spellPosition)
{
Creature* wpCreature =
bot->SummonCreature(15631, spellPosition.GetPositionX(), spellPosition.GetPositionY(),
spellPosition.GetPositionZ(), spellPosition.GetOrientation(),
TEMPSUMMON_TIMED_DESPAWN, 2000.0f);
wpCreature->SetObjectScale(0.5f);
}
return true;
}
if (command.find("show") != std::string::npos)
{
std::ostringstream out;
out << "saved: ";
for (auto value : botAI->GetAiObjectContext()->GetValues())
if (value.find("RTSC saved location::") != std::string::npos)
if (AI_VALUE2(WorldPosition, "RTSC saved location", value.substr(21).c_str()))
out << value.substr(21).c_str() << ",";
out.seekp(-1, out.cur);
out << ".";
botAI->TellMasterNoFacing(out);
}
if (command.find("go ") != std::string::npos)
{
std::string const locationName = command.substr(3);
WorldPosition spellPosition = AI_VALUE2(WorldPosition, "RTSC saved location", locationName);
if (spellPosition)
return MoveToSpell(spellPosition, false);
return true;
}
else if (command == "last")
{
WorldPosition spellPosition = AI_VALUE(WorldPosition, "see spell location");
if (spellPosition)
return MoveToSpell(spellPosition);
}
return false;
}