mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-03-22 23:30:14 +00:00
feat: add unit state query functions and fix UnitAffectingCombat
Add 6 commonly needed unit state functions: - UnitIsGhost(unit) checks ghost flag from UNIT_FIELD_FLAGS - UnitIsDeadOrGhost(unit) combines dead + ghost checks - UnitIsAFK(unit) / UnitIsDND(unit) check player flags - UnitPlayerControlled(unit) true for players and player pets - UnitSex(unit) reads gender from UNIT_FIELD_BYTES_0 byte 2 Fix UnitAffectingCombat to check UNIT_FLAG_IN_COMBAT (0x00080000) from entity update fields for any unit, not just "player". Previously returned false for all non-player units. These functions are needed by unit frame addons (SUF, Pitbull, oUF) to properly display ghost state, AFK/DND status, and combat state.
This commit is contained in:
parent
ec082e029c
commit
61b54cfa74
1 changed files with 141 additions and 1 deletions
|
|
@ -238,6 +238,129 @@ static int lua_UnitClass(lua_State* L) {
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UnitIsGhost(unit) — true if unit is in ghost form
|
||||||
|
static int lua_UnitIsGhost(lua_State* L) {
|
||||||
|
const char* uid = luaL_optstring(L, 1, "player");
|
||||||
|
auto* gh = getGameHandler(L);
|
||||||
|
if (!gh) { lua_pushboolean(L, 0); return 1; }
|
||||||
|
std::string uidStr(uid);
|
||||||
|
for (char& c : uidStr) c = static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
|
||||||
|
if (uidStr == "player") {
|
||||||
|
lua_pushboolean(L, gh->isPlayerGhost());
|
||||||
|
} else {
|
||||||
|
// Check UNIT_FIELD_FLAGS for UNIT_FLAG_GHOST (0x00000100) — best approximation
|
||||||
|
uint64_t guid = resolveUnitGuid(gh, uidStr);
|
||||||
|
bool ghost = false;
|
||||||
|
if (guid != 0) {
|
||||||
|
auto entity = gh->getEntityManager().getEntity(guid);
|
||||||
|
if (entity) {
|
||||||
|
uint32_t flags = entity->getField(game::fieldIndex(game::UF::UNIT_FIELD_FLAGS));
|
||||||
|
ghost = (flags & 0x00000100) != 0; // PLAYER_FLAGS_GHOST
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lua_pushboolean(L, ghost);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnitIsDeadOrGhost(unit)
|
||||||
|
static int lua_UnitIsDeadOrGhost(lua_State* L) {
|
||||||
|
const char* uid = luaL_optstring(L, 1, "player");
|
||||||
|
auto* unit = resolveUnit(L, uid);
|
||||||
|
auto* gh = getGameHandler(L);
|
||||||
|
bool dead = (unit && unit->getHealth() == 0);
|
||||||
|
if (!dead && gh) {
|
||||||
|
std::string uidStr(uid);
|
||||||
|
for (char& c : uidStr) c = static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
|
||||||
|
if (uidStr == "player") dead = gh->isPlayerGhost() || gh->isPlayerDead();
|
||||||
|
}
|
||||||
|
lua_pushboolean(L, dead);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnitIsAFK(unit), UnitIsDND(unit)
|
||||||
|
static int lua_UnitIsAFK(lua_State* L) {
|
||||||
|
const char* uid = luaL_optstring(L, 1, "player");
|
||||||
|
auto* gh = getGameHandler(L);
|
||||||
|
if (!gh) { lua_pushboolean(L, 0); return 1; }
|
||||||
|
std::string uidStr(uid);
|
||||||
|
for (char& c : uidStr) c = static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
|
||||||
|
uint64_t guid = resolveUnitGuid(gh, uidStr);
|
||||||
|
if (guid != 0) {
|
||||||
|
auto entity = gh->getEntityManager().getEntity(guid);
|
||||||
|
if (entity) {
|
||||||
|
// PLAYER_FLAGS at UNIT_FIELD_FLAGS: PLAYER_FLAGS_AFK = 0x01
|
||||||
|
uint32_t playerFlags = entity->getField(game::fieldIndex(game::UF::UNIT_FIELD_FLAGS));
|
||||||
|
lua_pushboolean(L, (playerFlags & 0x01) != 0);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lua_pushboolean(L, 0);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int lua_UnitIsDND(lua_State* L) {
|
||||||
|
const char* uid = luaL_optstring(L, 1, "player");
|
||||||
|
auto* gh = getGameHandler(L);
|
||||||
|
if (!gh) { lua_pushboolean(L, 0); return 1; }
|
||||||
|
std::string uidStr(uid);
|
||||||
|
for (char& c : uidStr) c = static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
|
||||||
|
uint64_t guid = resolveUnitGuid(gh, uidStr);
|
||||||
|
if (guid != 0) {
|
||||||
|
auto entity = gh->getEntityManager().getEntity(guid);
|
||||||
|
if (entity) {
|
||||||
|
uint32_t playerFlags = entity->getField(game::fieldIndex(game::UF::UNIT_FIELD_FLAGS));
|
||||||
|
lua_pushboolean(L, (playerFlags & 0x02) != 0); // PLAYER_FLAGS_DND
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lua_pushboolean(L, 0);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnitPlayerControlled(unit) — true for players and player-controlled pets
|
||||||
|
static int lua_UnitPlayerControlled(lua_State* L) {
|
||||||
|
const char* uid = luaL_optstring(L, 1, "player");
|
||||||
|
auto* gh = getGameHandler(L);
|
||||||
|
if (!gh) { lua_pushboolean(L, 0); return 1; }
|
||||||
|
std::string uidStr(uid);
|
||||||
|
for (char& c : uidStr) c = static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
|
||||||
|
uint64_t guid = resolveUnitGuid(gh, uidStr);
|
||||||
|
if (guid == 0) { lua_pushboolean(L, 0); return 1; }
|
||||||
|
auto entity = gh->getEntityManager().getEntity(guid);
|
||||||
|
if (!entity) { lua_pushboolean(L, 0); return 1; }
|
||||||
|
// Players are always player-controlled; pets check UNIT_FLAG_PLAYER_CONTROLLED (0x01000000)
|
||||||
|
if (entity->getType() == game::ObjectType::PLAYER) {
|
||||||
|
lua_pushboolean(L, 1);
|
||||||
|
} else {
|
||||||
|
uint32_t flags = entity->getField(game::fieldIndex(game::UF::UNIT_FIELD_FLAGS));
|
||||||
|
lua_pushboolean(L, (flags & 0x01000000) != 0);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnitSex(unit) → 1=unknown, 2=male, 3=female
|
||||||
|
static int lua_UnitSex(lua_State* L) {
|
||||||
|
const char* uid = luaL_optstring(L, 1, "player");
|
||||||
|
auto* gh = getGameHandler(L);
|
||||||
|
if (!gh) { lua_pushnumber(L, 1); return 1; }
|
||||||
|
std::string uidStr(uid);
|
||||||
|
for (char& c : uidStr) c = static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
|
||||||
|
uint64_t guid = resolveUnitGuid(gh, uidStr);
|
||||||
|
if (guid != 0) {
|
||||||
|
auto entity = gh->getEntityManager().getEntity(guid);
|
||||||
|
if (entity) {
|
||||||
|
// Gender is byte 2 of UNIT_FIELD_BYTES_0 (0=male, 1=female)
|
||||||
|
uint32_t bytes0 = entity->getField(game::fieldIndex(game::UF::UNIT_FIELD_BYTES_0));
|
||||||
|
uint8_t gender = static_cast<uint8_t>((bytes0 >> 16) & 0xFF);
|
||||||
|
lua_pushnumber(L, gender == 0 ? 2 : (gender == 1 ? 3 : 1)); // WoW: 2=male, 3=female
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lua_pushnumber(L, 1); // unknown
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
// --- Player/Game API ---
|
// --- Player/Game API ---
|
||||||
|
|
||||||
static int lua_GetMoney(lua_State* L) {
|
static int lua_GetMoney(lua_State* L) {
|
||||||
|
|
@ -1731,7 +1854,18 @@ static int lua_UnitAffectingCombat(lua_State* L) {
|
||||||
if (uidStr == "player") {
|
if (uidStr == "player") {
|
||||||
lua_pushboolean(L, gh->isInCombat());
|
lua_pushboolean(L, gh->isInCombat());
|
||||||
} else {
|
} else {
|
||||||
lua_pushboolean(L, 0);
|
// Check UNIT_FLAG_IN_COMBAT (0x00080000) in UNIT_FIELD_FLAGS
|
||||||
|
uint64_t guid = resolveUnitGuid(gh, uidStr);
|
||||||
|
bool inCombat = false;
|
||||||
|
if (guid != 0) {
|
||||||
|
auto entity = gh->getEntityManager().getEntity(guid);
|
||||||
|
if (entity) {
|
||||||
|
uint32_t flags = entity->getField(
|
||||||
|
game::fieldIndex(game::UF::UNIT_FIELD_FLAGS));
|
||||||
|
inCombat = (flags & 0x00080000) != 0; // UNIT_FLAG_IN_COMBAT
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lua_pushboolean(L, inCombat);
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
@ -2768,6 +2902,12 @@ void LuaEngine::registerCoreAPI() {
|
||||||
{"UnitLevel", lua_UnitLevel},
|
{"UnitLevel", lua_UnitLevel},
|
||||||
{"UnitExists", lua_UnitExists},
|
{"UnitExists", lua_UnitExists},
|
||||||
{"UnitIsDead", lua_UnitIsDead},
|
{"UnitIsDead", lua_UnitIsDead},
|
||||||
|
{"UnitIsGhost", lua_UnitIsGhost},
|
||||||
|
{"UnitIsDeadOrGhost", lua_UnitIsDeadOrGhost},
|
||||||
|
{"UnitIsAFK", lua_UnitIsAFK},
|
||||||
|
{"UnitIsDND", lua_UnitIsDND},
|
||||||
|
{"UnitPlayerControlled", lua_UnitPlayerControlled},
|
||||||
|
{"UnitSex", lua_UnitSex},
|
||||||
{"UnitClass", lua_UnitClass},
|
{"UnitClass", lua_UnitClass},
|
||||||
{"GetMoney", lua_GetMoney},
|
{"GetMoney", lua_GetMoney},
|
||||||
{"IsInGroup", lua_IsInGroup},
|
{"IsInGroup", lua_IsInGroup},
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue