|  | dirs = {
  "up-left": "Northwest",
  "up": "North",
  "up-right": "Northeast",
  "left": "West",
  "right": "East",
  "down-left": "Southwest",
  "down": "South",
  "down-right": "Southeast",
  "ascend": "Up",
  "descend": "Down"
}
function initWorld(worldChoice, state) {
  state.world = games[worldChoice]["world"];
  initRoomState(state);
}
function initRoomState(state) {
  state.player.rooms = {};
  Object.entries(state.world).forEach(([key, val]) => {
    state.player.rooms[key] = {};
  });
}
function showActionDescription(desc) {
  const descHolder = document.querySelector("#desc");
  descHolder.textContent = desc;
}
function removeActionDescription() {
  const descHolder = document.querySelector("#desc");
  descHolder.textContent = "";
}
function moveToRoom(src, exit, dest, state) {
  const room = state.world[dest];
  if (exit.hooks) {
    for (let hook of exit.hooks) {
      if (!hook(room, exit, state)) {
        return;
      }
    }
  }
  if (room.hooks) {
    for (let hook of room.hooks) {
      if (!hook(room, state)) {
        return;
      }
    }
  }
  state.world[dest].move(state.world[dest], state);
  state.player.location = dest;
  refresh();
}
function goToRoom(dest, state) {
  const room = state.world[dest];
  if (room.hooks) {
    for (let hook of room.hooks) {
      if (!hook(room, state)) {
        return;
      }
    }
  }
  state.player.location = dest;
  
  refresh();
}
function updateRoom(state) {
  const name = state.player.location
  const room = state.world[name];
  if (!state.player.rooms[name.id]) {
    state.player.rooms[name.id] = {};
  }
  const areaName = document.querySelector("#area-name");
  const areaDesc = document.querySelector("#area-desc");
  areaName.textContent = room.name;
  areaDesc.textContent = room.desc;
  const moveHolder = document.querySelector("#move-holder");
  moveHolder.innerHTML = "";
  Object.entries(dirs).forEach(([dir, name]) => {
    const button = document.createElement("button");
    button.classList.add("move-button")
    button.id = "move-" + dir;
    button.classList.add("disabled");
    button.setAttribute("disabled", "true");
    button.textContent = dirs[dir];
    moveHolder.appendChild(button);
  });
  if (room.exits) {
    Object.entries(room.exits).forEach(([dir, exit]) => {
      const button = document.querySelector("#move-" + dir);
      const dest = state.world[exit.target];
      // don't even show an exit if this fails!
      if (exit.show) {
        if (!exit.show.every(cond => cond(room, state))) {
          return;
        }
      }
      button.textContent = dest.name;
      // if any condition fails, don't enable/add a listener
      if (exit.conditions) {
        if (!exit.conditions.every(cond => cond(room,state))) {
          return;
        }
      }
      button.classList.remove("disabled");
      button.removeAttribute("disabled");
      button.addEventListener("click", () => {
        // todo: log
        moveToRoom(room, exit, exit.target, state);
      })
    });
  }
  const actionHolder = document.querySelector("#actions");
  actionHolder.innerHTML = "";
  if (room.actions) {
    room.actions.forEach(action => {
      const button = document.createElement("button");
      button.classList.add("action-button");
      if (action.show) {
        if (!action.show.every(cond => cond(room, state))) {
          return;
        }
      }
      button.textContent = action.name;
      actionHolder.appendChild(button);
      if (action.conditions) {
        if (!action.conditions.every(cond => cond(room, state))) {
          button.classList.add("disabled");
          button.setAttribute("disabled", "true");
          return;
        }
      }
      button.addEventListener("click", () => {
        action.execute(room, state);
        refresh();
      });
      button.addEventListener("mouseenter", () => {
        showActionDescription(action.desc);
      });
      button.addEventListener("mouseleave", () => {
        removeActionDescription();
      });
    });
  }
}
games = {
  "demo": {
    "id": "demo",
    "sounds": [
      "sfx/oof.ogg"
    ],
    "world": {
      "Home": {
        "id": "Home",
        "name": "Home",
        "desc": "Where the wifi autoconnects",
        "move": (room, state) => {
          print(["You go back to your living room"]);
        },
        "actions": [
          {
            "name": "Squint",
            "desc": "Squint in a very aggressive manner",
            "execute": (room, state) => {
              state.player.rooms[room.id].squinted = true;
              print(["You stare at the wall and notice a secret door. But where is the key?"]);
            }
          },
          {
            "name": "Find Keys",
            "desc": "Find your keys",
            "execute": (room, state) => {
              state.player.items.keys.push("Locked Room");
              print(["You found your keys under the couch cushions"]);
            },
            "show": [
              (room, state) => {
                return state.player.rooms[room.id].squinted;
              },
              (room, state) => {
                return !state.player.items.keys.includes("Locked Room");
              }
            ]
          }
        ],
        "exits": {
          "up": {
            "target": "Locked Room",
            "desc": "It's locked!",
            "conditions": [
              (room, state) => {
                return state.player.items.keys.includes("Locked Room");
              }
            ],
            "show": [
              (room, state) => {
                return state.player.rooms[room.id].squinted;
              }
            ]
          }
        },
        "hooks": [
          (room, state) => {
            print(["This is a test of the hooks"]);
            return true;
          }
        ]
      },
      "Locked Room": {
        "id": "Locked Room",
        "name": "Locked Room",
        "desc": "Super seecret",
        "move": (room, state) => {
          print(["You enter the locked room. wowie!"]);
        },
        "actions": [
          {
            name: "Oof",
            desc: "Oof",
            execute: (room, state) => {
              print(["Oof"]);
              playSfx("sfx/oof.ogg");
            }
          }
        ],
        "exits": {
          "down": {
            "target": "Home",
            "desc": "Back to home",
            "hooks": [
              (room, exit, state) => {
                print(["Potato"]);
                return true;
              }
            ]
          }
        }
      }
    }
  }
}
 |