Posted by
| Nick Gammon
Australia (23,068 posts) Bio
Forum Administrator |
Message
| Nick's mapper engine
I am pleased to release a generic "MUD mapper" engine. It is the product of a considerable amount of work that started off as a mapper for SmaugFUSS, then was modified to work with Achaea and Imperian. However eventually I realised the best thing was to abstract out the "core" mapping part (the non-MUD-specific part) and let individual MUDs just interface with it.
Features
- Draws in realtime your current room, and the rooms around you, by "walking" outwards from your current location.
- For each known room a box is drawn to represent the room, and lines for each exit.
- If the exit room is known then the process is repeated, potentially drawing hundreds of connected rooms.
- Under control of the calling plugin each room can be individually coloured (e.g. to show shops, trainers, or just to indicate terrain type like water, desert).
- You can zoom in to see more clearly, or zoom out to see "the big picture".
- The mapper can be dragged around the screen with the mouse.
- You can configure its size to be what you desire.
- You can configure the colours used to display things like known rooms, unknown rooms, etc.
- You can configure the depth of the search - the bigger the depth the slower it runs, but you see more detail.
- It is fast, even zoomed right out on Imperian, and displaying over 400 rooms at once, it takes about 0.07 seconds to draw. With 100 rooms visible (zoomed in) it takes about 0.01 seconds to draw.
- The room name, and area name (if supplied) are displayed on the map.
- You can LH click on any visible room to speedwalk to that room by the shortest route.
- Speedwalking is "throttled" so that it only moves from one room to the next once you arrive there. Even then you can add in a configurable delay, in case the MUD requires it.
- Speedwalking auto-cancels if it detects it has ended up in an unexpected room number enroute.
- There is a generic "room finder" built in. This can be called by the owner plugin to detect the shortest path to any room - you specify in the calling plugin the condition. For example, nearby shops, trainers, portals, or match on text in the room name. Found rooms can be walked to by just clicking on the hyperlink in the list of found rooms.
- If the player RH clicks on a room a user-supplied callback is called. This can be used to implement other behaviour. For example, in the Imperian plugin, I made a bookmark feature, so players can bookmark places of interest. You can then quickly go to any of your bookmarked rooms.
- If you hover over a room with the mouse a plugin-defined message appears (e.g. room name, terrain type, exits)
- Recently trod paths are shown with a thicker line, so you can see where you have come from.
- You can colour different areas in different ways, for example you might dim out all but the current area to make the current area stand out more.
- It is designed to be "MUD neutral". This is done by having the mapper "call back" to the calling plugin whenever it needs room details. The calling plugin can then read a database, get information from memory, or some other method to fill in things like the room name, desired colour, and other details.
How to use
Tutorial: http://www.gammon.com.au/forum/?id=12635
First you install it in a plugin like this:
Then in the plugin installation function you initialise the mapper like this:
mapper.init { config = config, get_room = get_room, show_help = OnHelp, room_click = room_click }
mapper.mapprint (string.format ("MUSHclient mapper installed, version %0.1f", mapper.VERSION))
This specifies some general configuration (like colours, mapper size), and a few callback functions.
- config is table of colours and other values used to control the mapper's behaviour. The plugin can serialise that to the save_state file to preserve settings between sessions.
- get_room is called when the mapper needs to know details about a room.
- show_help is called if the player clicks on the "?" help button on the map.
- room_click is called if the player RH-clicks on a room.
A simple get_room function might look like this:
function get_room (uid)
local room = load_room_from_database (uid)
if not room then
return nil -- room does not exist
end -- if
room.hovermessage = room.name -- for hovering the mouse
-- desired colours
room.bordercolour = ColourNameToRGB "lightseagreen"
room.borderpen = 0 -- solid
room.borderpenwidth = 1
room.fillcolour = ColourNameToRGB "green"
room.fillbrush = 0 -- solid
-- obviously you would look these up in practice
room.area = "Darkhaven"
room.exits = { n = 21001, s = 21002, se = 21003 }
return room
end -- function
The mapper uses the colours you supply to draw this room. It then uses the exits table to work out which rooms are connected to this one. So in this example the process would be repeated as it drew rooms 21001, 21002 and 21003 (and then repeated again for whatever exits they had).
In practice the function would be more complex, as you work out colour based on terrain or type of room, you would look up area names and exits, and have a more complex "hover" message. However it illustrates the general idea.
Drawing the map
The map is drawn when the plugin wants it to be, by calling the draw function, like this:
So once you detect you have changed rooms (however this is done) and you know the new room number or identifier, you just call "draw" to have it drawn. This will cause the mapper to first call back for information about the supplied room number (as described above) and then for each of that room's exits.
Various other function are exposed for use by the caller, such as hide (), show (), zoom_in (), zoom_out (), all of which might be called by aliases in the plugin.
Generic searching
The code below illustrates one of the searches I put into the Imperian/Achaea plugin. It reads from the database doing a full-text search for whatever words you supply in the search alias, getting a list of matching rooms.
It then calls the mapper.find function, passing down the starting room, and a callback function. The mapper then calls this function for each room it finds as it "walks" outwards from the starting room, asking if this room satisfies the condition. If it returns true (or a non-nil value) then that room will be displayed in the "matching rooms" list. It can also indicate if the search is to continue by returning true or false as the second return value. This lets the mapper know whether to keep searching or not. You might return false if you knew all desired rooms had been found, or if you simply only wanted to find one (e.g.. the nearest shop). The count, if supplied, is used as a hint message to the player that some rooms matched the condition, but couldn't be walked to in the scan distance.
function map_find (name, line, wildcards)
local rooms = {}
local count = 0
-- find matching rooms using FTS3
for row in db:nrows(string.format ("SELECT uid, name FROM rooms_lookup WHERE rooms_lookup MATCH %s", fixsql (wildcards [1]))) do
rooms [row.uid] = true
count = count + 1
end -- finding room
-- see if nearby
mapper.find (
function (uid)
local room = rooms [uid]
if room then
rooms [uid] = nil
end -- if
return room, next (rooms) == nil
end, -- function
true, -- show vnum
count -- how many to expect
)
end -- map_find
Download
The mapper module is available here:
http://github.com/nickgammon/mushclient/blob/master/lua/mapper.lua
It may have bugs, new versions will be uploaded from time to time. More documentation is in the source. I will publish an example plugin that uses it shortly.
[EDIT] Changed on 13 March to reverse the sense of LH and RH clicks.
See http://www.gammon.com.au/forum/?id=10138&page=7 (page 7 of this thread) for a suggested plugin that could be used on MUDs that don't directly supply room numbers. |
- Nick Gammon
www.gammon.com.au, www.mushclient.com | Top |
|