diff --git a/LogicBeacon/LogicBeacon.lua b/LogicBeacon/LogicBeacon.lua new file mode 100644 index 0000000..44212b3 --- /dev/null +++ b/LogicBeacon/LogicBeacon.lua @@ -0,0 +1,233 @@ +--[[ + 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 查看命令。") diff --git a/LogicBeacon/LogicBeacon.toc b/LogicBeacon/LogicBeacon.toc new file mode 100644 index 0000000..589090b --- /dev/null +++ b/LogicBeacon/LogicBeacon.toc @@ -0,0 +1,8 @@ +## Interface: 30300 +## Title: LogicBeacon +## Notes: 屏幕角落像素条,用颜色编码游戏状态 +## Author: LogicBeacon +## Version: 1.0.0 +## SavedVariablesPerCharacter: LogicBeaconDB + +LogicBeacon.lua diff --git a/recorder/祖达克-西莱图斯西面.json b/recorder/祖达克-西莱图斯西面.json new file mode 100644 index 0000000..65bbe9a --- /dev/null +++ b/recorder/祖达克-西莱图斯西面.json @@ -0,0 +1,178 @@ +[ + [ + 35.81, + 47.16 + ], + [ + 35.43, + 47.54 + ], + [ + 35.07, + 47.91 + ], + [ + 34.81, + 48.4 + ], + [ + 34.81, + 48.91 + ], + [ + 34.81, + 49.43 + ], + [ + 35.05, + 49.91 + ], + [ + 35.42, + 50.27 + ], + [ + 35.79, + 50.62 + ], + [ + 36.01, + 51.07 + ], + [ + 36.11, + 51.57 + ], + [ + 36.2, + 52.09 + ], + [ + 36.2, + 52.63 + ], + [ + 36.19, + 53.15 + ], + [ + 36.18, + 53.66 + ], + [ + 36.18, + 54.17 + ], + [ + 36.17, + 54.69 + ], + [ + 36.16, + 55.21 + ], + [ + 36.15, + 55.73 + ], + [ + 36.15, + 56.26 + ], + [ + 36.14, + 56.76 + ], + [ + 36.3, + 57.25 + ], + [ + 36.83, + 57.33 + ], + [ + 37.29, + 57.12 + ], + [ + 37.39, + 56.57 + ], + [ + 37.4, + 56.05 + ], + [ + 37.38, + 55.54 + ], + [ + 37.32, + 55.01 + ], + [ + 37.27, + 54.49 + ], + [ + 37.25, + 53.96 + ], + [ + 37.23, + 53.46 + ], + [ + 37.21, + 52.94 + ], + [ + 37.19, + 52.41 + ], + [ + 37.17, + 51.9 + ], + [ + 37.1, + 51.4 + ], + [ + 36.96, + 50.86 + ], + [ + 36.79, + 50.34 + ], + [ + 36.62, + 49.82 + ], + [ + 36.49, + 49.28 + ], + [ + 36.39, + 48.77 + ], + [ + 36.3, + 48.27 + ], + [ + 36.2, + 47.77 + ], + [ + 36.09, + 47.28 + ], + [ + 35.81, + 47.16 + ] +] \ No newline at end of file