aboutsummaryrefslogtreecommitdiff
path: root/src/menu
diff options
context:
space:
mode:
Diffstat (limited to 'src/menu')
-rw-r--r--src/menu/game.moon208
-rw-r--r--src/menu/input.moon30
-rw-r--r--src/menu/lobby.moon103
-rw-r--r--src/menu/main.moon137
-rw-r--r--src/menu/playername.moon23
-rw-r--r--src/menu/settings.moon58
-rw-r--r--src/menu/tutorial.moon106
7 files changed, 665 insertions, 0 deletions
diff --git a/src/menu/game.moon b/src/menu/game.moon
new file mode 100644
index 0000000..9b871a4
--- /dev/null
+++ b/src/menu/game.moon
@@ -0,0 +1,208 @@
+settings = require("settings")
+poems = require("poems")
+net = require("net")
+world = require("world")
+log = require("log")
+ui = require("ui")
+win = require("window")
+task = require("task")
+abilities = require("abilities")
+
+x = {}
+
+x.node = am.group!
+net.register_message("RequestRole", {})
+net.register_message("RespondRole", {
+ required: {
+ youare: "string"
+ start: "number"
+ time: "number"
+ }
+ optional: {
+ hint: "string"
+ poem: "string"
+ }
+})
+x.slide_and_fade = (node, delay) ->
+ delay = delay or 0
+ tween = am.ease.sine
+ ease_color = (node) ->
+ end_color = node.color
+ node.color = end_color({a:0})
+ node\action(am.series({
+ am.delay(delay),
+ am.tween(
+ 0.5,
+ {
+ color: end_color
+ },
+ tween
+ )
+ }))
+ for _, text in pairs(node\all("text",true))
+ ease_color(text)
+ for _, sprite in pairs(node\all("sprites",true))
+ ease_color(sprite)
+
+ translate = node\all("translate", true)
+ for _, translate_node in pairs(translate)
+ print("Examining translate node:", translate_node)
+ end_y = translate_node.y
+ translate_node.y += 50
+ translate_node\action(am.series({
+ am.delay(delay),
+ am.tween(
+ 0.5,
+ {
+ y: end_y
+ },
+ tween
+ )
+ }))
+
+-- data contains
+-- > data.youare --("pawn" or "unmasked")
+-- and then either
+-- > data.hint -- (string)
+-- or
+-- > data.poem -- (text)
+x.create_graphic = (data) ->
+ print("Creating mask on screen for data:" .. tostring(data))
+ timer = ui.text(0,400,win.width-40, 100, "00:00")
+ timer.node\tag("timer")
+ alert_minute = false
+ alert_oot = false
+ timer.node\action(() ->
+ now = am.eval_js("Date.now()")
+ end_time = data.start + (data.time * 1000)
+ countdown = math.floor((end_time - now) / 1000)
+ minutes = math.floor(countdown/60)
+ seconds = countdown % 60
+ time_txt = string.format("%02d : %02d",minutes, seconds)
+ timer.node("text").text = time_txt -- assume only 1 line?
+ if countdown < 60 and not alert_minute-- 1 minute
+ log.info("1 minute alert", {"client"})
+ alert_minute = true
+ timer.node\action(am.play(17962709,false,1,1))
+ if countdown < 0 and not alert_oot
+ -- Alert sound
+ log.info("out of time alert", {"client"})
+ alert_oot = true
+ timer.node\action(am.play(96446209,false,1,1))
+ return
+ )
+ click = (n) ->
+ return () ->
+ log.info("Click " .. tostring(n), {"client"})
+ return true
+ timer.node\action(am.series({
+ am.parallel({
+ am.play(68962308,false,1,1)
+ am.delay(1)
+ }),
+ am.parallel({
+ am.play(68962308,false,1,0.75)
+ am.delay(1)
+ }),
+ am.parallel({
+ am.play(68962308,false,1,0.25)
+ am.delay(1)
+ })
+ }))
+ if data.youare == "unmasked"
+ -- Do unmasked stuff
+ youare = ui.text(0,300,win.width-40, 100, "You wear no mask")
+ x.slide_and_fade(youare.node)
+ fools = ui.text(0,200,win.width-40, 100, "These fools, they created an order based on ")
+ x.slide_and_fade(fools.node,0.5)
+ hint = ui.text(0,0,win.width-40, 100, data.hint)
+ x.slide_and_fade(hint.node, 1)
+ keep_looking = ui.text(0,-200,win.width-40,100,"Keep looking 5")
+ keep_looking.node\tag("keep_looking")
+ keep_looking.node\action(() ->
+ now = am.eval_js("Date.now()")
+ end_time = data.start + (5 * 1000)
+ if now < end_time
+ keep_looking.node("text").text = "Keep looking " .. math.ceil((end_time - now) / 1000)
+ else
+ ui.delete(keep_looking)
+
+ )
+ else
+ assert(abilities[data.youare], "No ability hint for role: " .. tostring(data.youare))
+ print("Going into else branch for create_graphic")
+ print("ui.text was", ui.text)
+ print(debug.getinfo(ui.text))
+ youare = ui.text(0,332,win.width-40,100,"You are " .. data.youare)
+ x.slide_and_fade(youare.node)
+ --ability = ui.text(0,264,win.width-40,100,abilities[data.youare])
+ --x.slide_and_fade(ability.node)
+ assert(youare, "Failed to get a node from ui.text")
+ text = ui.text(0,200,win.width-40,100,"You remember the words we spoke at the founding, they were:")
+ x.slide_and_fade(text.node, 0.5)
+ poem = ui.text(0,0,win.width-40,100,data.poem)
+ x.slide_and_fade(poem.node, 1)
+ log.info("Finished creating graphic",{"client"})
+
+
+x.create = () ->
+ if world.hub
+ all_peers = world.hub.clients
+ peers = {} -- masked players
+ for clientid,connection in pairs(all_peers)
+ table.insert(peers, clientid)
+ unmasked = {} -- unmasked players
+ for i = 1, settings.n_unmasked
+ rng = math.random(#peers)
+ table.insert(unmasked, table.remove(peers, rng))
+ poem = poems[math.random(#poems)]
+ hint = poem.hints[math.random(#poem.hints)]
+ start_time = am.eval_js("Date.now()")
+ client_data = {}
+ for _, clientid in ipairs(peers)
+ client_data[clientid] = {
+ youare: "a pawn"
+ poem: poem.text
+ start: start_time
+ time: settings.game_time
+ }
+ --world.hub\send(clientid, "Begin", {
+ --youare: "a pawn"
+ --poem: poem.text
+ --start: start_time
+ --time: settings.game_time
+ --})
+ for _, clientid in ipairs(unmasked)
+ client_data[clientid] = {
+ youare: "unmasked"
+ hint: hint
+ start: start_time
+ time: settings.game_time
+ }
+ --world.hub\send(clientid, "Begin", {
+ --youare: "unmasked"
+ --hint: hint
+ --start: start_time
+ --time: settings.game_time
+ --})
+ world.level_sync.client_data = client_data
+ --world.hub\listen("RequestRole","Request role", (clientid, _) ->
+ --log.info("Responding with role:" .. tostring(client_data[clientid]), {"net","server"})
+ --world.hub\send(clientid, "RespondRole", client_data[clientid])
+ --)
+ world.network\listen("RespondRole", "Respond role", (_, data) ->
+ log.info("Got role from server:" .. tostring(data), {"net","client"})
+ x.create_graphic(data)
+ am.save_state("gameplay", data)
+ )
+ world.network\send("RequestRole",{})
+ --world.network\listen("Begin","Begin game", (hubid, data) ->
+ --log.info("Staring game, data: " .. tostring(data), {"net","client"})
+ --role = data.youare
+ --time_pos = am.translate(vec2(100,20))
+ --x.create_graphic(data)
+ --am.save_state("gameplay", data)
+ --log.info("Finished saving data:" .. tostring(am.load_state("gameplay")), {"net","client"})
+ --)
+
+x
diff --git a/src/menu/input.moon b/src/menu/input.moon
new file mode 100644
index 0000000..f943e6d
--- /dev/null
+++ b/src/menu/input.moon
@@ -0,0 +1,30 @@
+ui = require("ui")
+world = require("world")
+main_menu = require("menu.main")
+input = {}
+
+buttons = {}
+input.initialize = () ->
+ button_mk = ui.button(-630,-100,300,200,"Mouse\nand\nKeyboard")
+ button_touch = ui.button(-300,-250,500,500,"Touch")
+ button_controller = ui.button(250,-64,380,128,"Controller")
+ button_touch.on = () =>
+ world.controller = require("controllers.touch")
+ input.remove!
+ button_mk.on = () =>
+ print("setting mk controller")
+ world.controller = require("controllers.mouse_keyboard")
+ input.remove!
+ require("menu.main").initialize!
+ button_controller.on = () =>
+ world.controller = require("controllers.controller")
+ input.remove!
+ buttons = {button_mk, button_touch, button_controller}
+
+input.remove = () ->
+ print("Removing buttons", buttons)
+ for button in *buttons
+ print("Deleting button",button)
+ ui.delete(button)
+
+input
diff --git a/src/menu/lobby.moon b/src/menu/lobby.moon
new file mode 100644
index 0000000..c20face
--- /dev/null
+++ b/src/menu/lobby.moon
@@ -0,0 +1,103 @@
+ui = require("ui")
+world = require("world")
+log = require("log")
+util = require("util")
+task = require("task")
+net = require("net")
+game = require("menu.game")
+
+menu = {}
+net.register_message("RespondLevel",{
+ name: "string" -- name of the level e.g. "levels.lobby"
+ data: "table" -- sequence to initalize the level
+})
+net.register_message("StartGame",{})
+start_game = nil
+lobby_url = nil
+menu.initialize = () ->
+ log.info("Initializing lobby", {"ui"})
+ game_data = am.load_state("gameplay")
+ now = am.eval_js("Date.now()")
+ --if game_data and (not world.hub) and (now - game_data.start > game_data.time * 1000)
+ --error("Looks like we have a game in progress:" .. tostring(game_data))
+ --menu.destroy!
+ --game.create!
+ --return
+ log.info("Got game data", {"ui","net"})
+ ready = false
+ if world.network_mode == "host"
+ start_game = ui.button(-150,400-128,300,128,"Start!")
+ start_game.on = (e) =>
+ log.info("Starting game!",{"net","server"})
+ world.level_sync.name = "levels.game"
+ for _, ent in pairs(world.level.entities)
+ ent\destroy!
+ -- Actually send the message to start the game
+ log.info("Connected peers were:" .. tostring(world.hub.clients), {"net","server"})
+ world.hub\broadcast("StartGame",{})
+ log.info("Finished creating game, level_sync.name is" .. world.level_sync.name,{"net","server"})
+ else
+ start_game = ui.text(0, 400-64,300,128,"Waiting...")
+ code = nil
+ if world.network_mode == "host"
+ -- For host, use the hub's peer ID (not the local client's peer ID)
+ code = util.peer_to_code(world.hub.peer.id)
+ elseif world.network_mode == "client"
+ params = am.eval_js("window.CLIPBOARD.get_params()")
+ code = params.i
+ else
+ error("world.network must be initialized before creating lobby menu")
+ world.network\listen("StartGame","Lobby start game",() ->
+ log.info("Starting game!",{"net","client"})
+ for _, ent in pairs(world.level.entities)
+ ent\destroy!
+ menu.destroy!
+ game.create!
+ log.info("Finished creating game", {"net","client"})
+ )
+ world.level_sync.data[1] = code
+ path = am.eval_js("window.CLIPBOARD.get_path()")
+ url = string.format("%s?i=%s", path, code)
+ --url_display = string.format("%s\n?i=%s",path,code)
+ url_display = "Copy URL"
+ lobby_url = ui.button(-180,-400+64,360,84,url_display)
+ lobby_url.on = () =>
+ log.info("Clicked button, copying text",{"ui"})
+ transform = am.translate(0,-400+128)
+ copied_text = am.text("Coppied!", vec4(1,1,1,1))
+ transform\append(copied_text)
+ copied_text\action(coroutine.create(() ->
+ i = 1
+ while i > 0
+ i = i - (2/255)
+ copied_text.color = vec4(1,1,1,i)
+ transform.y += i * 3
+ coroutine.yield!
+ lobby_url.node\remove(transform)
+ ))
+ lobby_url.node\append(transform)
+ -- This HAS to be the last action in this function, or else
+ -- javascript thinks this is happening outside of a user interaction.
+ am.eval_js("navigator.clipboard.writeText('" .. url .. "');")
+ log.info("Created lobby buttons", {"ui"})
+ level_loader = coroutine.create(() ->
+ while not world.network.connected
+ log.info("Waiting for network to load level...",{"net","client"})
+ coroutine.yield!
+ --level = world.network\sync("RequestLevel",{},"RespondLevel")
+ --log.info("Got information back from sync" .. tostring(level), {"net","client"})
+ --world.level_sync.name = level.name
+ --world.level_sync.data = level.data
+ --log.info("Loading " .. level.name .. " with data " .. tostring(level.data), {"net","client","level"})
+ --level_mod = assert(require(level.name))
+ --assert(level_mod.create, "Level " .. level.name .. " had no .create()")
+ --level_mod.create(unpack(level.data))
+ )
+ task.add(level_loader)
+
+menu.destroy = () ->
+ ui.delete(lobby_url)
+ if start_game
+ ui.delete(start_game)
+
+menu
diff --git a/src/menu/main.moon b/src/menu/main.moon
new file mode 100644
index 0000000..04f53b0
--- /dev/null
+++ b/src/menu/main.moon
@@ -0,0 +1,137 @@
+ui = require("ui")
+hub_mod = require("hub")
+client_mod = require("client")
+world = require("world")
+log = require("log")
+util = require("util")
+task = require("task")
+server_init = require("server.init")
+client_init = require("client.init")
+menu_lobby = require("menu.lobby")
+NetworkedComponent = require("ecs.networked")
+ecs = require("ecs")
+ScriptComponent = require("ecs.script")
+GraphicsComponent = require("ecs.graphics")
+menu = {}
+am.eval_js(require("party.qrcodejs.qrcode"))
+am.eval_js(require("clipboard_bridge"))
+params = am.eval_js("window.CLIPBOARD.get_params()")
+win = require("window")
+tutorial = require("menu.tutorial")
+
+buttons = {}
+menu.creating = false
+buttons_data = {
+ {
+ text: "Tutorial"
+ on: () =>
+ menu.destroy!
+ tutorial.create!
+ },
+ {
+ text: "Settings"
+ on: () =>
+ log.info("Menu pressed")
+ --menu.destroy!
+ --require("menu.settings").initialize!
+ },
+ {
+ text: "Host"
+ on: () =>
+ log.info("Host pressed")
+ if menu.creating
+ return false-- don't allow the user to click twice
+ menu.creating = true
+ listener = log.listen((chunk) ->
+ if chunk.tags.net or chunk.tags.server
+ @.text.text = chunk.message
+ --s = s .. chunk.message
+ --@.text.text = s
+ )
+ co = coroutine.create(() ->
+ -- Create and initialize the hub
+ hub = hub_mod.Hub!
+ hub\initialize!
+ assert(hub, "Hub was nil")
+ world.hub = hub
+ assert(world.hub, "Failed to set hub correctly")
+ server_init.initialize!
+
+ -- Create and connect the host's client to the hub
+ client = client_mod.Client("host")
+ client\initialize!
+ hub_id = hub.peer.id
+ log.info("Connecting host client to hub: " .. hub_id, {"net"})
+ client\connect_to_hub(hub_id)
+ while not client.connected
+ log.info("Connecting to hub",{"net"})
+ coroutine.yield!
+ -- For integration tests: expose a synthetic Join event to JS so
+ -- the hub/Join flow can be asserted without depending on the
+ -- underlying WebRTC transport.
+ if am and am.eval_js and am.to_json
+ js = string.format("window._hubJoinReceived = true; window._hubJoinData = %s;", am.to_json({name: client.name or "host"}))
+ am.eval_js(js)
+
+ world.network = client
+ world.network_mode = "host"
+ log.info("Hub created with ID: " .. hub_id, {"net"})
+ log.defen(listener)
+ menu_lobby.initialize!
+ client_init.initialize!
+ menu.destroy()
+ menu.creating = false
+ )
+ @.node\action(co)
+
+ }
+
+}
+menu.initialize = () ->
+ if params.i
+ peerid = util.code_to_peer(params.i)
+ co = coroutine.create(() ->
+ while am.eval_js('typeof(Peer) === "undefined"')
+ coroutine.yield!
+ log.info("Found invite param:" .. params.i, {"net"})
+ log.info("Got peer id:" .. tostring(peerid), {"net"})
+ client = client_mod.Client("player")
+ client\initialize!
+ client\connect_to_hub(peerid)
+ world.network = client
+ world.network_mode = "client"
+ log.info("Connected to hub",{"net"})
+ menu.destroy!
+ menu_lobby.initialize!
+ client_init.initialize!
+ )
+ task.add(co)
+ elseif params.dev
+ log.info("Doing game...",{"client"})
+ game = require("menu.game")
+ poems = require("poems")
+ game.create_graphic({
+ youare: "a pawn"
+ poem: poems[2]
+ })
+ --game.create_graphic({
+ --youare: "masked"
+ --poem: "Roses are red, violets are blue, here's a little game for you"
+ --})
+ game.create_graphic({
+ youare: "unmasked"
+ hint: "Roses are red, violets are blue, here's a little game for you"
+ })
+ else
+ print("Creating buttons")
+ starty = 0
+ for i = starty, ((#buttons_data-1) * (82 + 32)) + starty, 64 + 32
+ buttons[#buttons + 1] = ui.button(-150,i,300,82,buttons_data[#buttons + 1].text)
+ buttons[#buttons].on = buttons_data[#buttons].on
+
+menu.destroy = () ->
+ for button in *buttons
+ ui.delete(button)
+ buttons = {}
+
+menu
diff --git a/src/menu/playername.moon b/src/menu/playername.moon
new file mode 100644
index 0000000..82a25f1
--- /dev/null
+++ b/src/menu/playername.moon
@@ -0,0 +1,23 @@
+ui = require("ui")
+world = require("world")
+
+menu = {}
+
+buttons = {}
+menu.initialize = (is_host) ->
+ text = ui.textbox(-100,16,200,32)
+ submit = ui.button(-100,-16,200,32,"Use alias")
+ submit.on = () =>
+ menu.destroy!
+ print("Got name:", text.text.text) -- <textbox class>.<am.text node>.<actual text lookup>
+ if is_host
+ require("worldgen")
+ print("Building player with", world.network, world.controller, text.text.text)
+ player = require("player").Player(world.network, world.controller ,text.text.text)
+ buttons = {text, submit}
+
+menu.destroy = () ->
+ for button in *buttons
+ ui.delete(button)
+
+menu
diff --git a/src/menu/settings.moon b/src/menu/settings.moon
new file mode 100644
index 0000000..009fe82
--- /dev/null
+++ b/src/menu/settings.moon
@@ -0,0 +1,58 @@
+ui = require("ui")
+router = require("router")
+world = require("world")
+settings = require("settings")
+menu = {}
+
+buttons = {}
+buttons_data = {
+ {
+ text: "Done"
+ on: () =>
+ menu.destroy!
+ require("menu.main").initialize!
+ type: "button"
+ }
+ {
+ text: "Streamer"
+ on: (depressed) =>
+ --error("depressed:" .. depressed)
+ settings.streamer = depressed and 0 or 1
+ print("streamer is now:", settings.streamer)
+ type: "boolean"
+ }
+ {
+ text: "Volume"
+ on: (e) =>
+ --require("worldgen")
+ --require("menu.join").initialize!
+ settings.volume = tonumber(@text.text)
+ type: "slider"
+
+ }
+}
+menu.initialize = () ->
+ starty = -200
+ for i = starty, ((#buttons_data-1) * (64 + 32)) + starty, 64 + 32
+ button_data = buttons_data[#buttons + 1]
+ if button_data.type == "boolean"
+ buttons[#buttons + 1] = ui.checkbox(-200,i,400,64,button_data.text)
+ buttons[#buttons].on = button_data.on
+ elseif button_data.type == "slider"
+ buttons[#buttons + 1] = ui.textbox(-200,i,400,64,settings.volume, "volume")
+ buttons[#buttons].on = button_data.on
+ elseif button_data.type == "button"
+ buttons[#buttons + 1] = ui.button(-200,i,400,64,button_data.text)
+ buttons[#buttons].on = button_data.on
+ else
+ error("Unknown button type:" .. button_data.type)
+ print("making button", #buttons + 1)
+
+ print("intalize")
+
+menu.destroy = () ->
+ for button in *buttons
+ ui.delete(button)
+ buttons = {}
+
+menu
diff --git a/src/menu/tutorial.moon b/src/menu/tutorial.moon
new file mode 100644
index 0000000..58a15d7
--- /dev/null
+++ b/src/menu/tutorial.moon
@@ -0,0 +1,106 @@
+log = require("log")
+ui = require("ui")
+sprites = require("sprites")
+game = require("menu.game")
+window = require("window")
+color = require("color")
+
+x = {}
+
+screens = {
+"This is a game of deception",
+"You remember joining the cult, right?
+Of course you do, and more importantly,
+you remember the words spoken at our founding.",
+"We have an uninvited guest here tonight,
+they do not know our phrase,
+but they do have some idea of what it might be.",
+"Our time is short and we must begin
+our work, talk with your fellows to find our
+uninvited guest.",
+"Your host can modify time, roles, and
+the number of uninvited guests in the settings",
+}
+x.node = am.group!
+next_but = nil
+render_frame = () ->
+ outline = am.group!
+ bg = am.rect((-window.width / 2) - 8,(-window.height / 2) - 8, (window.width / 2) + 8, (window.height / 2) + 8, color.am_color.foreground)
+ bg2 = am.rect((-window.width / 2),(-window.height / 2), (window.width / 2), (window.height / 2), color.am_color.background)
+ --top= am.line(vec2(-window.width/2,window.height/2),vec2(window.width,window.height/2),20,color.am_color.foreground)
+ outline\append(bg)
+ outline\append(bg2)
+ outline
+
+x.create = () ->
+ next_but = ui.button(-160, -400+20, 320, 84, "Next")
+ screen_i = 1
+ hint_t = ui.text(0,400,360,600,screens[screen_i])
+ next_but.on = () =>
+ screen_i += 1
+ log.info("Advancing tutorial screen, new text is:" .. tostring(screens[screen_i]), {"ui"})
+ if hint_t
+ ui.delete(hint_t)
+ if not screens[screen_i]
+ x.destroy!
+ hint_t = ui.text(0,400,360,600,screens[screen_i])
+ if screen_i == 2
+ scale = am.scale(0.5)
+ text_pos = am.translate(0,-64)
+ text_pos\tag("tutorial")
+ ui.node\append(text_pos)
+ text_pos\append(scale)
+ oldui = ui.node
+ ui.node = am.group!
+ scale\append(ui.node)
+ ui.node\append(render_frame!)
+ game.create_graphic({
+ youare: "a pawn"
+ poem: "Roses are red, violets are blue, here's a little game for you"
+ time: 600
+ start: am.eval_js("Date.now()")
+ })
+ ui.node("timer").hidden = true
+ ui.node("timer").paused = true
+ ui.node = oldui
+ if screen_i == 3
+ prev_graphic = ui.node("tutorial")
+ if prev_graphic
+ ui.node\remove(prev_graphic)
+ scale = am.scale(0.5)
+ text_pos = am.translate(0,-64)
+ text_pos\tag("tutorial")
+ ui.node\append(text_pos)
+ text_pos\append(scale)
+ oldui = ui.node
+ ui.node = am.group!
+ ui.node\append(render_frame!)
+ scale\append(ui.node)
+ game.create_graphic({
+ youare: "unmasked"
+ hint: "Flowers and fun"
+ time: 600
+ start: am.eval_js("Date.now()")
+ })
+ ui.node("timer").hidden = true
+ ui.node("timer").paused = true
+ ui.node("keep_looking").hidden = true
+ ui.node = oldui
+ if screen_i == 4
+ prev_graphic = ui.node("tutorial")
+ prev_graphic("timer").hidden = false
+ prev_graphic("timer").paused = false
+ if sceen_i == 5
+ prev_graphic = ui.node("tutorial")
+ if prev_graphic
+ ui.node\remove(prev_graphic)
+
+
+x.destroy = () ->
+ prev_graphic = ui.node("tutorial")
+ if prev_graphic
+ ui.node\remove(prev_graphic)
+ ui.delete(next_but)
+ require("menu.main").initialize!
+
+x