Chamois - Use it automatically!

Bale

Minion
Lovely update, but I see you've chosen current HP to be 1/6 of your max HP for triggering the hot-tub. Is this an arbitrary number? Would a "better" arbitrary number be the restore_hp trigger percentage, or would we then get scripts fighting each other to restore us?

I chose 1/6 based on how often it would choose to use the Hot Tub vs casting healing after using a chamois. I arrived there through a bit of trial and error. My basic thought was that as long as there is a decent amount of healing to do, the Hot Tub would suffice since it doesn't need to be perfectly conserved in aftercore. Remember that you're likely to be extremely low on HP due to the effects of being Coated in Slime until it finally exceeds max HP so the exactitude of 1/6 is very unlikely to matter.

Since the restore_hp trigger percentage could easily be anywhere between 20% and 60% depending on level and preference, I figured it would be tough to make meaningful use of that number. I don't think that there's any real problem with scripts "fighting each other to restore us" since the hot tub is a full heal. Full healing does work and play well with others through the simple expedient of making any other healing irrelevant.

If your preference differs from the 1/6th I chose, then feel free to change it. I just figured that would be a good generic number that would work well for anyone, even if some wouldn't find it 100% optimal.
 

Bale

Minion
It's perhaps a little beggy of me, but I'd like to ask that someone who is making good use of this script let me in on a nodule run.

I'd be glad to squeeze a gall bladder for you. (I'd actually be glad to squeeze gall bladders in quite a few runs.) In return for that and my work on this script, could someone see their way to giving me a caustic slime nodule? If I could get even 1 nodule I'd be very happy.

Thank you for considering this request.
 

TeKRunneR

New member
Hey, thanks for the script, it works pretty well, but I think there's a case it doesn't handle too well. If you run, say, +190ML, and someone squeezes a bladder, you may get beaten up every turn after cleaning the slime: the script doesn't heal you, thinking you'll get 8 turns of slime. In fact you get 7, which kills you. Is there any way to avoid that behavior, or am I just doing it wrong?
 
Last edited:

Bale

Minion
Bale, kmail me in-game
Thank you very much for the nodule! :D

Hey, thanks for the script, it works pretty well, but I think there's a case it doesn't handle too well. If you run, say, +190ML, and someone squeezes a bladder, you may get beaten up every turn after cleaning the slime: the script doesn't heal you, thinking you'll get 8 turns of slime. In fact you get 7, which kills you. Is there any way to avoid that behavior, or am I just doing it wrong?
The script won't deal with that at all. It doesn't take control of all healing any more than it takes control of deciding how to fight, so I'd suggest that you set mafia to heal you. If you don't like mafia's default healing

All this script does, is decide how to deal with wiping off slime. If you have no slime, it won't be triggered at all. Actually fighting and surviving slimes is up to you.
 

Veracity

Developer
Staff member
I quite like this script - even running an older version. I just got my third nodule while using it and it healed me after every battle and used a chamois every other battle and all went swimmingly. Tomorrow, I'll be starting a slow run to replenish my stock of chamois and I look forward to see how long it will go between healing with me wearing slime protection gear...

One suggestion: when it prints "Using chamois" in blue, it would be nice if it could report how many were left in the bucket; it' interesting to see that number going UP on low-ML runs, due to dropped chamoix, whenever I get un-Coated.
 

Bale

Minion
One suggestion: when it prints "Using chamois" in blue, it would be nice if it could report how many were left in the bucket; it' interesting to see that number going UP on low-ML runs, due to dropped chamoix, whenever I get un-Coated.

Good idea! I think I'll implement that when I get a chance. Probably some time before tomorrow.
 

Bale

Minion
One suggestion: when it prints "Using chamois" in blue, it would be nice if it could report how many were left in the bucket; it' interesting to see that number going UP on low-ML runs, due to dropped chamoix, whenever I get un-Coated.

This is proving non-trival for me. I decided to try using matchers for the first time and it isn't working as well as I'd hoped. While this isn't the only way to solve the problem, I'd like to get a handle on it. Here's my code:

