Groovy maid scripts

Forum for alternative clients, mods & discussions on the same.

Moderator: Phades

Detharon
Posts: 117
Joined: Sat Mar 26, 2011 2:16 pm

Groovy maid scripts

Post by Detharon »

There's a very active thread with Union client scripts, but apparently almost nothing has been published for groovy maid, so analyzing some working examples is next to impossible. That's why I've decided to create this thread.

Info:
Here you can find some information about groovy maid engine.
It's bundled with Anemone client, with few improvements.

Here's my plowdrink script, as written in the description, it plows a single tile, drinks water, and gets more water from a well. To succesfully run it, you need a bucket, waterflask / waterskin, and a well in given radius (30 tiles by default).

Code: Select all

/* ====================================================================================================
	Simple script to burn hunger, it plows a single tile and drinks water.
	To properly works, it requires: A bucket, waterflask or waterskin, an accessible well.
	
	It will keep plowing, drinking water, and refilling water when needed.
	Stops working when hunger drops below 30% (default value) of very hungry bar.
	
	Although it uses a pathfinder, it may occasionally get stuck if there are too many items
	between the well and plowing place.
*///====================================================================================================

import java.util.*;
import java.lang.*;
import haven.event.*;
import haven.*;

// ==================================================
// Settings			
// ==================================================

// Script will look for a well in given radius
int wellRadius = 30;
// A stop condition, minimum value of very hungry bar
int minHunger = 30;

// ==================================================
// Some checks	
// ==================================================

Item cup;
Item bucket;
Gob well;
inv = maid.getInventory();
Coord pos = maid.getCoord();

// Checking for a waterflask / waterskin
if (hasItem("waterflask") == true) {
	cup = maid.getItems(inv, "waterflask")[0];
} else if (hasItem("waterskin") == true) {
	cup = maid.getItems(inv, "waterskin")[0];
} else {
	println("Waterflask or waterskin is missing.");
	return;
}

// Checking for a bucket
if (hasItem("bucket") == true) {
	bucket = maid.getItems(inv, "bucket")[0];
} else {
	println("Bucket is missing.");
	return;
}

// Looking for a well
well = maid.doAreaFind(wellRadius, "well");
if (well == null) {
	println("Well was not found.");
	return;
}

// ==================================================
// Main loop	
// ==================================================

// Will work until the hunger bar drops below the given value of very hungry bar

starving = checkStarvation(minHunger);

while (!starving) {
	if (maid.meterStamina.value < 50) {
		if (getWaterValue(bucket) < 1) {
			getWater(well, bucket); // If we're running out of water, get some
			bucket = maid.getItems(inv, "bucket")[0]; // Need to reload the dropped bucket
			maid.pathFind(pos, 6, false); // Return to previous place
		}
		
		drinkSome(cup, bucket); 
		bucket = maid.getItems(inv, "bucket")[0]; // Need to reload the dropped bucket
	}
	
	maid.doAction("act", "plow"); // Time to plow!
	maid.doLeftClick(pos)
	maid.doRightClick(pos); // Get rid of plow icon
	maid.waitForTask();

	starving = checkStarvation(minHunger);
}
		
// ==================================================
// Helper functions			
// ==================================================

boolean checkStarvation(int minHunger) {
	if (maid.meterHunger.type == MeterEventObjectHunger.HungerType.VERY_HUNGRY && maid.meterHunger.value < minHunger) {
		return true;
	} 
	return false;
}

void getWater(Gob well, Item bucket) {
	maid.pathFind(maid.getCoord(well), 6, false);

	Coord bucketplace = maid.getCoord(bucket);

	maid.doTake(bucket);
	maid.waitForGrab();
	maid.doInteract(well);
	
	Thread.sleep(4500); // Not event based, error-prone
	
	inv.drop(null, new Coord(bucketplace.x*32,bucketplace.y*32)); // meh
	maid.waitForItemCreate();
}

boolean hasItem(String itemName) {
	if (maid.getItems(inv, itemName).length != 0) return true;
	return false;
}

void drinkSome(Item cup, Item bucket) {
	Coord bucketplace = maid.getCoord(bucket);

	maid.doTake(bucket);
	maid.waitForGrab();
	maid.doInteract(cup, 1);
	inv.drop(null, new Coord(bucketplace.x*32,bucketplace.y*32));
	
	maid.doInteract(cup);
	menu = maid.waitForFlowerMenu();
	maid.doSelect(menu, "Drink");
	maid.waitForTask();

}

