<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE muclient>
<!-- Saved on Sunday, May 24, 2015, 2:52 PM -->
<!-- MuClient version 4.98 -->

<!-- Plugin "Galabans_Partroxis_Plugin" generated by Galaban the XML Wizard -->

<!--
A Partroxis maze assistant with auto-hunt and guides for walking through the maze
-->

<muclient>
<plugin
   name="Galabans_Partroxis_Plugin"
   author="Galaban"
   id="b8cffcaabbf1abc78475946b"
   language="Lua"
   purpose="A simple maze solver for the Partroxis maze"
   save_state="y"
   date_written="2015-05-24 14:48:35"
   requires="4.98"
   version="1.0"
   >
<description trim="y">
<![CDATA[
This is Galaban's Partroxis plugin.

While in the Partroxis maze, it will show you the next exit to take. 
When a wrong direction is chosen, you can get a speedwalk back to the farthest room.
Also, an autohunt feature allows you to go directly to a mob within the maze.
]]>
</description>

</plugin>

<include name="constants.lua"/>


<aliases>

<alias
   match="partroxis return"
   enabled="y"
   script="partroxis_return"
   sequence="100">
</alias>

<alias
   match="partroxis reset"
   enabled="y"
   script="partroxis_reset_data"
   sequence="100">
</alias>

<alias
   match="partroxis help"
   enabled="y"
   script="partroxis_show_help"
   sequence="100">
</alias>

<alias
   match="partroxis listdata"
   enabled="y"
   script="partroxis_list_data"
   sequence="100">
</alias>

<alias
   match="partroxis guide"
   enabled="y"
   script="partroxis_alias_guides"
   sequence="100">
</alias>

<alias
   match="partroxis autohunt *"
   enabled="n"
   script="partroxis_mob_hunt"
   sequence="100">
</alias>

<alias
   match="partroxis autohunt"
   enabled="y"
   script="partroxis_mob_stophunt"
   sequence="100">
</alias>

<alias
   match="partroxis runto *"
   enabled="n"
   send_to="12"
   sequence="100">
  <send>
     partroxis_room_hunt("%1")
  </send>
</alias>

<alias
   match="partroxis runto"
   enabled="y"
   script="partroxis_room_stophunt"
   sequence="100">
</alias>


<alias
   match="partroxis off"
   enabled="y"
   script="partroxis_off"
   sequence="100">
</alias>

<alias
   match="partroxis debug"
   enabled="y"
   script="partroxis_set_debug"
   sequence="100">
</alias>

<alias
   match="partroxis showexits"
   enabled="n"
   group="partroxis_debug_aliases"
   script="show_partroxis_exits"
   sequence="100">
</alias>

<alias
   match="partroxis data"
   enabled="n"
   group="partroxis_debug_aliases"
   script="show_partroxis_debug_data"
   sequence="100">
</alias>

<alias
   match="partroxis printmap"
   enabled="n"
   group="partroxis_debug_aliases"
   script="show_partroxis_debug_printmap"
   sequence="100">
</alias>


<alias
   match="^(e|ea|eas|east)$"
   enabled="n"
   group="partroxis_movement"
   regexp="y"
   send_to="12"
   sequence="100"
  >
  <send>
    last_direction = "e"
    Send("east")
  </send>
</alias>

  <alias
   match="^(w|we|wes|west)$"
   enabled="n"
   group="partroxis_movement"
   regexp="y"
   send_to="12"
   sequence="100"
  >
  <send>
    last_direction = "w"
    Send("west")
  </send>
  </alias>

  <alias
   match="^(n|no|nor|north)$"
   enabled="n"
   group="partroxis_movement"
   regexp="y"
   send_to="12"
   sequence="100"
  >
  <send>
    last_direction = "n"
    Send("north")
  </send>
  </alias>

  <alias
   match="^(s|so|sou|south)$"
   enabled="n"
   group="partroxis_movement"
   regexp="y"
   send_to="12"
   sequence="100"
  >
  <send>
    last_direction = "s"
    Send("south")
  </send>
  </alias>

  <alias
   match="^(u|up)$"
   enabled="n"
   group="partroxis_movement"
   regexp="y"
   send_to="12"
   sequence="100"
  >
  <send>
    last_direction = "u"
    Send("up")
  </send>
  </alias>

  <alias
   match="^(d|do|dow|down)$"
   enabled="n"
   group="partroxis_movement"
   regexp="y"
   send_to="12"
   sequence="100"
  >
  <send>
    last_direction = "d"
    Send("down")
  </send>
  </alias>

</aliases>


<triggers>

  <trigger
   enabled="n"
   group="partroxis_area_triggers"
   match="The Partroxis has opened yet again."
   send_to="12"
   sequence="100"
  >
  <send>
    partroxis_area_reset()
  </send>
  </trigger>

  <trigger
   enabled="n"
   group="partroxis_area_triggers"
   match="You receive * experience points."
   send_to="12"
   sequence="100"
  >
  <send>
    partroxis_invis_reminder()
  </send>
  </trigger>

  <trigger
   enabled="n"
   group="partroxis_exit_triggers"
   match="Obvious exits from [*"
   name="PartroxisExitTrigger1"
   send_to="12"
   sequence="100"
  >
  <send>
    reset_curr_room_exits()
    DoAfterSpecial(0.1,"partroxis_exit_complete()",sendto.script)
  </send>
  </trigger>

  <trigger
   enabled="n"
   expand_variables="y"
   group="partroxis_exit_triggers"
   match="^ North          \: (.*?)$"
   name="PartroxisExitTrigger2"
   regexp="y"
   send_to="12"
   sequence="100"
  >
  <send>
     if ("%1" == "Too dark to see.") then
        partroxis_needs_nightvision()
     end
     if(curr_room ~= nil) then
         curr_room.exits.n = Trim("%1")
     end
  </send>
  </trigger>

  <trigger
   enabled="n"
   expand_variables="y"
   group="partroxis_exit_triggers"
   match="^ East           \: (.*?)$"
   name="PartroxisExitTrigger3"
   regexp="y"
   send_to="12"
   sequence="100"
  >
  <send>
     if ("%1" == "Too dark to see.") then
        partroxis_needs_nightvision()
     end
     if(curr_room ~= nil) then
         curr_room.exits.e = Trim("%1")
     end
  </send>
  </trigger>

  <trigger
   enabled="n"
   expand_variables="y"
   group="partroxis_exit_triggers"
   match="^ South          \: (.*?)$"
   name="PartroxisExitTrigger4"
   regexp="y"
   send_to="12"
   sequence="100"
  >
  <send>
     if ("%1" == "Too dark to see.") then
        partroxis_needs_nightvision()
     end
     if(curr_room ~= nil) then
         curr_room.exits.s = Trim("%1")
     end
  </send>
  </trigger>

  <trigger
   enabled="n"
   expand_variables="y"
   group="partroxis_exit_triggers"
   match="^ West           \: (.*?)$"
   name="PartroxisExitTrigger5"
   regexp="y"
   send_to="12"
   sequence="100"
  >
  <send>
     if ("%1" == "Too dark to see.") then
        partroxis_needs_nightvision()
     end
     if(curr_room ~= nil) then
         curr_room.exits.w = Trim("%1")
     end
  </send>
  </trigger>

  <trigger
   enabled="n"
   expand_variables="y"
   group="partroxis_exit_triggers"
   match="^ Up             \: (.*?)$"
   name="PartroxisExitTrigger6"
   regexp="y"
   send_to="12"
   sequence="100"
  >
  <send>
     if ("%1" == "Too dark to see.") then
        partroxis_needs_nightvision()
     end
     if(curr_room ~= nil) then
         curr_room.exits.u = Trim("%1")
     end
  </send>
  </trigger>

  <trigger
   enabled="n"
   expand_variables="y"
   group="partroxis_exit_triggers"
   match="^ Down           \: (.*?)$"
   name="PartroxisExitTrigger7"
   regexp="y"
   send_to="12"
   sequence="100"
  >
  <send>
     if ("%1" == "Too dark to see.") then
        partroxis_needs_nightvision()
     end
     if(curr_room ~= nil) then
         curr_room.exits.d = Trim("%1")
     end
  </send>
  </trigger>




</triggers>


<!--  Script  -->

<script>
<![CDATA[

require "gmcphelper"
require "wait"


-------------
-- GMCP Items
-------------
player_state = 3 -- "You presume too much"
function OnPluginBroadcast (msg, id, name, text)
   if id == "3e7dedbe37e44942dd46d264" then -- gmcphandler
      if performing_maintenance == true then
         queue_broadcast(msg, id, name, text)
         return
      end

      if (text == "room.info") then
         blinded = false
         res, gmcparg = CallPlugin("3e7dedbe37e44942dd46d264","gmcpval","room.info")
         luastmt = "gmcpdata = " .. gmcparg
         assert (loadstring (luastmt or "")) ()

         got_gmcp_room()
      end 

      if (text == "char.status") then
         res, gmcparg = CallPlugin("3e7dedbe37e44942dd46d264","gmcpval","char.status")
         luastmt = "gmcpdata = " .. gmcparg
         assert (loadstring (luastmt or "")) ()
         player_state = tonumber(gmcpdata.state)
      end 

   end --if gmcphandler
end

function got_gmcp_room()
    local room_id = gmcpval("num")

    if (curr_room ~= nil) then
        lastroom = {
            id = curr_room.id,
            exits = {},
            correct_dir = "",
            next_id = -1,
            wrong_dir1 = "",  -- these are set after the fact
            wrong_dir2 = "",
            temp_wrong_dir1 = "",  -- these are only set by "scan"
            temp_wrong_dir2 = "",
            pet = curr_room.pet
        }
        lastroom.exits.n = curr_room.exits.n
        lastroom.exits.e = curr_room.exits.e
        lastroom.exits.s = curr_room.exits.s
        lastroom.exits.w = curr_room.exits.w
        lastroom.exits.u = curr_room.exits.u
        lastroom.exits.d = curr_room.exits.d
    end
    curr_room = {
        id = tonumber(room_id),
        exits = {},
        correct_dir = "",
        next_id = -1,
        wrong_dir1 = "",
        wrong_dir2 = "",
        temp_wrong_dir1 = "",
        temp_wrong_dir2 = "",
        pet = ""
    }
    
    partroxis_room_entered()
end

function reset_curr_room_exits()
    if (curr_room == nil) then
        return
    end
    curr_room.exits.n = ""
    curr_room.exits.e = ""
    curr_room.exits.s = ""
    curr_room.exits.w = ""
    curr_room.exits.u = ""
    curr_room.exits.d = ""
end

-----------------
-- Alias Handlers
-----------------
function partroxis_mob_hunt(rName, rLine, rWildcards)
    local c_grey = ANSI(22)..ANSI(37)

    if (curr_room == nil or curr_room.id < 5763 or curr_room.id > 5862) then
        AnsiNote(c_grey.."Galaban whispers 'It looks like you're not in the maze.'")   
        return
    end

    local regx = "^(?<mob>.{30}) (?<room>.+)$"

    -- one-shot "where" triggers
    AddTriggerEx("tempTrgMapFindTrigger1", regx, "",  
         trigger_flag.Enabled + trigger_flag.OneShot + trigger_flag.RegularExpression, 
         -1, 0, "", "partroxis_where_match", sendto.script, 100)

    AddTriggerEx("tempTrgMapFindTrigger2", "There is no * around here.", "",  
         trigger_flag.Enabled + trigger_flag.OneShot, 
         -1, 0, "", "partroxis_where_nomatch", sendto.script, 100)

    Execute("where "..rWildcards[1])

end

function partroxis_mob_stophunt()
    local c_green = ANSI(1)..ANSI(32)
    local c_grey = ANSI(22)..ANSI(37)

    if(auto_hunt) then
        auto_hunt_set_off()
        Note("Turning off Auto-hunt")
    else
        AnsiNote(c_grey.."The imms have made it clear that a plugin that runs directly to a room is considered 'botting'.")
        AnsiNote(c_grey.."Auto-hunt is disabled.")
    end
end

function partroxis_room_stophunt()
    local c_green = ANSI(1)..ANSI(32)
    local c_grey = ANSI(22)..ANSI(37)

    if(auto_hunt) then
        auto_hunt_set_off()
        Note("Turning off runto")
    else
        AnsiNote(c_grey.."The imms have made it clear that a plugin that runs directly to a room is considered 'botting'.")
        AnsiNote(c_grey.."Runto is disabled.")
    end
end

function partroxis_room_hunt(inval)
    local c_grey = ANSI(22)..ANSI(37)

    if (curr_room == nil or curr_room.id < 5763 or curr_room.id > 5862) then
        AnsiNote(c_grey.."Galaban whispers 'You need to be in the maze to do that.'")   
        return
    end
    
    local room_num = tonumber(inval)
    if (room_num == nil) then
        AnsiNote(c_grey.."Galaban whispers 'To run to a room id, use '"..c_green.."partroxis runto <roomid>"..c_grey.."'")   
        return
    end

    if(room_num <= 5763 or room_num > 5803) then
        AnsiNote(c_grey.."Galaban whispers 'The room you're trying to runto is outside of the maze.'")   
        AnsiNote(c_grey.."Galaban whispers 'Try a number between 5763 and 5803.'")   
        return
    end

    if (room_mob_list == nil) then
        initialize()
    end

    local lookup = room_mob_list[room_num]
    if (lookup == nil) then
        AnsiNote(c_grey.."Galaban whispers 'I can't seem to find that room, oddly.'")   
        return
    end

    full_target_name = lookup.mob
    target_room = lookup.name
    target_room_id = room_num

    partroxis_start_autohunt()
end


isrunning = false;

function partroxis_return()
    local c_grey = ANSI(22)..ANSI(37)

    if (curr_room == nil or curr_room.id < 5763 or curr_room.id > 5812) then
        AnsiNote(c_grey.."Galaban whispers 'It looks like you're not in the maze.'")   
        return
    end

    local runstr = "run "
    local curr_id = curr_room.id
    while(curr_id > 0) do
        local room = rooms[curr_id]
        if (room == nil or room.correct_dir == nil or room.correct_dir == "") then
            curr_id = -1
        else
            local next_dir = ""..room.correct_dir
            if (next_dir == "enter gate") then
                runstr = runstr .. ";enter gate;run "
            else
                runstr = runstr .. next_dir
            end
            curr_id = room.next_id
        end
    end
    if (runstr == "run ") then
        if (auto_hunt == false) then
            local c_grey = ANSI(22)..ANSI(37)
            AnsiNote(c_grey.."Galaban whispers 'The maze has reset since you were last here. Just follow the guide.'")
            execute_correct_exit()
        end
        return
    end

    auto_exit_set_triggers()
    runstr = runstr..";exits"
    isrunning = true
    Execute (runstr)
end

function partroxis_reset_data()
    local c_grey = ANSI(22)..ANSI(37)

    if (curr_room == nil or curr_room.id < 5763 or curr_room.id > 5812) then
        AnsiNote(c_grey.."Galaban whispers 'It looks like you're not in the maze.'")   
        return
    end
    if (tablelength(rooms) == 0) then
        AnsiNote(c_grey.."Galaban whispers 'There's nothing to reset.'")
        return
    end
    AnsiNote(c_grey.."Galaban whispers 'I've reset everything the guides' memory. Sorry for the inconvenience.'")
    AnsiNote("")
    rooms = {}
end

function partroxis_alias_guides()
    local c_cyan = ANSI(1)..ANSI(36)
    local c_red = ANSI(1)..ANSI(31)
    local c_grey = ANSI(22)..ANSI(37)
    local c_green = ANSI(1)..ANSI(32)

    if (curr_room == nil or curr_room.id < 5763 or curr_room.id > 5812) then
        AnsiNote(c_grey.."Galaban whispers 'It looks like you're not in the maze.'")   
        return
    end

    if (show_partroxis_help == false) then
        AnsiNote("")
        AnsiNote(c_grey.."Galaban whispers 'Very well. The guides through the maze will assist you.'")
        if (curr_room.id > 5763) then
           AnsiNote(c_grey.."Galaban whispers 'Be aware that they haven't been paying attention so far.'")
           AnsiNote(c_grey.."Galaban whispers 'So they will not know all the directions that you've already tried.'")
        end
        Execute("")
        enable_partroxis_guides(true)
    else
        AnsiNote("")
        AnsiNote(c_grey.."Galaban whispers 'Very well. You are now on your own.'")
        if (curr_room.id > 5763) then
           AnsiNote(c_grey.."Galaban whispers 'Be aware that they will no longer pay attention to your movements.'")
           AnsiNote(c_grey.."Galaban whispers 'So they will not remember all your paths from here on out.'")
        end
        Execute("")
        enable_partroxis_guides(false)
    end

end

function partroxis_off()
    local c_grey = ANSI(22)..ANSI(37)

    -- KILL SWITCH. BOOM!
    AnsiNote(c_grey.."Partroxis plugin disabled")

    -- autohunt
    auto_hunt_set_off()

    -- guides
    enable_partroxis_guides(false)    
    
    -- debug
    partroxis_debug = false
    EnableAliasGroup("partroxis_debug_aliases", false)

end

function partroxis_show_help()

    local outstr = [[
Galaban's Partroxis Plugin

This plugin provides "guides" through the Partroxis maze.  When you enter a
room in the maze, the guide will provide the correct direction.  If multiple
directions exist, the guide will show you the two possibilities.  If you choose
wrong, the next time you enter the room, that exit will not be shown.

There is also a speedwalk function that will return you to the last correct
room in the maze:  "partroxis return"

   BY DEFAULT, these guides are not enabled. You will not receive any help.
Re-enter the area or use "partroxis guide" to turn the guides on.

Commands available:

partroxis help           -- this help screen
partroxis guide          -- Enable the maze guides

partroxis listdata       -- print out a list of the room/mob data
partroxis reset          -- reset the internal cache.
partroxis off            -- blanket disable for all plugin functionality
]]

    print(outstr)

    if (curr_room == nil or curr_room.id < 5763 or curr_room.id > 5812) then
        print("The plugin will feel like part of the area. Head to the Otherworld to see")
        print("for yourself.")
    end

end


-------------------------
-- (Debug) Alias Handlers 
-------------------------
partroxis_debug = false
function partroxis_set_debug()
   if (partroxis_debug == false) then
      Note("Setting Debug=True")
      partroxis_debug = true
      EnableAliasGroup("partroxis_debug_aliases", true)
   else
      Note("Setting Debug=False")
      partroxis_debug = false
      EnableAliasGroup("partroxis_debug_aliases", false)
   end
end

function show_partroxis_exits()

    if (curr_room == nil) then
        AnsiNote("Null room id?  Look around.")
        return
    end
    if (curr_room.id == -1) then
        AnsiNote("This room is no-map.")
        return
    end
    AnsiNote("--------------------")
    AnsiNote("North: "..curr_room.exits.n)
    AnsiNote("East:  "..curr_room.exits.e)
    AnsiNote("South: "..curr_room.exits.s)
    AnsiNote("West:  "..curr_room.exits.w)
    AnsiNote("Up:    "..curr_room.exits.u)
    AnsiNote("Down:  "..curr_room.exits.d)
    AnsiNote("--------------------")
end

function show_partroxis_debug_data()

    local pos_exit = ""
    if (possible_valid_exits ~= nil) then
        for i,k in pairs(possible_valid_exits) do
            pos_exit = pos_exit.." "..k
        end
    else
        pos_exit = "nil"
    end
    AnsiNote("------------------------------------")
    AnsiNote("show guides: "..printbool(show_partroxis_help))
    AnsiNote("auto-hunt: "..printbool(auto_hunt))
    AnsiNote("possible exits: "..pos_exit)
    AnsiNote("last_dir: ["..last_direction.."] ("..last_direction_prev..")")
    AnsiNote("rooms in cache: "..tablelength(rooms))
    if (lastroom == nil) then
        AnsiNote("last room: nil")
    else
        AnsiNote("last room: "..lastroom.id)
        if (rooms[lastroom.id] == nil) then
          AnsiNote("last room not in cache")
        end
        AnsiNote("last room dir: " .. lastroom.correct_dir .. "  leads to " .. lastroom.next_id)
        AnsiNote("last room wrong dir1: " .. lastroom.wrong_dir1 .. "   wrong dir2: " .. lastroom.wrong_dir2)
    
    end
    
    if (curr_room~= nil) then
        AnsiNote("current room: "..curr_room.id)
        if (rooms[curr_room.id] == nil) then
          AnsiNote("current room not in cache")
        end
        AnsiNote("current room correct dir: " .. curr_room.correct_dir .. "  leads to " .. curr_room.next_id)
        AnsiNote("current room wrong dir1: " .. curr_room.wrong_dir1 .. "   wrong dir2: " .. curr_room.wrong_dir2)
    end
    
    AnsiNote("------------------------------------")
    show_partroxis_exits()

end

function show_partroxis_debug_printmap()

    if (rooms == nil) then
        rooms = {}
    end
    AnsiNote("------------------------------------")
    AnsiNote("  ID    Good Exit     Bad Exits ")

    for i,iroom in pairs(rooms) do
        AnsiNote(iroom.id .."    "..iroom.correct_dir.." to "..iroom.next_id..
            "     wrong1["..iroom.wrong_dir1.."]  wrong2["..iroom.wrong_dir2.."]   pet["..iroom.pet.."]")
    end

    AnsiNote("------------------------------------")

end


-------------------
--  Auto-hunt stuff
-------------------
auto_hunt = false
full_target_name = ""
target_room = ""
target_room_id = -1


-- [AutoHunt] (Trigger callback)
-- Called when we have a "where <mob>" call that did find a mob
function partroxis_where_nomatch(rName, rLine, rWildcards)
    -- Remove the "found" trigger
    DeleteTrigger("tempTrgMapFindTrigger1")
    AnsiNote("Mob Not Found.  Try again.")
end


-- [AutoHunt] (Trigger callback)
-- Called when we have a "where <mob>" call that matched
function partroxis_where_match(rName, rLine, rWildcards)
    -- Remove the "not found" trigger
    DeleteTrigger("tempTrgMapFindTrigger2")

    -- 
    target_room = Trim(rWildcards.room)
    full_target_name = Trim(rWildcards.mob)

    if (room_mob_list == nil) then
        initialize()
    end

    -- Find the target mob in the list and get the room id
    target_room_id = -1
    for i,item in pairs(room_mob_list) do
        --Note("Comparing ["..item.name.."] to ["..target_room.."]")

        if(item.name == target_room) then
            if (string.lower(item.mob) == string.lower(full_target_name)) then
                target_room_id = i
                break
            elseif (string.len(item.mob) >= 28 and
                    string.startswith(item.mob, full_target_name)) then
                target_room_id = i
                break
            end
        end
    end

    if (target_room_id == -1) then
        Note("Mob-room combination not found.")
        return
    end

    partroxis_start_autohunt()

end


-- Initiates the auto-movement towards a target (autohunt/runto)
-- REQUIRES:  target_room_id, target_room, and target_mob to be set
function partroxis_start_autohunt()

    auto_hunt_set_on()
    enable_partroxis_guides(true)

    Note("Target Room ID: ".. target_room_id)

    -- get us to the maze... once we're there, the auto-hunt takes over.
    if (curr_room.id == 5862) then
        Execute("enter partroxis;enter partroxis;enter other;open n;n")
        return
    elseif (curr_room.id == 5814) then
        Execute("enter partroxis;enter other;open n;n")
        return
    elseif (curr_room.id == 5813) then
        Execute("enter other;open n;n")
        return
    elseif (curr_room.id == 5763) then
        Execute("open n;n")
        return
    else
        Execute("look")
    end
end

-------------------
--  Auto-scan stuff
-------------------

-- [Look evaluation]
-- Add triggers to see if there is a pet in this room
function check_room_for_pet()
    if (isrunning == true) then
        return
    end

    -- These rooms are the "false exits" for later rooms.  Check them for pets
    if (curr_room.id == 5766 or curr_room.id == 5769  or curr_room.id == 5772
        or curr_room.id == 5773  or curr_room.id == 5774 or curr_room.id == 5775
        or curr_room.id == 5779  or curr_room.id == 5788 or curr_room.id == 5797) then

        PartroxisDebugNote("Looking for pet...")

    else 
        return
    end

    AddTriggerEx("tempTrgPartroxPetCheck1", "(Charmed) *", "",  
         trigger_flag.Enabled + trigger_flag.OneShot, 
         -1, 0, "", "partroxis_pet_match_here", sendto.script, 100)

    AddTriggerEx("tempTrgPartroxPetCheck2", ".-.1", "",  
         trigger_flag.Enabled + trigger_flag.OneShot + trigger_flag.OmitFromOutput, 
         -1, 0, "", "partroxis_pet_match_complete", sendto.script, 100)

    -- just something unique to trigger the fact that we've looked through all the mobs in the room.
    PartroxisDebugSend("echo .-.1")

end

-- [Look evaluation]
-- Trigger callback: "look" matched a pet in this room
function partroxis_pet_match_here(rName, rLine, rWildcards)

    curr_room.pet = rWildcards[1]

    PartroxisDebugNote("Pet Found.  Saving to room map.")

end

-- [Look evaluation]
-- Trigger callback: "look" completed looking for a pet
function partroxis_pet_match_complete(rName, rLine, rWildcards)

    -- Delete this so it doesn't fire later
    DeleteTrigger("tempTrgPartroxPetCheck1")

end


-- (Bool) Returns whether we should perform the scanning for the pets
function should_scan_for_pet()

    -- Room X leads to false-exit Y  If they have a pet in those bad rooms (Y),
    -- let's go ahead and scan for it.

    local false_exit = get_false_exit_room_id(curr_room.id)
    if (false_exit == -1) then
        return false 
    end

    if (rooms[false_exit] ~= nil and rooms[false_exit].pet ~= "") then
        PartroxisDebugNote("Should scan for pet: yes")

        return true
    end
    PartroxisDebugNote("Should scan for pet: No.  False exit does not have pet")
    return false
end


-- Returns the room id of the false exit 
function get_false_exit_room_id(roomid)
    if(roomid == 5767) then
        return 5766
    elseif(roomid == 5775 or roomid == 5776 or roomid == 5787) then
        return 5772
    elseif(roomid == 5785) then
        return 5766
    elseif(roomid == 5789) then
        return 5788
    elseif(roomid == 5790) then
        return 5769
    elseif(roomid == 5793) then
        return 5774
    elseif(roomid == 5795) then
        return 5779
    elseif(roomid == 5796) then
        return 5797
    elseif(roomid == 5798) then
        return 5775
    elseif(roomid == 5800) then
        return 5773
    end
    return -1
end

-- (Asynch Callback) The initiator is: scan_for_pet
-- This is called after the scanning for the pet is complete
function partroxis_scan_for_pet_complete()

    -- We've looked at the exits,
    -- We've scanned for pets,
    -- Go ahead and find the correct exit and guide the player
    next_dir = find_partroxis_exit(next_room_name)

    guide_player(guide_name, next_dir)
end


tempScanTrigerPrefix = "tempPartTrigger_"

-- (Asynch Initiator) The callback is:  partroxis_scan_for_pet_complete()
-- Called when we need to perform the actual scanning
function scan_for_pet()
    PartroxisDebugNote("[enter]Scan for pets  ")

    scan_complete_called = false
    if (possible_valid_exits == nil or table.getn(possible_valid_exits) < 2) then
        if (possible_valid_exits == nil) then
            PartroxisDebugNote("Scan for pets called, possible exits is nil. Ignoring")
        else
            PartroxisDebugNote("Scan for pets called, but only "..table.getn(possible_valid_exits).." possible exits. Ignoring.")
        end
        scan_complete_called = true        --for completeness
        partroxis_scan_for_pet_complete()
        return
    end

    local have_valid_exit = false
    for i,dir in pairs(possible_valid_exits) do

        if (dir == nil) then
            PartroxisDebugNote("NIL Direction Found in possible directions")
        elseif (dir ~= "n" and dir ~= "s" and dir ~= "e" and dir ~= "w" and dir ~= "u" and dir ~= "d") then
            PartroxisDebugNote("Invalid Direction Found in possible directions:  ".. dir)
        else
            
            have_valid_exit = true
            local full_dir = translate_exit_to_readable(dir)

            -- Create the sequence of triggers
            create_pet_scan_sequence(full_dir)

            -- Then, fire off the scan in the correct direction, along with our echo.
            Execute("scan "..dir)
        end
    end

    PartroxisDebugSend("echo .-.as")

    
    if (have_valid_exit == false) then
         partroxis_scan_for_pet_complete()
    end
    
    -- Implementation Note:
    -- "pet_found_in_scanned_room()" will check if the "false exit" room has a pet
    -- If so, it will add that direction to the "bad_dir" list.
    -- Then do the auto-hunt. (eliminating the false exit)
end


-- Create the sequence of triggers for scanning in a given direction
function create_pet_scan_sequence(full_dir)
    local trigger_seq_name = tempScanTrigerPrefix..full_dir.."_"
    local trigger_text = full_dir.." from here you see:"
    
    --For each direction, add five triggers:
    --North from here you see:
    --2 North from here you see:
    --3 North from here you see:
    --Nothing to see around here, might as well move on. (Note: timing hole. don't use this one
    --a unique "echo" trigger to know that the scan is complete
    
    PartroxisDebugNote("Creating Scan Sequence ["..trigger_text.."]")

    AddTriggerEx(trigger_seq_name.."1", trigger_text, "",  
        trigger_flag.Enabled + trigger_flag.OneShot, 
        -1, 0, "", "auto_scan_found_direction", sendto.script, 100)

    AddTriggerEx(trigger_seq_name.."2", "2 "..trigger_text, "",  
        trigger_flag.Enabled + trigger_flag.OneShot, 
        -1, 0, "", "auto_scan_direction_complete", sendto.script, 100)
    AddTriggerEx(trigger_seq_name.."3", "3 "..trigger_text, "",  
        trigger_flag.Enabled + trigger_flag.OneShot, 
        -1, 0, "", "auto_scan_direction_complete", sendto.script, 100)
--    AddTriggerEx(trigger_seq_name.."4", "Nothing to see around here, might as well move on.", "",  
--        trigger_flag.Enabled + trigger_flag.OneShot, 
--        -1, 0, "", "auto_scan_direction_complete", sendto.script, 100)

    -- We know this one will trigger (and delete itself).
    AddTriggerEx(trigger_seq_name.."x", ".-.as", "",  
        trigger_flag.Enabled + trigger_flag.OneShot + trigger_flag.OmitFromOutput + trigger_flag.KeepEvaluating, 
        -1, 0, "", "auto_scan_matching_complete", sendto.script, 100)

end

function remove_pet_scan_sequence(callingTrigger)
    -- ugh:single quotes to allow for doubles
    DoAfterSpecial(0.1,'remove_pet_scan_sequence_async("'..callingTrigger..'")', sendto.script)
end

function remove_pet_scan_sequence_async(callingTrigger)
    local name = string.sub(callingTrigger,1,string.len(callingTrigger)-1)
    PartroxisDebugNote("Deleting Scan Sequence ["..name.."]")
    DeleteTrigger(name.."1")
    DeleteTrigger(name.."2")
    DeleteTrigger(name.."3")
    --DeleteTrigger(name.."4")
    DeleteTrigger(name.."5")
end


function auto_scan_found_direction(rName, rLine, rWildcards)
    local trigger_seq_name = string.sub(rName,1,string.len(rName)-1)

    AddTriggerEx(trigger_seq_name.."5", "     - (Charmed) *", "",  
        trigger_flag.Enabled + trigger_flag.OneShot, 
        -1, 0, "", "pet_found_in_scanned_room", sendto.script, 100)
end

function auto_scan_direction_complete(rName, rLine, rWildcards)
    remove_pet_scan_sequence(rName)
end

scan_complete_called = false
function auto_scan_matching_complete(rName, rLine, rWildcards)
    remove_pet_scan_sequence(rName)

    -- Let's pray that these aren't actually asynchronous!!
    -- Otherwise, we're going to have a juicy little timing hole right here:
    if (scan_complete_called == true) then
        return
    end
    scan_complete_called = true

    partroxis_scan_for_pet_complete()
end

function pet_found_in_scanned_room(rName, rLine, rWildcards)
    remove_pet_scan_sequence(rName)

    -- The direction of the scan will be in the trigger:
    local pref_len = string.len(tempScanTrigerPrefix)+1
    local dir = string.lower(string.sub(rName, pref_len, pref_len))
    local scanned_pet = rWildcards[1]
    PartroxisDebugNote("Found Pet for direction ["..dir.."]  Pet: ["..scanned_pet.."]")

    -- Sanity Check: make sure we have a false exit
    local false_exit = get_false_exit_room_id(curr_room.id)
    if (false_exit < 0) then
        return
    end


    --  When we enter a room, we look at the mob's LONG description;
        --A dust devil called icefall is sleeping here.
    -- When we scan, we look at it's short description:
        --A dust devil called icefall
    -- So, we can't match the names
    -- Add the direction to the "temporary" wrong direction so taht we'll try a different direction first.

    local false_exit_pet = rooms[false_exit].pet

    -- If there is a pet in the "false exit" room, check if it's this same pet
    -- If so, add this room as to the "wrong_dir" list
    --if (false_exit_pet == scanned_pet) then

    if (curr_room.temp_wrong_dir1 == "" or curr_room.temp_wrong_dir1 == dir) then
        curr_room.temp_wrong_dir1 = dir
    else
        curr_room.temp_wrong_dir2 = dir
    end
    PartroxisDebugNote("DEBUG: PET SCAN FOUND! Setting CURR room["..curr_room.id.."]  t_wrong_dir1["
          ..curr_room.temp_wrong_dir1.."]  t_wrongdir2["..curr_room.temp_wrong_dir2.."]")

    --  Note: The scan_for_pet_complete() should call the guide/autorun stuff.  So, we just have to
    --  set the bad direction and let everything else take its course
end


-------------------
-- Partroxis Events
-------------------
lastroom = nil
last_direction = ""
last_direction_prev = ""

function partroxis_room_entered()
    if (curr_room.id == nil) then
        --Not initialized?
        return
    end

    if (rooms == nil) then
        rooms = {}
    end

    reset_curr_room_exits()

    if (curr_room.id == 5862) then
        partroxis_area_entered()
    end
    if (curr_room.id == 5763) then
        greet()
    end
    if (curr_room.id == 5764) then
        partroxis_maze_entered()
    end

    --Above, we always want to fire.
    if(show_partroxis_help ~= nil and show_partroxis_help == false) then
       return
    end

    -- we were in the maze (show_help = true) and now we're not.
    -- The maze is 5763 to 5803.  
    -- 5812 is the exit. 5862/5813/5814 lead up to the maze
    -- Example:  Recall is 32418.  If we end up there, we will hit this
    if(curr_room.id < 5763 or curr_room.id > 5812) then
        if (curr_room.id ~= 5862 and curr_room.id ~= 5813 and curr_room.id ~= 5814) then
            partroxis_maze_exited()
        end
        return
    end

    -- Ok:  We are in the maze and we moved around
    -- Throw out a few triggers to look for pets
    check_room_for_pet()

    -- Check our last movement and see if it was correct
    check_last_exit_correct()

    -- If this is already in our map, just reload it and then call the "execute" function
    if (rooms[curr_room.id] ~= nil) then
        curr_room = rooms[curr_room.id]

        if (curr_room.correct_dir ~= "") then
            if (player_state == 3) then
                DoAfterSpecial(0.2,"execute_correct_exit()",12)
            end
            return
        end
        PartroxisDebugNote("Loaded room from map with no correct direction. Calling Auto-exits")
    end

    auto_exit()
end

function partroxis_bad_move()

    -- 5763 is the entrance room, 5803 is the exit room ignores those two
    if (curr_room.id <= 5763 or curr_room.id >= 5803) then
        return
    end

    -- if they're running, don't show this text.
    if (player_state > 8) then
        return
    end
   
    -- took a bad path.  Call this here.
    -- Note: This call will set isrunning which will prevent the guides from messing with us
    if(auto_hunt == true) then
        AnsiNote("Auto-Hunt:   Wrong turn. speedwalking back to latest.")
        PartroxisDebugNote("------------------------------------------------------")
        partroxis_return()
        return
    end

    wait.make (function()
        local c_grey = ANSI(22)..ANSI(37)
        local c_green = ANSI(1)..ANSI(32)

        wait.time(0.2)

        AnsiNote(c_grey.."Galaban whispers 'It looks like you got offtrack somewhere.'")
        if (tablelength(rooms) > 2) then
            ColourTell("gray", "black", "Galaban whispers 'You can follow the guides back or use ")
            Hyperlink("partroxis return", "[partroxis return]","Click to move","green","black",0)
            ColourTell("gray", "black", " to backtrack")
            AnsiNote("")

            AnsiNote(c_grey.."Galaban whispers 'It will put you back where you were.'")
        end
        AnsiNote(c_grey.."Galaban whispers 'Don't worry.  That guide won't give the same bad advice.'")

    end)


end


function partroxis_area_entered()
    show_greeting = true
    last_direction = ""
    auto_hunt_set_off()
    last_direction_prev = ""
    rooms = {}

    EnableTriggerGroup("partroxis_area_triggers",true)
end

function partroxis_maze_entered()
    clear_greetings_alias()

    EnableTriggerGroup("partroxis_area_triggers",true)
end

function partroxis_maze_exited()
    --reset the plugin
    show_greeting = true
    show_partroxis_help = false
    auto_hunt_set_off()
    last_direction = ""
    rooms = {}

    clear_greetings_alias()

    DoAfterSpecial(0.3,"clear_temporary_triggers()", sendto.script)

end

function partroxis_invis_reminder()
    local c_grey = ANSI(22)..ANSI(37)
    local c_white = ANSI(1)..ANSI(37)
    if (show_partroxis_help ~= true) then
        return
    end
    -- not in the maze (other parts of partroxis) ignore this.
    if (curr_room.id < 5763 or curr_room.id > 5803) then
        return
    end
    wait.make (function()

        wait.time(0.5)

        -- still fighting...
        if (player_state == 8) then
            return
        end

        -- Note: auto_hunt will always be false because we cleared it due to fighting
        if (auto_hunt) then
            AnsiNote("")
            AnsiNote(c_white.."Attempting to reset your invis spells.")
            Execute("c invis;hide;sneak")
            return
        end

        AnsiNote("")

        ColourTell("gray", "black", "Galaban whispers 'Don't forget to ")
        Hyperlink("c invis;hide;sneak", "[reset your invis spells]","Click to cast","green","black",0)
        ColourTell("gray", "black", ".'")
        AnsiNote("")


        execute_correct_exit()
        Execute("")

    end)

end

function partroxis_area_reset()
    local c_white = ANSI(1)..ANSI(37)
    AnsiNote(c_white.."+----------------------------------+")
    AnsiNote(c_white.."+-    The Partroxis has Reset     -+")
    AnsiNote(c_white.."+-  Cached rooms have been reset  -+")
    AnsiNote(c_white.."+----------------------------------+")

    rooms = {}
    lastroom = nil
    lastdirection = ""

end

--------------------
-- Actualy maze help
--------------------
rooms = {}

function auto_exit()
    if (show_partroxis_help == true and curr_room.id ~= 5763) then
        if (auto_hunt == true) then
            if(curr_room.id == target_room_id) then
                auto_hunt_found_target()
            end
        end
        auto_exit_set_triggers()
        PartroxisDebugSend("exits")
    end
end

function auto_exit_set_triggers()
    if (partroxis_debug ~= true) then
        SetTriggerOption("PartroxisExitTrigger1","omit_from_output","y")
        SetTriggerOption("PartroxisExitTrigger2","omit_from_output","y")
        SetTriggerOption("PartroxisExitTrigger3","omit_from_output","y")
        SetTriggerOption("PartroxisExitTrigger4","omit_from_output","y")
        SetTriggerOption("PartroxisExitTrigger5","omit_from_output","y")
        SetTriggerOption("PartroxisExitTrigger6","omit_from_output","y")
        SetTriggerOption("PartroxisExitTrigger7","omit_from_output","y")
    end
end

function auto_exit_clear_triggers()
    SetTriggerOption("PartroxisExitTrigger1","omit_from_output","n")
    SetTriggerOption("PartroxisExitTrigger2","omit_from_output","n")
    SetTriggerOption("PartroxisExitTrigger3","omit_from_output","n")
    SetTriggerOption("PartroxisExitTrigger4","omit_from_output","n")
    SetTriggerOption("PartroxisExitTrigger5","omit_from_output","n")
    SetTriggerOption("PartroxisExitTrigger6","omit_from_output","n")
    SetTriggerOption("PartroxisExitTrigger7","omit_from_output","n")
end

function partroxis_exit_complete()

    -- If we got an "exits" message, we know we're not running
    isrunning = false
    auto_exit_clear_triggers()

    if(auto_hunt == true) then
        -- store the last move we made and go make the next move.
        last_direction_prev = last_direction
        execute_correct_exit()
    
    else
        execute_correct_exit()
        
        last_direction_prev = last_direction
        -- Now that we've processed the last direction, clear it out to avoid accidents
        last_direction = ""
    end

end


function check_last_exit_correct()
    -- If our last room isn't already stored and our last movement is correct
    -- store the room with the correct direction

    if (lastroom == nil or lastroom.id == -1 or curr_room == nil) then
        return
    elseif (rooms[lastroom.id] ~= nil and rooms[lastroom.id].correct_dir == last_direction) then
        -- we already know that this was a correct exit.
        PartroxisDebugNote("[exit]CheckCorrectExit: last room already in map")
        return
    end

    -- just looking around?  Nothing to see here. Move long, move along.
    if(curr_room.id == lastroom.id) then
        return
    end

    -- If they entered a gate, it won't be caught by the aliases. Restore the value
    if (last_direction == "") then
        if(last_direction_prev == "enter gate") then
            last_direction = "enter gate"
        else
            return
        end
    end

    local goodmove = store_last_move()

    if (goodmove == false) then
        partroxis_bad_move()
    end
end

function store_last_move()
    -- Somehow got into a bad state.  Ignore this room.
    if (lastroom.id < 5763 or curr_room.id < 5763 or
        lastroom.id > 5803 or curr_room.id > 5803) then
        return true
    end

    -- The maze is 5763 to 5803
    if (rooms[lastroom.id] == nil) then
        rooms[lastroom.id] = lastroom
    end

    -- If we increased by one (eg 5778 to 5779), it's correct
    if (curr_room.id == (lastroom.id + 1)) then
        if (rooms[lastroom.id].correct_dir == "") then
            rooms[lastroom.id].correct_dir = last_direction
            rooms[lastroom.id].next_id = curr_room.id
            PartroxisDebugNote("DEBUG:  storing room["..lastroom.id.."]  direction["..last_direction.."] to_id["..curr_room.id.."]")
            return true
        end
        return true
    else
        -- whoops, wrong way. Store that bad direction
        if (rooms[lastroom.id].wrong_dir1 == "" or rooms[lastroom.id].wrong_dir1 == last_direction) then
            rooms[lastroom.id].wrong_dir1 = last_direction
        else
            rooms[lastroom.id].wrong_dir2 = last_direction
        end
        PartroxisDebugNote("DEBUG:  storing room["..lastroom.id.."]  wrong direction["..last_direction.."]")
        PartroxisDebugNote("DEBUG:     CURR room["..lastroom.id.."]  direction["..rooms[lastroom.id].correct_dir.."]  to_id["..rooms[lastroom.id].next_id.."]")
    end
    return false
end

guide_name = "Galaban"
next_room_name = ""
function execute_correct_exit()
    local next_dir = "unknown"

    --Exits populated... let's look for the correct one
    if (room_mob_list == nil) then
        initialize()
    end

    if (isrunning == true) then
        return
    end
    if (curr_room.id == 5763) then
        Note("Head north to start")
        return
    end

    -- make sure we can do this...
    if (curr_room == nil or curr_room.id < 5763 or curr_room.id > 5812 or 
        room_mob_list[curr_room.id] == nil) then
        Note("You're not in the Partroxis maze!  (room: "..curr_room.id..")")
        return
    end

    local next_room = nil
    if (curr_room.id == 5803) then
        next_room = room_mob_list[5812]
    else
        next_room = room_mob_list[curr_room.id + 1]
    end

    if (next_room == nil) then
        AnsiNote("I couldn't find the next room  (room: "..(curr_room.id+1)..")")
        return
    end

    next_room_name = next_room.name
    guide_name = room_mob_list[curr_room.id].mob

    if (curr_room.id == 5763) then
        Note("Just head north to start")
        return
    end

    -- Special rooms with gates rather than "exits"
    if (curr_room.id == 5777 or curr_room.id == 5792 or curr_room.id == 5803) then
        possible_valid_exits = {}
        table.insert(possible_valid_exits, "enter gate")
        guide_player(guide_name,translate_exit_to_readable("enter gate"))
        last_direction = "enter gate"
        return
    end 

    --"flavor_text" used to say "xx points yy". I used to force
    --if (curr_room.id == 5784 or curr_room.id == 5798 or curr_room.id == 5799 or 
    --    curr_room.id == 5800 or curr_room.id == 5801) then
    --    guide_name = "Galaban"
    --end

    -- Check for the next exit.  
    -- (We need to do this before scanning so that we know which valid exits we have.
    --  If we need to scan, we will process this again.)
    next_dir = find_partroxis_exit(next_room_name)

    -- If we need to scan for a pet in this room, go ahead and make
    -- the asynch callback (scan and wait for completion)
    -- Otherwise, go ahead and deal with the data we have (guide the player)
    if (should_scan_for_pet()) then
        scan_for_pet()
    else
        guide_player(guide_name, next_dir)
    end

end

function guide_player(guidename,next_dir)
    local c_grey = ANSI(22)..ANSI(37)

    if (auto_hunt == true) then
        auto_hunt_move(next_dir)
    else
        flavor_exit(guidename,next_dir)
    end
end

function auto_hunt_move(next_dir)
    local c_white = ANSI(1)..ANSI(37)
    if (auto_hunt == true) then
        if (curr_room.id == target_room_id) then
            auto_hunt_found_target()
            return
        end

        -- This happens if we repop at the wrong time or if we try to move during the autohunt.
        -- there might be some timing holes that cause this, as well
        if (next_dir == "to the void") then
            AnsiNote(c_white.."Patroxis Map Corrupted. Clearing cache.")
            rooms = {}
            return
        end

        -- not "ready" and not "running"? stop hunting
        if(player_state ~= 3) then
            if(player_state == 12) then
                return
            end
            auto_hunt_set_off()
            Note("Turning off autohunt.")
            PartroxisDebugNote("PlayerState = "..player_state)
            return
        end
        --perform the auto-hunt
        local exec_mov = next_dir
        if (next_dir == translate_exit_to_readable("enter gate")) then
            exec_mov = "enter gate"
        else
            --grab the first direction and go with it
            local short_dir = string.lower(string.sub(next_dir,1,1))
            exec_mov = short_dir
        end

        PartroxisDebugNote("Auto-Hunt:  "..exec_mov)

        -- Make sure to "Execute" so we get the aliases
        Execute(exec_mov)
    end
end

function auto_hunt_found_target()
    auto_hunt_set_off()

    wait.make (function()
        wait.time(0.1)
        AnsiNote(full_target_name.." is here")
        AnsiNote("")
    end)
end

function auto_hunt_set_on()
    auto_hunt = true
end

function auto_hunt_set_off()
    auto_hunt = false
end

possible_valid_exits = {}
function find_partroxis_exit(nextexit)
    possible_valid_exits = {}
    if (curr_room.correct_dir ~= "") then
        table.insert(possible_valid_exits, curr_room.correct_dir)
        return translate_exit_to_readable(curr_room.correct_dir)
    end

    -- This is very messy, but...
    -- Make up a list of all know bad directions (.wrong_dir1) and possible bad directions (.temp_wrong_dir1)
    -- The "temp" variables will be set by "scan" while the others will be set by *known* bad directions
    local bad_dirs = {}
    if (curr_room.temp_wrong_dir1 ~= "") then
        table.insert(bad_dirs, curr_room.temp_wrong_dir1)
    end
    if (curr_room.temp_wrong_dir2 ~= "" and (arraycontains(bad_dirs,curr_room.temp_wrong_dir2) == false)) then
        table.insert(bad_dirs, curr_room.temp_wrong_dir2)
    end
    if (curr_room.wrong_dir1 ~= "" and (arraycontains(bad_dirs, curr_room.wrong_dir1) == false)) then
        table.insert(bad_dirs, curr_room.wrong_dir1)
    end
    if (curr_room.wrong_dir2 ~= "" and (arraycontains(bad_dirs, curr_room.wrong_dir2) == false)) then
        table.insert(bad_dirs, curr_room.wrong_dir2)
    end

    if (table.getn(bad_dirs) > 0) then
        PartroxisDebugNote("[Find_exit] t_wr_dir1["..curr_room.temp_wrong_dir1.."]  t_wr_dir2["..curr_room.temp_wrong_dir2.."]"..
                "wrong_dir1["..curr_room.wrong_dir1.."]   wrong_dir2["..curr_room.wrong_dir2.."]")
    end

    local out_string = ""
    if (curr_room.exits.n ~= nil and curr_room.exits.n == nextexit and
        arraycontains(bad_dirs, "n") == false) then
        out_string = append_with_or(out_string,translate_exit_to_readable("n"))
        table.insert(possible_valid_exits, "n")
    end
    if (curr_room.exits.e ~= nil and curr_room.exits.e == nextexit and
        arraycontains(bad_dirs, "e") == false) then
        out_string = append_with_or(out_string,translate_exit_to_readable("e"))
        table.insert(possible_valid_exits, "e")
    end
    if (curr_room.exits.s ~= nil and curr_room.exits.s == nextexit and
        arraycontains(bad_dirs, "s") == false) then
        out_string = append_with_or(out_string,translate_exit_to_readable("s"))
        table.insert(possible_valid_exits, "s")
    end
    if (curr_room.exits.w ~= nil and curr_room.exits.w == nextexit and
        arraycontains(bad_dirs, "w") == false) then
        out_string = append_with_or(out_string,translate_exit_to_readable("w"))
        table.insert(possible_valid_exits, "w")
    end
    if (curr_room.exits.u ~= nil and curr_room.exits.u == nextexit and
        arraycontains(bad_dirs, "u") == false) then
        out_string = append_with_or(out_string,translate_exit_to_readable("u"))
        table.insert(possible_valid_exits, "u")
    end
    if (curr_room.exits.d ~= nil and curr_room.exits.d == nextexit and
        arraycontains(bad_dirs, "d") == false) then
        out_string = append_with_or(out_string,translate_exit_to_readable("d"))
        table.insert(possible_valid_exits, "d")
    end

    if (out_string == "") then
        -- OK, if we scanned and got two pets in both valid directions, clear out the
        -- temp directions and try again
        if (curr_room.temp_wrong_dir1 ~= "") then
            curr_room.temp_wrong_dir1 = ""
            curr_room.temp_wrong_dir2 = ""
            return find_partroxis_exit(nextexit)
        end

        out_string = "to the void"
    end

    PartroxisDebugNote("DEBUG:  found exits["..out_string.."]")

    return out_string
end

function translate_exit_to_readable(short_dir)
    if (short_dir == "n") then
        return "North"
    elseif (short_dir == "s") then
        return "South"
    elseif (short_dir == "e") then
        return "East"
    elseif (short_dir == "w") then
        return "West"
    elseif (short_dir == "u") then
        return "Up"
    elseif (short_dir == "d") then
        return "Down"
    elseif (short_dir == "enter gate") then
        return "Enter Gate"
    end
    return ""
end

function flavor_exit(mob_name, next_dir)
       local c_cyan = ANSI(1)..ANSI(36)
    local c_red = ANSI(1)..ANSI(31)
    local c_grey = ANSI(22)..ANSI(37)
    local c_green = ANSI(1)..ANSI(32)

    wait.make (function()
        wait.time(0.1)

        ColourNote("gray", "black", padright("Mob here:", 40).. "Correct Exit")
        ColourTell("gray", "black", padright(mob_name,40))

        for i,dir in pairs(possible_valid_exits) do
            if(i > 1) then
                ColourTell("gray", "black", " or ")
            end

            local full_dir = "["..translate_exit_to_readable(dir).."]"

            Hyperlink(dir, full_dir,"Click to move","green","black",0)

        end

        AnsiNote("")
        AnsiNote("")
    end)
end

--------------------
--  Temporary items
--------------------
function make_temporaries()

    -- greeting accept/decline response (temporary)
    -- Note: we have to use accept/decline instead of yes/no because "no" is also "north"
    AddAlias("tempPartroxisAlias1","accept","",alias_flag.Enabled + alias_flag.Temporary,"accept_partroxis_help")
    AddAlias("tempPartroxisAlias2","decline","",alias_flag.Enabled + alias_flag.Temporary,"decline_partroxis_help")

end

function clear_greetings_alias()
    DeleteAlias("tempPartroxisAlias1")
    DeleteAlias("tempPartroxisAlias2")
end

function clear_temporary_triggers()
    EnableTriggerGroup("partroxis_area_triggers",false)
    EnableTriggerGroup("partroxis_exit_triggers",false)
    EnableAliasGroup("partroxis_movement",false)
end



------------------
--  UI stuff
------------------
function greet()
    local c_cyan = ANSI(1)..ANSI(36)
    local c_red = ANSI(1)..ANSI(31)
    local c_grey = ANSI(22)..ANSI(37)
    local c_green = ANSI(1)..ANSI(32)

    if(show_greeting == false) then
        return
    end
    show_greeting = false

    -- If they are auto-hunting, they'll never get the greeting.
    -- They probably started at the beginning of the area and are blowing past this room
    -- Also, they are probably familiar enough with the plugin to know the "guides" command
    if (auto_hunt == true) then
        return
    end
    -- setup
    make_temporaries()
    if (show_partroxis_help == nil) then
        show_partroxis_help = false
    end

    wait.make (function()

        wait.time(0.5)

        AnsiNote("")
        AnsiNote(c_red.."A portal opens up and out steps Galaban.")

        wait.time(0.2)

        AnsiNote("")
        AnsiNote(c_cyan.."Galaban says 'Greetings.  Would you like assistance through the maze?'")
        AnsiNote(c_grey.."type '"..c_green.."accept"..c_grey.."' to ask for guides through the maze.")
        AnsiNote(c_grey.."type '"..c_red.."decline"..c_grey.."' to attempt without help.")
        Execute("")

    end)

end

show_partroxis_help = false
function enable_partroxis_guides(enabled)
    PartroxisDebugNote("Setting Partroxis Guides to: "..printbool(enabled))
    show_partroxis_help = enabled
    EnableTriggerGroup("partroxis_exit_triggers",enabled)
    EnableAliasGroup("partroxis_movement",enabled)

    -- should not be a problem, jsut make sure
    if( enabled == false) then
        DoAfterSpecial(0.5,"clear_greetings_alias()", sendto.script)
    end
end

function accept_partroxis_help()
    local c_cyan = ANSI(1)..ANSI(36)
    local c_grey = ANSI(22)..ANSI(37)
    local c_red = ANSI(1)..ANSI(31)

    DoAfterSpecial(0.5,"clear_greetings_alias()", sendto.script)
    enable_partroxis_guides(true)
    wait.make (function()

        AnsiNote("")
        AnsiNote(c_cyan.."Galaban says 'I'm glad to hear that.  My helpers will show you the way.'")
        AnsiNote(c_cyan.."Galaban says 'Sometimes they don't know the exact direction.'")
        AnsiNote(c_cyan.."Galaban says 'But do not fear.  They won't send you the wrong direction twice.'")
        AnsiNote(c_grey.."Galaban reaches into his pockets and throws lua dust over the maze.")
        AnsiNote(c_cyan.."Galaban says 'The first room is north.'")
        Execute("open north")

        wait.time(0.5)

        AnsiNote("")
        AnsiNote(c_red.."A portal opens up and Galaban disappears into it.")
        Execute("")

    end)

end

function decline_partroxis_help()
    local c_cyan = ANSI(1)..ANSI(36)
    local c_grey = ANSI(22)..ANSI(37)
    local c_red = ANSI(1)..ANSI(31)
    local c_green = ANSI(1)..ANSI(32)

    DoAfterSpecial(0.5,"clear_greetings_alias()", sendto.script)

    enable_partroxis_guides(false)

    wait.make (function()

        AnsiNote("")
        AnsiNote(c_grey.."Galaban nods.")
        AnsiNote(c_cyan.."Galaban says 'Very well.  The best of luck to you!'.")
        AnsiNote(c_cyan.."Galaban says 'If change your mind, use '"..c_green.."partroxis guide"..c_cyan.."' to ask for help.'.")
        AnsiNote(c_cyan.."Galaban says 'However, there will be no previous knowledge of the area.'.")

        wait.time(0.5)

        AnsiNote("")
        AnsiNote(c_red.."A portal opens up and Galaban disappears into it.")
        Execute("")

    end)


end

function partroxis_needs_nightvision()
    local c_grey = ANSI(22)..ANSI(37)
    local c_red = ANSI(1)..ANSI(31)
    AnsiNote(c_grey.."Galaban whispers 'You need "..c_red.."night vision"..c_grey.." to navigate this maze.'.")
end

-----------------
-- Partroxis Data
-----------------
function partroxis_list_data()
    if (room_mob_list == nil) then
        initialize()
    end

    local ordered_keys = {}
    for k in pairs(room_mob_list) do
        table.insert(ordered_keys, k)
    end
    table.sort(ordered_keys)


    AnsiNote("-----------------------------------------------------------------")
    AnsiNote("Room# "..padright("Mob Name", 40).."  Room name")

    --for i,item in pairs(room_mob_list) do

    for i = 1, #ordered_keys do
        local item = room_mob_list[ordered_keys[i]]
        AnsiNote(ordered_keys[i].."  "..padright(item.mob,40).. "  "..item.name)
    end
    AnsiNote("-----------------------------------------------------------------")
end

room_mob_list = nil
function initialize()
    room_mob_list = {}
    room_mob_list[5764] = {name = "In the Mountains", mob = "A Mountain of Rock"}
    room_mob_list[5765] = {name = "Through the Woods", mob = "The Rabid Tiger-man"}
    room_mob_list[5766] = {name = "The Forest", mob = "The man-eating wolfen"}
    room_mob_list[5767] = {name = "Swampy Path", mob = "The Buck-Toothed Lizard-Man"}
    room_mob_list[5768] = {name = "The Forest", mob = "The Living Tree"}
    room_mob_list[5769] = {name = "Along the River", mob = "The Furious Flying Fish Man"}
    room_mob_list[5770] = {name = "The Desert", mob = "The Quicksand"}
    room_mob_list[5771] = {name = "The Desert", mob = "The Flesh Eating Ants"}
    room_mob_list[5772] = {name = "The Wheat Fields", mob = "The Living Vines"}
    room_mob_list[5773] = {name = "In the Mountains", mob = "The Gigantic Bulette"}
    room_mob_list[5774] = {name = "In the Mountains", mob = "A Bird of Prey"}
    room_mob_list[5775] = {name = "A Cave", mob = "The Otherworld Assassin"}
    room_mob_list[5776] = {name = "The Wheat Fields", mob = "Vision of a False Portal"}
    room_mob_list[5777] = {name = "The Wheat Fields", mob = "The Hungry Dragon"}
    room_mob_list[5778] = {name = "The Forest", mob = "A Bloodthirsty Tiger-Man"}
    room_mob_list[5779] = {name = "The Swamp", mob = "The Cold Hearted Lizard-Man"}
    room_mob_list[5780] = {name = "The Swamp", mob = "The Insane Cheryb"}
    room_mob_list[5781] = {name = "River of Blood", mob = "Flowing Blood"}
    room_mob_list[5782] = {name = "A small Cave", mob = "A collapsing cave"}
    room_mob_list[5783] = {name = "A small Cave", mob = "The Dream Eater"}
    room_mob_list[5784] = {name = "Through the Passage of Time", mob = "Reality Check"}
    room_mob_list[5785] = {name = "The Swamp", mob = "Blood Sucking Vines"}
    room_mob_list[5786] = {name = "The Forest", mob = "The Golden Haired Assassin"}
    room_mob_list[5787] = {name = "The Wheat Fields", mob = "Mass of Flying Dismembered Body Parts"}
    room_mob_list[5788] = {name = "The Wheat Fields", mob = "Bloodthirsty Killer Gerbils"}
    room_mob_list[5789] = {name = "In the Mountains", mob = "A Monster Bulette"}
    room_mob_list[5790] = {name = "The Wheat Fields", mob = "the Thing"}
    room_mob_list[5791] = {name = "Along the River", mob = "The Big and Deadly Dragon"}
    room_mob_list[5792] = {name = "The Wheat Field", mob = "Soul of the Damned"}
    room_mob_list[5793] = {name = "In the Mountains", mob = "Lesser Chitryn"}
    room_mob_list[5794] = {name = "In the Mountains", mob = "Delusions of Hope"}
    room_mob_list[5795] = {name = "The Desert", mob = "Swarm of Blood Sucking Bio-chemical Gnats"}
    room_mob_list[5796] = {name = "The Swamp", mob = "It"}
    room_mob_list[5797] = {name = "The Desert", mob = "Your Worst Nightmare"}
    room_mob_list[5798] = {name = "The Wheat Field", mob = "Walking Suit of Armor"}
    room_mob_list[5799] = {name = "A Cave", mob = "Lesser Otherworld Dragon"}
    room_mob_list[5800] = {name = "A Cave", mob = "Insane Cheryb"}
    room_mob_list[5801] = {name = "In the Mountains", mob = "Otherworld Dragon"}
    room_mob_list[5802] = {name = "In the Mountains", mob = "Hell Hound Behemoths"}
    room_mob_list[5803] = {name = "A vast Expanse of Plains", mob = "Chitryn"}
    room_mob_list[5812] = {name = "The Opus", mob = "Grax, Lord of the Opus"}
end


--------------------
-- Utility Functions
--------------------
function tablelength(table)
  local count = 0
  for _ in pairs(table) do 
     count = count + 1 
  end
  return count
end

-- case insensitive
function string.startswith(strmatch,strstart)
   return string.sub(string.lower(strmatch),1,string.len(strstart))==string.lower(strstart)
end

function printbool(bval)
   if(bval == nil) then
      return "nil"
   elseif(bval == true) then
      return "true"
   end
   return "false"
end

function PartroxisDebugNote(text)
    if (partroxis_debug == true) then
        Note(text)
    end
end

function PartroxisDebugSend(cmd)
    if(partroxis_debug) then
        Send(cmd)
    else
        SendNoEcho(cmd)
    end
end

function append_with_or(curr_str, new_string)
    if (curr_str ~= "") then
        curr_str = curr_str .. " or "
    end
    curr_str = curr_str .. new_string
    return curr_str
end

function padright(instr,tolength)
    local strlen = string.len(instr)
    if (strlen > tolength) then
        return instr
    end
    strlen = tolength - strlen
    while strlen > 0 do
        instr = instr.." "
        strlen = strlen - 1
    end
    return instr
end

function arraycontains(arr, val)
    if (arr == nil or table.getn(arr) < 1) then
        return false
    end
    for ind,item in pairs(arr) do
        if (val == item) then
            return true
        end
    end
    return false
end


]]>
</script>


<!--  Plugin help  -->

<aliases>
  <alias
   script="OnHelp"
   match="Galabans_Partroxis_Plugin:help"
   enabled="y"
  >
  </alias>
</aliases>

<script>
<![CDATA[
function OnHelp ()
  world.Note (world.GetPluginInfo (world.GetPluginID (), 3))
end
]]>
</script> 

</muclient>