feat: add GetShapeshiftFormInfo for stance/form bar display

GetShapeshiftFormInfo(index) returns icon, name, isActive, isCastable
for each shapeshift form slot. Provides complete form tables for:

- Warrior: Battle Stance, Defensive Stance, Berserker Stance
- Druid: Bear, Travel, Cat, Swift Flight, Moonkin, Tree of Life
- Death Knight: Blood/Frost/Unholy Presence
- Rogue: Stealth

isActive is true when the form matches the current shapeshiftFormId_.
GetShapeshiftFormCooldown stub returns no cooldown.

Together with GetShapeshiftForm and GetNumShapeshiftForms from the
previous commit, this completes the stance bar API that addons use
to render and interact with form/stance buttons.
This commit is contained in:
Kelsi 2026-03-22 22:14:24 -07:00
parent 587c0ef60d
commit 9986de0529

View file

@ -5013,6 +5013,60 @@ void LuaEngine::registerCoreAPI() {
{"IsInRaid", lua_IsInRaid},
{"GetPlayerMapPosition", lua_GetPlayerMapPosition},
{"GetPlayerFacing", lua_GetPlayerFacing},
{"GetShapeshiftFormInfo", [](lua_State* L) -> int {
// GetShapeshiftFormInfo(index) → icon, name, isActive, isCastable
auto* gh = getGameHandler(L);
int index = static_cast<int>(luaL_checknumber(L, 1));
if (!gh || index < 1) { lua_pushnil(L); return 1; }
uint8_t classId = gh->getPlayerClass();
uint8_t currentForm = gh->getShapeshiftFormId();
// Form tables per class: {formId, spellId, name, icon}
struct FormInfo { uint8_t formId; const char* name; const char* icon; };
static const FormInfo warriorForms[] = {
{17, "Battle Stance", "Interface\\Icons\\Ability_Warrior_OffensiveStance"},
{18, "Defensive Stance", "Interface\\Icons\\Ability_Warrior_DefensiveStance"},
{19, "Berserker Stance", "Interface\\Icons\\Ability_Racial_Avatar"},
};
static const FormInfo druidForms[] = {
{1, "Bear Form", "Interface\\Icons\\Ability_Racial_BearForm"},
{4, "Travel Form", "Interface\\Icons\\Ability_Druid_TravelForm"},
{3, "Cat Form", "Interface\\Icons\\Ability_Druid_CatForm"},
{27, "Swift Flight Form", "Interface\\Icons\\Ability_Druid_FlightForm"},
{31, "Moonkin Form", "Interface\\Icons\\Spell_Nature_ForceOfNature"},
{36, "Tree of Life", "Interface\\Icons\\Ability_Druid_TreeofLife"},
};
static const FormInfo dkForms[] = {
{32, "Blood Presence", "Interface\\Icons\\Spell_Deathknight_BloodPresence"},
{33, "Frost Presence", "Interface\\Icons\\Spell_Deathknight_FrostPresence"},
{34, "Unholy Presence", "Interface\\Icons\\Spell_Deathknight_UnholyPresence"},
};
static const FormInfo rogueForms[] = {
{30, "Stealth", "Interface\\Icons\\Ability_Stealth"},
};
const FormInfo* forms = nullptr;
int numForms = 0;
switch (classId) {
case 1: forms = warriorForms; numForms = 3; break;
case 6: forms = dkForms; numForms = 3; break;
case 4: forms = rogueForms; numForms = 1; break;
case 11: forms = druidForms; numForms = 6; break;
default: lua_pushnil(L); return 1;
}
if (index > numForms) { lua_pushnil(L); return 1; }
const auto& fi = forms[index - 1];
lua_pushstring(L, fi.icon); // icon
lua_pushstring(L, fi.name); // name
lua_pushboolean(L, currentForm == fi.formId ? 1 : 0); // isActive
lua_pushboolean(L, 1); // isCastable
return 4;
}},
{"GetShapeshiftFormCooldown", [](lua_State* L) -> int {
// No per-form cooldown tracking — return no cooldown
lua_pushnumber(L, 0); lua_pushnumber(L, 0); lua_pushnumber(L, 1);
return 3;
}},
{"GetShapeshiftForm", [](lua_State* L) -> int {
auto* gh = getGameHandler(L);
lua_pushnumber(L, gh ? gh->getShapeshiftFormId() : 0);