Improved Aardwolf "bigmap" miniwindow-based plugin

Posted by Nick Gammon on Sun 26 Jul 2009 04:32 AM — 34 posts, 150,314 views.

Australia Forum Administrator #0
The plugin below is based on the "big map" plugin I did a while ago for Aardwolf. However the older one used a "dummy world" window, whereas this uses a miniwindow.

The miniwindow can be moved around to wherever you like. You can toggle it on or off by typing "bigmap" (it might be an idea to make a macro like F10 do that).

An improved feature of the map is a blue circle which is drawn around your current location, making it very obvious where you are on the map.

Template:saveplugin=Aardwolf_BigMap_v2
To save and install the Aardwolf_BigMap_v2 plugin do this:
  1. Copy the code below (in the code box) to the Clipboard
  2. Open a text editor (such as Notepad) and paste the plugin code into it
  3. Save to disk on your PC, preferably in your plugins directory, as Aardwolf_BigMap_v2.xml
    • The "plugins" directory is usually under the "worlds" directory inside where you installed MUSHclient.
  4. Go to the MUSHclient File menu -> Plugins
  5. Click "Add"
  6. Choose the file Aardwolf_BigMap_v2.xml (which you just saved in step 3) as a plugin
  7. Click "Close"
  8. Save your world file, so that the plugin loads next time you open it.


The plugin uses telnet negotation, so you also need this file:

http://www.gammon.com.au/mushclient/plugins/Aardwolf/telnet_options.lua

That should also go into the plugins folder.


<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE muclient>
<!-- Saved on Saturday, June 30, 2007, 10:48  -->
<!-- MuClient version 4.13 -->

<muclient>
<plugin
   name="Aardwolf_BigMap_v2"
   author="Nick Gammon"
   id="15f26e97b2d58b7b5412c278"
   language="Lua"
   purpose="Redirects Aardwolf bigmap messages to a miniwindow"
   date_written="2009-07-26"
   requires="4.42"
   version="1.0"
   save_state="y"
   >
<description trim="y">
Redirects the bigmap to a miniwindow.

Commands:

bigmap remove map cache  --> removes the cache, forcing maps to be downloaded
                               (only do this after a major continent upgrade)
                      
bigmap auto              --> toggle auto-minimize map
bigmap auto on           --> auto-hide map when you enter an area
bigmap auto off          --> manually hide map
bigmap on                --> show the map
bigmap off               --> hide the map

</description>

</plugin>

<!--  Triggers  -->

<triggers>

  <trigger
   enabled="y"
   match="^\{bigmap\}(?<zone>\d+)\,(?<zonename>.+)$"
   script="map_redirect"
   omit_from_output="y"
   name="map_start"
   sequence="100"
   regexp="y"
  >
  </trigger>
 
  <trigger
   enabled="n"
   match="*"
   script="map_redirect"
   name="multi_line_map"
   omit_from_output="y"
   sequence="10"
  >
  </trigger>

  <trigger
   enabled="y"
   match="^\{coords\}(?<zone>\d+)\,(?<x>\d+)\,(?<y>\d+)$"
   omit_from_output="y"
   regexp="y"
   script="updatelocation"
   sequence="100"
  >
  </trigger>
  

 <trigger
   enabled="y"
   match="{coords}-1"
   omit_from_output="y"
   sequence="100"
   send_to="14"
   script="in_zone"
  >
  </trigger>

</triggers>

<aliases>

  <alias
   name="remove_alias"
   script="remove_cache"
   match="bigmap remove map cache"
   enabled="y"
   sequence="100"
   ignore_case="y"
  >
  </alias>
  
 <alias
   script="auto_minimize_alias"
   match="^bigmap auto( on| off)?$"
   enabled="y"
   regexp="y"
   sequence="100"
   ignore_case="y"
  >
  </alias>
    
<alias
   script="map_on_off_alias"
   match="^bigmap( on| off)?$"
   enabled="y"
   regexp="y"
   sequence="100"
   ignore_case="y"
  >
  </alias>
    
</aliases>


<!--  Script  -->


