Login    Register

Mudlet Mapper

Greetings and salutations. Say hello to your fellow players!
  • Author
    Message

Re: Mudlet Mapper

Postby Torhild » Sun Aug 13, 2017 10:56 pm

For someone that has no clue what they are doing, where are the triggers supposed to be placed? Are they supposed to replace anything?
User avatar
Torhild
 
Posts: 4
Joined: Thu Aug 10, 2017 3:41 am

Re: Mudlet Mapper

Postby dresdor » Wed Aug 16, 2017 1:10 am

If someone could ELI5 this whole thing or create a complete idiot's guide for this complete idiot, I'd appreciate it.
dresdor
 
Posts: 11
Joined: Thu Aug 10, 2017 3:11 am

Re: Mudlet Mapper

Postby Votrepatron » Wed Aug 16, 2017 1:02 pm

I hear ya guys. ;D It took me some time to figure out exactly what is going on with it, especially since i have never coded in LUA before.

Let me explain the basic concepts of what is going on. Mudlet is customizable. It does not have an innate mapping function we can use for GNSmud. So we have to adapt a generic one. What we are doing is having Mudlet review the text that is being displayed in the console (The main window we play the game in) and make decisions or actions based on that.

So when talking about the things we need in order to make a map: room name, exits, prompt, area name, etc... Those are all within the game itself. We are just helping the computer identify those. The mapping script is already written, we just need to help the computer find those elements.

I am currently working on getting the "Room name" working 100% of the time. It is failing right now. It will grab the correct room name most of the time, but will occasionally grab a different part of the console and interpret it as a room name, making a new room that the map doesnt know what to do with. So it screws the map up entirely.

Will post an update when i get that working. I will also post Screenshots and try and make a step-by-step for a how-to.
Votrepatron
 
Posts: 10
Joined: Wed Aug 09, 2017 5:35 pm

Re: Mudlet Mapper

Postby Gibs » Sun Aug 20, 2017 2:23 pm

Any luck figuring out the get Room Name?
Gibs
 
Posts: 1
Joined: Sun Aug 20, 2017 4:03 am

Re: Mudlet Mapper

Postby Votrepatron » Wed Aug 23, 2017 1:46 pm

I figured it out about a week ago, but haven't had time to make this until now. Even now i am writing this in between calls at work. Apologies if it does not make sense.

Step 1:
Get the script: https://forums.mudlet.org/mudlet-mapper ... t6105.html
This is the website with the generic script we are using to map GSNMud. It has 2 things we need.

Here is the package. If you want to use this option, just paste it into the main mudlet console window, hit enter, and it will install for you. By far the easiest option. If you do not use this, you will need to copy/paste the script into mudlet.

Code: Select all
lua function downloaded_package(a,b) if not b:find("generic_mapper",1,true) then return end installPackage(b) os.remove(b) end registerAnonymousEventHandler("sysDownloadDone","downloaded_package") downloadFile(getMudletHomeDir().."/generic_mapper.mpackage","http://dslpnp.altervista.org/Generic_Mapper.mpackage")


