Ok, I know you would probably be more inclined to help me with this if I were to make an attempt and post it, but the simple truth is I know nothing about scripting and I'm hoping something familiar like this (I've done this in tintin++, zMud, and gMud)will help me understand scripting for other uses in MushClient.
Here's what I'm trying to do:
If I type "group" it pulls up text with vital stats of all my group members that looks like this:
[100H 100M 100V] Tim
[200H 100M 100V] Fred
etc.
What I want to do is check the numeric data before the "H" in the tanks line, the tanks name being a variable, @name, and if it's less than another variable, @hp, it will cast a spell, also a variable, @spell. Furthurmore, I would like to be able to set the name, hp, and spell from within the mud simply by typing "name Fred" or "name Zin" etc. Same for hp and spell.
It would work nicely with my already learned keystrokes if I could also use those variables in other aliases, like "a=assist @name" and "j=cast '@spell' @name".
Now I know I can't use variables in a trigger, so I will have to script this. Again, I am unfamiliar with any form of scripting, but I hope this will help me understand so I can create others.
I'll just answer the 'setting a variable part' of your question. The following is a Visual Basic Script example:
Sub Set_Name (thename, theoutput, arrWildcards)
World.SetVariable "Name", Trim(arrWildcards(1))
End Sub
Once you have that subroutine in your script file, you could create an alias:
Alias : name *
Send : <Leave blank>
Label : Name
Script: Set_Name
...that would allow you to set the name whenever you wish. Once the name is set, you can use "@Name" in any other alias. Make sure you click "Expand Variables" in any alias that uses one.
Now I know I can't use variables in a trigger, so I will have to script this.
You can use variables in triggers and aliases, just check the "expand variables" box. Then you can make an alias like you said:
Alias: a
Send: assist @name
Enabled: checked
Expand variables: checked
As Magnum said, you can make a small script that sets the "name" variable, and make another similar one for the spell variable.
As for the rest, you could make a trigger that matches on the appropriate things like this:
Trigger: [*H *M *V] *
Then inside the script the "H" number will be wildcard 1 and the name of the person will be wildcard 4 (the fourth asterisk). You can then make decisions about whether or not to cast a spell.
Ok, I think I've made some good progrgess on this, thanks for the assistance. Unfortunately, I'm coming up with an error in the name wildcard due to a tag (Head of group).
Here's what it looks like again (the complette string this time):
[ 100H 900M 99V] [40 Cl Hum] Fred (Head of group)
[1100H 100M 128V] [41 Wa Ogr] Steve
The trigger looks like:
*[*H *M *V] [*] *
But this picks up (Head of group) in %6 and throws off my name recognition. And if I use
*[*H *M *V] [*] * * * *
or
*[*H *M *V] [*] * (Head of group)
Then it won't match for Steve when he's the one I want to check (98% of the time).
Here's the script I have so far:
Sub Set_Name (thename, theoutput, arrWildcards)
World.SetVariable "name", Trim(arrWildcards(1))
End Sub
Sub Set_HP (thename, theoutput, arrWildcards)
World.SetVariable "hp", cint(arrWildcards(1))
End Sub
Sub Set_Spell
World.SetVariable "spell", Trin(arrWildcards(1))
End Sub
-just so I can set mym variables in the game.
Sub Set_CurrentHP
world.setvariable "CurrentHP", cint(arrWildCards(2))
world.setvariable "tank", Trin(arrWildcards(6))
call Heal_Action
End Sub
Sub Heal_Action
if world.getvariable("tank") = world.getvariable("name") then
if world.getvariable("CurrentHP") < world.getvariable("hp") then
world.send cast 'world.getvariable("spell")' world.getvariable("name")
end if
end if
End Sub
The error I get is "We expected your subroutine to have 3 arguements" when processing the Heal_Action sub.
So, the problem looks like, how can I get the %6 wildcard regardless if there's words after it or not. Thoughts?
Whenever you call a script routine with an alias or trigger, mushclient passes along three arguments to the script routine.
In the Set_Name subroutines, you see three variable names in brackets. These indicate that the subroutine expects 3 arguments to be passes to it when it is called.
"thename" is the name of the alias or trigger that made the call to this subroutine. (Mushclient sends this automatically)
"theoutput" is the line of output that caused your trigger to kick off. You still need this line even if you are only using an alias to call the subroutine. (Mushclient sends this automatically).
"arrWildcards" are the wildcards that were gathered by the alias or trigger. (Mushclient sends this automatically).
In the two routines that you made yourself, you do NOT accept arguments in either of them, yet it is likely that you are calling at least one of them from an alias or trigger.
If you call a subroutine from an alias or trigger, and the subroutine is NOT configured to accept 3 arguments, you will get the error message that you did.
Note: In a couple of places, you spelled "Trim" wrong. I hope that is not a direct copy & paste from your script file.
[ 100H 900M 99V] [40 Cl Hum] Fred (Head of group)
[1100H 100M 128V] [41 Wa Ogr] Steve
There are two ways (I can think of) to get around the problem presented here, in which extra text is presented after the final wildcard you would like to gather, but only some of the time:
One way is to write VBS script to check for the string, and remove it. You could use VBS functions like "InStr" to look for the text, and if exists there are other commands to pull a string apart (though I don't remember what they are off-hand).
The second method, and I'm sure this is the one Nick will advise, is to convert your trigger line to a 'regular expression' (by pressing that button in the trigger window), and then modifying the trigger line slightly.
Expect confusion and complexity to burst forth. You can try clicking "help" in the create/edit trigger window, and read up on "regular expressions", but I guarantee, you will never be totally clear on the matter. LOL.
When you use a regular expression, all sorts of characters suddenly have special meanings, so you have to be very careful about every character on the trigger line. Round brackets AND square brackets have special meanings, as well as several punctuation symbols. If you want to search for a line that contains, for example, a square bracket "[", then you must 'escape' it by proceeding it with a '\'.
Here's how I will go about it:
I put this on the trigger line:
*[*H *M *V] [*] * (Head of group)
I clicked "convert to regular expression", which changed the line to this:
^(.*?)\[(.*?)H (.*?)M (.*?)V\] \[(.*?)\] (.*?) \(Head of group\)$
Now, theoretically, if something is wrapped in square brackets (not 'escaped'), then it is a conditional wildcard, so I would try adding an extra [ and ] around the \(Head of group\) part of the trigger line, to say to mushclient "match this as a separate wildcard IF it exists". Here is the result, and this is the line you should try and C&P into your client:
^(.*?)\[(.*?)H (.*?)M (.*?)V\] \[(.*?)\] (.*?)[ \(Head of group\)]$
The $ signifies 'end of line', so I still left that after the final "]".
After quite a bit of testing of the regular expression Magnum advised, and some variants, I have come up with this that seems to work against your two test cases:
^(.*?)\[(.*?)H (.*?)M (.*?)V\] \[(.*?)\] (.*?)( \(Head of group\))*?$
The change is, that instead of using square brackets I used round brackets. Square brackets mean "one out of the following", eg.
b[ai]*t matches bat, bit and bt (and also baat, biit)
however
b(ai)*t matches bait, bt, baiait and so on.
Since you are are really trying to match on a string, and not just a character, I think the round brackets are better. Then you follow them with an asterisk to indicate "zero or more".
Magnum and Nick,
Yes, I cut and pasted. Thanks for pointing out the typoes. Also thanks for pointing out the missing arguement identifiers. I assumed they were descriptive in your original example. They've been corrected and work wonderfully.
Trying to get the string to match was a chore, and thank you both for your efforts. After a couple of tweaks for irregular spacing, I have it working using regular expressions.
Thanks for the support, the effort, and the handholding. I really couldn't have done this without your assistance.
Regarding regular expressions, could you help me some more Nick?
At the Mud I play, I have the prompt configured to simply be "> " .
Sometimes, text output will be appended to the same line as the prompt, and in rarer cases, multiple prompts.
For example:
as We have one.
[assassin] Magnum: We have one.
> [gossip]: Killa suggest making a fur coat from his cat
[gossip]: Killa grins evily
[gossip]: Joric protects his kitty.
Now... I have found that the following pre-pending text I would like to trigger on works:
(^|> )
...but I would like it to be absolutely fool-proof, so that no one could echo fake text to fool my trigger, and so that stacked prompts won't mess it up. For the most part, the regular expression above works, EXCEPT for triggers where the very first word is a wildcard:
^[> ]*(.*) thanks you\.$
That is one of my triggers... but it can be falsely set off if I type "say fake thanks you.", and also, if the trigger line appears with "> " in front, then the "> " is grabbed as part of the wildcard which is intended to be the name of the person. (%3).
I don't know if it's ever possible to make a fool-proof trigger where the first item is a wildcard... If it is, please advise. :)
You can probably do a couple of things to protect yourself.
Try something like this:
^(> )*(\w*) thanks you\.$
The first change is to put the prompt inside round brackets, so it must match on exactly "> " not just things like >>>> or a whole lot of spaces.
The second change is to use \w for the character name (\w is a "word") and thus it will match on one word (eg. "nick thanks you." but not a faked line (eg. "john says, nick thanks you.").
If you have more complex prompts, try using \d for digits rather than just ".". (\d is "any decimal digit").
For example, a prompt line with HP etc might look like this:
\<\d+hp \d+m \d+mv\>
This is better than, say:
\<.*hp .*m .*mv\>
because we are matching one "one or more digits" not "zero or more of anything".
Ok, here's a little twist that is difficult for me to check, but will be coming up more frequently as I group with higher level players more often.
When the %2 value is greater than 999 and I'm trying to determine if it is less than @hp where @hp is less than 1000, I get a true value if (I think) the %2 value last 3 digits is less than the @hp value. i.e. 1200 comes back as less than 700. How can I fix this? Here's the script I'm using:
Sub Set_Spell (thename, theoutput, arrWildcards)
World.SetVariable "spell", Trim(arrWildcards(1))
End Sub
Sub Set_CurrentHP (thename, theoutput, arrWildcards)
world.setvariable "CurrentHP", cint(arrWildCards(2))
world.setvariable "tank", Trim(arrWildcards(6))
call Heal_Action
End Sub
Sub Heal_Action
if world.getvariable("tank") = world.getvariable("name") then
if world.getvariable("CurrentHP") < world.getvariable("hp") then
World.Send "cast '" & World.GetVariable("spell") & "' " & World.GetVariable("name")
end if
end if
End Sub
When I am attempting to debug my script, and am having trouble because everything 'looks' correct, I will often insert World.Note lines to echo the values stored in variables. Quite often, the value is not what i expect, and that points me in the direction to look for the error.
Here is one of the lines from your script:
if world.getvariable("CurrentHP") < world.getvariable("hp") then
Try entering this line BEFORE the one quoted above:
Sub Set_HP (thename, theoutput, arrWildcards)
World.SetVariable "hp", cint(arrWildcards(1))
End Sub
I've inserted your line to display the CurrentHP variable, but I'll have to wait until I can find someone with >999 hp to check it out. And yes, there are no commas.
Now that I've looked at it, I think it may be the trigger line. When someone has >999 it makes for some different spacing. I'll have to cut and paste that as well when I get the chance.
Hrm, I wasn't actually able to add that line. I end up with an error "Expected end of statement" in column 74 of your line. I think that's right after World.Note " HP: ". It may have something to do with the line wrap, so I've amended it to look like this:
Careful about making assumptions about what you expect to be in a variable, especially when you are attempting to debug your script.
Nick is correct, of course. I put an extra "World.Note" in by mistake.
Try his line for a while to confirm BOTH variables are what you expect. When you are sure one or both are correct, remove what you don't want to see anymore.
Ok, used it and here's what I get: When @hp<1000 and @CurrentHP>999, except when @hp=100, there is an error in the math function.
Example:
@CurrentHP=1123 @hp=250 comes back as @CurrentHP<@hp.
@CurrentHP=1123 @hp=100 comes back as @CurrentHP>@hp.
@CurrentHP=1123 @hp=1050 comes back as @CurrentHP>@hp.
It's not the trigger, it's not the variables. I even put a "." at the end of the variable to make sure there wasn't a wierd space there when displaying it. Here's the VB script again:
Sub Heal_Action
if world.getvariable("tank") = world.getvariable("name") then
World.Note " CurrentHP: " & World.GetVariable("CurrentHP") &"." & " HP: " & World.GetVariable("hp") &"."
if world.getvariable("CurrentHP") < world.getvariable("hp") then
World.Send "cast '" & World.GetVariable("spell") & "' " & World.GetVariable("name")
end if
end if
End Sub
The way that variables are stored is as text, so the comparison is between "1123" and "250", and since "1xxx" is less than "2xxx" it comes back as "less than".
You can fix that by converting to integer (cint), in which case the comparison works correctly, eg.
if cint(world.getvariable("CurrentHP")) < cint(world.getvariable("hp")) then