tf sipper code woes.

by Unknown

Back to Mechanic's Corner.

Unknown2010-01-21 03:16:30
Hi, I'm still have the odd issue with tf. First of all, when the sipper runs it will sip two times before it stops. Here is a sample of what I'm looking at.

+--------| RIGHT ARM BALANCE |--------+
You swing a well-balanced wooden training broadsword at a taurian hunter. You
cut him, opening up deep lacerations.

You bleed 47 health.

+--------| LEFT ARM BALANCE |--------+
You do not bleed, my friend.
You swing a well-balanced wooden training broadsword at a taurian hunter. You
cut him, opening up deep lacerations.
The blade shears through a taurian hunter's body, coming clean through the
other
side with a strangely quiet swish. He appears momentarily surprised, before
his
eyes glaze over in death and he collapses to the ground.
You have slain a taurian hunter.

You may drink another health, mana, or bromide potion.
You must regain balance first.
You take a drink from a glowing amethyst vial.
balHealth1 is 0
The potion heals and soothes you.
You must regain balance first.
You take a drink from a glowing amethyst vial.
balHealth2 is 0
The potion flows down your throat without effect.

+--------| RIGHT ARM BALANCE |--------+

+--------| LEFT ARM BALANCE |--------+

You may drink another health, mana, or bromide potion.
You pick up the corpse of a taurian hunter.

The code at the time had variable echos inserted which are not there now in the following code snippet.
CODE
/def -wlusternia -mregexp -p1975 -F autoSip = \\
        /if (({healthSip}==1) & ({continueSip}==1) & ({balHealth}==1)) \\
                /if (({perHealth} <= 0.40)|(({perHealth}<=0.70)&({perMana}>=0.60
)&({perEgo}>=0.60))|({perEgo}==0)) \\
                        get health from backpack%;drink health%; \\
                /elseif ((({perEgo} <= 0.50) | (({perEgo} <= 0.70) & ({perMana}
>= 0.60))) & ({perEgo} != 0.0)) \\
                        get bromide from backpack%;drink bromide%; \\
                /elseif (({perMana} < 0.60)) \\
                        set mana from backpack%;drink mana%; \\
                /endif%; \\
                /if ((({perHealth} <= 0.25) | ({perMana} <= 0.25) | ({perEgo} <=
0.25) & ({perEgo} != 0.0)) & ({balSBerry}==1)) \\
                        outr sparkleberry%;eat sparkleberry%; \\
                /endif %; \\
        /endif

Not shown is the on/off toggle.

As an additional issue, if there is no more potion left in the vial, and no vials of health in the backpack, the system manically retries the command eventually causing tf to unhook the system. I'm thinking of putting the "get from backpack/sip health" commands in a special macro that would help the sipper exit a bit more sanely instead of bringing the whole thing down.

Anybody have any ideas on how to do this, or would a simple else on the ind of the if statements provide a safe way to break out?
Zallafar2010-01-21 04:40:07
You don't say how you determine balHealth, but here is my guess. Since you don't change balHealth right here where you are drinking, I suspect you are waiting for a trigger to do it. The problem is that you can get another prompt before the game has processed your drink command. So the same situation still exists, with it looking like you have balHealth and your health is low and so another drink is issued. I always say that I don't have balance before sending the command to avoid this issue.

It starts getting more complicated at that point. What if the command didn't go through? How do you restore the balance since you won't see a trigger that you have balance again? I have timers. What if you are in blackout and don't see the command going through, but it did? I always take down balance both before performing the command and also when I see the game confirm the command went through. Some people use 1, .5, and 0 for the three states of having balance, command sent that takes down balance, game confirms that balance was taken down.

Also you have a typo "set mana from backpack" and you want "get".
Unknown2010-01-21 05:28:37
QUOTE (Zallafar @ Jan 20 2010, 09:40 PM) <{POST_SNAPBACK}>
You don't say how you determine balHealth, but here is my guess. Since you don't change balHealth right here where you are drinking, I suspect you are waiting for a trigger to do it. The problem is that you can get another prompt before the game has processed your drink command. So the same situation still exists, with it looking like you have balHealth and your health is low and so another drink is issued. I always say that I don't have balance before sending the command to avoid this issue.


Indeed I do depend on triggers. What you describe didn't even occur to me so I didn't think to show that. That sounds like a very good idea.

QUOTE (Zallafar)
It starts getting more complicated at that point. What if the command didn't go through? How do you restore the balance since you won't see a trigger that you have balance again? I have timers. What if you are in blackout and don't see the command going through, but it did? I always take down balance both before performing the command and also when I see the game confirm the command went through. Some people use 1, .5, and 0 for the three states of having balance, command sent that takes down balance, game confirms that balance was taken down.


