Help with string comparisons.

Posted by Noodle on Wed 07 Jul 2004 03:46 PM — 5 posts, 16,895 views.

#0
I am working on a script that will react to certain events in the world. I know I can do this with a trigger and maybe I need to use the trigger to pass info to the scipt.

The current portion of the scipt that is giving me trouble...

Dim WorldReply 

world.note "-----------Commencing sequence--------"
world.execute "Do something"

WorldReply = getRecentLines (3)
world.note "-------------This is what I just picked up---------------"
world.note WorldReply

Do Until (WorldReply Like "*partial string*")
	world.note "Waiting..."
	WorldReply = (getRecentLines (3))
	Loop
world.note "Loop conditions met."


The trouble I believe stems from the "like" comparator. Everything seems to run fine until that line, then I get a line error.
Help and suggestions please. Maybe I should be using a different language?
USA #1
Hmm. Few issues here. First off.. getRecentLines returns a 'block' of lines, so you are trying to compare an array with a string. This probably won't work. You need something more like:

for each Teststr in WorldReply
  if Teststr like "..." then
    ...
  end if
next

Second problem.. This isn't zMud, in zMud scripts are processed parallel to the input/output of the client. What do I mean by this? Example:

Mud lines              Script
---------              ------
Fred says: ...         line 1 (trigger on Fred)
You say: ...           line 2
                       line 3
                       line 1 (timer)
Fred says: ...         line 2 (timer) + line 1 (trigger on Fred)
                       line 2
You say: ...           line 3


The lines being executed above could be anything, from any trigger, alias, timer, etc., or even several at the same time. The point is that scripts run continuously as needed. In Mushclient it works like this:

Mud lines              Script
---------              ------
Fred says: ...         line 1 (trigger on Fred)
                       line 2
                       line 3
You say: ...
                       line 1 (timer)
                       line 2
Fred says: ...         line 1 (trigger on Fred)
                       line 2
                       line 3


New input from you *or* the mud cannot be accepted in Mushclient until 'after' the script finishes. So Even though VBScript and others provide things like 'do until', they should always be avoided, unless they are being used to process something you are 100% sure will never loop endlessly. In your case it will loop endlessly, since this happens:

1. Script called.
2. Script retrieves last 3 lines.
3. There are no lines to retrieve.
4. Tests with 'like' and fails to exit.
5. Tries to retrieve the last 3 lines again.
6. Since the script is active and no lines *can* be recieved while it is active, the array is still empty.
7. Repeat steps 4-7.

Needless to say, this isn't going to work. What you need to do instead is use a trigger that matches on all lines to call the script, then test that line with a simple if-then, or one of the callbacks like OnPluginLineRecieved, where it makes sense to employ the getRecentLines function. But in that case you still need to change the method to a 'for each'.

I am sure Nick can give a better explaination as to why scripts don't run parallel to the input/output. I believe it has something to do with the use of the external script engine, instead of a built in one. With a built in one you have more flexibility, but you have to have a fairly complex system to handle execution, not unlike what muds themselves employ to handle mob programs and user commands. Like such mud systems, it is prone to error though, since unexpected delays in execution and unintended interactions are possible. Nor are such interactions always consistent. Personally, I think that 'some' parallel scripting, for cases like what you tried or a few other situations, like trying to use Windows Internet Controls to read in a web page, without IE. Some situations have unknown delay times or require loops, both of which badly lag or just plain hung the client. However, in most cases, like what you are trying to do, there is a way around it and the result is usually more reliable.
#2
I see what you mean about the array versus the string.
So really I should use a trigger to call bits of script then?

Here is the problem. I would just use triggers but I need to set up an If...Then... statement that will check to see if something has allready happened.

Basically I want the script to do this...
execute "Move to fence"

Command: Move to fence
World Output: "You move."
If world output = "You move" Then proceed Else Wait or check for error


execute "Jump over fence"

Command: Jump over fence.
(Some period of time, depending on distance to fence or something.)
World Output: "You jump over fence."
If "You jump over fence" returned THEN Proceed Else Wait or check for other known error like "There is no fence"

