--[[ LogicBeacon - 多状态像素编码器 在屏幕角落显示横向像素条,每个像素对应一个游戏状态, 供外部 Python 等脚本截取小区域即可获取完整状态机。 ]] -- 配置:8个状态位(1个白色锚点 + 7个数据位) local PIXEL_SIZE = 10 local STATUS_COUNT = 8 local ADDON_NAME = "LogicBeacon" -- 默认配置(可被 SavedVariables 覆盖) local defaults = { pixelSize = PIXEL_SIZE, statusCount = STATUS_COUNT, point = "TOPLEFT", x = 10, -- 整体向右偏移 10 像素 y = 0, scale = 1, locked = false, } -- 确保每角色存储存在 LogicBeaconDB = LogicBeaconDB or {} for k, v in pairs(defaults) do if LogicBeaconDB[k] == nil then LogicBeaconDB[k] = v end end -- 升级:至少 8 个状态位(含目标位+后勤位+坐标朝向) LogicBeaconDB.statusCount = math.max(LogicBeaconDB.statusCount or 0, 8) local db = LogicBeaconDB -- 主框架 local f = CreateFrame("Frame", "LogicBeaconFrame", UIParent) local totalW = db.pixelSize * db.statusCount local totalH = db.pixelSize f:SetSize(totalW, totalH) f:SetScale(db.scale) f:SetPoint(db.point, UIParent, db.point, db.x, db.y) f:SetFrameStrata("TOOLTIP") f:SetClampedToScreen(true) -- 背景底色(防止半透明干扰) local bg = f:CreateTexture(nil, "BACKGROUND") bg:SetAllPoints() bg:SetColorTexture(0, 0, 0, 1) -- 像素纹理([1]=锚点 [2~8]=数据位) local pixels = {} for i = 1, db.statusCount do local tex = f:CreateTexture(nil, "OVERLAY") tex:SetSize(db.pixelSize, db.pixelSize) tex:SetPoint("LEFT", f, "LEFT", (i - 1) * db.pixelSize, 0) pixels[i] = tex end -- 后勤位:背包空格、装备耐久、死亡/灵魂状态 local function GetLogisticsInfo() -- 1. 检查背包空格 (0 - 100+) local freeSlots = 0 for i = 0, 4 do local numFree = GetContainerNumFreeSlots(i) freeSlots = freeSlots + numFree end -- 2. 检查装备最低耐久度 (0.0 - 1.0) local minDurability = 1 for i = 1, 18 do local current, maximum = GetInventoryItemDurability(i) if current and maximum and maximum > 0 then minDurability = math.min(minDurability, current / maximum) end end -- 3. 死亡状态 (0:存活, 0.5:死尸, 1.0:灵魂) local dState = 0 if UnitIsGhost("player") then dState = 1.0 elseif UnitIsDead("player") then dState = 0.5 end return freeSlots, minDurability, dState end -- 地图坐标(现代 C_Map API,返回 0~1 比例) local function GetPlayerCoords() local mapID = C_Map.GetBestMapForUnit("player") if mapID then local mapPos = C_Map.GetPlayerMapPosition(mapID, "player") if mapPos then return mapPos:GetXY() end end return 0, 0 end f:SetScript("OnUpdate", function() -- [1] 锚点:永远纯白 (255, 255, 255) pixels[1]:SetColorTexture(1, 1, 1) -- [2] 血量:红色通道 local hp = UnitHealth("player") / math.max(1, UnitHealthMax("player")) local targetHp = UnitHealth("target") / math.max(1, UnitHealthMax("target")) pixels[2]:SetColorTexture(hp, targetHp, 0) -- [3] 法力/能量:蓝色通道 local mp = UnitPower("player") / math.max(1, UnitPowerMax("player")) pixels[3]:SetColorTexture(0, 0, mp) -- [4] 战斗状态:绿色通道 (255=战斗中) if UnitAffectingCombat("player") then pixels[4]:SetColorTexture(0, 1, 0) else pixels[4]:SetColorTexture(0, 0, 0) end -- [5] 目标状态:红色通道 (255=有敌对目标) -- 逻辑:可以攻击 AND 目标不是玩家 AND 不是灰名怪 AND 不是玩家宠物 if UnitCanAttack("player", "target") and not UnitIsPlayer("target") and not UnitIsTapDenied("target") and not UnitPlayerControlled("target") then -- 只有满足这三个条件,才输出“有效目标”信号(红色) pixels[5]:SetColorTexture(1, 0, 0) else -- 只要其中一个条件不满足(比如怪被抢了,或者是玩家),就输出黑色 pixels[5]:SetColorTexture(0, 0, 0) end -- [6] 综合后勤与死亡位 local free, repair, dead = GetLogisticsInfo() -- R: 空格数 (0-1,Python *255 还原) -- G: 耐久度 (0-1) -- B: 死亡状态 (0=存活, 0.5=死尸, 1.0=灵魂) pixels[6]:SetColorTexture(free / 255, repair, dead) -- [7][8] 地图坐标与朝向(C_Map 现代 API,0~1 比例) local mapX, mapY = GetPlayerCoords() local facing = GetPlayerFacing() or 0 -- [7] X:R=整数部分(×100),G=小数部分,B=朝向/2π pixels[7]:SetColorTexture( math.floor(mapX * 100) / 255, math.floor((mapX * 10000) % 100) / 255, facing / 6.28318 ) -- [8] Y:R=整数部分(×100),G=小数部分,B=预留 pixels[8]:SetColorTexture( math.floor(mapY * 100) / 255, math.floor((mapY * 10000) % 100) / 255, 0 ) end) -- 可拖动 f:SetMovable(not db.locked) f:EnableMouse(not db.locked) f:RegisterForDrag("LeftButton") f:SetScript("OnDragStart", function() if not db.locked then f:StartMoving() end end) f:SetScript("OnDragStop", function() f:StopMovingOrSizing() local _, _, _, x, y = f:GetPoint(1) db.x = x db.y = y end) -- 右键菜单:锁定/解锁、重置位置 local menu = CreateFrame("Frame", "LogicBeaconMenu", f, "UIDropDownMenuTemplate") f:SetScript("OnMouseDown", function(_, button) if button == "RightButton" then local menuList = { { text = db.locked and "解锁位置" or "锁定位置", func = function() db.locked = not db.locked f:SetMovable(not db.locked) f:EnableMouse(not db.locked) end, }, { text = "重置到左上角", func = function() db.point = "TOPLEFT" db.x = 10 db.y = 0 f:ClearAllPoints() f:SetPoint(db.point, UIParent, db.point, db.x, db.y) end, }, } EasyMenu(menuList, menu, "cursor", 0, 0, "MENU") end end) -- 登录完成后确保显示 local event = CreateFrame("Frame") event:RegisterEvent("PLAYER_LOGIN") event:SetScript("OnEvent", function() f:Show() end) -- Slash 命令 SlashCmdList["LOGICBEACON"] = function(msg) msg = msg:lower():gsub("^%s*(.-)%s*$", "%1") if msg == "lock" or msg == "锁定" then db.locked = true f:SetMovable(false) f:EnableMouse(false) print("|cff00ff00[LogicBeacon]|r 已锁定") elseif msg == "unlock" or msg == "解锁" then db.locked = false f:SetMovable(true) f:EnableMouse(true) print("|cff00ff00[LogicBeacon]|r 已解锁") elseif msg == "reset" or msg == "重置" then db.point, db.x, db.y = "TOPLEFT", 10, 0 f:ClearAllPoints() f:SetPoint(db.point, UIParent, db.point, db.x, db.y) print("|cff00ff00[LogicBeacon]|r 已重置到左上角") else print("|cff00ff00[LogicBeacon]|r 用法: /lb lock|unlock|reset (锁定|解锁|重置位置)") end end SLASH_LOGICBEACON1 = "/lb" SLASH_LOGICBEACON2 = "/logicbeacon" print("|cff00ff00[LogicBeacon]|r 已加载。右键像素条可锁定/重置,/lb 查看命令。")