Second: We need to ensure a window manager script is installed. This one is just Copy and paste and done.
Code: Select all
-- Window Manager Script --
--  Zachary Hiland
--  10/22/2016
--  v2.00c
--
--  Functions Details
--
--      windowManager.create(name, type, x, y, width, height, origin, [font_size]) or windowManager.add(info_table)
--      creates a window and adds it to the windowManager
--
--      info_table must have a valid entry for each argument, by the same name, as in the normal function call
--      name - name of already created window (label, miniConsole, gauge, mapper, menu, or autowrap)
--          Note: for a mapper window, use any name you like, so long as it isn't the name of some other object
--      type - identify the type of window, must be label, miniConsole, gauge, mapper, or menu
--      x - distance horizontally from the origin corner
--      y - distance vertically from the origin corner
--      width - width of window
--      height - height of window
--      origin - corner to act as origin for this window, must be topleft, topright, bottomleft, or bottomright
--      font_size - only used for autowrap windows, will be automatically set as the font size for the created window
--
--      note: all measurements should be numbers, or strings with values measured in percent or pixels (or unlabeled)
--          if a measurement contains both percent and pixel values (or multiple values of the same type), they should be separated
--          by a "+" symbol. Example: "25% + 50px + 16"
--      important: no negative numbers
--
--      windowManager.add(name, type, x, y, width, height, origin, font_size) or windowManager.create(info_table)
--      adds an already created window to the windowManager, uses the exact same arguments as those in the "create" function
--
--      windowManager.remove(name)
--      removes a window from the windowManager
--
--      windowManager.move(name, x, y)
--      moves a window with the windowManager
--
--      windowManager.resize(name, width, height)
--      resizes a window with the windowManager
--
--      windowManager.relocate(name, origin)
--      changes the corner acting as the origin for a window in the windowManager
--
--      windowManager.show(name)
--      shows a window that is managed by windowManager (you can also use showWindow or showGauge functions)
--          Note: this is only really important for a mapper window
--
--      windowManager.hide(name)
--      hides a window that is managed by windowManager (you can also use hideWindow or hideGauge functions)
--          Note: this is only really important for a mapper window
--
--      windowManager.getValue(name, value)
--      returns the calculated size or position values, or the origin, for a window in the windowManager
--
--      windowManager.math(value1, value2, operation)
--      allows addition and subtraction of measurements with each other,
--      and multiplication and division of a measurement by a normal number
--
--      windowManager.simplify(measurement)
--      returns a simplified version of a measurement (all percent and pixel values are combined together)
--
--      windowManager.refresh(name)
--      sets the size and location of a window in the windowManager using previously set values
--      note: generally this function does not need to be called
--
--      windowManager.refreshAll()
--      note: this function is called automatically when a sysWindowResizeEvent event occurs,
--          and generally does not need to be called manually
--
--      windowManager.createBuffer(name)
--      creates a buffer to be used with an autowrap window, only needed if miniconsole added manually to windowManager
--
--      windowManager.append(name)
--      appends text to an autowrap window, works just like appendBuffer()
--
--      windowManager.echo(name, text)
--      echoes text to an autowrap window. cecho, decho, and hecho are also available.
--
--      windowManager.clear(name)
--      clears an autowrap window.
--
--      windowManager.setFontSize(name, font_size)
--      sets the font size for an autowrap window.

windowManager = windowManager or {}
windowManager.list = windowManager.list or {}