execute "Move to fence"

Command: Move to fence
World Output: "You move."
If world output = "You move" Then proceed Else Wait or check for error


execute "Jump over fence"

Command: Jump over fence
(Some period of time, depending on distance to fence or something.)
World Output: "You jump over fence."
If "You jump over fence" returned THEN Proceed Else Wait or check for other known error like "There is no fence"

But after two jumps over the fence, I want to "look for a rabbit."
IF Fencejump = 2 THEN Execute "look for rabit" ELSE GoTo Jump Fence

command: Look for rabbit
World Output: "Rabbit found"
IF world output = "Rabbit found" Then execute "Move to rabbit" ELSE GoTo Jump fence 

command: Move to rabbit
World Output: "You Move"

The problem is with the triggers. I need an If then statement to seperate out actions. Most of the time I am moving to the fence and jumping over, at some point I want to look for a rabit. If I find the rabbit then output would show I found a rabit. But then when I want to move to the rabit the output looks the same as when I move to the fence. So I need to distinguish that somehow. I can set up triggers to move to a fence when it is present and jump over it when I am done moving but I need them to not jump over the fence and instead "catch the rabbit" When I am moving to the rabbit. Does this help clarify what I am trying to do?

Now, from what you said I think what I need to do is this. Set up triggers that call up a script that will do either one or the other depending on what was last done, am I correct?

Thanks for the help.

Amended on Wed 07 Jul 2004 06:37 PM by Noodle
USA #3
Yes, basically.

I don't know how you are sending the first 'move to fence' command, but you would need something like the following triggers and script:

<triggers>
  <trigger
   enabled="y"
   match="*"
   name="fence"
   script="fencetest"
   sequence="100"
  >
  </trigger>
  <trigger
   enabled="y"
   group="rabbit"
   match="rabbit found"
   name="rabbit1"
   sequence="100"
  >
  <send>move to rabbit</send>
  </trigger>
  <trigger
   enabled="y"
   group="rabbit"
   match="You move."
   name="rabbit2"
   sequence="100"
  >
  <send>catch the rabbit</send>
  </trigger>
  <trigger
   enabled="y"
   group="rabbit"
   match="You caught a rabbit!"
   name="rabbit3"
   sequence="100"
   script="rabbitcatch"
  >
  </trigger>
</triggers>

sub fencetest (name, output, wilds)
  select case wilds(10)
    case "You move."
      send "jump over fence"
    case "You jump over fence."
      setvariable "fences", getvariable("fences") + 1
      if getvariable("fences") = 2 then
        send "look for rabbit"
        enabletriggergroup "rabbit", 1
        enabletrigger "fence", 0
      else
        send "move to fence" '??? jump fence again? I have no idea from your example.
      end if
    case else
      setvariable ("fences"), 0
  end select
end sub

sub rabbitcatch (name, output, wilds)
  enabletrigger "fence", 1
  enabletriggergroup "rabbit", 0
end sub


This is more flexible than if-then stuff, however it may not work 100% like you need. Usually a complex set of specific triggers work better, with some enabling/disabling each other, but that requires a very precise idea of what errors and other things to expect. In the above code, anything that is an error *or* any other unmatched line will cause 'fences' to be set to 0. This however includes messages, etc. so you are better off removing 'case else' and replacing it with the actual errors you expect. You can stack more than one match in a case like 'case "You can't move that way!", "Their is no fence."' or make one for each error and just copy the line for setting the varible to 0 into each one.

Note.. Since you may not really want to jump over every fence you come across, you may want to remove the 'enabletrigger "fence", 1' line in the last sub, then use an alias to activate that and send the first 'move to fence' command instead. In which case, you also probably want to make the trigger so it is 'enabled="n"' initially.
USA #4
The alias in for sending the first command would then be:

<aliases>
  <alias
   match="^mf"
   enabled="y"
   regexp="y"
   send_to="12"
   sequence="100"
  >
  <send>enabletriggergroup &quot;Fence&quot;,1
send &quot;move to fence&quot;</send>
  </alias>
</aliases>