Need help with while (have_effect($effect

tgetgel

Member
I have a piece of code that does not seem to work.
Code:
while (have_effect($effect[ode to booze]) == 0)
{
print("Waiting for ode to kick in");
cli_execute("Wait 5"); // can track to see how long this takes
}
A bit before this, I purchase a buff, run 10 adventures, and do maximize. The idea is that since this character cannot cast ode to booze, I buy it, wait a bit, then drink. But this does not work. I have even gone to a multi and cast ode to booze on this character during the while and the while loops forever.
It seems like the while does not check for a status change in the effect. :confused:
I know, ascend and perm the skill. But until then?
Is there another function I can use within the while to update then have_effect status? Do I need to use a For, Next loop with a limit to avoid the endless loop? Is this a problem with the while, my code, or just how I am trying to use it?
Thanks in advance.
 

mredge73

Member
This is an exerpt out of my function library (not a stand alone function so it won't work if you just copy/paste):

Code:
// gets Ode from IocaineBot
//$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
boolean GotOde(boolean get)
{
    if(have_effect($effect["Ode to Booze"]) > 0)
        return True;
    if(get)
    {
        print("Getting Ode from IocaineBot!");
        if(kmail("IocaineBot", "", 23, EmptyList))
        {WaitMinutes(1);}
        refresh_status( );
        if(have_effect($effect["Ode to Booze"]) > 0)
            return True;
    }
     return false;    
}
notice after waiting I use the command refresh_status( );
It takes about 30-45 seconds for Iocainebot to respond so I wait 1minute then issue refresh before re-checking.
 
Last edited:

Veracity

Developer
Staff member
KoLmafia cannot detect that you've had Ode cast on you by someone else unless it receives an event saying so. If you are in chat, that polls the server periodically and the event gets picked up. If you are NOT in chat, you should visit_url( "main.php" ), say, in your main loop.

Is there a reason you are doing cli_execute( "wait 5" ) rather than using the ASH built in function wait( 5 )?
 

Grotfang

Developer
I'm hypothesising here, but maybe your while gets itself into a loop (as you suggest) and it doesn't recheck status. How about this as an alternative:

Code:
int ode_effect = have_effect( $effect[ode to booze] );
while (ode_effect == 0)
{
print("Waiting for ode to kick in");
cli_execute("Wait 5"); // can track to see how long this takes
ode_effect = have_effect( $effect[ode to booze] );
}
 

Veracity

Developer
Staff member
Mr. Edge's idea of calling "refresh_status" seems good; that refreshes the charpane, and active effects are listed there. You don't need no stinkin' event to tell you that the buffbot has oded you when you can detect the effect directly on the charpane. So, simply add a refresh_status() in your loop following the call to wait( 5 ).
 

mredge73

Member
Yea, I have used the function posted above for a while now and it has worked correctly for me every time since it forces mafia to refresh the charpanel instead of relying on periodic polls. My favorite buff-bot has been reliable as well.
 

tgetgel

Member
Is there a reason you are doing cli_execute( "wait 5" ) rather than using the ASH built in function wait( 5 )?
Coding in CLI is more familiar to me. I am still learning the syntax and capabilities of ASH. As I learn them, I convert my cli_execute over to ASH.

@mredge73: calling "refresh_status" - that is a good idea.
@Veracity: adding a refresh_status() in the loop and changing to wait( 5 ).
@Grotfang: I wonder if that would suffer the same problem due to the lack of a refresh, or do you think that by having it as a separate line it might force a refresh?

I will try both approaches and report! (tomorrow at the earliest)
 

tgetgel

Member
This is an exerpt out of my function library:

Code:
        print("Getting Ode from IocaineBot!");
        if(kmail("IocaineBot", "", 23, EmptyList))

My analysis of this code:
Kmail and IF are CLI commands (they are listed in the CLI HELP but not the ASHREF list). But they seem to work without the cli_execute, so they must be either inherent or enabled in both but these are written in ASH.
The Parameters for ASH kmail seem to be - recipient, message, meat, items. This seems like the IF will always be true since I do not see how to have it be false. How do you know if IocaineBot is online?

Thanks one and all!
 

Bale

Minion
I don't know why nobody else has pointed out that wait(5) is abusive. When you're going to hit the server for an indefinite period of time, doing it every 5 seconds seems excessive. I wouldn't less than wait(20). Here's my ode getting function of ultimate awesomeness. Note that it will give up if it takes more than 15 minutes to get buffbot response. That is rare, but it happens.

Code:
// shot = 1 for first shot of Ode and 2 for second shot.
boolean get_ode(int shot) {
	if(have_effect($effect[Ode To Booze]) < 1) {
		if(current_at() >= max_at()) {
			print("Too many AT songs to cast Ode to Booze", "red");
			return false;
		}
		if(have_skill($skill[The Ode To Booze])) {
			if(my_mp()< mp_cost($skill[The Ode To Booze])) {
				restore_mp(mp_cost($skill[The Ode To Booze]));
				if(my_mp()< mp_cost($skill[The Ode To Booze])) {
					print("Can't cast Ode to Booze due to lack of MP!", "red");
					return false;
				}
			}
			use_skill(1, $skill[The Ode To Booze]);
			if(have_effect($effect[Ode To Booze]) <1)
				return false;
		} else {
			# lets try get it from a buffbot
			print("purchasing Ode to Booze from a few buffbots...", "blue");
			if(shot == 1) {
				cli_execute("csend 1 meat to Testudinata");
				cli_execute("csend 23 meat to Iocainebot");
			} else {
				cli_execute("csend 11 meat to Testudinata");
				cli_execute("csend 80 meat to Iocainebot");
			}
			int iterations = 0;
			while( have_effect($effect[Ode to Booze]) < 1) {
				if (iterations > (30)) {
					print("failed to get Ode to Booze", "red");
					return false;
				}
				wait(30);
				cli_execute("effects refresh");
				iterations = iterations + 1;
			}
		}
	}
	return true;
}


The Parameters for ASH kmail seem to be - recipient, message, meat, items. This seems like the IF will always be true since I do not see how to have it be false.
Actually, that won't work at all since kmail is not an ash function. mredge73 is assuming you use his script library where kmail is defined. That's why he said it won't work as a stand alone function. Obviously there is a situation he's defined where it can return false.
 
Last edited:

tgetgel

Member
I'm hypothesising here, but maybe your while gets itself into a loop (as you suggest) and it doesn't recheck status. How about this as an alternative:

Code:
int ode_effect = have_effect( $effect[ode to booze] );
while (ode_effect == 0)
{
print("Waiting for ode to kick in");
cli_execute("Wait 5"); // can track to see how long this takes
ode_effect = have_effect( $effect[ode to booze] );
}

Just confirmed that this approach infinitely loops.

Adding refresh_status() as mentioned by mredge73 works just fine.
 

tgetgel

Member
Is there a reason you are doing cli_execute( "wait 5" ) rather than using the ASH built in function wait( 5 )?

Interesting to note that the cli_execute( "wait 5" ) gives a countdown in the session log whereas the wait( 5 ) does not. I am okay with that. It was just interesting to note.
 
Last edited:

tgetgel

Member
I don't know why nobody else has pointed out that wait(5) is abusive. When you're going to hit the server for an indefinite period of time, doing it every 5 seconds seems excessive.
I like statistics, so I was gathering data on the response time of the bot to buff requests. I figured that if the normal response time is 35 to 45 seconds, then a 5 second sampling would give me the resolution that I needed for a Pareto chart. Then, knowing the typical response time (4-sigma w/o outliers), I could add an appropriate error margin to create a reasonable upper time-waiting limit before exiting the loop.

Actually, that won't work at all since kmail is not an ash function. mredge73 is assuming you use his script library where kmail is defined. That's why he said it won't work as a stand alone function. Obviously there is a situation he's defined where it can return false.
Good point. I did not apply his 'won't stand alone' comment to that particular line of code - not realizing that kmail was a function defined elsewhere.
 

tgetgel

Member
Here's my ode getting function of ultimate awesomeness. Note that it will give up if it takes more than 15 minutes to get buffbot response. That is rare, but it happens.
Nice piece of code. It accounts for some things that I had not. (None of the characters have ascended, so I did not have to deal with some of the possibilities yet.) As an assembly coder, I am still learning the higher level languages. As a quality engineer, I like the structure. Thanks for the response.
 

mredge73

Member
The code that I posted was meant to just be pseudo code to demonstrate where to put in the refresh_status(), hence the disclaimer. The function is designed to return true if you have ode and false if you don't (after a single attempt to gain it). It is much simpler than Bale's ode function of ultimate awesomeness.

If you need kmail() you can find it as part of Zlib.ash
 

Bale

Minion
Oops. I just noticed that my script wasn't stand-alone either! It requires these two functions:

Code:
int max_at() {
	if(have_equipped($item[plexiglass pendant]) || have_equipped($item[brimstone beret]))
		return 4;
	return 3;
}

int current_at() {
	int total = 0;
	foreach song in $effects[The Moxious Madrigal, The Magical Mojomuscular Melody, Cletus's Canticle of Celerity,
		The Power Ballad of the Arrowsmith, The Polka of Plenty, Jackasses' Symphony of Destruction, Fat Leon's Phat Loot Lyric,
		Brawnee's Anthem of Absorption, The Psalm of Pointiness, Stevedave's Shanty of Superiority, Aloysius' Antiphon of Aptitude,
		The Ode to Booze, The Sonata of Sneakiness, Carlweather's Cantata of Confrontation, Ur-Kel's Aria of Annoyance,
		Dirge of Dreadfulness, The Ballad of Richie Thingfinder, Benetton's Medley of Diversity, Elron's Explosive Etude,
		Chorale of Companionship, Prelude of Precision, Donho's Bubbly Ballad];
			if(song.have_effect() > 0)
				total = total + 1;
	return total;
}

As a quality engineer, I like the structure.
Thanks for the compliment.
 
Last edited:

zarqon

Well-known member
@Bale: those two support functions could be simplified greatly by a) checking boolean_modifier("Four Songs"), or whatever it's called, and b) iterating over skill numbers. I think AT skills are in the 6000's, and you don't want to include the first one, so you'd start at 6002 or somesuch.

@tgetgel: There is an ASH is_online() function if you want to test if a buffbot is online.
 
Last edited:

Bale

Minion
Didn't notice Four Songs. That's nice to know and I appreciate it. I can only kick myself for not thinking of the other suggestion. It makes for a weird series of functions, but it should work beautifully. song.to_skill().to_effect() is necessary since not all the effects are contiguous.

Code:
int max_at() {
	if(boolean_modifier("Four Songs"))
		return 4;
	return 3;
}

int current_at() {
	int total = 0;
	for song from 6003 to 6026
		if(song.to_skill().to_effect().have_effect() > 0)
			total = total + 1;
	return total;
}
That checks a couple of unnecessary skills (one that doesn't exist and one that is an attack skill), but it should work perfectly. So tell me, do you prefer that version of max_at, or would you prefer this one?

Code:
int max_at() {
	return (boolean_modifier("Four Songs").to_int() + 3);
}
 

zarqon

Well-known member
If it were me, I would eliminate the function altogether and just use the condition you specified in your second variant in place of function calls.

Also, to_effect() prints a nice red error if you call it on a skill that doesn't have an effect. Won't harm your operation, but might look a bit ugly.
 

Bale

Minion
Also, to_effect() prints a nice red error if you call it on a skill that doesn't have an effect. Won't harm your operation, but might look a bit ugly.
You're mistaken. I had also thought it would do that, but I tested it before posting it here, just to see if I needed to check song != 6019 && song != 6025, but mafia didn't even hiccup at converting those skills to effects. Though THIS was a trifle odd...

Code:
> ash to_skill(6025)

Returned: Sing

> ash to_effect(6025.to_skill())

Returned: [COLOR="Red"][B]Blessing of Bulbazinalli[/B][/COLOR]

> ash to_skill(6019)

Returned: none

> ash to_effect(6019.to_skill())

Returned: none
 
Last edited:
Top