Mudlet IRE Mapping Script

by Janalon

Back to Mechanic's Corner.

Janalon2011-08-24 02:20:03
Just downloaded Mudlet's IRE mapping script and absolutely love it. The accuracy, speed, and range cannot be matched elsewhere. Love the support given on the Mudlet Wiki Map Page, and came across support for the goto syntax:

CODE
goto

    goto - goes to a room of that id
    goto - goes to a specific area
    goto sprint/dash/gallop - goes to a place, sprinting, dashing or galloping whenever possible
    goto # - goes to an area - the number specifies which one exactly if more than one matches


I am looking to add "GLIDE" as an additional syntax to sprint/dash/gallop. Vadi suggested that I use Mudlet's search to look for instances of "SPRINT" to see where I can add glide. Seemed easy enough in the following script:

CODE
speedWalkWatch = createStopWatch()
speedWalkPath = speedWalkPath or {}
speedWalkDir = speedWalkDir or {}
speedWalkCounter = 0

-- mmp = mudlet mapper
mmp = mmp or {
  paused = false,
  autowalking = false,
  currentroom = false,
  currentroomname = false,
  firstRun = true
}

function mmp.startup()
  if not mmp.firstRun then
    return
  end

  local private_settings = {}
  private_settings = createOption(false, mmp.changeBoolFunc, { "boolean" }, "Use Glide?")
  private_settings = createOption(false, mmp.changeBoolFunc, { "boolean" }, "Use Dash?")
  private_settings = createOption(false, mmp.changeBoolFunc, { "boolean" }, "Use Gallop?")
  private_settings = createOption(false, mmp.changeBoolFunc, { "boolean" }, "Use Sprint?")
  private_settings = createOption(false, mmp.changeBoolFunc, { "boolean" }, "Use Jester Runaway?")


  mmp.settings = createOptionsTable(private_settings)
  mmp.settings.disp = mmp.echo

  mmp.settings.dispOption = function(opt, val)
    cecho("Use " .. opt .. "?" .. string.rep(" ", 15 - opt:len()) .. tostring(val.value) .. "\\n")
  end

  mmp.settings.dispDefaultWriteError = function()
    mmp.echo("Please use the mconfig alias to set options!")
  end

  raiseEvent("mmp areas changed")
  mmp.firstRun = false
end