// Stolen, I mean, adapted from Anemone client code. Slightly modified. Lemme know if there's a better way to do that
double getWaterValue(Item bucket) {
	if (bucket.tooltip.indexOf('/') < 0) return 0;

	String valStr = bucket.tooltip.substring(bucket.tooltip.indexOf('(') + 1, bucket.tooltip.indexOf('/'));
	double val = Double.parseDouble(valStr);
}
Over time, I'll keep adding other scripts.
Last edited by Detharon on Thu Apr 24, 2014 8:54 pm, edited 1 time in total.
User avatar
caz
Posts: 542
Joined: Fri Jul 16, 2010 7:27 pm

Re: Groovy maid scripts

Post by caz »

thanks for making this :)
Image
mvgulik
Posts: 4094
Joined: Fri May 21, 2010 2:29 am

Re: Groovy maid scripts

Post by mvgulik »

Just some Anemone script-related index.
* Limited to stuff in this topic.
* Order: Posted.
* Updates: Whenever I feel like it.

=== ►index◄ ===

* plowdrink » Detharon » Apr 2014.
Code: Did not work for me on Anemone client. Seems incomplete. But was useful as example script.

* printing to area chat » romovs » Mar 2015.
Doc: In a nutshell. maid.doSayAreaChat("Hello World") only works with old chat-box enabled.

* getCropTypeNearCurrentLocation() » mvgulik » Apr 2015.
Code: Experimental crop detection code.

* fill_barrel_from_well() » mvgulik » May 2015.
Code: Taking the sting out of well clicking. [v0.2]

* session break detection. » mvgulik » May 2015.
Code: Running scripts could linger around in closed sessions, this can fix that.

* Open seedbag shuffle. » mvgulik » Juni 2015.
Code: Just for fun and giggles. [v0.1]

* getPlayerOrientation() » mvgulik » Juli 2015.
Code: working snippet. [v0.1]

* getTileCenter() » mvgulik » Juli 2015.
Code: working snippet. [v0.1]

* "Walk around object" experiment. » mvgulik » Aug 2015.
Code: working example. [v0.2]

--- Old post content ---
Anemone client.