local function calcScaledNum(scale,num)
    scale_table = string.split(scale," %+ ")
    if #scale_table > 2 then
        scale = windowManager.simplify(scale)
        scale_table = string.split(scale," %+ ")
    end
    scale = 0
    if #scale_table == 2 then
        scale = string.cut(scale_table[1],#scale_table[1] - 1) * num / 100
        scale = scale + string.gsub(scale_table[2],"px","")
    elseif string.find(scale_table[1],"%%") then
        scale = string.cut(scale_table[1],#scale_table[1] - 1) * num / 100
    else
        scale = string.gsub(scale_table[1],"px","")
    end
    scale = math.floor(scale + 0.5)
    return scale
end

local function rewrap_window(name)
    local info = windowManager.list[name]
    local buffer = name .. "_windowManager_buffer"
    local wrap = math.floor(windowManager.getValue(name,"width") / calcFontSize(info.font))
    local line, moved
    setWindowWrap(name,wrap)
    clearWindow(name)
    line = 0
    moved = moveCursor(buffer,1,line)
    while moved do
        selectCurrentLine(buffer)
        copy(buffer)
        line = line + 1
        moved = moveCursor(buffer,1,line)
        appendBuffer(name)
    end
end

function windowManager.simplify(measure)
    measure = string.gsub(measure,"%s*-%s*([%d%%]+)"," + -%1")
    measure = string.gsub(measure,"%-%-","")
    measure = string.gsub(measure,"%+%s*%+","+")
    measure = string.gsub(measure,"^%s*%+","")
    local measure_table = string.split(measure,"+")
    local percent, pixel = 0,0
    for k,v in ipairs(measure_table) do
        v = string.trim(v)
        if string.find(v,"%%") then
            v = string.gsub(v,"%%","")
            if not tonumber(v) then display(measure) end
            percent = percent + v
        elseif v ~= "" then
            v = string.gsub(v,"px","")
            if not tonumber(v) then display(measure) end
            pixel = pixel + v
        end
    end
    percent = math.floor(1000 * percent + .5) / 1000
    pixel = math.floor(1000 * pixel + .5) / 1000
    if percent == 0 then
        measure = pixel .. "px"
    elseif pixel == 0 then
        measure = percent .. "%"
    else
        measure = percent .. "% + " .. pixel .. "px"
    end
    return measure
end

function windowManager.math(measure,num,op)
    if not table.contains({"multiply","divide", "add", "subtract"},op) then
        error("windowManager.math: bad argument #3 \"operation\", must be add, subtract, multiply or divide",2)
    end
    if op == "divide" or op == "multiply" then
        if string.find(num,"%%") then
            num = string.gsub(num,"%%","") / 100
        end
        if not tonumber(num) then
            error("windowManager.math: bad argument #2 \"num\", must be a number",2)
        end
        num = tonumber(num)
        measure = string.gsub(measure,"%s*-%s*([%d%%]+)"," + -%1")
        measure = string.gsub(measure,"%+%s*%+","+")
        measure = string.gsub(measure,"^%s*%+","")
        local measure_table = string.split(measure,"+")
        if op == "divide" then num = 1 / num end
        for k,v in ipairs(measure_table) do
            v = string.trim(v)
            v = (string.gsub(v,"([%d%.]+).*","%1") * num) .. string.gsub(v,".*[%d%.]+(.*)","%1")
            measure_table[k] = v
        end
        measure = table.concat(measure_table," + ")
    else
        if op == "subtract" then
            num = windowManager.math(num,"-1","multiply")
        end
        measure = measure .. " + " .. num
        measure = string.gsub(measure,"([^%s%+%-]+)%s*-%s*([%d%.%-]+)","%1 + -%2")
    end
    return windowManager.simplify(measure)
end

function windowManager.create(name, window_type, ...)
    local tbl = {}
    local is_table = false
    if type(name) == "table" then
        table.update(tble,name)
        name = tbl.name
        window_type = tbl.type
        is_table = true
    end
    if type(window_type) ~= "string" then
        error("windowManager.create: bad argument #2 \"type\", must be string.",2)
    end
    window_type = string.lower(window_type)
    if not table.contains({"label","miniconsole","gauge","mapper","menu","autowrap"},window_type) then
        error("windowManager.create: invalid type",2)
    end
    if window_type == "label" then
        createLabel(name, 0,0,0,0,1)
    elseif window_type == "miniconsole" then
        createMiniConsole(name,0,0,0,0)
    elseif window_type == "gauge" then
        createGauge(name,0,0,0,0)
    elseif window_type == "menu" then
        createMenu(name,0,0,0,0)
    elseif window_type == "autowrap" then
        createMiniConsole(name,0,0,0,0)
        createBuffer(name .. "_windowManager_buffer")
        setWindowWrap(name .. "_windowManager_buffer",1000)
    end
    if is_table then
        return windowManager.add(tbl)
    else
        return windowManager.add(name, window_type, ...)
    end
end

function windowManager.makeBuffer(name)
    createBuffer(name .. "_windowManager_buffer")
    setWindowWrap(name .. "_windowManager_buffer",1000)
end

function windowManager.add(name, window_type, x, y, w, h, origin, font)
    local tbl = {}
    if type(name) == "table" then
        tbl = table.update(tbl,name)
        name = tbl.name
        x = tbl.x
        y = tbl.y
        w = tbl.width
        h = tbl.height
        origin = tbl.origin
        window_type = tbl.type
        font = tbl.font_size
        tbl = {}
    end
    font = font or 10
    if not name then
        error("windowManager.add: bad argument #1 \"name\".",2)
    end
    windowManager.list[name] = nil
    if type(window_type) ~= "string" then
        error("windowManager.add: bad argument #2 \"type\", must be string.",2)
    end
    window_type = string.lower(window_type)
    if not table.contains({"label","miniconsole","gauge","mapper","menu","autowrap"},window_type) then
        error("windowManager.add: invalid type",2)
    end
    if not (x and y and w and h) then
        error("windowManager.add: must have x, y, width, and height.",2)
    end
    origin = origin or "topleft"
    origin = string.lower(origin)
    if not table.contains({"topleft","topright","bottomleft","bottomright"},origin) then
        error("windowManager.add: bad argument #7 \"origin\".",2)
    end
    x = windowManager.simplify(x)
    y = windowManager.simplify(y)
    w = windowManager.simplify(w)
    h = windowManager.simplify(h)
    tbl = {
        type = window_type,
        x = x, y = y, h = h, w = w,
        origin = origin}
    if window_type == "autowrap" then
        tbl.font = font
        setMiniConsoleFontSize(name, font)
    end
    windowManager.list[name] = tbl
    windowManager.refresh(name)
end

function windowManager.remove(name)
    windowManager.list[name] = nil
end

function windowManager.refresh(name, main_w, main_h)
    local info = windowManager.list[name]
    if not info then error("windowManager.refresh: no such window.",2) end
    local x,y,w,h,origin,win_type = info.x, info.y, info.w, info.h, info.origin, info.type
    if not (main_w and main_h) then
        main_w, main_h = getMainWindowSize()
    end
    w = calcScaledNum(w,main_w)
    x = calcScaledNum(x,main_w)
    h = calcScaledNum(h,main_h)
    y = calcScaledNum(y,main_h)
    if string.find(origin,"right") then
        x = main_w - x - w
    end
    if string.find(origin,"bottom") then
        y = main_h - y - h
    end
    if win_type == "gauge" then
        moveGauge(name,x,y)
        resizeGauge(name,w,h)
    elseif win_type == "mapper" then
        if not info.hide then
            createMapper(x,y,w,h)
        end
    elseif win_type == "menu" then
        moveMenu(name,x,y)
        resizeMenu(name,w,h)
    else
        moveWindow(name,x,y)
        resizeWindow(name,w,h)
        if win_type == "autowrap" then
            rewrap_window(name)
        end
    end
end

function windowManager.resize(name, w, h)
    local info = windowManager.list[name]
    if not info then error("windowManager.resize: no such window.",2) end
    if not (w and h) then error("windowManager.resize: must have both width and height.",2) end
    w = windowManager.simplify(w)
    h = windowManager.simplify(h)
    windowManager.list[name].w = w
    windowManager.list[name].h = h
    windowManager.refresh(name)
end

function windowManager.move(name, x, y)
    local info = windowManager.list[name]
    if not info then error("windowManager.move: no such window.",2) end
    if not (x and y) then error("windowManager.move: must have both x and y.",2) end
    x = windowManager.simplify(x)
    y = windowManager.simplify(y)
    windowManager.list[name].x = x
    windowManager.list[name].y = y
    windowManager.refresh(name)
end

function windowManager.relocate(name, origin)
    local info = windowManager.list[name]
    if not info then error("windowManager.relocate: no such window.",2) end
    origin = origin or "topleft"
    origin = string.lower(origin)
    if not table.contains({"topleft","topright","bottomleft","bottomright"},origin) then
        error("windowManager.relocate: bad argument #2 \"origin\".",2)
    end
    windowManager.list[name].origin = origin
    windowManager.refresh(name)
end

function windowManager.hide(name)
    local info = windowManager.list[name]
    if not info then error("windowManager.hide: no such window.",2) end
    local info = windowManager.list[name]
    if info.type == "gauge" then
        hideGauge(name)
    elseif info.type == "mapper" then
        windowManager.list[name].hide = true
        createMapper(0,0,0,0)
    elseif info.type == "menu" then
        hideMenu(name)
    else
        hideWindow(name)
    end
end

function windowManager.show(name)
    local info = windowManager.list[name]
    if not info then error("windowManager.show: no such window.",2) end
    local info = windowManager.list[name]
    if info.type == "gauge" then
        showGauge(name)
    elseif info.type == "mapper" then
        windowManager.list[name].hide = false
        windowManager.refresh(name)
    elseif info.type == "menu" then
        showMenu(name)
    else
        showWindow(name)
    end
end

function windowManager.setFontSize(name, font_size)
    local info = windowManager.list[name]
    if not info then error("windowManager.setFontSize: no such window.",2) end
    windowManager.list[name].font = font_size
    setMiniConsoleFontSize(name, font_size)
    windowManager.refresh(name)
end

function windowManager.clear(name)
    local info = windowManager.list[name]
    if not info then error("windowManager.clear: no such window.",2) end
    clearWindow(name)
    clearWindow(name .. "_windowManager_buffer")
end

function windowManager.append(name)
    local info = windowManager.list[name]
    if not info then error("windowManager.append: no such window.",2) end
    appendBuffer(name)
    appendBuffer(name .. "_windowManager_buffer")
end

function windowManager.echo(name, text)
    local info = windowManager.list[name]
    if not info then error("windowManager.echo: no such window.",2) end
    echo(name, text)
    echo(name .. "_windowManager_buffer", text)
end

function windowManager.cecho(name, text)
    local info = windowManager.list[name]
    if not info then error("windowManager.cecho: no such window.",2) end
    cecho(name, text)
    cecho(name .. "_windowManager_buffer", text)
end

function windowManager.hecho(name, text)
    local info = windowManager.list[name]
    if not info then error("windowManager.hecho: no such window.",2) end
    hecho(name, text)
    hecho(name .. "_windowManager_buffer", text)
end

function windowManager.decho(name, text)
    local info = windowManager.list[name]
    if not info then error("windowManager.decho: no such window.",2) end
    decho(name, text)
    decho(name .. "_windowManager_buffer", text)
end

function windowManager.getValue(name, value)
    local info = windowManager.list[name]
    if not info then error("windowManager.getValue: no such window.",2) end
    if not table.contains({"x","y","width","height","w","h","origin"},value) then
        error("windowManager.getValue: no such value.",2)
    end
    local sys_w, sys_h = getMainWindowSize()
    if value == "width" then value = "w" end
    if value == "height" then value = "h" end
    local tmp = windowManager.list[name][value]
    if value == "w" or value == "x" then
        tmp = calcScaledNum(tmp,sys_w)
    elseif value == "h" or value == "y" then
        tmp = calcScaledNum(tmp,sys_h)
    end
    return tmp
end

function windowManager.refreshAll()
    local main_w, main_h = getMainWindowSize()
    for k,v in pairs(windowManager.list) do
        windowManager.refresh(k, main_w, main_h)
    end
end

registerAnonymousEventHandler("sysWindowResizeEvent", "windowManager.refreshAll")


Alright. If you are going about the copy paste option for the two scripts pasted above, You need to paste them into the 'script' tab on mudlet. Name it whatever you want, it doesn't matter. I titled mine 'Generic Mapping Script' and 'Window Manager'. You have successfully completed the first step!

Step Two: Triggers
If you used the install method above than you already have the generic triggers created. If you did not, i am going to go over them either way so you will just have to type them out.
Click on the Trigger button on Mudlet.
We will be creating these:
http://imgur.com/RIeF4i8
As you can see my triggers are located under "Generic Mapper"
The essential ones you will need are 'Move Fail Trigger', 'Prompt Trigger', 'Rooms and Exits', and 'Extended Exits Capture Trigger'. The room name and exits capture are unnecessary.
We will start at the top.

Move Fail Trigger
Make it look just like mine. Add any other triggers that would cause your character not to move that you would like. This one is very straight forward.
http://imgur.com/ZTfW5zp

You only need to adjust line 1 on the triggers and line 1 on the script. No adjustment besides the trigger line 1 if you downloaded the script through the package.
Done.

Prompt Trigger
This one is a tad bit trickier. You may need to brush up on your regex(if you know it, I didn't know for sure what it was so i did a lot of research for this.) *important Note Lua uses % instead of / for regex.

If you have not customized your prompt (by prompt i mean the line that shows up every 2 seconds and states your HP/MP/etc...) Than you can use the one i created(it is long and ugly but it works.)
http://imgur.com/S8CdHsD

Edit line 1 of trigger if you already have it, if not just type it in.
*Note to change trigger type to 'perl regex' And you do not need line 3 it is merely for testing purposes.

Rooms and Exits
This one was the most difficult. Shadowdale/gnsmud have no distinguishing color or feature of the room name to use for this. So we are using a script that will gather every line and sort through them to find it. This one we will just copy/paste it into the script tab under a new script.
Code: Select all
local desc = {}

function get_desc(line)
   if not string.starts(line,"Exits") then
      table.insert(desc,line)
   else
      local index
      for i,v in ipairs(desc) do
         if i ~= 1 and string.match(v, "^%s+%w+") then
            index = i - 1
            break
         end
      end
      map.prompt.room = desc[index]
      map.prompt.exits = string.match(line,"Exits: (.*)")
      raisEvent("onNewRoom")
   end
end

function reset_desc()
   desc = {}
end


After copy/pasting this into a script we need to set up the trigger to call it. It is quite easy.
The trigger is a color trigger. FG color white(the darker of the two) BG color is black. and the script to call is "get_desc(line)".

http://imgur.com/JPV5hGV

And that is it!
The last trigger is the Extended Exits Capture Trigger, Which we will not be adjusting at all(it activates and deactivates on it's own.) I didnt grab a screenshot of it and i'm at work, so i cant help you if you need to type it up yourself until later.

In order to begin mapping just type "Start Mapping <area name>" and go for it! Mapping does have a learning curve to it, being that there are not maps built in to mudlet for gndmud yet.

I have not had time to play with it since i have gotten it working but here are some things i have learned:

When mapping, if you are going to walk into a room you have already mapped you need to type move <direction> the direction being the direction opposite of that you are going to move to. then type 'merge rooms' if they are the same room. The mapper does not have any way of knowing if the room you are going into has already been mapped. I don't know about this in particular, I haven't had that much time with it.

The aliases needed to create a valid map are listed in the notes at the beginning of the script. Refer to them for more information on how to map properly. Mapping is not super easy, but if we want to map all of gnsmud than we need to work at it together. Save, export and share maps for other so that we can all learn where to go and what we can do better.

If you see me in game and have a question feel free to ask as well.
My toons:
Votrepatron - MU
Tera - Ba
Creed - CL/WA/SO

Let me know if anything is unclear. I will try and answer questions as best i can.
Good luck!

edit 1: Images didn't show, changed them to URL's. Link goes to imgur link of images.

edit 2: Clarification on how to use the alias commands.
Votrepatron
 
Posts: 10
Joined: Wed Aug 09, 2017 5:35 pm

Re: Mudlet Mapper

Postby Brennor » Thu Aug 24, 2017 4:13 pm

Cool, thanks for the information. I'm going to start playing with this and see what comes of it.

Any ideas how we'd go about sharing maps around?
Brennor
 
Posts: 4
Joined: Mon Aug 14, 2017 3:21 pm
Location: NE USA

Re: Mudlet Mapper

Postby Clarky_MacLeod » Fri Sep 08, 2017 9:29 pm

Hey!
Sorry for the noob questions, but i don't have any LUA nor Perl experience. Could you please explain the Prompt trigger a little bit more? My Prompt is $kW($kR%h$kW/$kr%H$kW) ($kG%v$kW/$kg%V$kW) ($kB%x$kW) ($kY%g$kW) C:$kY%c$kW/$kR%C$kW>. Should i just translate into perl and write it after ^Shadowdale:\(type help prompt\) ?

Also, could you please explain what those triggers do? What are they displaying or doing?

Everytime i try to start mapping <Shadowdale Village>, i get "Start Mapping Error: No room detected!" as response. what does that imply?

There is so much to learn with this game :D

Thanks for your support.
Clarky_MacLeod
 
Posts: 1
Joined: Wed Aug 16, 2017 5:15 pm

Previous

Return to General Discussion

Who is online

Users browsing this forum: No registered users and 0 guests

cron