local state = runtime.import("state") local rules = runtime.import("rules") local ui = runtime.import("ui") local animation = runtime.import("animation") ---@type RuntimeWidgets local widgets = runtime.import("runtime_widgets") local theme = runtime.import("theme") widgets.configure({ primary = theme.colors.dice_button, secondary = theme.colors.board_inner, success = theme.colors.green, overlay = "#99000000", surface = theme.colors.top_bar, surfaceAlt = theme.colors.board_inner, card = theme.colors.top_bar, text = theme.colors.text, muted = theme.colors.muted_text, progress = theme.colors.green, transparent = "#00000000" }) function smoke_test(ctx) return ctx ~= nil and ctx.runtimeApiVersion ~= nil and state.current_player ~= nil and rules.plan_move ~= nil and ui.create_board_nodes ~= nil and animation.move_piece ~= nil and widgets.dialog ~= nil end function init(ctx) return { render = { creates = ui.create_board_nodes() }, ui = { creates = ui.create_ui_nodes() }, commands = {} } end local function handle_roll_dice() if state.phase == "game_over" then return { commands = { animation.toast("游戏已结束") } } end if state.phase ~= "waiting_roll" then return { commands = { animation.toast("请先完成当前移动") } } end state.dice = rules.next_dice() local movable = rules.movable_pieces() if #movable == 0 then local message = state.current_player .. " 无可移动飞机" if state.dice ~= 6 then state.current_player = rules.next_player() end state.phase = "waiting_roll" return { ui = { updates = ui.dice_and_status_updates() }, render = { updates = ui.highlight_updates(rules.all_piece_ids(), false) }, commands = { animation.toast(message) } } end state.phase = "waiting_piece" return { ui = { updates = ui.dice_and_status_updates() }, render = { updates = ui.highlight_updates(movable, true) } } end local function handle_piece_tap(piece_id) if state.phase ~= "waiting_piece" then return {} end local piece = state.pieces[piece_id] if piece == nil or piece.owner ~= state.current_player or not rules.can_move(piece, state.dice) then return { commands = { animation.toast("该飞机不能移动") } } end local plan = rules.plan_move(piece, state.dice) state.phase = "animating" state.selected_piece = piece_id state.pending_move = plan return { ui = { updates = ui.dice_and_status_updates() }, render = { updates = ui.highlight_updates(rules.all_piece_ids(), false) }, commands = { animation.move_piece(piece_id, plan.path) } } end local function handle_move_done() local plan = state.pending_move if plan == nil then state.phase = "waiting_roll" return { ui = { updates = ui.dice_and_status_updates() } } end rules.commit_move(plan) local moved_piece = state.pieces[plan.piece_id] local updates = ui.piece_position_updates(plan.captures) table.insert(updates, ui.piece_position_update(plan.piece_id)) local messages = {} if #plan.captures > 0 then table.insert(messages, "撞回 " .. tostring(#plan.captures) .. " 架飞机") end if rules.player_finished(moved_piece.owner) then state.winner = moved_piece.owner state.phase = "game_over" table.insert(messages, moved_piece.owner .. " 获胜") else if state.dice ~= 6 then state.current_player = rules.next_player() else table.insert(messages, "掷出 6,额外回合") end state.phase = "waiting_roll" end state.selected_piece = nil state.pending_move = nil local commands = {} if #messages > 0 then commands = { animation.toast(table.concat(messages, ";")) } end return { ui = { updates = ui.dice_and_status_updates() }, render = { updates = updates }, commands = commands } end function on_event(event) if event.handler == "roll_dice" then return handle_roll_dice() end if event.handler == "piece_tap" then return handle_piece_tap(event.target) end if event.handler == "piece_move_done" then return handle_move_done() end return {} end