smart healing triggers

Posted by Cron0 on Sat 14 Dec 2002 02:10 PM — 32 posts, 130,073 views.

United Kingdom #0
It's been a while since i did any scripting, so please bear with me, but here's my problem:

I have various afflictions i wish to heal, and each affliction has an associated cure. I want to get a system where i can use a single alias to cure one affliction at a time.

So far i am thinking of a trigger for each affliction which adds to an array, then a cure alias which calls a cure script to take one entry from the array, check it against a list of afflictions, then perform the cure.

My problem is that certain afflictions have a higher priority than others, so some kind of sorting or prioritising is needed. Whether i can sort the afflictions array, or have my cure script check against the highest priority afflictions first, i don't know. I would also need to trigger the 'you have been cured of affliction001' text to remove affliction001 from the array etc.

I'm not sure if this makes any sense :) but any pointers would be appreciated, thanks.
Australia Forum Administrator #1
Do you mean a cure alias, or to be more automatic, with a timer maybe? Can you post some example output?
United Kingdom #2
Sorry for not giving specifics, what i am looking for is a manual solution curing one affliction each time from a selection affecting my character, but where the particular affliction cured each time is selected automatically based on a priority list.

lol, that doesn't make any sense at all.

ok, here's an example.

Trigger match:Why does the world act so unfairly to you
Name:despair
Trigger match:Your breathing becomes rasping
Name:asthma

It's possible to get these two afflictions at once, and as the second one prevents the cure for the first one, if you trigger the cures automatically you'll be in trouble.

I would like to set up triggers for every affliction for a 'addaffliction' script is called which builds a variable/array of all the ailments my character has. Then i can run a 'cure' alias which looks in the affliction array and heals ONE affliction with each execution, but here's the trick, i want to be able to cure them in a specific order, ie not necessarily cure the afflictions in the order they were received.

This would also require a trigger for each of the cures, eg 'you are cured of despair' calls script 'removeaffliction' so i don't heal that one again next time i run my 'cure' alias.

I had a look on the forums and there is some good stuff i could adapt here:

http://www.gammon.com.au/forum/bbshowpost.php?bbsubject_id=2081

but i am not really sure of how to achieve everything i want, particularly curing just 1 affliction with each instance of the 'cure' alias, and also curing afflictions i am effected by in a specific order.
United Kingdom #3
ok, had a think about this and one solution would be to have a variable for every possible affliction. Say @affliction001 would be despair, my top priority to cure, then asthma as @affliction002 etc. So i can set up some triggers for the afflictions:

Trigger:why you ask does the world act so unfairly towards you
Send to variable:despair
Label:affliction001

Trigger:your breath becomes rasping
Send to variable:asthma
Label:affliction002

Then my 'cure' alias would run a script which first looks at @affliction001, if affliction001 = despair then do some commands to heal despair and exit. If affliction001 = empty then look at affliction002, if affliction002 = asthma then do commands to heal asthma and exit. If affliction002 = empty then move to affliction003 etc.

Would also need the corresponding cured triggers.

Trigger:you are cured of despair
Send to variable:(nothing in here?)
Label:affliction001

etc.

Is this doable? and does this make any sense? *g*
USA #4
Hmm. One comment.. You may be able to use the sort() command of an array in javascript. You would assign each affliction a priority number and just store those numbers. So if despair had a higher priority than asthma you would assign 1 to the first and 2 to the second, etc. depending on which ones you want treated first. So, when you are afflicted with despair your trigger would call a sub to retrieve the current index, increase it by one, then add the priority number to the array:

var a,Indx,temp;
temp = world.getvariable("Afflicts");
a = temp.split(",");
Indx = world.getvariable("Index") + 1;
a(Indx) = 1;
temp = a.join(",");
world.setvariable ("Afflicts",temp);

Then your alias to do the cures would call a script with:
var a,l,temp;
temp = world.getvariable("Afflicts");
a = temp.split(",");
l = a.sort();
if (a(0) == 1)
  world.send ("do whatever...");
if (a(0) == 2)
  world.send ("do the next thing");
a(0) = 999
temp = a.join(",");
world.setvariable ("Afflicts",temp);

and so on. Note: I don't know jscript real well so this is bound to be wrong. lol However, since vbscript has no built in sort... If you are already using VB, it may be necessary to make this into a plugin or find a sorting solution for VB instead.