-- moves to the next room we need to.
function mmp.move()
  if mmp.paused or not mmp.autowalking or mmp.movetimer then return end
  send(speedWalkDir, false)
  cecho(string.format("(%d - %s)", #speedWalkDir - speedWalkCounter + 1, speedWalkDir))

  -- timeout
  if mmp.movetimer then killTimer(mmp.movetimer) end
  mmp.movetimer = tempTimer(getNetworkLatency()+0.5, function ()
    mmp.movetimer = false
    mmp.move()
  end)
end

function mmp.swim()
  send("swim " .. speedWalkDir, false)
  cecho(string.format("(%d - swim %s)", #speedWalkDir - speedWalkCounter + 1, speedWalkDir))

  if mmp.movetimer then killTimer(mmp.movetimer) end
  mmp.movetimer = tempTimer(getNetworkLatency()+2.5, function ()
    mmp.movetimer = false
    mmp.move()
  end)
end

function mmp.customwalkdelay(delay)
  if mmp.movetimer then killTimer(mmp.movetimer) end
  mmp.movetimer = tempTimer(getNetworkLatency()+delay, function ()
    mmp.movetimer = false
    mmp.move()
  end)
end

function mmp.stop()
  speedWalkPath = {}
  speedWalkDir = {}
  speedWalkCounter = 0
  stopStopWatch(speedWalkWatch)
  if speedWalkTimerID then killTimer( speedWalkTimerID ) end
  mmp.autowalking = false

  mmp.echo("Stopped walking.")
  raiseEvent("mmapper stopped")
end

local oldnum
function speedwalking( event, num )
  local num = tonumber(num) or tonumber(gmcp.Room.Info.num)
  mmp.currentroom = num
  mmp.currentroomname = next(gmcp) and gmcp.Room.Info.name or atcp.RoomName

  -- workaround for Aetolia spamming us with multiple nums per room
  if oldnum == num or not mmp.autowalking then return else oldnum = num end
  if mmp.movetimer then killTimer(mmp.movetimer) end

  if mmp.movetimer then killTimer(mmp.movetimer); mmp.movetimer = false end
  if num == speedWalkPath then
    local walktime = stopStopWatch(speedWalkWatch)
    mmp.echo(string.format("We've arrived! Took us %.1fs.\\n", walktime))
    raiseEvent("mmapper arrived")
    speedWalkPath = {}
    speedWalkDir = {}
    speedWalkCounter = 0
    mmp.autowalking = false
  elseif speedWalkPath == num then
    speedWalkCounter = speedWalkCounter + 1
    mmp.move()
  elseif #speedWalkPath> 0 then -- ended up somewhere we didn't want to be?
    speedWalkMoved = false

    -- re-calculate path then
    mmp.echo("Ended up off the path, recalculating a new path...")
    local destination = speedWalkPath
    if not getPath(num, destination) then
      mmp.echo(string.format("Don't know how to get to %d (%s) anymore :(",
        destination, mmp.searchRoom(destination)))
    else
        mmp.gotoRoom (destination)
    end
  end
end

function mmp.gotoRoom (where, dashtype)
  if not where or not tonumber(where) then
    mmp.echo("Where do you want to go to?") return end

  if tonumber(where) == mmp.currentroom then
    mmp.echo("We're already at "..where.."!")
   raiseEvent("mmapper arrived")
   return
  end

  if not mmp.getPath(mmp.currentroom, tonumber(where)) then
    mmp.echo("Don't know how to get there from here :(")
    speedWalkPath = {}
    speedWalkDir = {}
    speedWalkCounter = 0
    raiseEvent("mmapper failed path")
    return
  end

  doSpeedWalk(dashtype)
end

function mmp.gotoArea (where, number, dashtype, exact)
  if not where or not type(where)=="string" then
    mmp.echo("Where do you want to go to?") return end
  number = tonumber(number)

  local possibleRooms, shortestPath, shortestBorder = {}, {}, 0

  local areaid, msg, multiples = mmp.findAreaID(where, exact)
  if areaid then
     possibleRooms = mmp.getAreaBorders(areaid)

  elseif not areaid and #multiples > 0 then
    if number and number<=#multiples then
        mmp.gotoArea(multiples, nil, dashtype, true)
        return
    end
    mmp.echo("Which area would you like to go to?")
    fg("DimGrey")
    for key, areaname in ipairs(multiples) do
      echo"  "; echoLink(key .. ") ", 'mmp.gotoArea("'..areaname..'", '..(dashtype and '"'..dashtype..'"' or "nil")..', true)', "Click to go to "..areaname, true)
        setUnderline(true) echoLink(areaname, 'mmp.gotoArea("'..areaname..'", '..(dashtype and '"'..dashtype..'"' or "nil")..', true)', "Click to go to "..areaname, true) setUnderline(false) echo"\\n"
    end
    resetFormat()
    return
  else
    mmp.echo(string.format("Don't know of any area named '%s'.", where))
    return
  end

  for id, _ in pairs(possibleRooms) do
    if mmp.getPath(mmp.currentroom, tonumber(id)) then
      if shortestBorder==0 or #shortestPath > #speedWalkPath then
        shortestPath = speedWalkPath
        shortestBorder = tonumber(id)
      end
    end
  end

  if shortestBorder == 0 then
    mmp.echo("Don't know how to get there from here :(")
    speedWalkPath = {}
    speedWalkDir = {}
    speedWalkCounter = 0
    raiseEvent("mmapper failed path")
    return
  end

  mmp.gotoRoom(shortestBorder, dashtype)
end

function doSpeedWalk(dashtype)
  resetStopWatch(speedWalkWatch)
  startStopWatch(speedWalkWatch)
  if mmp.settings or mmp.settings or mmp.settings.sprint or dashtype then
    mmp.fixPath(mmp.currentroom, speedWalkPath,
      (mmp.settings and "gallop") or (mmp.settings and "dash") or (mmp.settings.sprint and "sprint") or (mmp.settings.runaway and "runaway") or dashtype)
  end

  if #speedWalkPath == 0 then
    mmp.echo("Couldn't find a path to the destination :(")
    raiseEvent("mmapper failed path")
    return
  end

  mmp.autowalking = true

  -- this is a fix: convert nums to actual numbers
  for i = 1, #speedWalkPath do
    speedWalkPath = tonumber(speedWalkPath)
  end

  if not mmp.paused then
    mmp.echo("Starting speedwalk from "..(atcp.RoomNum or gmcp.Room.Info.num).." to ") echoLink(speedWalkPath, 'gotoRoom "' .. speedWalkPath.. '"', 'Go to ' .. speedWalkPath) echo(": ")
    speedWalkCounter = 1
    mmp.move()
  else
    mmp.echo("Will go to "..speedWalkPath.." as soon as the mapper is unpaused.")
  end
end

function mmp.failpath()
  if speedWalkTimerID then
    local walktime = stopStopWatch(speedWalkWatch)
    mmp.echo(string.format("Can't continue further! Took us %.1fs to get here.\\n", walktime))
  end

  raiseEvent("mmapper failedpath")
  speedWalkPath = {}
  speedWalkDir = {}
  speedWalkCounter = 0
  if speedWalkTimerID then killTimer( speedWalkTimerID ); speedWalkTimerID = nil end
end

function mmp.changeBoolFunc(name, option)
  local en
  if option then en = "will now use" else en = "will no longer use" end
  mmp.echo("Okay, the mapper " .. en .. " " .. name .. "!")
end

function mmp.fixPath(rFrom,rTo,dashtype)
  local currentPath, currentIds = {}, {}
  local dRef = { = "north", = "east", = "south", = "west"}
  if not getPath(rFrom,rTo) then return false end

  -- Logic: Look for a direction repeated at least two times.
  -- count the number of times it repeats, then look that many rooms ahead.
  -- if that room also contains the direction we're headed, just travel that many directions.
  -- otherwise, dash.

  local repCount = 1
  local index = 1
  local dashExaust = false
  while speedWalkDir do
    dashExaust = false
    repCount = 1
    while speedWalkDir == speedWalkDir do
      repCount = repCount + 1
      if repCount == 11 then
        dashExaust = true
        break
      end
    end
    if repCount > 1 then
      -- Found direction repitition. Calculate dash path.
      local exits = getRoomExits(speedWalkPath)
      local pname = ""
      for word in speedWalkDir:gmatch("%w") do pname = pname .. (dRef or word) end
      if not exits or dashExaust then
        -- Final room in this direction does not continue, dash!
        table.insert(currentPath,string.format("%s %s",dashtype,speedWalkDir))
        currentIds = speedWalkPath
      else
        -- Final room in this direction continues onwards, don't dash
        for i = 1,repCount do
          table.insert(currentPath,speedWalkDir)
          currentIds = speedWalkPath
        end
      end
      index = index + repCount
    else
      -- No repetition, just add the direction.
      table.insert(currentPath,speedWalkDir)
      currentIds = speedWalkPath
      index = index + 1
    end
  end

  speedWalkDir = currentPath
  speedWalkPath = currentIds
  return true
end


Though, I am not exactly sure what to do in the alias:

CODE
local where = matches
local gallop
if command:ends("gallop") then
  gallop = "gallop"
  where = where:sub(1, -8)
elseif command:ends("sprint") then
  gallop = "sprint"
  where = where:sub(1, -8)
elseif command:ends("dash") then
  gallop = "dash"
  where = where:sub(1, -7)
elseif command:ends("runaway") then
  gallop = "runaway"
  where = where:sub(1, -9)
end


-- goto room ID
if tonumber(where) then
    mmp.gotoRoom(where, gallop)
else
    -- goto area
    local split = where:split(" ")
    if tonumber(split) then
        mmp.gotoArea(where:sub(1, -#(split)-2), tonumber(split), gallop)
    else
        mmp.gotoArea(where, nil, gallop)
    end
end


I figure I might have to insert the following in the appropriate place:

CODE
elseif command:ends("glide") then
  gallop = "glide"
  where = where:sub(1, -8)


Just not sure what the where:sub(1, -8) means, or if/how I should adjust these numbers.

Vadi2011-08-24 05:30:23
Take a look at http://www.lua.org/manual/5.1/manual.html#pdf-string.sub - I believe this'll do it for you:

CODE
local where = matches
local gallop
if command:ends("gallop") then
  gallop = "gallop"
  where = where:sub(1, -8)
elseif command:ends("sprint") then
  gallop = "sprint"
  where = where:sub(1, -8)
elseif command:ends("dash") then
  gallop = "dash"
  where = where:sub(1, -7)
elseif command:ends("runaway") then
  gallop = "runaway"
  where = where:sub(1, -9)
elseif command:ends("glide") then
  gallop = "glide"
  where = where:sub(1, -7)
end
Janalon2011-08-24 09:37:23
QUOTE (Vadi @ Aug 24 2011, 01:30 AM) <{POST_SNAPBACK}>
Take a look at http://www.lua.org/manual/5.1/manual.html#pdf-string.sub - I believe this'll do it for you:


Read through the Lua manual. Unfortunately, it gets too technical for someone completely unfamilar with the language. The example helps a ton, and I will try the values -7, -8, or -9 until I find one that works! Thank you for your help.
Vadi2011-08-24 21:09:07
The numbers I gave you work smile.gif
Janalon2011-08-25 01:17:49
QUOTE (Vadi @ Aug 24 2011, 05:09 PM) <{POST_SNAPBACK}>
The numbers I gave you work smile.gif


Oops. Yeah, didn't see that at first. THANK YOU!
Vadi2011-09-23 21:55:11
If you haven't updated in a while, update now, because since 11.9.8 the script won't walk off-balance in Lusternia, plus earlier features like automatic map+mapper script update checking are awesome.

Code contributions are very welcome, the script is open source - if you'd like to add something feel free to post in the thread!
Janalon2011-10-03 02:48:22
QUOTE (Vadi @ Sep 23 2011, 05:55 PM) <{POST_SNAPBACK}>
If you haven't updated in a while, update now, because since 11.9.8 the script won't walk off-balance in Lusternia, plus earlier features like automatic map+mapper script update checking are awesome.

Code contributions are very welcome, the script is open source - if you'd like to add something feel free to post in the thread!


What's the address to DL? Would be useful to post here.
Vadi2011-10-03 02:57:52
wiki.mudlet.org/w/IRE_mapping_script
Unknown2011-10-13 09:42:30
Is there a way to stop the mapper from going through certain or specific rooms/areas?
Vadi2011-10-13 09:55:07
Yeah, arealock and arealock
Reyl2011-11-05 06:05:42
All of a sudden i'm having a problem where the speedwalker thinks i'm off balance, and not even reinstalling has helped. I can't think what the problem might be, the only change i've made recently is installing m&m. Anybody else had similar problems?

EDIT: Updating to a newer release of mudlet fixed this problem - now the map works, but the graphics in 2d mode are corrupt.

2x EDIT: Welp, i had a disconnect, and now the balance problem is back. I had a look throughout the triggers/scripts - is there any way to manually reset this? Are the balances supposed to be picked up via GMCP? Any idea what's happening?
Unknown2012-01-05 11:20:09
This is also a super super super late response to Reyl. And hopefully this post will help others as well. I've noticed that the mudlet mapper plugin cannot speedwalk if the psionic channels are locked. Is there anything I can do to change the bolded parts to make it more psionic friendly for people (Yay Monks!) who keep their channels locked most of the time? Aside from deleting the snippet of code I've bolded? >_>


function mmp.canmove(fromtimer)
if not gmcp.Char then return true end
if (gmcp.Char and
(not gmcp.Char.Vitals.balance or gmcp.Char.Vitals.balance == "1") and
(not gmcp.Char.Vitals.equilibrium or gmcp.Char.Vitals.equilibrium == "1") and
(not gmcp.Char.Vitals.right_arm or gmcp.Char.Vitals.right_arm == "1") and
(not gmcp.Char.Vitals.left_arm or gmcp.Char.Vitals.left_arm == "1") and
(not gmcp.Char.Vitals.right_leg or gmcp.Char.Vitals.right_leg == "1") and
(not gmcp.Char.Vitals.left_leg or gmcp.Char.Vitals.left_leg == "1") and
(not gmcp.Char.Vitals.psisuper or gmcp.Char.Vitals.psisuper == "1") and
(not gmcp.Char.Vitals.psisub or gmcp.Char.Vitals.psisub == "1") and
(not gmcp.Char.Vitals.psiid or gmcp.Char.Vitals.psiid == "1") and
(not gmcp.Char.Vitals.prone or gmcp.Char.Vitals.prone == "0")
) then
if fromtimer then
mmp.move()
else return true end
else
tempTimer(0.2, ])
return false
end
end

Also deleting those three lines is the quick and dirty way to 'fix' the speedwalk problem (For psionics users who like to keep a channel or two locked) in the mudlet mapper. I haven't had any problems with speedwalking after removing them and playing for a couple hours with locked psi channels.
Iosai2012-01-05 12:54:51
Change the lines to the following:


(not gmcp.Char.Vitals.psisuper or gmcp.Char.Vitals.psisuper ~= "0") and
(not gmcp.Char.Vitals.psisub or gmcp.Char.Vitals.psisub ~= "0") and
(not gmcp.Char.Vitals.psiid or gmcp.Char.Vitals.psiid ~= "0") and


GMCP sends -1 if a psionic channel is locked, 1 if it is free, and 0 if it has recently been used and is returning.
Zynna2012-01-05 14:34:52
Thank you!! This makes things so much better.
Unknown2012-01-05 20:49:58
Ooh! Thank you so much. :)

And I've just learned a lot about how GMCP works through looking into all this too. XD