Yeah, blackout situations i had considered, but I wanted to keep it simple till I learned more about what I was doing. I guess I'm at that point now. Assuming balance state before game confirms it via timers and such might be what i'm looking for.

By the G's! This stuff is complicated. :-(

QUOTE (Zallafar)
Also you have a typo "set mana from backpack" and you want "get".


Silly typos! Thanks for catching that.
Unknown2010-01-21 05:52:36
I'm not here to comment on code, because I hate TF, but why are you taking vials from pack? Never, ever have them there. All vials should always be out.
Unknown2010-01-21 10:53:11
QUOTE (AllergictoSabres @ Jan 20 2010, 10:52 PM) <{POST_SNAPBACK}>
I'm not here to comment on code, because I hate TF, but why are you taking vials from pack? Never, ever have them there. All vials should always be out.


Vials are out, it's just in case I don't have what I need out for one reason or another. It's simply a precaution.
Unknown2010-01-21 12:42:08
Your vials should never be in your pack, unless maybe they're empty. If you get hit with any of a number of afflictions, you cannot take things out of your pack, and then you're screwed. There's little reason not to keep them all in your hands at all times.
Zallafar2010-01-21 12:48:53
I make my vials all the same as much as possible so they don't clutter up my inventory.

QUOTE
You are wielding a simple mandolin in your left hand.
You are holding:
86 beryl vials, ...
Unknown2010-01-21 12:57:15
See, I make all my vials unique per each type of fluid, so I can tell what I'm sipping. Inventories can be searched easily enough, so clutter isn't really a problem.
Unknown2010-01-22 01:09:40
But I don't usually keep my vials in my backpack, it's a "just in case I was dumb enough to do so, forgot and get mugged" scenario where I "might" have a chance to pull it out before I die.

Now, that said, I have been dumb enough to leave my pipes in my backpack and learned the "don't do that" the hard way. smile.gif
Unknown2010-01-22 11:04:01
In a related question, is having "get $item from backpack" command a possible source of problems, regardless whether, or not I have my vials/pipes/herbs out already?
Unknown2010-01-22 11:27:52
Choke.
Unknown2010-01-22 11:35:29
It's mostly just spam. In Choke (and other slow-type things), it's just going to be replaced by the command right after it, so it's not that big a deal. Still pretty much unnecessary, though...
Unknown2010-01-22 11:41:33
QUOTE (Zarquan @ Jan 22 2010, 04:35 AM) <{POST_SNAPBACK}>
It's mostly just spam. In Choke (and other slow-type things), it's just going to be replaced by the command right after it, so it's not that big a deal. Still pretty much unnecessary, though...


Okay, well maybe I'll just remove the command. I think I'll just have some command that fires on login to remind me to take any necessary items out, or attempts to take them out, if I want to be on the safe side. I'll have to do something about putting riftable items back when I logout then too.
Unknown2010-01-27 14:32:54
Okay, just for posterity's sake and other tf'rs who might be struggling with this, here is my timer code that I worked out between reading the tf help pages, discussions with Zallafar and Zarquan, and experimenting with the implementation of ideas.

CODE
;######################
;# timer.tf           #
;######################

;**********************
;* timer              *
;**********************

/def -wlusternia doIdle = \\
        /if (({balHealth}==0)|({balSBerry}==0)|({balPotion}==0)|({balSalve}==0)|
(balHerb=0)|({balWrithe}==0)) \\
                /let i=$%; \\
                /repeat -2 1 /doIdle%; \\
        /else \\
                /balResets %{1}%; \\
        /endif


/doIdle receives a value from the curing queues that tell it what cure balance was used. If the loop finishes and the balance isn't restored then /doIdle passes the received value onto /balResets routine which then sets the appropriate value to 1 so tf knows that that balance should be currently restored.

So far, I haven't had any issues and things seem to be working.

If you're new to tf and you've been using a /while loop, forget it. The tf help pages for /repeat specifically tell you not to use /while for timing purposes. I had tried using a /while loop and I can tell you that it doesn't work the way you think it might.

Any thoughts, or comments?
Unknown2010-01-27 15:00:57
I just did a search for "tinyfugue timers" and found a web site that looks like it might be really useful to you. The first file listed has code for doing timers.

http://www.angelfire.com/creep/heidel/tf/
Sephrenia2010-01-27 16:58:46
QUOTE (Nodel @ Jan 22 2010, 04:41 AM) <{POST_SNAPBACK}>
If you're new to tf and you've been using a /while loop, forget it. The tf help pages for /repeat specifically tell you not to use /while for timing purposes. I had tried using a /while loop and I can tell you that it doesn't work the way you think it might.