In any case, by sorting the array, the first item should always be the highest priority affliction you currently have, and thus the one that will be cured by the alias.
Amended on Sun 15 Dec 2002 04:19 AM by Shadowfyr
USA #5
While VB doesnt offer a sort function it does offer a rather solid case structure that can be used without having to go thru the insanity of assigning each affliction a severity rating of some kind. It shouldnt be particularly processor intensive to have each affliction trigger the case check and heal every affliction you suffer from at the time in the order they appear in the case structure. So for your linked afflictions you could use something like:

case 0:
cure asthma
case 1:
cure despair
case 2:
cure next_spell

Granted, that wont work as written but you get the idea. Actually, it might be easier to have the case only for the linked afflictions and just run everything else on triggers, though if you did that a simple
if is_afflicted <linked affliction> 

check of some kind should work
Amended on Sun 15 Dec 2002 02:11 PM by Meerclar
USA #6
Umm.. Meerclar I think you missed the point. Yes you could use a case statement, but then you would have to employ some sort of loop that would find the highest priority item in the current list, otherwise you are not healing the afflictions 'in the order of priority'. Instead you would end up healing the first one in the list, or a series of them, but in the wrong order. As I understand what Cron0 wants, it is to only heal one affliction each time he uses the command, but for that one to always be the affliction that is the most dangerous or debilitating of the ones that currently affect him. You can't do this without some way to either find the lowest number in the list (highest priority), but sorting them is the fastest means to do so and VB can't do that without writing your own sorting routine. Then there is the issue that VB doesn't let you expand arrays by simply using a new index value as jscript will, so you have to have an array that is exactly the same size as the total number of affliction you expect to be effected by at any one time, right from the start.

Otherwise I agree that the case structure in VB would be much easier to use and modify when needed.
USA #7
Actually, with a lil creative variable handling, a case structure wouldn't have any problem at all adjusting to any number spell affects on a single structure. An elaborate elseif structure would probably be easier to write but a case could handle the demands of curing a single affliction with every running of the script without much difficulty I would think.
Canada #8
Sigh. I've been too lazy to do my own scripting, but I can't allow this madness to continue, so I'll come out of my semi-retirement to offer my viewpoint:

:)

Now, it doesn't seem like there is a need to remember the state of afflictions between MUSHclient sessions. I'm betting you won't be quitting the mud while you are afflicted with something. Given that, you don't need to use MUSHclient variables. Regular script variables should safice. I would build an array of all the afflictions, doing so as mainline code, outside any subroutines:

(In Visual Basic Scripting)

Dim BodyState(6,2)

BodyState(1,1) = "asthma"
BodyState(2,1) = "despair"
BodyState(3,1) = "gangreen"
BodyState(4,1) = "arthritis"
BodyState(5,1) = "stupidity"
BodyState(6,1) = "delusional"

The order of afflictions in the array indicates their priority, so if one affliction needs to be cured before another, then that first affliction should be above the second in the list.

Now, a subroutine to reset all Afflictions to cured:

Sub BodyState_Reset (AliasName, AliasLine, arrWildcards)
  Dim x
  For x = LBound(BodyState) to UBound(BodyState)
    BodyState(x,2) = vbFalse
  Next
  World.Note "Afflictions reset."
End Sub

You can create an alias to call that subroutine, in case you are having some problems and just want to reset everything. You must call the routine once from the script when you first load the world, so put the following line in your mainline script, outside any subroutines (I would put it right under where I set up the array):

Call BodyState_Reset "Mainline", Empty, Empty

Now, the subroutines to call when you are inflicted and cured of afflictions. For afflictions, start all your trigger labels with "BA_" followed by the name of the affliction. (BA for Body Afflicted). For cures, start all your trigger labels with "BC_" followed by the name of the affliction. (BC for Body Cured):

Sub Body_Afflicted (TriggerName, TriggerLine, arrWildcards)
  Dim x
  TriggerName = World.Replace(TriggerName, "BA_", "", True)
  For x = LBound(BodyState) to UBound(BodyState)
    If BodyState(x,1) = TriggerName Then
      BodyState(x,2) = vbTrue
      World.Note BodyState(x,1) & ": Afflicted"
    End If
  Next
End Sub

It's important that you label your triggers correctly. Examples might be:

Trigger:why you ask does the world act so unfairly towards you
Label:BA_despair
Script:Body_Afflicted

Trigger:your breath becomes rasping
Label:BA_asthma
Script:Body_Afflicted

On to curing. First, the subroutine to call when you trigger that you have been cured:

Sub Body_Cured (TriggerName, TriggerLine, arrWildcards)
  Dim x
  TriggerName = World.Replace(TriggerName, "BC_", "", True)
  For x = LBound(BodyState) to UBound(BodyState)
    If BodyState(x,1) = TriggerName Then
      BodyState(x,2) = vbFalse
      World.Note BodyState(x,1) & ": Cured"
    End If
  Next
End Sub

It's important that you label your triggers correctly. An Example might be:

Trigger:you are cured of despair
Label: BC_despair
Script: Body_Cured

Now, all the monitoring is done, just to write the actual script to perform the required service:

Sub Body_Heal_Affliction (AliasName, AliasLine, arrWildcards)
  Dim x
  Dim SubtoCall
  For x = LBound(BodyState) to UBound(BodyState)
    If BodyState(x,2) Then
      SubtoCall = "call Cure_" & BodyState(x,1) & " " & Chr(34) & "Body_Heal_Affliction" & Chr(34) & ", Empty, Empty"
      ExecuteGlobal SubtoCall
      Exit For
    End If
  Next
End Sub

Setting up the 'SubtoCall' is a bit complicated, but it allows for more flexibility. The last step is to create a subroutine for each affliction, which sends to the mud whatever you need to do to cure that particular affliction. For example:

Sub Cure_despair (AliasName, AliasLine, arrWildcards)
  World.Note "Attempting to cure: despair"
  World.LogSend "cast cure despair"
End Sub

The name of these subroutines is VERY important, since they are called by the routine "Body_Heal_Affliction". (Make sure each one starts with "Cure_" followed by the name of the affliction). The flexibilty comes in that you can create seperate aliases if you wish, for each particular affliction, and have them call the same routines.

Regarding that sub, "Body_Heal_Affliction", it will only make a call to cure one affliction at a time, based on the order they are placed in the array. If you want to cure them all at the same time (but still in the proper order), simply delete the line "Exit For".

As a final project, it would be real simple to write one more routine to display all the possible afflictions (in the array), and display a chart indicating your current state of health. I'll leave that to you.
Canada #9
Actually, upon further reflection, I would probably add an additional element to the array which would be the line(s) to send to the mud to cure the affliction. It's a little more efficient and less prone to errors, although not as flexible.

Here's the whole thing, modified a little:

Dim BodyState(4,3)

BodyState(1,1) = "asthma"
BodyState(1,2) = "use inhaler"

BodyState(2,1) = "despair"
BodyState(2,2) = "visit psychiatrist"

BodyState(3,1) = "gangreen"
BodyState(3,2) = "amputate limb"

BodyState(4,1) = "arthritis"
BodyState(4,2) = "request family member do chores for me"

Call BodyState_Reset "Mainline", Empty, Empty

Sub BodyState_Reset (AliasName, AliasLine, arrWildcards)
  Dim x
  For x = LBound(BodyState) to UBound(BodyState)
    BodyState(x,3) = vbFalse
  Next
  World.Note "Afflictions reset."
End Sub

Sub Body_Afflicted (TriggerName, TriggerLine, arrWildcards)
  Dim x
  TriggerName = World.Replace(TriggerName, "BA_", "", True)
  For x = LBound(BodyState) to UBound(BodyState)
    If BodyState(x,1) = TriggerName Then
      BodyState(x,3) = vbTrue
      World.Note BodyState(x,1) & ": Afflicted"
    End If
  Next
End Sub

Sub Body_Cured (TriggerName, TriggerLine, arrWildcards)
  Dim x
  TriggerName = World.Replace(TriggerName, "BC_", "", True)
  For x = LBound(BodyState) to UBound(BodyState)
    If BodyState(x,1) = TriggerName Then
      BodyState(x,3) = vbFalse
      World.Note BodyState(x,1) & ": Cured"
    End If
  Next
End Sub

Sub Body_Heal_Affliction (AliasName, AliasLine, arrWildcards)
  Dim x
  For x = LBound(BodyState) to UBound(BodyState)
    If BodyState(x,3) Then
      World.Note "Attempting to cure: " & BodyState(x,1)
      World.LogSend BodyState(x,2)
      Exit For
    End If
  Next