Any help, or examples, on how to do some on-screen (game-window, not console) feedback in Anemone/Maid client. (either with @#Chat or some other way.)
The simpler the better, with plenty of info if possible, as I'm having two left hands when it comes to Java/Groovy or internal Haven.stuff.

(Scrounged some other script related topics, but I came up empty.)
Last edited by mvgulik on Fri Aug 14, 2015 12:38 pm, edited 7 times in total.
mvgulik
Posts: 4094
Joined: Fri May 21, 2010 2:29 am

Re: Groovy maid scripts

Post by mvgulik »

Nothing so far. Bummer. O well.
User avatar
romovs
Posts: 1472
Joined: Sun Sep 29, 2013 9:26 am
Location: The Tabouret

Re: Groovy maid scripts

Post by romovs »

There is a method for printing to area chat:

Code: Select all

maid.doSayAreaChat("hello");
It only works if "use new chat" is enabled in the settings and doesn't work with the vanilla chat. Or maybe it's vice versa, can't recall...
User avatar
shubla
Posts: 13041
Joined: Sun Nov 03, 2013 11:26 am
Location: Finland

Re: Groovy maid scripts

Post by shubla »

Is it okay to make bot that spams something stupid and then afk with it somewhere?
Image
I'm not sure that I have a strong argument against sketch colors - Jorb, November 2019
http://i.imgur.com/CRrirds.png?1
Join the moderated unofficial discord for the game! https://discord.gg/2TAbGj2
Purus Pasta, The Best Client
mvgulik
Posts: 4094
Joined: Fri May 21, 2010 2:29 am

Re: Groovy maid scripts

Post by mvgulik »

romovs wrote:There is a method for printing to area chat:

Code: Select all

maid.doSayAreaChat("hello");
It only works if "use new chat" is enabled in the settings and doesn't work with the vanilla chat. Or maybe it's vice versa, can't recall...
*big sigh*. So that's why it was trowing me a general error. I was using the wrong chat. :cry:

Thanks for the info.

---
shubla wrote:Is it okay to make bot that spams something stupid and then afk with it somewhere?
Duh ... *Checked user's posts* ... No. Wrong thread to, now shoo.
mvgulik
Posts: 4094
Joined: Fri May 21, 2010 2:29 am

Re: Groovy maid scripts

Post by mvgulik »

Anemone client.

Kinda bored with manual fishing for fishing data ...
Ergo: A other try to pry lose some more scripting related information.

How to go about getting character equipment data ?
Like ... character current equipped fishing pole setup.
mvgulik
Posts: 4094
Joined: Fri May 21, 2010 2:29 am

Re: Groovy maid scripts

Post by mvgulik »

Pfew, finally something that seems to work.
Still WIP stage. Only stage I know.

Code: Select all

def getCropTypeNearCurrentLocation() {

	def range = 1.0;
	def target = '/plants/';
	def clip = 'gfx/terobjs/plants/';

	// excluded: tobacco, pumpkin.
	def crops = ['beetroot','carrot','flax','hemp','hops','onion','peas','pepper','poppy','tea','wheat','wine'];
	def cropdata = ['beetroot':[0,6,null],
				'carrot':[0,3,null],
				'flax':[3,0,'flaxfibre'],
				'hemp':[3,0,'flaxfibre'],
				'hops':[0,3,null],
				'onion':[0,3,null],
				'peas':[0,3,null],
				'pepper':[3,0,null],
				'poppy':[3,0,'flower-poppy'],
				'tea':[2,2,null],
				'wheat':[0,3,'straw'],
				'wine':[0,3,null]];

	def cord = maid.getCoord(maid.getPlayer());
	
	def crop_gob = maid.doAreaFind(cord, range, target);
	if (crop_gob == null){
		return null;
	};

	def crop_str = maid.getName(crop_gob);
	crop_str = crop_str.replace(clip, '');

	if (crops.contains(crop_str)) {
		def stage = crop_gob.getblob(0);
		return [crop_str,stage,cropdata[crop_str]];
	} else {
		return null;
	}
	
}

def output = getCropTypeNearCurrentLocation();
maid.doSay("output == " + output);
return
◄index►
Last edited by mvgulik on Wed Jul 15, 2015 9:39 am, edited 2 times in total.
mvgulik
Posts: 4094
Joined: Fri May 21, 2010 2:29 am

Re: Groovy maid scripts

Post by mvgulik »

Anemone client.

Code: Select all

def Item fill_barrel_from_well(Gob well, Gob barrel, Item bucket) {
	// The only detectable change here is if the bucket changes.
	// This code don't cares if its a barrel, or a tanning tub.
	def bucket_pos_last = maid.getCoord(bucket);
	maid.doTake(bucket);
	maid.waitForGrab();
	def wdg = getDraggedItem();
	while (true){// untill bucket no longer empties.
		if (wdg != null && wdg.GetResName() != 'gfx/invobjs/buckete') {
			maid.doInteract(barrel);
			waitForEmptyBucket(wdg);
			if (wdg != null && wdg.GetResName() != 'gfx/invobjs/buckete') {
				maid.getInventory().drop(null, new Coord(bucket_pos_last.x*32,bucket_pos_last.y*32));
				bucket = maid.waitForItemCreate();
				maid.doRightClick(barrel);
				break;
			}
		}
		maid.doInteract(well);// waiting untill bucket fills up.
		while (wdg != null && wdg.GetResName() == 'gfx/invobjs/buckete'){
			Thread.sleep(250);
		}
	}
	return bucket;
}

def getDraggedItem() {
	if (!maid.isDragging()) {return null}
	def wdg_out = null;
	def Widget root = UI.instance.root;
	for (Widget wdg = root.child; wdg != null; wdg = wdg.next) {
		if (wdg.getClass() == haven.Item) {
			wdg_out = wdg
			break
		}
	}
	return wdg_out;
}

def void waitForEmptyBucket(wdg, int timeout=1000, int timestep=100) {
	def int baileout = timeout/timestep;
	while (wdg != null && wdg.GetResName() != 'gfx/invobjs/buckete') {
		baileout -= 1;
		if (baileout < 0) {break}
		Thread.sleep(timestep);
	}
}
[v0.2]: fixed weak point in code.
◄index►
Last edited by mvgulik on Wed Jul 15, 2015 9:39 am, edited 2 times in total.

Return to “The Wizards' Tower”