Yeah, /while would create a busy loop, which would lock up tf like zmud's #wait or whatever it was.

I'm not sure about the purpose of your /let statement in there, or even if the scope carries through to the process created by /repeat. Also, it looks like you might need to pass %{1} to the /doIdle in the repeat statement to make sure it carries through.
Unknown2010-01-28 01:10:03
QUOTE (Zarquan @ Jan 27 2010, 08:00 AM) <{POST_SNAPBACK}>


Yeah, I ran across this before too. I've been meaning to take a closer look at it once I understood things a bit better.
Unknown2010-01-28 01:15:54
QUOTE (Sephrenia @ Jan 27 2010, 09:58 AM) <{POST_SNAPBACK}>
I'm not sure about the purpose of your /let statement in there, or even if the scope carries through to the process created by /repeat. Also, it looks like you might need to pass %{1} to the /doIdle in the repeat statement to make sure it carries through.


It's official, I suck. smile.gif You're probably right about passing the value to /doIdle in repeat statement, I don't know how I missed that and my only excuse is that I'm not a programmer.

As for /let in the repeat body I only have it there as a command for /repeat to call on. I don't know if it's optional that a command be there, or not as the help pages don't really say, so I put that in. Perhaps that's dangerous and I should find something safer, or see if I can do without it at all.

Back to testing.
Charune2010-01-28 01:36:33
This is code for making zmud-style alarms:

CODE
/def alarm=\\
     /if ( getopts("t:f:","") ) \\
         /let timeToHit=%{opt_t}%;\\
         /if (timeToHit > 0) \\
             /let functionToCall=%{opt_f}%;\\
             /if (functionToCall !~ "") \\
                 /let varname=$%;\\
                 /if ( get_val(varname) != 0 ) \\
                     /kill $%;\\
                     /set %{varname} 0%;\\
                 /endif%;\\
                 /set %{varname}=$%;\\
             /else \\
                   /sys_warning No function given for alarm.%;\\
             /endif%;\\
         /else \\
               /sys_warning No time above 0 given for alarm - you gave %{timeToHit}.%;\\
         /endif%;\\
     /else \\
          /sys_warning Fix this later.%;\\
     /endif

/def kill_alarm=\\
     /let name=%{1}%;\\
     /if (name !~ "") \\
         /let varname=$%;\\
         /if ( get_val(varname)!= 0 ) \\
             /kill $%;\\
             /set %{varname} 0%;\\
         /endif%;\\
     /else \\
           /sys_warning kill_alarm: ERROR: Invalid name of alarm to kill.%;\\
     /endif

/def reset_alarm_pid=\\
     /let name=%{1}%;\\
     /if (name !~ "") \\
         /let varname=$%;\\
         /set %{varname} 0%;\\
     /else \\
           /sys_warning reset_alarm_pid: ERROR: Invalid name of alarm to reset pid.%;\\
     /endif


In practice, it means you do stuff like /alarm -t"0.4" -f"herbBalance_recover"

And herbBalance recover would look like:
CODE
/def herbBalance_recover=\\
     /reset_alarm_pid herbBalance_recover%;\\
     /if (herbBalance==0) \\
         /set herbBalance 1%;\\
     /else \\
           /sys_alert Herb balance recover not where it should be.%;\\
     /endif%;\\
     /newLine


And there's this, for when the balance kind of beats it and you don't want the alarm to continue:
CODE
/def -mregexp -ahCGreen -t"^You may eat another plant\\.$" herbbalance_regain_message=\\
     /kill_alarm herbBalance_recover%;\\
     /set herbBalance 1
Zallafar2010-01-28 08:42:57
QUOTE (Nodel @ Jan 27 2010, 06:32 AM) <{POST_SNAPBACK}>
CODE
/def -wlusternia doIdle = \\
        /if (({balHealth}==0)|({balSBerry}==0)|({balPotion}==0)|({balSalve}==0)|
(balHerb=0)|({balWrithe}==0)) \\
                /let i=$%; \\
                /repeat -2 1 /doIdle%; \\
        /else \\
                /balResets %{1}%; \\
        /endif

This assumes that all those balances have the same timeout value. I'm pretty sure they don't but I don't have hard numbers to give you.

I don't really understand how this accomplishes what you want. If some balance is 0, go off for 2 seconds, then if that balance is still 0 go off for two seconds again, etc. It's only when all the balances are one that you will reset the balance to 1? Or am I just misinterpreting this?