End Sub
#10
I wonder if someone's doing PvP on Achaea... *grin*

I have the same issue, and I'm doing things a bit differently. I am setting up variables and flags for each affliction and doing the following:

Let's assume I'm hit with a message for stupidity:

"Hmmmm. Why must everything be difficult to figure out."

I have a trigger that calls a script "affSetStupidity"

affSetStupidity sets a variable called "affStupidity" to 1.

I then have a macro (F7) that sends "herbCure" to world, and an alias "herbCure" that calls a function "herbCure".

herbCure is a huge IF statement, that is set up in priority of cures. So:

If world.getVariable("affStupidity") = "1" Then
world.send "get goldenseal from belt"
world.send "eat goldenseal"
...
ElseIf ...

I then wait for a cured message from the world:

"You aren't such a complete idiot anymore." (

(whoohoo! Heh) I then have a trigger on that message that calls a script "affClearStupidity" which sets "affStupidity" to 0.

Now in the case where you might be "locked" from one cure because of another cure, I'm actually working on that - I think I will I will have some ANDS so that if I'm trying to eat something and I have an affliction that keeps me from eating, then that If condition won't be met and the ElseIf would drop to something else.

A LOT of programming. But fairly straightforward.

All this leads me to an interesting question. Which is faster in regexp processing?

If I have a "message" - will doing this as a trigger .*message.* be faster that just having "message" (no quotes) as the trigger? Is there a real difference in either?

Regards,
Neurowiz
(Tirell in Achaea)
Canada #11
I thought about using a series of IF statements, or a CASE statement (as others have suggested), but I thought my approach works well because it's easy to edit, should you want to add a new affliction.

With your approach, if you discover a new affliction, you have to add lines all over the place.

To send multiple lines like you mention in your example, and using my method, you might set up one of the array records like this:

BodyState(5,1) = "stupidity"
BodyState(5,2) = "get goldenseal from belt" & Chr(10) & "eat goldenseal"

Regarding triggers, I personally don't know which are 'faster' to process. In many cases I prefer to use a regular expression unless it's a straight-forward line with no wildcards, and one I am fairly sure won't be accidently preceded by a prompt.
United Kingdom #12
Thanks for all the suggestions guys, and Magnum that script looks like it does exactly what i am looking for. Just one small point on syntax, i was getting quite a few errors when i copied it directly, for example it just didn't like:

Call BodyState_Reset "Mainline", Empty, Empty


but when i changed it to:

BodyState_Reset "Mainline", "", ""


which seems to me to be substantively the same, it worked fine. Not sure if this is a different version of vbscript or whatever. But with a bit of tweaking and some testing, it seems to be working great, so thanks a lot mate!

Oh and Neurowiz, i don't play achaea, i play the mud they ripped all their ideas from ;) by the way, i would be interested in knowing how you build a delay into your pipe lighting trigger? I know in zmud and tintin you can just disable/enable on a timer, and in tinyfugue i used to change the trigger probability on a timer (most redundant feature ever?), but what's the mushclient/vbscript solution?
Canada #13
Heh... I -never- use "call" myself (to call subroutines), but rather just use the sub name as you did. I was fairly sure that "call" is a valid function though, so I wrote it in the forum as a means to help clarify what was being done.

Anyway, I'm glad you got it working relatively easily. It's tough to write fool-proof script directly into a forum posting without testing it at all. :)
USA #14
Actually, my idea for the case structure involved MC variables for every possible affliction with triggers to set the values true and the case to evaluate true flags in order of severity. Assign everything a variable to begin with and there's no need to change the script unless new spells are added to the mud that will need to be handled by the script instead of pure triggers.
#15
Hi Magnum

When does this array get initialized originally? It's not clear to me when this array would get "built" with the various afflictions/cures.

Hi Cron0

Can't comment on other MUDs, I've only played Achaea and it takes up enough time. For my pipes - I'm not sure what you are asking?
Canada #16
Well, the array is outside any subroutines, which means it gets executed immediately, when the script is loaded.

The script is loaded when you open the world file. You can also force a reload of the script from the menu options or by pressing SHIFT-CTRL-R.

