Skip to content

Instantly share code, notes, and snippets.

@taotao54321
Created May 9, 2023 15:14
Show Gist options
  • Save taotao54321/96c2b1b329613cf67d0282e16ef2d73a to your computer and use it in GitHub Desktop.
Save taotao54321/96c2b1b329613cf67d0282e16ef2d73a to your computer and use it in GitHub Desktop.
紫禁城 (FC) HUD script for Mesen
--[[
紫禁城 (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