GroupHUD

Edit

-- ============================================================
-- Group Frames for LegendMUD (Mudlet)

-- Shows a frame per group member (HP/Mana/Move, rank, room status)
-- and hides itself entirely when you're not in a group.

-- group.info is request-only (never pushed), so this polls on a
-- timer. Solo -> group.info returns an empty/absent list -> panel
-- hides. In a group -> panel reappears and fills in member frames.
-- ============================================================

groupHUD = groupHUD or {}

-- ---- Reload-safe cleanup ----
if groupHUD.container then
groupHUD.container:hide()
groupHUD.container = nil
end
if groupHUD.infoHandlerID then killAnonymousEventHandler(groupHUD.infoHandlerID) end
if groupHUD.pollTimerID then killTimer(groupHUD.pollTimerID) end

-- ---- CONFIG ----
groupHUD.config = {
x = "76%", y = "26%", width = "22%", -- right side, beneath the vitals HUD
maxMembers = 6, -- fixed slot count; extra members beyond this won't show
rowHeight = 36, -- px per member row
pollSeconds = 3, -- how often to silently poll group.info
}

-- ---- Build window (starts hidden - shown only when grouped) ----
local totalHeight = 20 + (groupHUD.config.maxMembers * groupHUD.config.rowHeight)

groupHUD.container = Geyser.Container:new({
name = "groupHUD_container",
x = groupHUD.config.x, y = groupHUD.config.y,
width = groupHUD.config.width, height = totalHeight .. "px",
})
groupHUD.container:hide()

groupHUD.title = Geyser.Label:new({
name = "groupHUD_title", x = 0, y = 0, width = "100%", height = "20px",
}, groupHUD.container)
groupHUD.title:setStyleSheet("background-color: rgba(20,20,60,200); color:white; font-weight:bold;")
groupHUD.title:echo("Group")

-- ---- Build fixed member slots ----
groupHUD.slots = {}
for i = 1, groupHUD.config.maxMembers do
local rowY = 20 + (i - 1) * groupHUD.config.rowHeight

local nameLabel = Geyser.Label:new({
name = "groupHUD_name" .. i, x = 0, y = rowY .. "px", width = "100%", height = "18px",
}, groupHUD.container)
nameLabel:setStyleSheet("color:white; background: rgba(20,20,20,150);")

local hpGauge = Geyser.Gauge:new({
name = "groupHUD_hpGauge" .. i, x = 0, y = (rowY + 18) .. "px", width = "100%", height = "18px",
}, groupHUD.container)
hpGauge:setColor(200, 40, 40)

local hpLabel = Geyser.Label:new({
name = "groupHUD_hpLabel" .. i, x = 0, y = (rowY + 18) .. "px", width = "100%", height = "18px",
}, groupHUD.container)
hpLabel:setStyleSheet("color:white; background: transparent;")

groupHUD.slots[i] = { nameLabel = nameLabel, hpGauge = hpGauge, hpLabel = hpLabel }
nameLabel:hide()
hpGauge:hide()
hpLabel:hide()
end

-- ---- Update from group.info ----
function groupHUD.onGroupInfo()
local info = gmcp.group and gmcp.group.info
local members = info and info.groups

-- Filter out the player's own entry - their info is already on the
-- vitals HUD, no need to repeat it here.
local ownName = gmcp.char and gmcp.char.prompt and gmcp.char.prompt.n
local others = {}
if members then
for _, m in ipairs(members) do
if not ownName or (m.name ~= ownName and m.longName ~= ownName) then
table.insert(others, m)
end
end
end

if #others == 0 then
groupHUD.container:hide()
return
end

groupHUD.container:show()

for i = 1, groupHUD.config.maxMembers do
local slot = groupHUD.slots[i]
local m = others[i]

if m then
  local rankSymbol = ""
  if m.rank == "L" then rankSymbol = "[Leader] "
  elseif m.rank == "f" then rankSymbol = "[Following] "
  elseif m.rank == "2" then rankSymbol = "[Next] "
  end

  local nameColor = m.sameRoom and "white" or "grey"
  slot.nameLabel:setStyleSheet("color:" .. nameColor .. "; background: rgba(20,20,20,150);")
  slot.nameLabel:echo(rankSymbol .. tostring(m.longName or m.name))

  if m.hp and m.maxHp then
    slot.hpGauge:setValue(m.hp, m.maxHp)
    slot.hpLabel:echo(string.format("HP: %s/%s  Mana: %s/%s  Move: %s/%s",
      tostring(m.hp), tostring(m.maxHp),
      tostring(m.mana), tostring(m.maxMana),
      tostring(m.move), tostring(m.maxMove)))
  end

  slot.nameLabel:show()
  slot.hpGauge:show()
  slot.hpLabel:show()
else
  slot.nameLabel:hide()
  slot.hpGauge:hide()
  slot.hpLabel:hide()
end

end
end

groupHUD.infoHandlerID = registerAnonymousEventHandler("gmcp.group.info", "groupHUD.onGroupInfo")

function groupHUD.poll()
sendGMCP("group.info")
end

groupHUD.pollTimerID = tempTimer(groupHUD.config.pollSeconds, groupHUD.poll, true)

-- ---- Initial check ----
groupHUD.poll()

cecho("<cyan>[GroupHUD] <white>Loaded. Hidden when solo, polling every " ..
groupHUD.config.pollSeconds .. "s while checking group status.\n")