Because the script does NOT use MUSHclient variables, it will forget any afflictions you have (they will be reset), whenever you [re]load the script file. People don't often force a reset of their script unless they are busy debugging something. I also doubt people will quit their mud while afflicted with something (or that they will still be afflicted if they log on a while later), which is why I proposed MUSHclient variables not be used. Using MUSHclient variables makes things just a tiny bit slower, so I avoid them when possible.
United Kingdom #17
Hi Neurowiz, i just meant that do you have a trigger to keep your pipes lit at all times? and how do you get around disabling/enabling the trigger so you don't light each pipe multiple times and create a load of spam.

I'm pretty sure you achaea guys smoke as much as us avalon junkies, but if you have no idea what i'm talking about please ignore me :)
#18
I have a trigger/timer combination. I use an alias to fill and light the pipes and enable a timer. Then the timer autosmokes every 1.25 minutes. I also have a macro for smoking manually and some triggers on afflictions or events to smoke. I also have a trigger for if a pipe goes empty. When I'm done with smoking, I have an alias that will empty the pipes and shut the timer off.

HTH.
#19
Hi Magnum

I like your approach, although I've had to add a couple of additional elements - I use the InfoLine to give me a "gauge" of which herbs I need to eat/salves I need to apply, so I had to add an array element that indicates which Gauge is affected by each affliction.

Alternatively, since I have to do some curing by herbs and some by salves, I've had to use two different keys (there are issues about trying to do it all with one key, the timing of curing what/when would be a bit trickier with just one big run through the array.

There's also issues of some afflictions cannot be cured because of other afflictions. For instance, I may be afflicted by anorexia, which prevents me from eating, so I have to apply a salve.

I've therefore added another element to the array that indicates what type of cure it is: herb or salve.

For now, until I figure out a more elegant way, I'm using boolean flags to indicate the "special" afflictions that might stop herb or salve cures.

Thanks for the code, I'm actually now converting many of my "temporary" variables to non-MC variables - although some I am going to keep - have to retain from connection to connection.

#20
can you post all you put up and how to do it, thats exactly what i need, so please if you could help me?
Canada #21
Laf. I found this post by doing a search for "arthritis". (I remembered using that as an affliction).

Bumping this thread for someone who wants the exact same thing.
Israel #22
I know this is an old subject, but there's one thing that kind of sparked my curiousity. I know this may sound dumb, but whats an InfoLine?
Australia Forum Administrator #23
If you go to the View menu you can see an "Info Bar" entry which can be toggled on and off. This is a status bar near the bottom of the screen that can be programmed from a script to contain various things.
Israel #24
Ok. Thanks Nick. But what the exact command to get it to show somethign on the info line. Lets say I get a certain affliction, and I want it to show on the INfo line. E.g. (Stupidity,Paralysis).
Thanks
Australia Forum Administrator #25
See Info
Israel #26
Ok thanks. Only, is there any way not to clear the whole thing at once and just one specific thing?
Australia Forum Administrator #27
Not really, the only thing I can suggest is remembering what you put there, and putting it back.
Russia #28
This probably belongs in the Bugs section, but since it was the result of my own stupidity... After reading one of your posts about Info bar I went and did something extremely odd, Nick - I repeated what you told us not to repeat, namely dragged the bar into the middle of the output screen and dropped it. Don't ask why... Now, I've tried to reinstall Mushclient but my Info bar still stays broken, is there any more or less easy way to fix it?
Australia Forum Administrator #29
  • Click right near the left of the info bar (between the double lines) but with the mouse still an arrow and not a double-arrow. If you get it right you can then drag the info bar away.
  • Drag it right away from the MUSHclient window, until you see the outline change to thicker lines.
  • Let go - it will become an independent window.
  • Then drag it again, and drop it over the status bar. It should then reappear in its correct spot.
Australia Forum Administrator #30
The other approach is to uninstall MUSHclient - which should fix up the position of the info bar, which is in the Registry. Then reinstall it. However then you will need to re-enter your registration code.

NB - I see the forum has put this on a separate page - read my earlier post first, that should fix it without having to reinstall MUSHclient.
Russia #31
thanks, Nick

Your instructions worked. Somehow I was afraid to fiddle with it anymore than I already did, and I can't even say how happy I am to have that bar back and functioning - now I don't have to check what mode my triggers are in every 5 seconds.