-- =========================================================================== -- RadBois.lua — The Rad Bois for Mudlet: an automatic map and vitals bars. -- -- How to install (once): -- 1. In Mudlet, open the Scripts editor (the "Scripts" button). -- 2. Click "Add Item", name it "Rad Bois", and paste this whole file in. -- 3. Click "Save Item". Make sure Settings > General > "Enable GMCP" is ticked, -- then reconnect. -- -- LESSON: The game sends hidden GMCP messages (see network/telnet/gmcp.js). -- Mudlet puts each one in the "gmcp" table and raises an event named after -- it, like "gmcp.Room.Info". Below we listen for those events: every time you -- enter a room we add it to Mudlet's map, and every time your health changes -- we redraw the bars. Nothing here sends commands for you. -- =========================================================================== radbois = radbois or {} -- ---- Layout: a map on the right, bars along the bottom -------------------- local function buildUI() if radbois.ui then return end radbois.ui = true setBorderRight(math.floor(getMainWindowSize() * 0.32)) setBorderBottom(64) radbois.mapper = Geyser.Mapper:new({ name = "radboisMapper", x = "-32%", y = 0, width = "32%", height = "60%" }) local function gauge(name, x, color) local g = Geyser.Gauge:new({ name = name, x = x, y = "-58px", width = "22%", height = "22px" }) g.front:setStyleSheet("background-color: " .. color .. "; border-radius: 3px;") g.back:setStyleSheet("background-color: #1a1412; border-radius: 3px;") return g end radbois.health = gauge("radboisHealth", "1%", "#7A1515") radbois.mana = gauge("radboisMana", "24%", "#2c4f8a") radbois.stamina = gauge("radboisStamina", "47%", "#6b7a2c") radbois.rt = Geyser.Label:new({ name = "radboisRT", x = "70%", y = "-58px", width = "28%", height = "22px" }) radbois.rt:setStyleSheet("background-color: #1a1412; color: #E8DFD0; qproperty-alignment: 'AlignCenter';") radbois.chat = Geyser.MiniConsole:new({ name = "radboisChat", x = "-32%", y = "61%", width = "32%", height = "39%", autoWrap = true, scrollBar = true, fontSize = 9 }) radbois.chat:setColor(14, 11, 10) radbois.status = Geyser.Label:new({ name = "radboisStatus", x = "1%", y = "-30px", width = "97%", height = "22px" }) radbois.status:setStyleSheet("background-color: #0E0B0A; color: #C2A36B;") end -- ---- Vitals and status --------------------------------------------------- function radbois.onVitals() buildUI() local v = gmcp.Char.Vitals radbois.health:setValue(v.hp, math.max(v.maxhp, 1), string.format("
Health %d/%d
", v.hp, v.maxhp)) radbois.mana:setValue(v.mp, math.max(v.maxmp, 1), string.format("
Mana %d/%d
", v.mp, v.maxmp)) radbois.stamina:setValue(v.sp, math.max(v.maxsp, 1), string.format("
Stamina %d/%d
", v.sp, v.maxsp)) if v.rt and v.rt > 0 then radbois.rt:echo(string.format("
Roundtime %d
", v.rt)) else radbois.rt:echo("
Ready
") end end function radbois.onStatus() buildUI() local s = gmcp.Char.Status radbois.status:echo(string.format(" %s, level %d %s %s | %s | %s | %d silver%s", s.name, s.level, s.race, s.profession, s.stance, s.fatigue or "", s.silver or 0, s.target and (" | target: " .. s.target) or "")) end -- ---- Chat tab: TELLs, CHAT, SHOUTs and group talk, kept in one place ------ local chatColors = { tell = "", chat = "", shout = "", gsay = "", emote = "" } function radbois.onChannel() buildUI() local c = gmcp.Comm.Channel.Text if not c or c.channel == "emote" then return end radbois.chat:cecho((chatColors[c.channel] or "") .. c.text .. "\n") end -- ---- The automatic map --------------------------------------------------- -- Mudlet's short direction names; anything else (GO MILL) is a "special exit". local short = { north = "n", south = "s", east = "e", west = "w", northeast = "ne", northwest = "nw", southeast = "se", southwest = "sw", up = "up", down = "down", ["in"] = "in", out = "out" } local function areaId(name) local areas = getAreaTable() if areas[name] then return areas[name] end return addAreaName(name) end function radbois.onRoom() buildUI() local r = gmcp.Room.Info if not r or not r.num then return end local id = r.num if not roomExists(id) then addRoom(id) end setRoomName(id, r.name) setRoomArea(id, areaId(r.area)) if r.coords then -- The game's y grows to the south; Mudlet's grows to the north. setRoomCoordinates(id, r.coords[1], -r.coords[2], r.coords[3] or 0) end -- Exits to rooms already on the map are drawn now; exits to rooms we -- haven't seen yet wait in radbois.pending until we get there. radbois.pending = radbois.pending or {} local cmds = r.commands or {} local function link(from, to, dir) if short[dir] then setExit(from, to, short[dir]) else addSpecialExit(from, to, cmds[dir] or ("go " .. dir)) end end for dir, to in pairs(r.exits or {}) do if roomExists(to) then link(id, to, dir) else radbois.pending[to] = radbois.pending[to] or {} table.insert(radbois.pending[to], { from = id, dir = dir, cmd = cmds[dir] }) end end for _, p in ipairs(radbois.pending[id] or {}) do if roomExists(p.from) then if short[p.dir] then setExit(p.from, id, short[p.dir]) else addSpecialExit(p.from, id, p.cmd or ("go " .. p.dir)) end end end radbois.pending[id] = nil centerview(id) updateMap() end -- Click a room on the map and Mudlet works out the path; this walks it. function doSpeedWalk() for _, step in ipairs(speedWalkDir or {}) do send(step, false) end end -- Saving the script again shouldn't stack up a second copy of each listener. for _, h in ipairs(radbois.handlers or {}) do killAnonymousEventHandler(h) end radbois.handlers = { registerAnonymousEventHandler("gmcp.Char.Vitals", radbois.onVitals), registerAnonymousEventHandler("gmcp.Char.Status", radbois.onStatus), registerAnonymousEventHandler("gmcp.Room.Info", radbois.onRoom), registerAnonymousEventHandler("gmcp.Comm.Channel.Text", radbois.onChannel), } cecho("\n[Rad Bois] Map and bars ready. Walk around and the map draws itself.\n")