<script>
<![CDATA[
folder = "Aardwolf"

require "serialize"  -- needed to serialize table to string
require "checkplugin"
require "movewindow"

map = {}
continents = {}
xref = {}
auto_minimize = true
show_map = true
background_colour = 0x000028
title_colour = 0x696969
zone_name_colour = ColourNameToRGB "yellow"

function remove_cache ()
  continents = {}
  xref = {}
  ColourNote ("white", "blue", "Big maps removed from cache.")
end -- remove_cache

function auto_minimize_alias (name, line, wildcards)
  if wildcards [1] == false then
    auto_minimize = not auto_minimize
  elseif wildcards [1]:lower () == " on" then
    auto_minimize = true
  elseif wildcards [1]:lower () == " off" then
    auto_minimize = false
  end -- if
  
  if auto_minimize then
    ColourNote ("yellow", "", "Bigmap auto-hide enabled.")
  else
    ColourNote ("yellow", "", "Bigmap auto-hide DISABLED.")
  end -- if  
    
end -- auto_minimize_alias

function map_on_off_alias (name, line, wildcards)
  if wildcards [1] == false then
    show_map = not show_map
  elseif wildcards [1]:lower () == " on" then
    show_map = true
  elseif wildcards [1]:lower () == " off" then
    show_map = false
  end -- if
  
  if show_map then
    ColourNote ("yellow", "", "Bigmap enabled.")
    if map and #map > 0 then
      WindowShow (win, true)
    end -- showing
  else
    ColourNote ("yellow", "", "Bigmap DISABLED - type 'bigmap' to re-enable.")
    WindowShow (win, false)
  end -- if  
    
end -- auto_minimize_alias


function in_zone (name, line, wildcards)
  if auto_minimize then
     WindowShow (win, false)
  end -- if
end -- in_zone


function InsertLocation (line, x)
  t = {}
  col = 1
  
  for i, item in ipairs (line) do

    -- to make it easier for me, I will expand out multiple-column runs    
    if item.length > 1 then
      for j = item.length, 2, -1 do
        table.insert (line, i + 1,
                            { text = item.text:sub (j, j), 
                              textcolour = item.textcolour, 
                              backcolour = item.backcolour, 
                              length = 1, 
                              style = style } )
      end -- adding new ones
      
      item.length = 1
      item.text = item.text:sub (1, 1)
    end -- if multiple columns
    
    -- at column, do *
    
    if col == x then
      table.insert (t, { text = "*", textcolour = 0x00FFFF, backcolour = 0x000000 } )
    else
      table.insert (t, item)
    end -- if column
    
    col = col + item.length
  end -- for
  
  return t
  
end -- InsertLocation

function Display_Styled_Line (line, styles, id)

local left = 5
local top = (line - 1) * font_height + 5

  for _, v in ipairs (styles) do
    left = left + WindowText (win, id, v.text, left, top, 0, 0, v.textcolour)
  end -- for each style run                 

end -- Display_Styled_Line

function Display_Line (line, text, id, colour)

local left = 5
local top = (line - 1) * font_height

  WindowText (win, id, text, left, top, 0, 0, colour)

end -- Display_Line

function DrawMap (x, y)

  local origx, origy = x, y
  x = x + 1  -- allow for border, make 1-relative
  y = y + 1  -- ditto
  
  if not map or #map == 0 then
    return
  end -- no map
   
  local lines = #map + 2
  local columns = 0
  for _, v in ipairs (map [1]) do
    columns = columns + v.length
  end -- for
  local window_width = columns * font_width + 10
  local window_height =  lines * font_height + 15
   -- recreate the window the correct size
   WindowCreate (win, 
                 windowinfo.window_left, 
                 windowinfo.window_top, 
                 window_width,     -- width
                 window_height,  -- height
                 windowinfo.window_mode,   
                 windowinfo.window_flags,
                 background_colour) 
  
   WindowDeleteAllHotspots (win)
   movewindow.add_drag_handler (win, 0, 0, 0, font_height, 1)
   
  local name = continent or ""
  local namewidth = WindowTextWidth (win, font_id, name)
  WindowText (win, font_id, name, (window_width - namewidth) / 2, 5, 0, 0, zone_name_colour)  -- title
  
  
  for i, v in ipairs (map) do
    if i == y then
      Display_Styled_Line (i + 1, InsertLocation (v, x), font_id)
    else
      Display_Styled_Line (i + 1, v, font_id)
    end
  end -- for
  
  local our_location_x = (x - 1) * font_width + (font_width / 2) + 5
  local our_location_y = (y) * font_height + (font_height / 2) + 5
  
  -- draw circle around us
  WindowCircleOp (win, 1, 
                  our_location_x - 20, our_location_y - 20,
                  our_location_x + 20, our_location_y + 20,
                  ColourNameToRGB "cornflowerblue",  -- pen colour
                  0, -- solid pen
                  3, -- pen width
                  0, -- brush colour
                  1 ) -- null brush
                  
  WindowCircleOp (win, 1, 
                  our_location_x - 20, our_location_y - 20,
                  our_location_x + 20, our_location_y + 20,
                  ColourNameToRGB "cyan",  -- pen colour
                  0, -- solid pen
                  1, -- pen width
                  0, -- brush colour
                  1 ) -- null brush
  
  local coords = string.format ("Location: %2i, %2i", origx, origy)
  local coordswidth = WindowTextWidth (win, font_id, coords)
  WindowText (win, font_id, coords, (window_width - coordswidth) / 2, 
             (#map + 1) * font_height + 5, 0, 0, zone_name_colour)  -- title
  
  Display_Line (#map + 1, coords, font_id, 0x000000)
 
  -- DrawEdge rectangle
  WindowRectOp (win, 5, 0, 0, 0, 0, 10, 15)
  
  WindowShow (win, true)
  
  Repaint ()
end -- DrawMap

function updatelocation (name, line, wildcards)
  -- where we are
  x = tonumber (wildcards.x) 
  y = tonumber (wildcards.y)
  zone = tonumber (wildcards.zone)
  
  -- changed continent?
  if old_zone ~= zone then
  
    -- grab cached map
    map = continents [zone]
    continent = xref [zone]
    
    -- no cached map? better get it
    if not map then
      SendNoEcho "bigmap noself" -- grab map
    end -- don't know this one
    old_zone = zone
  end -- need big map
  
  -- draw our location
  if map then
    DrawMap (x, y)
  end -- if
end -- updatelocation


-- map redirector
function map_redirect (name, line, wildcards, styles)

  EnableTrigger ("multi_line_map", true)  -- capture subsequent lines

  if name == "map_start" then
    map = {}  -- start new map
    continent = wildcards.zonename
    zone = tonumber (wildcards.zone)
    xref [zone] = wildcards.zonename
  elseif line == "{/bigmap}" then
    EnableTrigger ("multi_line_map", false)  -- no more lines to go
    
    table.remove (map, 1)  -- remove first line (the border) 
    map [#map] = nil  -- remove last line (the other border)
    
    for _, v in ipairs (map) do
      
      if v [1].text == "|" then
        table.remove (v, 1)
      end -- remove first border
      
     if v [#v].text == "" then
        v [#v] = nil
      end -- remove last border
      
      if v [#v].text == "|" then
        v [#v] = nil
      end -- remove last border
    
    end -- for
    
    if zone then
      continents [zone] = map  -- cache it
    end -- we know the continent
    
    DrawMap (x, y)
  else
    table.insert (map, styles)
  end -- if

  
end -- function map_redirect 

function OnPluginInstall ()
  assert (loadstring (GetVariable ("continents") or "")) ()
  assert (loadstring (GetVariable ("xref") or "")) ()
  auto_minimize = (GetVariable ("auto_minimize") or auto_minimize) == "true"

  win = GetPluginID ()

  local fonts = utils.getfontfamilies ()
  if fonts.Dina then
    font_size = 8
    font_name = "Dina"    -- the actual font
  else
    font_size = 10
    font_name = "Courier"
  end -- if
    
  font_id = "map_font"  -- our internal name
  font_id_bold = "map_font_bold"  -- our internal name

  windowinfo = movewindow.install (win, 6)
  
  -- make miniwindow so I can grab the font info
  check (WindowCreate (win, 
                 windowinfo.window_left, 
                 windowinfo.window_top, 
                 1, 1,  
                 windowinfo.window_mode,   
                 windowinfo.window_flags,
                 background_colour) )
  
  check (WindowFont (win, font_id, font_name, font_size, false, false, false, false, 0, 49))  -- normal
  font_height = WindowFontInfo (win, font_id, 1) -  WindowFontInfo (win, font_id, 4) + 1 -- height
  font_width = WindowFontInfo (win, font_id, 6)  -- avg width
  descent = WindowFontInfo (win, font_id, 3)
  
  if GetVariable ("enabled") == "false" then
    ColourNote ("yellow", "", "Warning: Plugin " .. GetPluginName ().. " is currently disabled.")
    check (EnablePlugin(GetPluginID (), false))
    return
  end -- they didn't enable us last time
  
  OnPluginEnable ()  -- do initialization stuff
  
end -- OnPluginInstall

function OnPluginSaveState ()
  SetVariable ("continents", 
               "continents = " .. serialize.save_simple (continents))
               
  SetVariable ("xref", 
               "xref = " .. serialize.save_simple (xref))
               
  SetVariable ("enabled", tostring (GetPluginInfo (GetPluginID (), 17)))
  SetVariable ("auto_minimize", tostring (auto_minimize))
               
  movewindow.save_state (win)
  
end -- function OnPluginSaveState

-- pull in telnet option handling
dofile (GetPluginInfo (GetPluginID (), 20) .. "telnet_options.lua")

function OnPluginConnect ()
  TelnetOptionOn (TELOPT_BIGMAP)
end -- function OnPluginConnect

function OnPluginClose ()
  -- if enabled
  if GetPluginInfo (GetPluginID (), 17) then  
    TelnetOptionOff (TELOPT_BIGMAP)
  end -- currently enabled
end -- OnPluginClose

function OnPluginEnable ()

  -- if we are connected when the plugin loads, it must have been reloaded whilst playing
  if IsConnected () then
    OnPluginConnect ()
  end -- if already connected

end -- OnPluginEnable

function OnPluginDisable ()
  TelnetOptionOff (TELOPT_BIGMAP)

  WindowShow (win, false)
  
end -- OnPluginDisable

]]>
</script>
</muclient>

Amended on Wed 19 Aug 2009 05:51 AM by Nick Gammon
Australia Forum Administrator #1

Here is an example of the bigmap window:

Germany #2
It looks really good, but like all the other maps I've seen it's still using ASCII characters. How much effort would it take to use little texture images instead? I know you support them - are there any problems with using so many at the same time? Or is it just that you wanted a generic solution, rather than one which relied on lots of predefined graphics and a mud-specific terrain set?
Netherlands #3
There shouldn't be any problems to add such functionality.

Don't forget that these plugins have a secondary purpose of being examples on how to do more complicated things in MUSHclient. If it were to throw too many different things together in one file it would become far harder for people to get started to understand how this kind of plugin works.

Basically, the current plugin is a (simple) matter of creating the window, parsing data, and re-outputting them in a miniwindow. If it were to involve custom images and such it would be just that bit more complicated - and it is actually quite simply to add if you have the images ready.
Australia Forum Administrator #4

It can certainly be done, as Worstje said. Just to show the general idea I adapted it to draw with various brushes rather than use text - the brush was selected based on the underlying character. The colour is unchanged. It looks OK, it would probably be better if you sat down and worked out individual images for each terrain type.

Notice the aspect ratio is different - each tile is now square, they weren't when drawing with a font.

Australia Forum Administrator #5
The other thing you could do is to get someone artistic to simply draw a nice map of the continent, and draw that. Then just use the circle to show whereabouts you are on it.
Australia Forum Administrator #6
The differences are:


*** Aardwolf_bigmap_miniwindow.xml	Sun Jul 26 12:18:03 2009
--- Aardwolf_bigmap_miniwindow_graphical.xml	Wed Jul 29 07:42:14 2009
***************
*** 135,140 ****
--- 136,142 ----
  background_colour = 0x000028
  title_colour = 0x696969
  zone_name_colour = ColourNameToRGB "yellow"
+ rectangle_size = 8
  
  function remove_cache ()
    continents = {}
***************
*** 224,236 ****
    
  end -- InsertLocation
  
  function Display_Styled_Line (line, styles, id)
  
  local left = 5
! local top = (line - 1) * font_height + 5
  
    for _, v in ipairs (styles) do
!     left = left + WindowText (win, id, v.text, left, top, 0, 0, v.textcolour)
    end -- for each style run                 
  
  end -- Display_Styled_Line
--- 226,259 ----
    
  end -- InsertLocation
  
+ brushes = {
+   ["~"] = 11,
+   ["?"] = 9,
+   ["^"] = 12,
+   ["."] = 5,
+   }
+   
  function Display_Styled_Line (line, styles, id)
  
  local left = 5
! local top = (line - 1) * rectangle_size + 15
  
    for _, v in ipairs (styles) do
!     
!     for i = 1, #v.text do
!       local char = string.sub (v.text, i, i)
!       local brush = brushes [char] or 8
!       local backcolour = 0x000000
!       if brush == 0 then 
!         backcolour = v.textcolour
!       end -- if 
!       WindowCircleOp(win, 2, left, top, left + rectangle_size, top + rectangle_size,
!                     v.textcolour, 5, 0,   -- pen colour, null pen, pen width
!                     backcolour, brush)  -- brush colour, style
!       
!       left = left + rectangle_size
!     end -- for each character
!         
    end -- for each style run                 
  
  end -- Display_Styled_Line
***************
*** 259,266 ****
    for _, v in ipairs (map [1]) do
      columns = columns + v.length
    end -- for
!   local window_width = columns * font_width + 10
!   local window_height =  lines * font_height + 15
     -- recreate the window the correct size
     WindowCreate (win, 
                   windowinfo.window_left, 
--- 282,289 ----
    for _, v in ipairs (map [1]) do
      columns = columns + v.length
    end -- for
!   local window_width = columns * rectangle_size + 10
!   local window_height =  lines * rectangle_size + 15 + (font_height * 2)
     -- recreate the window the correct size
     WindowCreate (win, 
                   windowinfo.window_left, 
***************
*** 287,294 ****
      end
    end -- for
    
!   local our_location_x = (x - 1) * font_width + (font_width / 2) + 5
!   local our_location_y = (y) * font_height + (font_height / 2) + 5
    
    -- draw circle around us
    WindowCircleOp (win, 1, 
--- 310,317 ----
      end
    end -- for
    
!   local our_location_x = (x - 1) * rectangle_size + (rectangle_size / 2) + 5
!   local our_location_y = (y) * rectangle_size + (rectangle_size / 2) + 15
    
    -- draw circle around us
    WindowCircleOp (win, 1, 
***************
*** 312,318 ****
    local coords = string.format ("Location: %2i, %2i", origx, origy)
    local coordswidth = WindowTextWidth (win, font_id, coords)
    WindowText (win, font_id, coords, (window_width - coordswidth) / 2, 
!              (#map + 1) * font_height + 5, 0, 0, zone_name_colour)  -- title
    
    Display_Line (#map + 1, coords, font_id, 0x000000)
   
--- 335,341 ----
    local coords = string.format ("Location: %2i, %2i", origx, origy)
    local coordswidth = WindowTextWidth (win, font_id, coords)
    WindowText (win, font_id, coords, (window_width - coordswidth) / 2, 
!              window_height - font_height - 10, 0, 0, zone_name_colour)  -- title
    
    Display_Line (#map + 1, coords, font_id, 0x000000)
   



Basically, Display_Styled_Line was rewritten, and a couple of spots that worked out window size based on the font size used the rectangle size instead.
Australia Forum Administrator #7

The new look is growing on me. ;)

Compare these two different views of the same place:

USA #8
Very cool. :)

But...


+ brushes = {
+   ["~"] = 11,
+   ["?"] = 9,
+   ["^"] = 12,
+   ["."] = 5,
+   }
...
!       local brush = brushes [char] or 8
!       local backcolour = 0x000000
!       if brush == 0 then 
!         backcolour = v.textcolour
!       end -- if 


brush will never equal 0. If it's not in the table, it's 8. So why test for it?

Australia Forum Administrator #9
lol

Yes, true. But when I was testing, I tried brush 0 for some terrain types. However for brush 0 the background colour needs to change, not the foreground colour, hence that line of code.

So, if you tweak it, and use brush 0, it will work. :)
#10
That looks great and frees up screen space.
Australia Forum Administrator #11

Thanks! And if you want to take even less space, drop down the rectangle size in the code. The example below reduced from 8 x 8 to 6 x 6 pixels:

Australia Forum Administrator #12
I experimented with a custom image for the zone entrance, to see how well that went. The creation was here (after creating the map window):


 WindowCreateImage (win, "zone",
        tonumber ("00011000", 2),  -- row 8
        tonumber ("00111100", 2),  -- row 7
        tonumber ("01000010", 2),  -- row 6
        tonumber ("10011001", 2),  -- row 5
        tonumber ("10011001", 2),  -- row 4
        tonumber ("01000010", 2),  -- row 3
        tonumber ("00111100", 2),  -- row 2
        tonumber ("00011000", 2))  -- row 1


And now Display_Styled_Line looks like this:


brushes = {
  ["~"] = 11,
  ["?"] = 9,
  ["^"] = 12,
  ["."] = 5,
  }
  
function Display_Styled_Line (line, styles, id)

local left = 5
local top = (line - 1) * rectangle_size + 15

  for _, v in ipairs (styles) do
    
    for i = 1, #v.text do
      local char = string.sub (v.text, i, i)
      local brush = brushes [char] or 8
      local backcolour = background_colour
      if brush == 0 then 
        backcolour = v.textcolour
      end -- if 
      WindowCircleOp(win, 2, left, top, left + rectangle_size, top + rectangle_size,
                    v.textcolour, 5, 0,   -- pen colour, null pen, pen width
                    backcolour, brush)  -- brush colour, style
                    
      -- special image for the zone entrance
      if char == "?" then
        WindowDrawImage (win, "zone", left, top, left + rectangle_size, top + rectangle_size, 2)
      end -- if

      left = left + rectangle_size
    end -- for each character
        
  end -- for each style run                 

end -- Display_Styled_Line

Australia Forum Administrator #13

With this result (the zone entrances are the things that look like circles with a dot in the middle):

USA #14
That looks great!
Australia Forum Administrator #15
OK, the improved bigmap plugin is below...

Template:saveplugin=Aardwolf_BigMap_Graphical
To save and install the Aardwolf_BigMap_Graphical plugin do this:
  1. Copy the code below (in the code box) to the Clipboard
  2. Open a text editor (such as Notepad) and paste the plugin code into it
  3. Save to disk on your PC, preferably in your plugins directory, as Aardwolf_BigMap_Graphical.xml
    • The "plugins" directory is usually under the "worlds" directory inside where you installed MUSHclient.
  4. Go to the MUSHclient File menu -> Plugins
  5. Click "Add"
  6. Choose the file Aardwolf_BigMap_Graphical.xml (which you just saved in step 3) as a plugin
  7. Click "Close"
  8. Save your world file, so that the plugin loads next time you open it.




<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE muclient>
<!-- Saved on Saturday, June 30, 2007, 10:48  -->
<!-- MuClient version 4.13 -->

<muclient>
<plugin
   name="Aardwolf_BigMap_Graphical"
   author="Nick Gammon"
   id="07a562eee63e9577db747e32"
   language="Lua"
   purpose="Redirects Aardwolf bigmap messages to a miniwindow"
   date_written="2009-07-26"
   date_modified="2009-07-29"
   requires="4.42"
   version="1.3"
   save_state="y"
   >
<description trim="y">
Redirects the bigmap to a miniwindow.

Commands:

bigmap remove map cache  --> removes the cache, forcing maps to be downloaded
                               (only do this after a major continent upgrade)
                      
bigmap auto              --> toggle auto-minimize map
bigmap auto on           --> auto-hide map when you enter an area
bigmap auto off          --> manually hide map
bigmap on                --> show the map
bigmap off               --> hide the map

</description>

</plugin>

<!--  Triggers  -->

<triggers>

  <trigger
   enabled="y"
   match="^\{bigmap\}(?<zone>\d+)\,(?<zonename>.+)$"
   script="map_redirect"
   omit_from_output="y"
   name="map_start"
   sequence="100"
   regexp="y"
  >
  </trigger>
 
  <trigger
   enabled="n"
   match="*"
   script="map_redirect"
   name="multi_line_map"
   omit_from_output="y"
   sequence="10"
  >
  </trigger>

  <trigger
   enabled="y"
   match="^\{coords\}(?<zone>\d+)\,(?<x>\d+)\,(?<y>\d+)$"
   omit_from_output="y"
   regexp="y"
   script="updatelocation"
   sequence="100"
  >
  </trigger>
  

 <trigger
   enabled="y"
   match="{coords}-1"
   omit_from_output="y"
   sequence="100"
   send_to="14"
   script="in_zone"
  >
  </trigger>

</triggers>

<aliases>

  <alias
   name="remove_alias"
   script="remove_cache"
   match="bigmap remove map cache"
   enabled="y"
   sequence="100"
   ignore_case="y"
  >
  </alias>
  
 <alias
   script="auto_minimize_alias"
   match="^bigmap auto( on| off)?$"
   enabled="y"
   regexp="y"
   sequence="100"
   ignore_case="y"
  >
  </alias>
    
<alias
   script="map_on_off_alias"
   match="^bigmap( on| off)?$"
   enabled="y"
   regexp="y"
   sequence="100"
   ignore_case="y"
  >
  </alias>
    
</aliases>


<!--  Script  -->


<script>
<![CDATA[
folder = "Aardwolf"

require "serialize"  -- needed to serialize table to string
require "checkplugin"
require "movewindow"

map = {}
continents = {}
xref = {}
auto_minimize = true
show_map = true
background_colour = 0x000028
title_colour = 0x696969
zone_name_colour = ColourNameToRGB "yellow"
rectangle_size = 8
        
function remove_cache ()
  continents = {}
  xref = {}
  ColourNote ("white", "blue", "Big maps removed from cache.")
end -- remove_cache

function auto_minimize_alias (name, line, wildcards)
  if wildcards [1] == false then
    auto_minimize = not auto_minimize
  elseif wildcards [1]:lower () == " on" then
    auto_minimize = true
  elseif wildcards [1]:lower () == " off" then
    auto_minimize = false
  end -- if
  
  if auto_minimize then
    ColourNote ("yellow", "", "Bigmap auto-hide enabled.")
  else
    ColourNote ("yellow", "", "Bigmap auto-hide DISABLED.")
  end -- if  
    
end -- auto_minimize_alias

function map_on_off_alias (name, line, wildcards)
  if wildcards [1] == false then
    show_map = not show_map
  elseif wildcards [1]:lower () == " on" then
    show_map = true
  elseif wildcards [1]:lower () == " off" then
    show_map = false
  end -- if
  
  if show_map then
    ColourNote ("yellow", "", "Bigmap enabled.")
    if map and #map > 0 then
      WindowShow (win, true)
    end -- showing
  else
    ColourNote ("yellow", "", "Bigmap DISABLED - type 'bigmap' to re-enable.")
    WindowShow (win, false)
  end -- if  
    
end -- auto_minimize_alias


function in_zone (name, line, wildcards)
  if auto_minimize then
     WindowShow (win, false)
  end -- if
end -- in_zone

brushes = {
  ["~"] = 11,
  ["?"] = 9,
  ["^"] = 12,
  ["."] = 5,
  }
  
function Display_Styled_Line (line, styles, id)

local left = 5
local top = (line - 1) * rectangle_size + 15

  for _, v in ipairs (styles) do
    
    for i = 1, #v.text do
      local char = string.sub (v.text, i, i)
      local brush = brushes [char] or 8

      local forecolour = v.textcolour
      local backcolour = background_colour

      if brush == 0 then 
        backcolour = v.textcolour
      end -- if 
      if char == " " then
        forecolour = background_colour -- invisible
       end -- if

      WindowCircleOp(win, 2, left, top, left + rectangle_size, top + rectangle_size,
                    forecolour, 5, 0,   -- pen colour, null pen, pen width
                    backcolour, brush)  -- brush colour, style
                    
      -- special image for the zone entrance
      if char == "?" then
        WindowDrawImage (win, "zone", left, top, left + rectangle_size, top + rectangle_size, 2)
      end -- if
      left = left + rectangle_size
    end -- for each character
        
  end -- for each style run                 

end -- Display_Styled_Line

function Display_Line (line, text, id, colour)

local left = 5
local top = (line - 1) * font_height

  WindowText (win, id, text, left, top, 0, 0, colour)

end -- Display_Line

function DrawMap (x, y)

  local origx, origy = x, y
  x = x + 1  -- allow for border, make 1-relative
  y = y + 1  -- ditto
  
  if not map or #map == 0 then
    return
  end -- no map
   
  local lines = #map + 2
  local columns = 0
  for _, v in ipairs (map [1]) do
    columns = columns + v.length
  end -- for
  local window_width = columns * rectangle_size + 10
  local window_height =  lines * rectangle_size + 10 + (font_height * 2)
   -- recreate the window the correct size
   WindowCreate (win, 
                 windowinfo.window_left, 
                 windowinfo.window_top, 
                 window_width,     -- width
                 window_height,  -- height
                 windowinfo.window_mode,   
                 windowinfo.window_flags,
                 background_colour) 
  
   WindowDeleteAllHotspots (win)
   movewindow.add_drag_handler (win, 0, 0, 0, font_height, 1)
   
  local name = continent or ""
  local namewidth = WindowTextWidth (win, font_id, name)
  WindowText (win, font_id, name, (window_width - namewidth) / 2, 5, 0, 0, zone_name_colour)  -- title
  
  
  for i, v in ipairs (map) do
    Display_Styled_Line (i + 1, v, font_id)
  end -- for
  
  local our_location_x = (x - 1) * rectangle_size + (rectangle_size / 2) + 5
  local our_location_y = (y) * rectangle_size + (rectangle_size / 2) + 15
  
  -- draw circle around us
  WindowCircleOp (win, 1, 
                  our_location_x - 20, our_location_y - 20,
                  our_location_x + 20, our_location_y + 20,
                  ColourNameToRGB "cornflowerblue",  -- pen colour
                  0, -- solid pen
                  3, -- pen width
                  0, -- brush colour
                  1 ) -- null brush
                  
  WindowCircleOp (win, 1, 
                  our_location_x - 20, our_location_y - 20,
                  our_location_x + 20, our_location_y + 20,
                  ColourNameToRGB "cyan",  -- pen colour
                  0, -- solid pen
                  1, -- pen width
                  0, -- brush colour
                  1 ) -- null brush

 -- draw circle around us

  WindowCircleOp (win, 1, 
                  our_location_x - 8, our_location_y - 8,
                  our_location_x + 8, our_location_y + 8,
                  ColourNameToRGB "cornflowerblue",  -- pen colour
                  0, -- solid pen
                  3, -- pen width
                  0, -- brush colour
                  1 ) -- null brush
                    
  WindowCircleOp (win, 1, 
                  our_location_x - 8, our_location_y - 8,
                  our_location_x + 8, our_location_y + 8,
                  ColourNameToRGB "cyan",  -- pen colour
                  0, -- solid pen
                  1, -- pen width
                  0, -- brush colour
                  1 ) -- null brush
                  
  local coords = string.format ("Location: %2i, %2i", origx, origy)
  local coordswidth = WindowTextWidth (win, font_id, coords)
  WindowText (win, font_id, coords, (window_width - coordswidth) / 2, 
             window_height - font_height - 10, 0, 0, zone_name_colour)  -- title
  
  Display_Line (#map + 1, coords, font_id, 0x000000)
 
  -- DrawEdge rectangle
  WindowRectOp (win, 5, 0, 0, 0, 0, 10, 15)
  
 if show_map then
    WindowShow (win, true)
    Repaint ()
  end -- if

end -- DrawMap

function updatelocation (name, line, wildcards)
  -- where we are
  x = tonumber (wildcards.x) 
  y = tonumber (wildcards.y)
  zone = tonumber (wildcards.zone)
  
  -- changed continent?
  if old_zone ~= zone then
  
    -- grab cached map
    map = continents [zone]
    continent = xref [zone]
    
    -- no cached map? better get it
    if not map then
      SendNoEcho "bigmap noself" -- grab map
    end -- don't know this one
    old_zone = zone
  end -- need big map
  
  -- draw our location
  if map then
    DrawMap (x, y)
  end -- if
end -- updatelocation


-- map redirector
function map_redirect (name, line, wildcards, styles)

  EnableTrigger ("multi_line_map", true)  -- capture subsequent lines

  if name == "map_start" then
    map = {}  -- start new map
    continent = wildcards.zonename
    zone = tonumber (wildcards.zone)
    xref [zone] = wildcards.zonename
  elseif line == "{/bigmap}" then
    EnableTrigger ("multi_line_map", false)  -- no more lines to go
    
    table.remove (map, 1)  -- remove first line (the border) 
    map [#map] = nil  -- remove last line (the other border)
    
   for _, v in ipairs (map) do
      
      if v [1].text == "|" then
        table.remove (v, 1)
      elseif string.match (v [1].text, "^|") then
        v [1].text = string.sub (v [1].text, 2)
        v [1].length = #v [1].text
      end -- remove first border
      
     if v [#v].text == "" then
        v [#v] = nil
      end -- remove last border
      
      if v [#v].text == "|" then
        v [#v] = nil
      elseif string.match (v [#v].text, "|$") then
        v [#v].text = string.sub (v [#v].text, 1, -2)
        v [#v].length = #v [#v].text
      end -- remove last border
    
    end -- for
    
    if zone then
      continents [zone] = map  -- cache it
    end -- we know the continent
    
    DrawMap (x, y)
  else
    table.insert (map, styles)
  end -- if

  
end -- function map_redirect 

function OnPluginInstall ()
  assert (loadstring (GetVariable ("continents") or "")) ()
  assert (loadstring (GetVariable ("xref") or "")) ()
  auto_minimize = (GetVariable ("auto_minimize") or auto_minimize) == "true"

  win = GetPluginID ()

  local fonts = utils.getfontfamilies ()
  if fonts.Dina then
    font_size = 8
    font_name = "Dina"    -- the actual font
  else
    font_size = 10
    font_name = "Courier"
  end -- if
    
  font_id = "map_font"  -- our internal name
  font_id_bold = "map_font_bold"  -- our internal name

  windowinfo = movewindow.install (win, 6)
  
  -- make miniwindow so I can grab the font info
  check (WindowCreate (win, 
                 windowinfo.window_left, 
                 windowinfo.window_top, 
                 1, 1,  
                 windowinfo.window_mode,   
                 windowinfo.window_flags,
                 background_colour) )
  
  check (WindowFont (win, font_id, font_name, font_size, false, false, false, false, 0, 49))  -- normal
  font_height = WindowFontInfo (win, font_id, 1) -  WindowFontInfo (win, font_id, 4) + 1 -- height
  font_width = WindowFontInfo (win, font_id, 6)  -- avg width
  descent = WindowFontInfo (win, font_id, 3)
  
 WindowCreateImage (win, "zone",
        tonumber ("00011000", 2),  -- row 8
        tonumber ("00111100", 2),  -- row 7
        tonumber ("01000010", 2),  -- row 6
        tonumber ("10011001", 2),  -- row 5
        tonumber ("10011001", 2),  -- row 4
        tonumber ("01000010", 2),  -- row 3
        tonumber ("00111100", 2),  -- row 2
        tonumber ("00011000", 2))  -- row 1
          
  if GetVariable ("enabled") == "false" then
    ColourNote ("yellow", "", "Warning: Plugin " .. GetPluginName ().. " is currently disabled.")
    check (EnablePlugin(GetPluginID (), false))
    return
  end -- they didn't enable us last time
  
  OnPluginEnable ()  -- do initialization stuff
  
end -- OnPluginInstall

function OnPluginSaveState ()
  SetVariable ("continents", 
               "continents = " .. serialize.save_simple (continents))
               
  SetVariable ("xref", 
               "xref = " .. serialize.save_simple (xref))
               
  SetVariable ("enabled", tostring (GetPluginInfo (GetPluginID (), 17)))
  SetVariable ("auto_minimize", tostring (auto_minimize))
               
  movewindow.save_state (win)
  
end -- function OnPluginSaveState

-- pull in telnet option handling
dofile (GetPluginInfo (GetPluginID (), 20) .. "telnet_options.lua")

function OnPluginConnect ()
  TelnetOptionOn (TELOPT_BIGMAP)
end -- function OnPluginConnect

function OnPluginClose ()
  -- if enabled
  if GetPluginInfo (GetPluginID (), 17) then  
    TelnetOptionOff (TELOPT_BIGMAP)
  end -- currently enabled
end -- OnPluginClose

function OnPluginEnable ()

  -- if we are connected when the plugin loads, it must have been reloaded whilst playing
  if IsConnected () then
    OnPluginConnect ()
  end -- if already connected

end -- OnPluginEnable

function OnPluginDisable ()
  TelnetOptionOff (TELOPT_BIGMAP)

  WindowShow (win, false)
  
end -- OnPluginDisable

]]>
</script>
</muclient>



This version removes the yellow dot where the player is, and instead has more of a bulls-eye look to show the current location - that way you can see what you are on top of (eg. is it a zone entrance or not).

[EDIT] Amended on 4 August 2009 to fix bug where map would keep appearing as you moved around even if you had typed "bigmap off".

[EDIT] Amended on 6 August 2009 to fix bug in rendering spaces, particularly in Vidblain. Also fixed problem with the "|" at the edges not always being removed.
Amended on Wed 19 Aug 2009 05:52 AM by Nick Gammon
Australia Forum Administrator #16

It looks like this:

USA #17
Now that is sexy. Making it smaller may also make it more usable for those of us with less screen space. If only they let me bring in a spare monitor to work.
USA #18
Impressive work! It is very nice plugin to use. :)
Amended on Mon 03 Aug 2009 04:31 PM by Maxhrk
Australia Forum Administrator #19

I've been experimenting a bit with this plugin. It looks good so far, but I still like to know *what* is around me - just seeing a lot of zone entrances is kind-of unhelpful. Like, which zone is which? Where should I go to next? This enhancement attempts to address this issue.

What this is showing is:

  • If you mouse-over a zone entrance a tooltip window pops up telling you the zone name, level range, and minimum level requirement.
  • Zones within your area range have their names shown on the map, optionally. The reason for not showing all of them is that, first it is cluttered, and second, you don't care as much about zones outside your level range.
  • At the bottom of the map it shows which zone you are currently in.
  • Zone entrances are colour-coded, as follows:
    • Cyan - Zone name (and therefore, its information) is not known
    • Green - too low for your level
    • Yellow - appropriate for your level
    • Red - too high for your level
    • White - your level is not known - install the Stats plugin

It is hard to cram the information on the window without it looking a mess, even using a 6-point typeface. Still, I am reasonably pleased with the result. It gives a better idea of where to explore.

The information is kept in a SQLite database, so it can be shared between all characters you might have, more easily.


The image above shows the zones with the names toggled off - you can still see from the entrance colours which ones are appropriate for you, so you might mouse-over the yellow ones to work out which ones to explore.

Amended on Mon 03 Aug 2009 12:15 AM by Nick Gammon
#20
It looks better, but there is a problem. Typing bigmap to disable it so I can see my screen to read when I don't need my bigmap doesn't work how it was intended idt. Everytime I look or move the bigmap pops up taking up my screen again when it was suppose to be disabled. Then I have to enter bigmap twice to get it back off my screen, but it'll come back up if I move or look.
Australia Forum Administrator #21
Edit the plugin, and in it, near the end of function DrawMap (around line 325), change:


  -- DrawEdge rectangle
  WindowRectOp (win, 5, 0, 0, 0, 0, 10, 15)
  
  WindowShow (win, true)
  
  Repaint ()
end -- DrawMap


to:


  -- DrawEdge rectangle
  WindowRectOp (win, 5, 0, 0, 0, 0, 10, 15)
  
  if show_map then
    WindowShow (win, true)
    Repaint ()
  end -- if

end -- DrawMap



I amended the post at the top of this page to have the change in it.
Amended on Mon 03 Aug 2009 11:06 PM by Nick Gammon
USA #22
This is quite cool!

Only problem is that the brushes seem to bleed while on Vidblain for me. I haven't yet tried to debug it, so I'm not sure what the cause is.
Australia Forum Administrator #23
Doesn't look too bad to me. Can you post a screen shot somewhere?
USA #24
http://frostblade.net/aardwolf/vidblain.png
Australia Forum Administrator #25

It's not bleeding. Perhaps an optical illusion from the ragged edges. See your original:

And now part of it enlarged by zooming in:

The edges are crisp and regular.

USA #26
Oops. Maybe I mis-described the problem, or didn't describe it enough. Sorry about that.

I've now looked into this a little more, and I still think the bigmap isn't showing how it ideally should. For a good example of the problem, note the blue star of Ultima. In the actual bigmap, it's a single star. In the plugin, it's a blue bar. This happens with all objects in Vidblain though.

For a screen shot of the original bigmap, see
[img]http://frostblade.net/aardwolf/vidblain_actual.png[/img]

The cause of this is that the bigmap plugin bases the brush based on the text color. Aardwolf exploits the fact that a space character doesn't have any text to color, so all of the maps and bigmaps "color bleed" (or at least that's what we would call it in Aardwolf. I realize now that color bleeding means an entirely different thing in this real world!)

See this screen shot for an example-- it is just Vidblain highlighted to show the foreground colors:
[img]http://frostblade.net/aardwolf/vidblain_highlighted.png[/img]

A possible fix, I thought, would be to check to see if the character is a space, and if so, set the foreground color to be the background color of the bigmap.

The small code changes on approx. line 210 in function Display_Styled_Line:

      local forecolour = v.textcolour
      if brush == 0 then 
        backcolour = v.textcolour
      end -- if
      if char == " " then
        forecolour = background_colour -- invisible
       end -- if
      WindowCircleOp(win, 2, left, top, left + rectangle_size, top + rectangle_size,
                    forecolour, 5, 0,   -- pen colour, null pen, pen width
                    backcolour, brush)  -- brush colour, style


This makes things look much better-- see the following screenshot.

[img]http://frostblade.net/aardwolf/vidblain_better.png[/img]

It's now usable, but for some reason, there are several visual mistakes on Vidblain such as the vertical bar on the left and two squares that are cut off on the right. I haven't yet looked into those.

Edit: How do you get the images to show up in the post, Nick? Is that a moderator-only thing, or is it an undocumented forum code?
Amended on Wed 05 Aug 2009 11:33 PM by Artel
Australia Forum Administrator #27
I have incorporated your changes into my latest version of the plugin. I see your point about the space, however the plugin was just drawing a space in a textured way in the current colours, as you noticed. You might argue that Aardwolf is drawing a space "in the wrong colour". ;)

Incorporating images is a moderator-only thing.

As for the other anomalies, they are caused by the detection code for the "|" symbols. In the function map_redirect replace:


    for _, v in ipairs (map) do
      
      if v [1].text == "|" then
        table.remove (v, 1)
      end -- remove first border
      
     if v [#v].text == "" then
        v [#v] = nil
      end -- remove last border
      
      if v [#v].text == "|" then
        v [#v] = nil
      end -- remove last border
    
    end -- for


by:


   for _, v in ipairs (map) do
      
      if v [1].text == "|" then
        table.remove (v, 1)
      elseif string.match (v [1].text, "^|") then
        v [1].text = string.sub (v [1].text, 2)
        v [1].length = #v [1].text
      end -- remove first border
      
     if v [#v].text == "" then
        v [#v] = nil
      end -- remove last border
      
      if v [#v].text == "|" then
        v [#v] = nil
      elseif string.match (v [#v].text, "|$") then
        v [#v].text = string.sub (v [#v].text, 1, -2)
        v [#v].length = #v [#v].text
      end -- remove last border
    
    end -- for


This additional code handles the case of the "|" being in a style run with a space - which is what happens in this particular case. Then force the cache to be reloaded by typing:

bigmap remove map cache

Amended on Thu 06 Aug 2009 01:10 AM by Nick Gammon
Australia Forum Administrator #28

This is what Vidblain looks like now, for me:

I edited the plugin above to reflect these changes.

Amended on Thu 06 Aug 2009 12:44 AM by Nick Gammon
Australia Forum Administrator #29
The whole thing might look better if someone (hint) did graphics for every possible terrain type (like I did for the zone entrances) rather than relying on the built-in textures which are not entirely appropriate. Then stars could look like, well, stars.
#30
This plugin looks great but I can't seem to get the mouseovers or zone names to work at all. Are there options for this in game I just haven't found? Also the map never goes away when I enter an area regardless of the 'bigmap auto on/off' setting.

From a purely aesthetic perspective would it be possible to not have the dual targeting rings surrounding the player position? The near ring obscures the nearest surrounding tiles. Maybe instead of an inner ring just make the square the player is occupying currently stand out in a different manner. The outside ring is great.

Thank You

EDIT: The map is turning off/on properly now, mouseover/label issues remain.

EDIT 2: Well it only worked for a brief while and I cant get it to work again. I do not know if another plugin is messing with it or it is the plugin itself or simply user error.

If it helps, I am running the following plugins + AardMUSH client updated to 4.42:

Fiendish's Chat
Colored Consider Messages from here somewhere
Bast Spellups
Bast Quest Miniwindow
Bast Campaign Miniwindow
Blainers Inventory Miniwindow
Amended on Fri 07 Aug 2009 06:06 PM by Safiya
Australia Forum Administrator #31
Quote:

I can't seem to get the mouseovers or zone names to work at all


That is an experimental version I haven't released yet. It isn't supposed to work in your version. I am having some technical difficulties, for example in Vidblain all the zones are called the same thing. Also some zones are inside others (eg. the Academy is inside Aylor).


I cant get it to work again.


Maybe you toggled it off? If you type "bigmap" on its own it turns the map off permanently, until you type it again. Also check the plugin is enabled in the plugins list.

Quote:

... would it be possible to not have the dual targeting rings surrounding the player position?


Sure, anything is possible. In the plugin are four sets of lines like this:


-- draw circle around us
  WindowCircleOp (win, 1, 
                  our_location_x - 20, our_location_y - 20,
                  our_location_x + 20, our_location_y + 20,
                  ColourNameToRGB "cornflowerblue",  -- pen colour
                  0, -- solid pen
                  3, -- pen width
                  0, -- brush colour
                  1 ) -- null brush


The first two do the outer ring, which is a 3-pixel wide "cornflowerblue" ring, with a 1-pixel wide "cyan" ring in the middle of it. This is drawn 20 pixels out from where you are (see the + / - 20 above).

The second two do the inner ring, which is 8 pixels from where you are.

To get rid of one of the rings delete the appropriate batch of lines. To change the diameter change the "20" or the "8" to some other number.

You could make the rings narrower by changing the "3" (pen width) above to 2 or 1.
#32
Ok, thank you for the response and the info. I saw the screenshot with mouseovers and started drooling :P

As to the bigmap not hiding when it should, it varies from zone to zone it seems. For example I can go to Nulan or Flying Citadel and the BigMap always vanishes as it should and reappears when I leave. many other areas however, it does not go away.

I'll fiddle around with it s'more and try to note when it works and when it does not, maybe it'll be useful.

Australia Forum Administrator #33
Ah, I noticed that a bit too - the auto hide doesn't always work. Here's why ...

When you are "at large" on the big map, the server sends your coordinates, which are what you see at the bottom of the map, like this:


{coords}2,45,22


This means you are at 45,22 in zone 2.

When you enter a zone it sometimes sends:


{coords}-1


When the plugin sees that it hides the map. However some zones (eg. Aylor) don't send either. Thus, the map stays visible. I think, for example, in the Academy it sends "{coords}-1" so the big map disappears when you enter that.

I just made a macro key F5 which sends "bigmap" which toggles the map on and off, and hit F5 when I want to show/hide the map.