# Midgarth > Midgarth is a small online role-playing game in the style of the early > Tibia, set in Tolkien's Middle-earth, played in the browser. Bots are > welcome: a program plays over the same websocket the browser uses, logs in > with a name and password like anybody else, and is held to exactly the same > rules. There are no bot accounts, no API keys and nothing to sign up for. > This file is for AI agents and people writing bots. ## Worlds Each world is its own server with its own characters; a character on one does not exist on the other. - Sydney: https://midgarth.quest (the old address, https://tinytibia.anacrolix.link, redirects there). Websocket: `wss://midgarth.quest/ws` - Toronto: https://yyz.midgarth.quest. Websocket: `wss://yyz.midgarth.quest/ws` Every world serves this file and the documents below at the same paths. ## Documents - [Protocol](/protocol.md): everything a client needs, checked against the server's code by its tests. Connecting, logging in, limits, timing, coordinates, walking, every message both ways and every field. - [Game guide](/guide.md): the in-game help as text (long: search it). Controls, races, skills, fighting, spells and their words, food, potions, shops, the depot, the market, quests and places. - [Status](/status): JSON about the server, no login needed: `proto` (the protocol version to send), who is online, which of them are bots. - [Highscores](/highscores) as JSON, and `/character?name=Name` for one character's level, deaths and kills. ## Start botting in five minutes 1. Open a websocket to `wss://midgarth.quest/ws` (or another world's). Every message either way is one text frame of one JSON object with a `"t"` field saying what it is. 2. Send a login. A name nobody has yet makes a new character with that password; keep the password, it is the only way back in. `{"t":"login","name":"Examplebot","password":"...","proto":2,"bot":true}` - `name`: one word of 2 to 20 letters, starting with a capital. - `proto`: the protocol version; read it from `/status` (it is 2 now). A login without it, or with another, is refused with an `error` saying so. - `bot: true` says a program is playing. It changes nothing in play, but lists you under `bots` in `/status`, so people counting players online leave you out. Please send it. - Do not send `build`: that is for the browser's own bundle. 3. Read `welcome` (your creature `id`, the map you have explored, item definitions, the temple, the protected zones, and the NPCs with what they can be asked). A new character then gets `chooserace`: answer `{"t":"race","text":"hobbit"}` (`elf`, `man`, `dwarf` or `hobbit`). 4. From then on `state` comes whenever anything in sight changes, up to ten a second. Each is the whole view, not a difference: `you` (hp, mana, level, skills, bag, gear, spells, gold), `creatures` (everything in sight, you included, with `id`, `kind`, `x`, `y`, `z`, `hp`), and `items` on the ground. `text` messages bring chat, server lines and refusals (kind `error`). 5. Act: `{"t":"walk","x":100,"y":82}` (the server finds the way, up to 40 tiles), `{"t":"move","dir":"n"}`, `{"t":"attack","id":557}` (the server then swings for you while it is in reach), `{"t":"say","text":"hello"}` (spells are said: their words are in `you.spells`), `{"t":"pickup",...}`, `{"t":"ask","id":...,"topic":...}` for an NPC. All of them are in the protocol. 6. Leave with `{"t":"logout"}`. It is refused for 10 seconds after a fight off protected ground, so a character stays in the world, and can die, while that runs out. A complete client in Node 22 or later, with no packages to install, that logs in, says hello, watches for 10 seconds and logs out: ```js // node bot.mjs (SERVER, NAME, PASSWORD from the environment) const SERVER = process.env.SERVER ?? "wss://midgarth.quest/ws"; const NAME = process.env.NAME ?? "Examplebot"; // one word, capital first const PASSWORD = process.env.PASSWORD ?? "change me"; const ws = new WebSocket(SERVER); const send = (m) => ws.send(JSON.stringify(m)); let me = 0, npcKinds = new Set(), shown = 0; ws.onopen = () => send({ t: "login", name: NAME, password: PASSWORD, proto: 2, bot: true }); ws.onmessage = (ev) => { const m = JSON.parse(ev.data); switch (m.t) { case "welcome": me = m.id; npcKinds = new Set(Object.keys(m.npcs ?? {})); break; case "chooserace": send({ t: "race", text: "hobbit" }); break; case "state": { if (Date.now() - shown < 1000) break; // states come up to 10 a second shown = Date.now(); const self = m.creatures.find((c) => c.id === me); const monsters = m.creatures.filter((c) => c.kind !== "player" && !npcKinds.has(c.kind) && c.z === self.z); console.log(`hp ${m.you.hp}/${m.you.maxhp} at ${self.x},${self.y},${self.z}; ${monsters.length} monsters in sight`); break; } case "text": console.log(`[${m.kind}] ${m.from ? m.from + ": " : ""}${m.text}`); break; case "error": case "bye": console.log(m.t, m.text ?? ""); break; } }; ws.onclose = () => process.exit(0); setInterval(() => send({ t: "ping", seq: Date.now() }), 5000); setTimeout(() => send({ t: "say", text: "Hello from a bot!" }), 3000); setTimeout(() => send({ t: "logout" }), 10000); ``` In Python, `pip install websockets` and do the same with `websockets.connect("wss://midgarth.quest/ws", max_size=None)`: the welcome of a character who has explored a lot is a few hundred kilobytes, so lift any small read limit. ## How the world works - Positions are tiles: x grows east, y grows south, (0,0) is the north-west corner. `z` is the level: 0 the ground, 1 above it (rooftops, hilltops), negative underground. Stairs, ladders and holes move you between levels. - Distance is the larger of the two axes; melee reaches the eight tiles around you. You see 10 tiles each way. - You start, and come back after a death, at the temple in Hobbiton. Protection zones (the temple, towns) are safe: no fighting there. - Attacking a monster sets your target; the server swings on its own clock while it is in reach. Kills give experience and sometimes loot on the ground. Small creatures (rats, snakes, wolves) near the start suit a new character; much of the world is far too dangerous at level 1. - Health potions heal over time. Carry food in your bag: it is eaten for you, and you only heal over time while fed. A death costs experience and leaves your things where you fell; send `respawn` to go back to the temple. - NPCs have menus of topics; some keep shops, a depot or quests. Ask them. - Other characters are real people. Be a good neighbour: talk to them in plain words, don't flood chat, and don't steal kills or loot. ## Rules for bots - The same game rules as everybody, enforced by the server for every connection alike. Player killing is part of the game, with skulls for those who kill the unmarked. - Send `"bot": true` on the login. - Keep under the limits: 40 messages a second per connection with a burst of 200; past that, messages are dropped with an `error` to slow down, and 800 dropped in 10 seconds closes the connection. Nothing is gained by sending faster than you need: the game paces every step, swing and spell itself. About four messages a second is plenty. - Keep reading the socket all the time. The server pings every 25 seconds and drops a connection that has not answered for 60, and one that falls 256 messages behind. - Ignore message types and fields you don't know: new ones are added without the protocol version changing. - One connection per character: logging in again puts the older connection out. - Reconnect with backoff (a few seconds, doubling to a minute), not in a tight loop.