Code:
void chamois() {
	string page;
	if(my_hp() < my_maxhp() /6)
		hot_tub();
	if(have_effect($effect[Coated in Slime]) > 0) {
		print("Using chamois.", "blue");
		page = visit_url("clan_slimetube.php?action=chamois&pwd");
		}
	matcher cham_left = create_matcher("There are (\\d+) chamoix in the bucket" , page);
	cham_left. find();
	print("There are "+ to_int(cham_left. group(1))+ " chamois left in the bucket.", "blue");
	if(have_effect($effect[Coated in Slime]) > 0)
		abort("Failed to use a chamois. You'll need to find some other way to clean yourself up.");
}
This gives me "Unexpected error, debug log printed." which is far from the most helpful error message ever. Here's the debug log:
Code:
Unexpected error, debug log printed.
class java.lang.IllegalStateException: No match found
java.lang.IllegalStateException: No match found
	at java.util.regex.Matcher.group(Unknown Source)
	at net.sourceforge.kolmafia.textui.RuntimeLibrary.group(RuntimeLibrary.java:2782)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.lang.reflect.Method.invoke(Unknown Source)
	at net.sourceforge.kolmafia.textui.parsetree.LibraryFunction.execute(LibraryFunction.java:119)
	at net.sourceforge.kolmafia.textui.parsetree.FunctionCall.execute(FunctionCall.java:157)
	at net.sourceforge.kolmafia.textui.parsetree.FunctionCall.execute(FunctionCall.java:112)
	at net.sourceforge.kolmafia.textui.parsetree.Operator.applyTo(Operator.java:279)
	at net.sourceforge.kolmafia.textui.parsetree.Expression.execute(Expression.java:111)
	at net.sourceforge.kolmafia.textui.parsetree.Operator.applyTo(Operator.java:139)
	at net.sourceforge.kolmafia.textui.parsetree.Expression.execute(Expression.java:111)
	at net.sourceforge.kolmafia.textui.parsetree.FunctionCall.execute(FunctionCall.java:112)
	at net.sourceforge.kolmafia.textui.parsetree.BasicScope.execute(BasicScope.java:383)
	at net.sourceforge.kolmafia.textui.parsetree.UserDefinedFunction.execute(UserDefinedFunction.java:125)
	at net.sourceforge.kolmafia.textui.parsetree.FunctionCall.execute(FunctionCall.java:157)
	at net.sourceforge.kolmafia.textui.parsetree.BasicScope.execute(BasicScope.java:383)
	at net.sourceforge.kolmafia.textui.parsetree.Conditional.execute(Conditional.java:88)
	at net.sourceforge.kolmafia.textui.parsetree.If.execute(If.java:67)
	at net.sourceforge.kolmafia.textui.parsetree.BasicScope.execute(BasicScope.java:383)
	at net.sourceforge.kolmafia.textui.parsetree.UserDefinedFunction.execute(UserDefinedFunction.java:125)
	at net.sourceforge.kolmafia.textui.Interpreter.executeScope(Interpreter.java:240)
	at net.sourceforge.kolmafia.textui.Interpreter.execute(Interpreter.java:185)
	at net.sourceforge.kolmafia.textui.Interpreter.execute(Interpreter.java:178)
	at net.sourceforge.kolmafia.KoLmafiaCLI.executeScriptCommand(KoLmafiaCLI.java:4770)
	at net.sourceforge.kolmafia.KoLmafiaCLI.executeScript(KoLmafiaCLI.java:4669)
	at net.sourceforge.kolmafia.KoLmafiaCLI.executeCommand(KoLmafiaCLI.java:569)
	at net.sourceforge.kolmafia.KoLmafiaCLI.executeLine(KoLmafiaCLI.java:455)
	at net.sourceforge.kolmafia.swingui.CommandDisplayFrame$CommandQueueHandler.handleQueue(CommandDisplayFrame.java:317)
	at net.sourceforge.kolmafia.swingui.CommandDisplayFrame$CommandQueueHandler.run(CommandDisplayFrame.java:298)
