const WebSocket = require("ws"); const { Client } = require("node-osc"); const ws = new WebSocket( "wss://relaxed-werewolf.reticulum.io/socket/websocket?vsn=2.0.0" ); const STATE_STARTING = "starting"; const STATE_JOINING = "joining"; const STATE_CONNECTED = "connected"; let state = STATE_STARTING; let hubId = "qPxWfFA"; let fullHubId = `hub:${hubId}`; let receiveId = 1; let sendId = 1; let botSessionId; let vapidPublicKey; let avatarId = "qPxWfFA"; let displayName = "000"; // Members keyed by session ID. let members = {}; let chatStates = {}; const oscClient = new Client("127.0.0.1", 3333); let dialogOptions = [ ["START", /(hello|hi)/, "Welcome to the attic, you are getting close.", "START"], ["START", /(shell)/, "One correct!", "SHELL"], ["START", /(mirror)/, "One correct!", "MIRROR"], ["START", /(computer)/, "One correct!", "COMPUTER"], ["SHELL", /(shell)/, "You already said that!!", "SHELL"], ["SHELL", /(mirror)/, "Two correct!", "SHELL_MIRROR"], ["SHELL", /(computer)/, "Two correct!", "SHELL_COMPUTER"], [ "SHELL_COMPUTER", /(shell|computer)/, "You already said that!", "SHELL_COMPUTER"], [ "SHELL_COMPUTER", /(mirror)/, "Ahhhhh...... the number of the portal is... 32!", "WIN"], [ "SHELL_MIRROR", /(shell|mirror)/, "You already said that!", "SHELL_MIRROR"], [ "SHELL_MIRROR", /(computer)/, "Ahhhhh...... the number of the portal is... 32!", "WIN"], ["MIRROR", /(mirror)/, "You already said that!!", "MIRROR"], ["MIRROR", /(shell)/, "Two correct!", "MIRROR_SHELL"], ["MIRROR", /(computer)/, "Two correct!", "MIRROR_COMPUTER"], [ "MIRROR_COMPUTER", /(mirror|computer)/, "You already said that!", "MIRROR_COMPUTER"], [ "MIRROR_COMPUTER", /(shell)/, "Ahhhhh...... the number of the portal is... 32!", "WIN"], [ "MIRROR_SHELL", /(shell|mirror)/, "You already said that!", "MIRROR_COMPUTER"], [ "MIRROR_SHELL", /(computer)/, "Ahhhhh...... the number of the portal is... 32!", "WIN"], ["COMPUTER", /(comptuer)/, "You already said that!!", "COMPUTER"], ["COMPUTER", /(mirror)/, "Two correct!", "COMPUTER_MIRROR"], ["COMPUTER", /(shell)/, "Two correct!", "COMPUTER_SHELL"], [ "COMPUTER_SHELL", /(shell|computer)/, "You already said that!", "COMPUTER_SHELL"], [ "COMPUTER_SHELL", /(mirror)/, "Ahhhhh...... the number of the portal is... 32!", "WIN"], [ "COMPUTER_MIRROR", /(computer|mirror)/, "You already said that!", "COMPUTER_MIRROR"], [ "COMPUTER_MIRROR", /(shell)/, "Ahhhhh...... the number of the portal is... 32!", "WIN"], // Guessing game ]; function sendMessage(roomId, command, body) { const message = JSON.stringify([receiveId, sendId, roomId, command, body]); ws.send(message); sendId++; } function receiveMessage(data) { const [n1, n2, channel, command, body] = JSON.parse(data); if (Number.isInteger(n1)) { receiveId = n1; } if (command === "phx_reply" && state === STATE_STARTING) { if (body.status === "ok") { console.log("Joining Hubs..."); state = STATE_JOINING; botSessionId = body.response.session_id; vapidPublicKey = body.response.vapid_public_key; sendMessage(fullHubId, "phx_join", { profile: { avatarId, displayName }, auth_token: null, perms_token: null, context: { mobile: false, embed: false }, }); } else { console.log(`ERROR WHILE STARTING: ${JSON.stringify(body)}`); } } else if (command === "phx_reply" && state == STATE_JOINING) { if (body.status === "ok") { const hub = body.response.hubs[0]; console.log(`Connected to ${hub.name}.`); state = STATE_CONNECTED; setInterval(sendHeartbeat, 30000); } else { console.log(`ERROR WHILE JOINING: ${JSON.stringify(body)}`); } } else if (command === "message" && state === STATE_CONNECTED) { console.log(body); handleChatMessage(body); } else if (command === "presence_diff") { for (const sessionId of Object.keys(body.joins)) { if (sessionId === botSessionId) continue; const meta =body.joins[sessionId].metas[0]; if (meta.presence !== 'room') continue; const displayName = meta.profile.displayName; const message = `Welcome, dear ${displayName}, to my attic..I like to listen here for any sounds from the outside.. So few come in… Stay here among the paintings for a while, you will see there is no way out..But let’s play a game! In each of these images, there is one element which you must name… For each image, this will be the most central object. But beware! Name all of the elements, and I shall steal your voice. Lo, I shall join the other world. You shall also be set free, for I shall tell you the secret of the portal...`; sendMessage(fullHubId, "message", { body: message, type: "chat" }); } } else { //console.log(`Unknown command ${command}`); } } function handleChatMessage(message) { if (message.type !== "chat") return; // This is the user that sent the message. const sessionId = message.session_id; // Ignore messages we sent ourselves. if (sessionId === botSessionId) return; const body = message.body.trim(); let chatState = chatStates[sessionId] || "START"; // Find a suitable dialog option. for (const [startState, input, output, endState] of dialogOptions) { if (startState !== chatState) continue; if (body.match(input)) { console.log(sessionId, chatState, output); setTimeout(() => { sendMessage(fullHubId, "message", { body: output, type: "chat" }); chatState = endState; chatStates[sessionId] = chatState; if (chatState === 'WIN') { oscClient.send("/win"); chatStates[sessionId] = 'START'; } }, 500 + Math.random() * 1000); break; } } } function sendHeartbeat() { sendMessage("phoenix", "heartbeat", {}); } ws.on("open", function () { sendMessage("ret", "phx_join", { hub_id: hubId }); }); ws.on("message", receiveMessage);