mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-03-22 23:30:14 +00:00
Add Tier 8 commands: advanced targeting system
Targeting Commands: - /cleartarget - Clear current target selection - /targetenemy - Cycle to next hostile target (Tab equivalent) - /targetfriend - Cycle to next friendly player - /targetlasttarget, /targetlast - Switch to previous target - /targetlastenemy - Cycle to previous hostile target - /targetlastfriend - Cycle to previous friendly player - /focus - Set current target as focus (client-side) - /clearfocus - Clear focus target Implementation: - Added focusGuid and lastTargetGuid to GameHandler for client-side tracking - setTarget() now automatically saves previous target to lastTargetGuid - setFocus() and clearFocus() manage focus target with user feedback - targetLastTarget() swaps current and previous targets - targetEnemy() cycles through hostile entities (Units) - targetFriend() cycles through friendly entities (Players) - Both targetEnemy/targetFriend support reverse parameter for backwards cycling Features: - Focus targeting is client-side (no server opcode in 3.3.5a) - Last target tracking happens automatically on every target change - Enemy/friend cycling iterates through visible entities - Provides user feedback when no targets available - Tab-like cycling behavior with wraparound All commands work entirely client-side for responsive targeting.
This commit is contained in:
parent
bca3f64af6
commit
dfc4008ec7
3 changed files with 206 additions and 0 deletions
|
|
@ -202,6 +202,18 @@ public:
|
|||
bool hasTarget() const { return targetGuid != 0; }
|
||||
void tabTarget(float playerX, float playerY, float playerZ);
|
||||
|
||||
// Focus targeting
|
||||
void setFocus(uint64_t guid);
|
||||
void clearFocus();
|
||||
uint64_t getFocusGuid() const { return focusGuid; }
|
||||
std::shared_ptr<Entity> getFocus() const;
|
||||
bool hasFocus() const { return focusGuid != 0; }
|
||||
|
||||
// Advanced targeting
|
||||
void targetLastTarget();
|
||||
void targetEnemy(bool reverse = false);
|
||||
void targetFriend(bool reverse = false);
|
||||
|
||||
// Inspection
|
||||
void inspectTarget();
|
||||
|
||||
|
|
@ -646,6 +658,8 @@ private:
|
|||
|
||||
// Targeting
|
||||
uint64_t targetGuid = 0;
|
||||
uint64_t focusGuid = 0; // Focus target
|
||||
uint64_t lastTargetGuid = 0; // Previous target
|
||||
std::vector<uint64_t> tabCycleList;
|
||||
int tabCycleIndex = -1;
|
||||
bool tabCycleStale = true;
|
||||
|
|
|
|||
|
|
@ -1521,6 +1521,12 @@ void GameHandler::handleMessageChat(network::Packet& packet) {
|
|||
|
||||
void GameHandler::setTarget(uint64_t guid) {
|
||||
if (guid == targetGuid) return;
|
||||
|
||||
// Save previous target
|
||||
if (targetGuid != 0) {
|
||||
lastTargetGuid = targetGuid;
|
||||
}
|
||||
|
||||
targetGuid = guid;
|
||||
|
||||
// Inform server of target selection (Phase 1)
|
||||
|
|
@ -1548,6 +1554,135 @@ std::shared_ptr<Entity> GameHandler::getTarget() const {
|
|||
return entityManager.getEntity(targetGuid);
|
||||
}
|
||||
|
||||
void GameHandler::setFocus(uint64_t guid) {
|
||||
focusGuid = guid;
|
||||
if (guid != 0) {
|
||||
auto entity = entityManager.getEntity(guid);
|
||||
if (entity) {
|
||||
std::string name = "Unknown";
|
||||
if (entity->getType() == ObjectType::PLAYER) {
|
||||
auto player = std::dynamic_pointer_cast<Player>(entity);
|
||||
if (player && !player->getName().empty()) {
|
||||
name = player->getName();
|
||||
}
|
||||
}
|
||||
addSystemChatMessage("Focus set: " + name);
|
||||
LOG_INFO("Focus set: 0x", std::hex, guid, std::dec);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GameHandler::clearFocus() {
|
||||
if (focusGuid != 0) {
|
||||
addSystemChatMessage("Focus cleared.");
|
||||
LOG_INFO("Focus cleared");
|
||||
}
|
||||
focusGuid = 0;
|
||||
}
|
||||
|
||||
std::shared_ptr<Entity> GameHandler::getFocus() const {
|
||||
if (focusGuid == 0) return nullptr;
|
||||
return entityManager.getEntity(focusGuid);
|
||||
}
|
||||
|
||||
void GameHandler::targetLastTarget() {
|
||||
if (lastTargetGuid == 0) {
|
||||
addSystemChatMessage("No previous target.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Swap current and last target
|
||||
uint64_t temp = targetGuid;
|
||||
setTarget(lastTargetGuid);
|
||||
lastTargetGuid = temp;
|
||||
}
|
||||
|
||||
void GameHandler::targetEnemy(bool reverse) {
|
||||
// Get list of hostile entities
|
||||
std::vector<uint64_t> hostiles;
|
||||
auto& entities = entityManager.getEntities();
|
||||
|
||||
for (const auto& [guid, entity] : entities) {
|
||||
if (entity->getType() == ObjectType::UNIT) {
|
||||
// Check if hostile (this is simplified - would need faction checking)
|
||||
auto unit = std::dynamic_pointer_cast<Unit>(entity);
|
||||
if (unit && guid != playerGuid) {
|
||||
hostiles.push_back(guid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hostiles.empty()) {
|
||||
addSystemChatMessage("No enemies in range.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Find current target in list
|
||||
auto it = std::find(hostiles.begin(), hostiles.end(), targetGuid);
|
||||
|
||||
if (it == hostiles.end()) {
|
||||
// Not currently targeting a hostile, target first one
|
||||
setTarget(reverse ? hostiles.back() : hostiles.front());
|
||||
} else {
|
||||
// Cycle to next/previous
|
||||
if (reverse) {
|
||||
if (it == hostiles.begin()) {
|
||||
setTarget(hostiles.back());
|
||||
} else {
|
||||
setTarget(*(--it));
|
||||
}
|
||||
} else {
|
||||
++it;
|
||||
if (it == hostiles.end()) {
|
||||
setTarget(hostiles.front());
|
||||
} else {
|
||||
setTarget(*it);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GameHandler::targetFriend(bool reverse) {
|
||||
// Get list of friendly entities (players)
|
||||
std::vector<uint64_t> friendlies;
|
||||
auto& entities = entityManager.getEntities();
|
||||
|
||||
for (const auto& [guid, entity] : entities) {
|
||||
if (entity->getType() == ObjectType::PLAYER && guid != playerGuid) {
|
||||
friendlies.push_back(guid);
|
||||
}
|
||||
}
|
||||
|
||||
if (friendlies.empty()) {
|
||||
addSystemChatMessage("No friendly targets in range.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Find current target in list
|
||||
auto it = std::find(friendlies.begin(), friendlies.end(), targetGuid);
|
||||
|
||||
if (it == friendlies.end()) {
|
||||
// Not currently targeting a friend, target first one
|
||||
setTarget(reverse ? friendlies.back() : friendlies.front());
|
||||
} else {
|
||||
// Cycle to next/previous
|
||||
if (reverse) {
|
||||
if (it == friendlies.begin()) {
|
||||
setTarget(friendlies.back());
|
||||
} else {
|
||||
setTarget(*(--it));
|
||||
}
|
||||
} else {
|
||||
++it;
|
||||
if (it == friendlies.end()) {
|
||||
setTarget(friendlies.front());
|
||||
} else {
|
||||
setTarget(*it);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GameHandler::inspectTarget() {
|
||||
if (state != WorldState::IN_WORLD || !socket) {
|
||||
LOG_WARNING("Cannot inspect: not in world or not connected");
|
||||
|
|
|
|||
|
|
@ -1460,6 +1460,63 @@ void GameScreen::sendChatMessage(game::GameHandler& gameHandler) {
|
|||
return;
|
||||
}
|
||||
|
||||
// Targeting commands
|
||||
if (cmdLower == "cleartarget") {
|
||||
gameHandler.clearTarget();
|
||||
chatInputBuffer[0] = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
if (cmdLower == "targetenemy") {
|
||||
gameHandler.targetEnemy(false);
|
||||
chatInputBuffer[0] = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
if (cmdLower == "targetfriend") {
|
||||
gameHandler.targetFriend(false);
|
||||
chatInputBuffer[0] = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
if (cmdLower == "targetlasttarget" || cmdLower == "targetlast") {
|
||||
gameHandler.targetLastTarget();
|
||||
chatInputBuffer[0] = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
if (cmdLower == "targetlastenemy") {
|
||||
gameHandler.targetEnemy(true); // Reverse direction
|
||||
chatInputBuffer[0] = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
if (cmdLower == "targetlastfriend") {
|
||||
gameHandler.targetFriend(true); // Reverse direction
|
||||
chatInputBuffer[0] = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
if (cmdLower == "focus") {
|
||||
if (gameHandler.hasTarget()) {
|
||||
gameHandler.setFocus(gameHandler.getTargetGuid());
|
||||
} else {
|
||||
game::MessageChatData msg;
|
||||
msg.type = game::ChatType::SYSTEM;
|
||||
msg.language = game::ChatLanguage::UNIVERSAL;
|
||||
msg.message = "You must target a unit to set as focus.";
|
||||
gameHandler.addLocalChatMessage(msg);
|
||||
}
|
||||
chatInputBuffer[0] = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
if (cmdLower == "clearfocus") {
|
||||
gameHandler.clearFocus();
|
||||
chatInputBuffer[0] = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
// Chat channel slash commands
|
||||
bool isChannelCommand = false;
|
||||
if (cmdLower == "s" || cmdLower == "say") {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue