The Instr Function

Posted by Duma on Sun 15 Apr 2007 03:08 AM — 11 posts, 35,161 views.

USA #0
I'm trying to make a compass for the game "Aetolia".

Everything is working except for one problem, when I use the instr function to find 'north', it finds the 'north' in 'northeast' or 'northwest' and returns north as > 0.

Is there a way to not catch the 'north' in 'northwest'?
Australia Forum Administrator #1
It would help to see more of your code, but I would personally check for northwest before north.

That is, if you look for "northwest" first, then you know you have northwest, and nor the first part of north.
USA #2
Alright, it's pretty long though. It's probably longer than it needs to be even. Here it is -


Sub Compass(Name, Line, Wildcards)
	dim n, ne, e, se, s, sw, w, nw, u, d, i, o, exits
	exits = Wildcards(1)
	dim tExits(12)
	tExits(1) = "north"
	tExits(2) = "northeast"
	tExits(3) = "east"
	tExits(4) = "southeast"
	tExits(5) = "south"
	tExits(6) = "southwest"
	tExits(7) = "west"
	tExits(8) = "northwest"
	tExits(9) = "up"
	tExits(10) = "down"
	tExits(11) = "in"
	tExits(12) = "out"
	dim a
	for a = 1 to 12
		if instr(exits, tExits(a)) > 0 then
			select case a
				case 1
					n = 1
				case 2
					ne = 1
				case 3
					e = 1
				case 4
					se = 1
				case 5
					s = 1
				case 6
					sw = 1
				case 7
					w = 1
				case 8
					nw = 1
				case 9
					u = 1
				case 10
					d = 1
				case 11
					i = 1
				case 12
					o = 1
			end select
		else
			select case a
				case 1
					n = 0
				case 2
					ne = 0
				case 3
					e = 0
				case 4
					se = 0
				case 5
					s = 0
				case 6
					sw = 0
				case 7
					w = 0
				case 8
					nw = 0
				case 9
					u = 0
				case 10
					d = 0
				case 11
					i = 0
				case 12
					o = 0
			end select
		end if
	next
	world.replaceNotepad "Compass", ""
	if o = 1 and i = 1 then
		world.appendToNotepad "Compass", "Out In     " & vbcrlf
	elseif o = 1 and i = 0 then
		world.appendToNotepad "Compass", "Out        " & vbcrlf
	elseif o = 0 and i = 1 then
		world.appendToNotepad "Compass", "    In     " & vbcrlf
	else
		world.appendToNotepad "Compass", vbcrlf
	end if
	if n = 1 then
		world.appendToNotepad "Compass", "   N       " & vbcrlf
	end if
	if ne = 1 and nw = 1 then
		world.appendToNotepad "Compass", "NW | NE    " & vbcrlf
	elseif ne = 1 and nw = 0 then
		world.appendToNotepad "Compass", "   | NE    " & vbcrlf
	elseif ne = 0 and nw = 1 then
		world.appendToNotepad "Compass", "NW |       " & vbcrlf
	else  
		world.appendToNotepad "Compass", "   |       " & vbcrlf
	end if
	if u = 1 then
		world.appendToNotepad "Compass", "  \|/   up " & vbcrlf
	else
		world.appendToNotepad "Compass", "  \|/      " & vbcrlf
	end if
	if w = 1 and e = 1 then
		world.appendToNotepad "Compass", "W--X--E    " & vbcrlf
	elseif w = 1 and e = 0 then
		world.appendToNotepad "Compass", "W--X--     " & vbcrlf
	elseif w = 0 and e = 1 then
		world.appendToNotepad "Compass", " --X--E    " & vbcrlf
	else
		world.appendToNotepad "Compass", " --X--     " & vbcrlf
	end if
	if d = 1 then
		world.appendToNotepad "Compass", "  /|\  down" & vbcrlf
	else
		world.appendToNotepad "Compass", "  /|\      " & vbcrlf
	end if
	if sw = 1 and se = 1 then
		world.appendToNotepad "Compass", "SW | SE    " & vbcrlf
	elseif sw = 1 and se = 0 then
		world.appendToNotepad "Compass", "SW |       " & vbcrlf
	else
		world.appendToNotepad "Compass", "   |       " & vbcrlf
	end if
	if s = 1 then
		world.appendToNotepad "Compass", "   S       " & vbcrlf
	end if
	MoveNotepadWindow "Compass", 758,0,262,401
End Sub


This is the trigger that calls the script -


<triggers>
  <trigger
   enabled="y"
   match="^You see exits leading (.*?)$"
   regexp="y"
   script="Compass"
   sequence="100"
  >
  </trigger>
</triggers>


And here's what you see when you enter a room -

A quiet hallway near the Hall of Inner Peace.
A vigilant monk stands here, alert and watchful for enemies of the city.
You see exits leading north, east, south and west(closed).
H:2380 M:2848 E:99% W:93% B:100% [eb]
Amended on Sun 15 Apr 2007 04:48 AM by Duma
Australia Forum Administrator #3
This is one of the reasons why I am recommending Lua scripting. This is much more easily solved with a simple regular expression. Take this test:


test = "You see exits leading north, northeast, east, south and west(closed)."

for exit in string.gmatch (test, "%w+") do
  print (exit)
end -- for


Running this prints:


You
see
exits
leading
north
northeast
east
south
and
west
closed


What it has done is broken the line into words, and you can see that there is no problem here with northeast and north being confused.

Obviously we have a few extraneous words (like "you" and "see") but we can ignore those.

Now to do something useful with those words, we can directly enter them into a table, for looking up later:


test = "You see exits leading north, northeast, east, in, south and west(closed)."

directions = {}  -- empty table

for exit in string.gmatch (test, "%w+") do
  directions [exit] = true
end -- for

if directions.out and directions ["in"] then
  AppendToNotepad ("Compass", "Out In     \r\n")
elseif directions.out then
  AppendToNotepad ("Compass", "Out        \r\n")
elseif directions ["in"] then
  AppendToNotepad ("Compass", "    In     \r\n")
else
  AppendToNotepad ("Compass", "\r\n")
end -- out


Each exit that was found will be in the table with a "true" value, so we can test for it, as I have shown.

I had to treat "in" a bit differently because "in" is a Lua keyword.

The other exits will be similar (eg. directions.north, directions.south and so on).
Amended on Sun 15 Apr 2007 05:09 AM by Nick Gammon
Australia Forum Administrator #4
You can save a bit of typing too by making a helper function to do the appending, because there is a lot of repetition there with the notepad name:


function appendit (s)
  AppendToNotepad ("Compass", s .. "\r\n")
end -- appendit 

if directions.out and directions ["in"] then
  appendit ("Out In     ")
elseif directions.out then
  appendit ("Out        ")
elseif directions ["in"] then
  appendit ("    In     ")
else
  appendit ("")
end -- out


That makes the whole thing easier to read. You could do a similar thing in VBscript too. When you find yourself doing something lengthy over and over, it is probably time to make a small subroutine to do it for you.
Amended on Sun 15 Apr 2007 05:14 AM by Nick Gammon
Australia Forum Administrator #5
Here is a replacement for the whole script, done in Lua. I think this is much easier to read.

Instead of having heaps of "if" statements, I made a small "choose" function. You supply it a word and a condition (eg. "E"). If the condition is true, it returns the word, otherwise it returns the same number of spaces, as the word is long.

That way, if you can't go that way, it automatically space-fills your compass with the correct gap.


function Compass(Name, Line, Wildcards)

  local dir = {}  -- no directions yet
  
  for exit in string.gmatch (Wildcards [1], "%w+") do
    dir [exit] = true
  end -- for
  
  -- append to the notepad for us
  local function appendit (s)
    AppendToNotepad ("Compass", s .. "\r\n")
  end -- appendit 
  
  -- return the word, or equivalent spaces
  local function choose (what, condition)
    if condition then
      return what
    end -- if
  
   return string.rep (" ", #what)
  end -- choose
  
  -- clear the notepad
  ReplaceNotepad ("Compass", "")
  
  -- draw the compass
  appendit (choose ("Out", dir.out) .. " " .. choose ("In", dir ["in"]))
  appendit ("   " .. choose ("N", dir.north))
  appendit (choose ("NW", dir.northwest) .. " | " .. choose ("NE", dir.northeast))
  appendit ("  \\|/   " .. choose ("up", dir.up))
  appendit (choose ("W", dir.west) .. "--|--" .. choose ("E", dir.east))
  appendit ("  /|\\   " .. choose ("down", dir.down))
  appendit (choose ("SW", dir.southwest) .. " | " .. choose ("SE", dir.southeast))
  appendit ("   " .. choose ("S", dir.south))
  MoveNotepadWindow ("Compass", 758, 0, 262, 401)
end -- function



With a test of:

"You see exits leading north, northeast, southwest, southeast, east, up, down, in, south and west(closed)."

My compass looked like this:


    In
   N
   | NE
  \|/   up
W--|--E
  /|\   down
SW | SE
   S


With a test of:

"You see exits leading southeast, east, up, out, in, south and west(closed)."

My compass looked like this:


Out In
    
   |   
  \|/   up
W--|--E
  /|\       
   | SE
   S
Amended on Sun 15 Apr 2007 09:16 PM by Nick Gammon
USA #6
I don't think I'm quite ready to switch to Lua yet. Do you need to rewrite all of your old scripts to change your programming language?

But anyways I found a way to get it to work, like you said I should've I checked for 'northeast' before 'north' but now I delete the 'northeast' from the string. So far it is working out alright.

Thanks for all the help recently.
Australia Forum Administrator #7
Glad you got it to work. :)

Quote:

Do you need to rewrite all of your old scripts to change your programming language?


With something simple like that, which is really one trigger, you could turn it into a plugin. The plugin can be in Lua, even if your other scripts are in VBscript. Here is how I did that:


<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE muclient>
<!-- Saved on Sunday, April 15, 2007, 4:31 PM -->
<!-- MuClient version 3.85 -->

<!-- Plugin "Compass" generated by Plugin Wizard -->

<muclient>
<plugin
   name="Compass"
   author="Nick Gammon"
   id="c176d579effc57ef104fc407"
   language="Lua"
   purpose="Shows the exits in a compass-style notepad window"
   date_written="2007-04-15 16:31:08"
   requires="3.85"
   version="1.0"
   >

</plugin>


<!--  Triggers  -->

<triggers>
  <trigger
   enabled="y"
   match="^You see exits leading (.*?)$"
   regexp="y"
   send_to="12"
   sequence="100"
  >
  <send>  local dir = {}  -- no directions yet
  
  for exit in string.gmatch ("%1", "%%w+") do
    dir [exit] = true
  end -- for
  
  -- append to the notepad for us
  local function appendit (s)
    AppendToNotepad ("Compass", s .. "\\r\\n")
  end -- appendit 
  
  -- return the word, or equivalent spaces
  local function choose (what, condition)
    if condition then
      return what
    end -- if
  
   return string.rep (" ", #what)
  end -- choose
  
  -- clear the notepad
  ReplaceNotepad ("Compass", "")
  
  -- draw the compass
  appendit (choose ("Out", dir.out) .. " " .. choose ("In", dir ["in"]))
  appendit ("   " .. choose ("N", dir.north))
  appendit (choose ("NW", dir.northwest) .. " | " .. choose ("NE", dir.northeast))
  appendit ("  \\\\|/   " .. choose ("up", dir.up))
  appendit (choose ("W", dir.west) .. "--|--" .. choose ("E", dir.east))
  appendit ("  /|\\\\   " .. choose ("down", dir.down))
  appendit (choose ("SW", dir.southwest) .. " | " .. choose ("SE", dir.southeast))
  appendit ("   " .. choose ("S", dir.south))

  MoveNotepadWindow ("Compass", 758, 0, 262, 401)</send>
  </trigger>
</triggers>

</muclient>



I changed from using a script file function to "send to script" which required some minor changes to the way the code looks.
USA #8
Ok, my compass was working for a while, but now I'm confused on using multi-line triggers.

Most rooms look like this -

Valley road before city. (road).
The bright sun shines down, blanketing you with its life-giving warmth. A large
block of stone is standing here, waiting to be carried out of the quarry. A
bright-eyed missionary serenely patrols the streets of Enorian.
You see exits leading southeast and northwest.

And my trigger worked fine, but now I've run into some problems with rooms like this -

Bend in the highway. (road).
Small flakes of white float through your field of vision here and there. You see
exits leading northeast and west

And some are like this -

Highway surrounded by lush plains. (road).
Snowflakes float down around you, colouring the world white. You see exits
leading northeast, southeast and southwest

I've tried making a multi-line trigger -


<triggers>
  <trigger
   enabled="y"
   group="Compass"
   lines_to_match="2"
   match="^You see exits leading\n(.*)"
   multi_line="y"
   regexp="y"
   script="Compass"
   sequence="100"
  >
  </trigger>
</triggers>

and..

<triggers>
  <trigger
   enabled="y"
   group="Compass"
   lines_to_match="2"
   match="^You see\nexits leading (.*)"
   multi_line="y"
   regexp="y"
   script="Compass"
   sequence="100"
  >
  </trigger>
</triggers>


But they don't seem to work, any suggestions?
Australia Forum Administrator #9
You have a few problems with the regular expression. For a start you had "^You", the "^" symbol says to anchor to the start of the line, which it won't be in many cases.

Secondly, you have got "You see" which is specifying literally a space between "You" and "see" whereas you might get a newline.

Third, you need the (?s) option which is "dot matches all". That allows for a newline in the middle of the directions list. Otherwise a newline (eg. between "north" and "south") will fail to match.

This worked for me:


match="(?s)You[\s]see[\s]exits[\s]leading[\s](.*)"


Australia Forum Administrator #10
Here is an adapted version of the plugin I made. I moved the script from "send to script" to a separate <script> part of the plugin - I think that is less confusing with the % and \ symbols in it. Also, it has the multi-line stuff in it:


<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE muclient>
<!-- Saved on Sunday, April 15, 2007, 4:31 PM -->
<!-- MuClient version 3.85 -->

<!-- Plugin "Compass" generated by Plugin Wizard -->

<muclient>
<plugin
   name="Compass"
   author="Nick Gammon"
   id="f806d9a43613c1983f95e697"
   language="Lua"
   purpose="Shows the exits in a compass-style notepad window"
   date_written="2007-04-16 07:30"
   requires="3.85"
   version="1.1"
   >

</plugin>


<!--  Triggers  -->

<triggers>
  <trigger
   enabled="y"
   lines_to_match="2"
   match="(?s)You[\s]see[\s]exits[\s]leading[\s](.*)"
   multi_line="y"
   regexp="y"
   script="Compass"
   sequence="100"
  >
  </trigger>
</triggers>

<script>
<![CDATA[

function Compass (Name, Line, Wildcards)

  local dir = {}  -- no directions yet
  
  for exit in string.gmatch (Wildcards [1], "%w+") do
    dir [exit] = true
  end -- for
  
  -- append to the notepad for us
  local function appendit (s)
    AppendToNotepad ("Compass", s .. "\r\n")
  end -- appendit 
  
  -- return the word, or equivalent spaces
  local function choose (what, condition)
    if condition then
      return what
    end -- if
  
   return string.rep (" ", #what)
  end -- choose
  
  -- clear the notepad
  ReplaceNotepad ("Compass", "")
  
  -- draw the compass
  appendit (choose ("Out", dir.out) .. " " .. choose ("In", dir ["in"]))
  appendit ("   " .. choose ("N", dir.north))
  appendit (choose ("NW", dir.northwest) .. " | " .. choose ("NE", dir.northeast))
  appendit ("  \\|/   " .. choose ("up", dir.up))
  appendit (choose ("W", dir.west) .. "--|--" .. choose ("E", dir.east))
  appendit ("  /|\\   " .. choose ("down", dir.down))
  appendit (choose ("SW", dir.southwest) .. " | " .. choose ("SE", dir.southeast))
  appendit ("   " .. choose ("S", dir.south))
  MoveNotepadWindow ("Compass", 758, 0, 262, 401)
end -- function

]]>
</script> 

</muclient>