Created
May 9, 2023 15:14
-
-
Save taotao54321/96c2b1b329613cf67d0282e16ef2d73a to your computer and use it in GitHub Desktop.
紫禁城 (FC) HUD script for Mesen
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--[[ | |
紫禁城 (FC) HUD script for Mesen | |
--]] | |
local function warn(msg) | |
emu.log(msg) | |
end | |
local function mem_read(addr) | |
return emu.read(addr, emu.memType.cpu) | |
end | |
local function color_rgba(r, g, b, a) | |
local a_inv = 0xFF - a | |
return (a_inv << 24) | (r << 16) | (g << 8) | b | |
end | |
local function color_rgb(r, g, b) | |
return color_rgba(r, g, b, 0xFF) | |
end | |
local BOARD_W = 14 | |
local BOARD_H = 8 | |
local BOARD_LEN = BOARD_W * BOARD_H | |
local PAI_COUNT_MAX = 85 | |
local PIT_COUNT_MAX = 60 | |
local function unpack_pai_value(value) | |
local id = value & 0x7F | |
local fixed = (value & 0x80) ~= 0 | |
return id, fixed | |
end | |
local function get_pai(idx) | |
local addr = 0x0620 + 3 * idx | |
local state = mem_read(addr) | |
local pos = mem_read(addr + 1) | |
local value = mem_read(addr + 2) | |
-- 無効な牌なら nil を返す。一応バグ面にも対応可能にしておく。 | |
if state == 0 or pos == 0 or pos > BOARD_LEN then | |
return nil | |
end | |
local hidden = nil | |
if state >= 2 then | |
local id, fixed = unpack_pai_value(state - 2) | |
hidden = { | |
pos = pos, | |
id = id, | |
fixed = fixed, | |
} | |
end | |
local id, fixed = unpack_pai_value(value) | |
return { | |
pos = pos, | |
id = id, | |
fixed = fixed, | |
hidden = hidden, | |
} | |
end | |
local function get_pai_board() | |
local board = {} | |
for _pos = 1, BOARD_LEN do | |
table.insert(board, {}) | |
end | |
for i = 1, PAI_COUNT_MAX do | |
local pai = get_pai(i - 1) | |
if pai ~= nil then | |
table.insert(board[pai.pos], pai) | |
end | |
end | |
return board | |
end | |
local function get_pit(idx) | |
local addr = 0x079F + idx | |
local pos = mem_read(addr) | |
-- 落とし穴の位置が無効なら nil を返す。一応バグ面にも対応可能にしておく。 | |
if pos == 0 or pos > BOARD_LEN then | |
return nil | |
end | |
return pos | |
end | |
local function get_pit_board() | |
local board = {} | |
for _pos = 1, BOARD_LEN do | |
table.insert(board, false) | |
end | |
for i = 1, PIT_COUNT_MAX do | |
local pos = get_pit(i - 1) | |
if pos ~= nil then | |
board[pos] = true | |
end | |
end | |
return board | |
end | |
local function get_history_count() | |
return mem_read(0x07DE) | |
end | |
local COLOR_TEXT = color_rgb(0xFF, 0xFF, 0xFF) | |
local COLOR_PAI_NORMAL = color_rgb(0, 0xFF, 0xFF) | |
local COLOR_PAI_FIXED = color_rgb(0xFF, 0, 0) | |
local COLOR_PAI_HIDDEN = color_rgb(0, 0xFF, 0) | |
local COLOR_PAI_HIDDEN_FIXED = color_rgb(0xFF, 0x80, 0) | |
local COLOR_PIT = color_rgb(0xFF, 0, 0xFF) | |
local COLOR_BG = color_rgba(0, 0, 0, 0xC0) | |
local function base36_char(x) | |
if x <= 9 then | |
return string.char(0x30 + x) | |
elseif x <= 35 then | |
return string.char(0x41 + x - 10) | |
else | |
return "?" | |
end | |
end | |
local function pos_to_screen_coord(pos) | |
local col = (pos - 1) % 14 | |
local row = (pos - 1) // 14 | |
local x = 16 + 16 * col | |
local y = 16 + 24 * row | |
return x, y | |
end | |
local function color_pai_shown(pai) | |
if pai.fixed then | |
return COLOR_PAI_FIXED | |
else | |
return COLOR_PAI_NORMAL | |
end | |
end | |
local function color_pai_hidden(pai) | |
if pai.fixed then | |
return COLOR_PAI_HIDDEN_FIXED | |
else | |
return COLOR_PAI_HIDDEN | |
end | |
end | |
local function draw() | |
local pai_board = get_pai_board() | |
local pit_board = get_pit_board() | |
local history_count = get_history_count() | |
for pos = 1, BOARD_LEN do | |
local x_base, y_base = pos_to_screen_coord(pos) | |
-- 牌または落とし穴があるならマスを枠で囲む。 | |
if #pai_board[pos] ~= 0 or pit_board[pos] then | |
emu.drawRectangle(x_base, y_base, 16, 24, color_rgb(0xC0, 0x40, 0)) | |
end | |
-- 牌たちを表示。 | |
for i, pai in ipairs(pai_board[pos]) do | |
local x = x_base | |
local y = y_base + 8 * (i - 1) | |
emu.drawString(x, y, base36_char(pai.id), color_pai_shown(pai), COLOR_BG) | |
if pai.hidden ~= nil then | |
emu.drawString(x + 8, y, base36_char(pai.hidden.id), color_pai_hidden(pai.hidden), COLOR_BG) | |
end | |
end | |
-- 落とし穴を表示。 | |
if pit_board[pos] then | |
local x = x_base + 8 | |
local y = y_base + 16 | |
emu.drawString(x, y, "*", COLOR_PIT, COLOR_BG) | |
end | |
end | |
emu.drawString(224, 232, string.format("HIST:%d", history_count), COLOR_TEXT, COLOR_BG) | |
end | |
local function main() | |
emu.addEventCallback(draw, emu.eventType.endFrame) | |
end | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment