function dump(x, idt) local p = {} local idt = idt or 0 for k, v in pairs(x) do local s if type(v) == "table" then s = dump(v, idt+1) elseif type(v) == "string" then s = ("\"%s\""):format(v) else s = tostring(v) end table.insert(p, ("%s%s = %s"):format((" "):rep(4*(idt+1)), k, s)) end return ("{\n%s\n%s}"):format(table.concat(p, ", \n"), (" "):rep(4*idt)) end local client = require("client") local server = require("server") local main_menu = require("main_menu") local ui = require("ui") local color = ui.color local clt local dialog = {} local last_status, last_info local function show(dg, ...) dialog.active = dg if dg.show then dg:show(...) end end local function connect(invite) local c, err = client.join(invite) if err then show(dialog.error, "Invalid invite") else clt = c end end local function disconnect(msg) client.close(clt) clt = nil last_status = nil if msg then show(dialog.error, msg) else show(dialog.main_menu, msg) end end local function select_player(name, create) client.select_player(clt, name, create) show(dialog.loading, "Joining Lobby...") end local function update_client() client.update(clt) local status = client.status(clt) if status == "timeout_match" then disconnect("Failed to connect to match server (match server down?)") elseif status == "fail_match" then disconnect("Game not found (invalid invite?)") elseif status == "timeout_server" then disconnect("Failed to connect to server (NAT punch failure?)") elseif status == "fail_server" then disconnect("Incorrect secret (invalid invite?)") elseif status == "disco" then disconnect("Lost connection to server (Server shut down?)") elseif status ~= last_status then if status == "active" then show(dialog.loading, "Waiting for info...") elseif status == "wait_match" then show(dialog.loading, "Waiting for match server...") elseif status == "wait_server" then show(dialog.loading, "Waiting for server...") end end if not clt then return end if clt.player_error then show(dialog.error, clt.player_error, dialog.select_player) clt.player_error = nil elseif clt.player and (not in_lobby or (in_lobby and last_info ~= clt.info)) then show(dialog.lobby) elseif not clt.player and last_info ~= clt.info and (not last_info or dialog.active == dialog.select_player) then show(dialog.select_player) end last_info = clt.info last_status = status end local function create_dialog_box(title, elem, width) return ui.new(ui.center_y(ui.stack_x( ui.flex(1), ui.flex(width or 2, main_menu.box(title, elem)), ui.flex(1) ))) end local function create_info_box(title, action_name, action, show) local box = main_menu.box(title, ui.button(action_name, action)) local dg = ui.new(ui.center_x(ui.center_y(box))) function dg.set_title(self, x) box.box_title.text:set(x) end dg.show = show return dg end local function create_loading() return create_info_box("Loading...", "Cancel", function() disconnect() end, function(self, msg) self:set_title(msg) end ) end local function create_error() local back_menu return create_info_box("Error", "Back", function() show(back_menu or dialog.main_menu) end, function(self, msg, back) self:set_title(msg) back_menu = back end ) end local function create_player_indicator(player, text_size) local name = player.name if clt and clt.player == player.name then name = name .. " [YOU]" end local text = ui.text(name, text_size, color(0x000000)) local status_size = text.text:getHeight()-10 return ui.stack_x( ui.center_y({ fill = player.active and color(0x23cf3a) or color(0xc21b3a), size = { x = status_size, y = status_size } }), ui.pad_x(10), text ) end local function create_select_player() local contents = {} local dg = create_dialog_box("Select Player", contents) dg.show = function() local stack = ui.stack_y() for _, p in ipairs(clt.info.players) do local button = ui.button_elem(create_player_indicator(p, 25), function() if not p.active then select_player(p.name, false) end end) button.line = nil if p.active then button.fill_normal = color(0x122194) button.fill_hover = color(0x122194) else button.fill_normal = color(0x223ebd) button.fill_hover = color(0x2d95d6) end table.insert(stack, button) end local create = ui.button("+", function() show(dialog.create_player) end) create.line = nil create.fill_normal = color(0x7e1dbf) create.fill_hover = color(0x9540cf) table.insert(stack, create) contents[1] = stack end return dg end local function create_create_player() local input = ui.input("Player name") return create_dialog_box("Create Player", ui.stack_y( input, ui.pad_y(10), ui.pad_x(10, ui.button("Back", function() show(dialog.select_player) end), ui.flex(1, ui.button("Create", function() if input.input_value ~= "" then select_player(input.input_value, true) end end)) ) )) end local function create_lobby() local player_list = {} local dg = create_dialog_box("Lobby", ui.stack_y( player_list, ui.center_x(ui.button("Disconnect", function() disconnect() end)) ), 3) function dg.show(self) local players = ui.stack_y() for _, p in ipairs(clt.info.players) do table.insert(players, create_player_indicator(p, 20)) end player_list[1] = players end return dg end function love.load() love.graphics.setBackgroundColor(color(0xffffff)) love.window.setTitle("RAINBOW SIX: PANOPTICON") dialog.main_menu = main_menu.create({ join_game = connect }) dialog.loading = create_loading() dialog.error = create_error() dialog.create_player = create_create_player() dialog.select_player = create_select_player() dialog.lobby = create_lobby() show(dialog.main_menu) end function love.mousepressed(x, y, button) if dialog.active then ui.mousepressed(dialog.active, x, y, button) end end function love.mousereleased(x, y, button) if dialog.active then ui.mousereleased(dialog.active, x, y, button) end end function love.textinput(text) if dialog.active then ui.textinput(dialog.active, text) end end function love.keypressed(key) if dialog.active then ui.keypressed(dialog.active, key) end end function love.update() if clt then update_client() end end function love.draw() if dialog.active then ui.update(dialog.active) ui.render(dialog.active) end end function love.quit() print("shutting down") if clt then client.close(clt) end end