Can anyone give me a hint to solving the problem?
 
Last edited:

Alhifar

Member
Code:
matcher cham_left = create_matcher("There (are|is) (\\d+) chamoi(s|x) in the bucket" , page);
	cham_left. find();
	print("There are "+ to_int(cham_left. group(2))+ " chamois left in the bucket.", "blue");
I think that should take care of it, you weren't accounting for the possibility of one chamois. Otherwise, I'd have to take a closer look.
 

Veracity

Developer
Staff member
I pulled the bucket reporting into a separate file and did this to it:

Code:
void bucket()
{
        string page = visit_url("clan_slimetube.php?action=bucket");

        // The bucket is empty.
        // There is 1 chamois left in the bucket.
        // There are 66 chamoix left in the bucket.

        matcher cham_left = create_matcher("There (is|are) (\\d+) chamoi(s|x) in the bucket" , page);
        int left = 0;
        if ( cham_left.find() )
        {
                left = cham_left.group(2).to_int();
        }
        print("There are "+ left + " chamois left in the bucket.", "blue");
}

bucket();
There are only two essential differences:

1) Ahlifar's suggestion about chamois vs. chamoix
2) The case of the empty bucket.

I detect the latter by checking the return value of find() - a good idea, regardless - and not trying to call group() when the pattern did not match.

Regardless, we try to turn Java errors and stack traces into ASH runtime errors with a meaningful message and file/line. Apparently we not do this for matchers. I'll look into it.

Edit: I suppose I should tell you whether it worked...

> bucket

There are 66 chamois left in the bucket.
06/20/09 08:02 AM - Now pledging your allegiance to <different clan>.

> bucket

There are 0 chamois left in the bucket.

Edit 2: In the context of your function, the match will also not be found if you just soaked in the hot tub. I made a mod to visit the bucket just to see what's in it, in that case. Here's the code (hopefully using your brace style, which is not mine. ;) ):

Code:
void chamois() {
	if(my_hp() < my_maxhp() /6)
		hot_tub();

	string page;

	if(have_effect($effect[Coated in Slime]) > 0) {
		print("Using chamois.", "blue");
		page = visit_url("clan_slimetube.php?action=chamois&pwd");
		}
        else {
		page = visit_url("clan_slimetube.php?action=bucket");
		}

        // The bucket is empty.
        // There is 1 chamois left in the bucket.
        // There are 66 chamoix left in the bucket.

        matcher cham_left = create_matcher("There (is|are) (\\d+) chamoi(s|x) in the bucket" , page);
        int left = 0;
        if ( cham_left.find() ) {
                left = cham_left.group(2).to_int();
	        }
        print("There are "+ left + " chamois left in the bucket.", "blue");

	if(have_effect($effect[Coated in Slime]) > 0)
		abort("Failed to use a chamois. You'll need to find some other way to clean yourself up.");
}

Soaking in the VIP Hot Tub to remove the slime. Ahhhhh....
Visiting Relaxing Hot Tub in clan VIP lounge
You lose an effect: Coated in Slime
You gain 1,812 hit points
Strangely the other VIPs don't appreciate the thin layer of ooze now floating on the top of the water. :D
There are 21 chamois left in the bucket.
 
Last edited:

Bale

Minion
Update!
New version reports number of remaining chamoix.

Thanks to everyone for their help understanding how matchers work.
 
Last edited:

Oakianus

New member
Just wanted to drop a note to say that the latest version works amazingly - I'm running the slime tube with no ML while playing as an 8th level PM in ronin, and it's kept me perfectly balanced - I've only had a few beaten ups, mostly because they're inevitable with so few HP and the chance of the slimes breaking my noodles before I can kill them.
 

Bale

Minion
Very glad it has been helpful.

I guess it is inevitable that an 8th level PM might not be able to kill a slime in 2 hits, so just being in that tube is a triumph. ;)
 
Top