Groovy maid scripts

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

Moderator: Phades

mvgulik
Posts: 4096
Joined: Fri May 21, 2010 2:29 am

Re: Groovy maid scripts

Post by mvgulik »

Anemone client.

Code: Select all

// general session break detection support.
gmf_ind = MaidFrame.index;
gmf_str = MaidFrame.getSessionList()[gmf_ind].toString();
boolean session_exit() {
	return (MaidFrame.getSessionList()[gmf_ind].toString() != gmf_str);
}// bailout check => "if (session_exit()) {return}"
[v0.2]
Cleaned up version from this post.
◄index►
Last edited by mvgulik on Wed Jul 15, 2015 9:40 am, edited 1 time in total.
mvgulik
Posts: 4096
Joined: Fri May 21, 2010 2:29 am

Re: Groovy maid scripts

Post by mvgulik »

Just for fun and giggles.
(default/minimum client size advised, and a bunch of open seedbags of course.)

Anemone client.

Code: Select all

maid.doSay(">> Seedbags_Move_Test()");
maid.doSay("");

startSound();
Seedbags_Move_Test();
return;//alt quit.

def startSound() {
	def Resource resSound = Resource.load("sfx/fail");
	Audio.play(resSound);
}

def Seedbags_Move_Test() {
	int step_time = 50;
	int steps = 10;
	
	windows = getOpenSeedbags();
	int win_count = windows.size();
	if (win_count < 2) return; // exit, nothing to do.
	Collections.shuffle(windows);
	
	def win_size = windows[0].sz;
	def ui_size = MaidFrame.innerSize;
	int max_x = ui_size.x / win_size.x;
	int max_y = ui_size.y / win_size.y;
	List loc_org = [];
	for (win in windows) {loc_org.add(new Coord(win.c))}
	List loc_des = [];
	int loop_count = 0;
	for (win in windows) {
		int x = loop_count%max_x;
		int y = loop_count/max_x;
		loc_des.add(new Coord(x*win_size.x, y*win_size.y));
		loop_count += 1;
	}
	for (i in 1..steps) {
		int win_counter = 0;
		for (win in windows) {
			diff = new Coord(0,0);
			diff.x = loc_des[win_counter].x - loc_org[win_counter].x;
			diff.y = loc_des[win_counter].y - loc_org[win_counter].y;
			new_pos = new Coord(0,0);
			new_pos.x = loc_org[win_counter].x + (diff.x/steps*i);
			new_pos.y = loc_org[win_counter].y + (diff.y/steps*i);
			win.c = new_pos;
			win_counter += 1;
		}
		Thread.sleep(step_time);
	}
}

List getOpenSeedbags() {
	List list = [];
	Widget root = UI.instance.root;
	for (Widget wdg = root.child; wdg != null; wdg = wdg.next) {
		if (wdg.getClass() == haven.Window && wdg.cap.text == "Seedbag") {
			list.add(wdg);
		}
	}
	return list;
}
[v0.1]: None optimized code.
◄index►
Last edited by mvgulik on Wed Jul 15, 2015 9:41 am, edited 1 time in total.
mvgulik
Posts: 4096
Joined: Fri May 21, 2010 2:29 am

Re: Groovy maid scripts

Post by mvgulik »

getPlayerOrientation()

Anemone client.

Code: Select all

import haven.*;
maid.doLeftClick(cord_offset(maid.getCoord(), orientationToCoord(getPlayerOrientation()), 11))
return //alt quit.

def int getPlayerOrientation() {
	player_gob = maid.getPlayer()
	def l = player_gob.resnames()
	def m = [:]
	for (e in l) {
		r = e.find("\\d+\$")
		if (r==null) continue
		if (!m.containsKey(r)) m[r]=0
		m[r]+=1
	}
	di = m.max {it.value}.key
	return di.toInteger()
}

def Coord orientationToCoord(int di) {
	def Map oc = [0:[-1,-1], 1:[0,-1], 2:[1,-1], 3:[1,0], 4:[1,1], 5:[0,1], 6:[-1,1], 7:[-1,0]]
	return new Coord(oc[di][0], oc[di][1])
}
def Coord cord_offset(Coord cord1, Coord cord2, f=1) {
	return new Coord(cord1.x - (cord2.x * f), cord1.y - (cord2.y * f))
}
[v0.1]: working snippet.
◄index►
mvgulik
Posts: 4096
Joined: Fri May 21, 2010 2:29 am

Re: Groovy maid scripts

Post by mvgulik »

getTileCenter()

Anemone client.

Code: Select all

import haven.*;
maid.doLeftClick(getTileCenter(maid.getCoord()))
return;//alt quit.

def Coord getTileCenter(Coord rc) {
	def tc = [(rc.x/11).toBigInteger(), (rc.y/11).toBigInteger()]
	if (tc[0]>0) tc[0]+=1
	if (tc[1]<0) tc[1]-=1
	tc = [tc[0]*11, tc[1]*11]
	tc = [tc[0]-5, tc[1]+5]
	return new Coord(tc[0], tc[1])
}
[v0.1]: working snippet.
Note: Same process also works for minimap's, or server sectors for that matter. Just plug in the right values.
Note2: This is not the same auto selected position when using certain actions like dig.

◄index►
mvgulik
Posts: 4096
Joined: Fri May 21, 2010 2:29 am

Re: Groovy maid scripts

Post by mvgulik »

"Walk around object" experiment.

Anemone client.

Code: Select all

//import java.util.* // default Groovy import.
//import java.lang.* // default Groovy import.
import haven.*

maid.doSay("")
maid.doSay("Walk around object experiment)")

startSound()
Map negMAP = load_ResNEG_data("scripts/ResNEG.dat")
test_case()
return

def void test_case() {
	// walk around some object(with known hitbox).
	
	// optionals
	def int range = 8
	def String name = "cart"
	def int steps = 8 // Pos:clockwise, Neg:anti-clockwise. FullCircle:8.
	def skip1st = true // false|true
	
	name = "trough"
	name = "raftpart"
	name = "plow"
	name = "cart"
	
	steps = 0
	steps = -8
	steps = -8-8
	
	
	
	def home = maid.getCoord()
	def targ_gob = maid.doAreaFind(range, name)
	if (!targ_gob)  {
		maid.doSay('No "'+name+'" Found!')
		warningSound()
		return
	}
	
	if(!moveAroundObject(targ_gob, steps, skip1st)) return
	
	// assuming character finished at general same side as home location.
	if (!move_checked(home)) return
}

// ---- MAIN STUFF ----

def boolean moveAroundObject(targ_gob, steps, skip1st=true){
	def targ_hit = getHitboxPoints(targ_gob)
	if (!targ_hit) {warningSound();return false}
	
	def player_gob = maid.getPlayer()
	def player_hit = getHitboxPoints(player_gob)
	if (!player_hit) {warningSound();return false}
	
	def hit_both = listMath(targ_hit, player_hit, {a,b -> a+b})
	
	def Map d = [W:0, N:1, E:2, S:3]
	def Map hb = [
		0:new Coord(-hit_both[d.E], -hit_both[d.S]),
		1:new Coord(             0, -hit_both[d.S]),
		2:new Coord(-hit_both[d.W], -hit_both[d.S]),
		3:new Coord(-hit_both[d.W],              0),
		4:new Coord(-hit_both[d.W], -hit_both[d.N]),
		5:new Coord(             0, -hit_both[d.N]),
		6:new Coord(-hit_both[d.E], -hit_both[d.N]),
		7:new Coord(-hit_both[d.E],              0),
	]
	
	// ISSUE: when to close to the target, it could pick an angle that will not work as intended.
	// Case: picking diagonal angle when start location is inside ver/hor width of target.
	def double rad = getDirectionAngle(player_gob.c, targ_gob.c)
	def int di = radToOrientationId(rad)
	
	if (!skip1st && !steps) {
		if (!move_checked(cord_offset(targ_gob.c, hb[di], 1))) return false
	}
	
	// InCON: same steps can give different result for perpendicular or diagonal starting point.
	while (steps!=0) { // kinda unsave bailout.
		if (steps>0) {
			if (di%2 || steps==1) {di++;steps--}else{di+=2;steps-=2}
			if (di>7) di-=8
			if (steps<0) steps=0 // failsafe.
		}else{
			if (di%2 || steps==-1) {di--;steps++}else{di-=2;steps+=2}
			if (di<0) di+=8
			if (steps>0) steps=0 // failsafe.
		}
		if (!move_checked(cord_offset(targ_gob.c, hb[di], 1))) return false
	}
	
	return true
}

def double getDirectionAngle(cord1, cord2) {
	def delta = cord_offset(cord2, cord1)
	return Math.atan2(delta.y, delta.x)
}
def int radToOrientationId(double rad) {
	def tmp = rad/Math.PI * 4 + 1/2 + 3
	if (tmp < 0) tmp+=8
	return tmp
}
def Coord orientationIdToCoord(int di) {
	//def Map o1 = [0:'SE', 1:'S', 2:'SW', 3:'W', 4:'NW', 5:'N', 6:'NE', 7:'E']
	def Map o2 = [0:[-1,-1], 1:[0,-1], 2:[1,-1], 3:[1,0], 4:[1,1], 5:[0,1], 6:[-1,1], 7:[-1,0]]
	return new Coord(o2[di][0], o2[di][1])
}

def List getHitboxPoints(Gob targ_gob) {
	def Coord bc1, bc2
	def List neg_alt = null
	def Map map = file_base_data()
	
	for (e in map) {
		if (targ_gob.resname().contains(e.key.toLowerCase())) {
			neg_alt = e.value
			bc1 = new Coord(neg_alt[0], neg_alt[1])
			bc2 = new Coord(neg_alt[2], neg_alt[3])
			bc1 = MapView.s2m(bc1)
			bc2 = MapView.s2m(bc2)//.add(bc1.inv())
			break
		}
	}
	
	if (!neg_alt) {
		def neg = targ_gob.getneg()
		bc1 = neg.bc
		bc2 = neg.bs.add(bc1)
	}
	
	def List hitpoints = null
	if (bc1.x || bc1.y || bc2.x || bc2.y) {
		hitpoints = [bc1.x, bc1.y, bc2.x, bc2.y]
	}
	
	return hitpoints
}

// ---- GENERAL STUFF ----

def startSound() {
	def Resource resSound = Resource.load("sfx/fail")
	Audio.play(resSound)
	Thread.sleep(100)
}
def warningSound() {
	def Resource resSound = Resource.load("sfx/fail")
	Audio.play(resSound)
	Thread.sleep(150)
	Audio.play(resSound)
	Thread.sleep(100)
}

def Coord cord_offset(Coord cord1, Coord cord2, int f=1) {
	return new Coord(cord1.x - (cord2.x * f), cord1.y - (cord2.y * f))
}
static List listMath(List A, List B, Closure closure){ 
	def tmp = [] 
	A.eachWithIndex { item, i -> tmp << closure.call(A[i], B[i]) } 
	return tmp 
}// Quick 'copied and pasted' general list-math solution code.

def move_checked(Coord ct) {
	maid.doLeftClick(ct)
	maid.waitForMoveStop(5000, 100)
	if (maid.getCoord() != ct) {
			maid.doSay("\tPath Blocked ?")
			maid.doSay("\t\tct" +" == "+ ct)
			maid.doSay("\t\tmaid.getCoord()" +" == "+ maid.getCoord())
		maid.doLeftClick(ct)
		maid.waitForMoveStop(5000, 100)
		if (maid.getCoord() != ct) {
			maid.doSay("\tPath Blocked !")
			maid.doSay("\t\tct" +" == "+ ct)
			maid.doSay("\t\tmaid.getCoord()" +" == "+ maid.getCoord())
			warningSound()
			return false
		}
	}
	return true
}

def Map load_ResNEG_data(String filespec) {
	def Map map = null
	def file = new File(filespec)
	if (file.isFile()) {
		map = Eval.me(file.text)
	} else {
		map = file_base_data()
		file.text = map.inspect()
	}
	return map
}
def file_base_data() {
	Map map = [:]
	map["/boat/"] = [0,-24,0,28] // WNES:[-12,-12,14,14]
	map["/cart/"] = [0,-10,0,10] // WNES:[-5,-5,5,5]
	map["/plow/"] = [0,-6,0,6] // WNES:[-3,-3,3,3]
	map["/bed-sturdy"] = [-6,-13,4,18] // WNES:[-8,-5,10,8]
	map["/cclosed"] = [0,-6,6,5] // WNES:[-3,-3,4,1] // chest
	map["/copen"] = [0,-6,6,5] // WNES:[-3,-3,4,1] // chest
	map["/htable"] = [6,-7,-4,12] // WNES:[-2, -5, 5, 7]
	map["/ladder"] = [-6,-5,8,6] // WNES:[-4, -1, 5, 1]
	map["/trough"] = [-6,-11,16,20] // WNES:[-7,-4,14,6]
	map["/vclaim"] = [-16,-16,22,19] // WNES:[-12,-4,15,4]
	
	//map["/hare/"] = [0,0,0,2] // WNES:[..] // issue: is using other named res as base res.
	//map["/frog/"] = [0,0,0,2] // WNES:[..] // issue: is using other named res as base res.
	
	// general fix for none blocking items.
	map["/plants/"] = [0,0,0,0]
	map["/anthill-r"] = [0,0,0,0]
	map["/flavobjs/"] = [0,0,0,0]
	//map["/moth/"] = [0,0,0,0] // seems not really needed.
	//map["/eagle/"] = [0,0,0,0] // seems not really needed.
	
	// verified to be ok:
	// [borka,skeleton,raftpart,runestone,wbasket|wbasketo,lbox,coffer,bhive|bhived,
	// bumlings/02|,bumlings/03,barrel,chair,table,dreca,demijohn,winepress,quern|querna,
	// alloyer,churn|churna,sbasket|sbasketo,ttub|ttuba|ttubw,cndlbr|cndlbrc|cndlbrl,
	// cupboard,cauldron,cheeserack,swheel|swheela,mgrind,loom,crate,birchbasket,torchpost,
	// urn,oven,kiln|kilna,pow|powf|powr/roast|hearth-play,well|wella,bed-sprucebough,anthill,
	// bonfire,germania,sherlock,surg,(all tree's:06), ..]
	
	return map
	
	// Xcom converted leftover data.
	// Source-link: http://www.havenandhearth.com/forum/viewtopic.php?p=471487#p471487
	map["gfx/arch/door-inn"] = [-18,-13,10,11]
	map["gfx/arch/gates/brick-ns"] = [12,-16,-10,15]
	map["gfx/arch/gates/brick-we"] = [-12,-16,10,15]
	map["gfx/arch/gates/fence-ns"] = [12,-16,-10,15]
	map["gfx/arch/gates/fence-we"] = [-12,-16,10,15]
	map["gfx/arch/gates/palisade-ns"] = [12,-16,-10,15]
	map["gfx/arch/gates/palisade-we"] = [-12,-16,10,15]
	map["gfx/arch/stairs-inn"] = [8,-18,-14,17]
	map["gfx/kritter/bear/s"] = [0,-16,0,16]
	map["gfx/kritter/cow/s"] = [0,-8,0,14]
	map["gfx/kritter/deer/s"] = [0,-8,0,14]
	map["gfx/kritter/fox/s"] = [0,-6,0,8]
	map["gfx/kritter/rat/s"] = [0,0,0,2]
	map["gfx/kritter/troll/s"] = [0,-16,0,16]
	map["gfx/terobjs/blood"] = [0,-10,0,12] // none blocking.(?)
	map["gfx/terobjs/dframe2"] = [10,-11,-18,11]
	map["gfx/terobjs/furniture/leanto"] = [-8,-14,14,17]
	map["gfx/terobjs/furniture/wardrobe"] = [-10,-11,12,18]
	map["gfx/terobjs/mining/ladder"] = [-6,-5,8,6]
	map["gfx/terobjs/ridges/grass/e"] = [20,-14,-14,17]
	map["gfx/terobjs/ridges/grass/e2s"] = [44,-22,44,28]
	map["gfx/terobjs/ridges/grass/ee"] = [12,-14,-2,7]
	map["gfx/terobjs/ridges/grass/es"] = [2,-11,-16,12]
	map["gfx/terobjs/ridges/grass/s2w"] = [0,-22,-2,23]
	map["gfx/terobjs/ridges/grass/ss"] = [-12,-14,2,7]
	map["gfx/terobjs/ridges/mountain/ee"] = [20,-10,22,11]
	map["gfx/terobjs/ridges/mountain/ne"] = [0,-22,-22,11]
	map["gfx/terobjs/ridges/mountain/ns"] = [22,-11,0,22]
	map["gfx/terobjs/ridges/mountain/ss"] = [-20,-10,-22,11]
	map["gfx/terobjs/ridges/mountain/we"] = [-22,-11,0,22]
	map["gfx/terobjs/ridges/mountain/ws"] = [0,-22,22,11]
}
[v0.2]: working test example.
Main v0.2 fix: Hitbox processing. Should now work for all solid objects (with correct Neg-Res data).
++ Added additional checked hitbox data.

◄index►
Last edited by mvgulik on Tue Aug 18, 2015 12:31 pm, edited 3 times in total.
mvgulik
Posts: 4096
Joined: Fri May 21, 2010 2:29 am

Re: Groovy maid scripts

Post by mvgulik »

Major Update:
* "Walk around object" experiment. [v0.2]

--- --- ---

Plugin this code for easy testing on other objects.

Code: Select all

//def targ_gob = distanceSort_gobList(maid.getCoord(), maid.doAreaList(6))[1]
def distanceSort_gobList(cord1, data_list) {
	def Map data_map = list_to_map(data_list)
	for (e in data_list) {data_map[e] = cord1.dist(e.c)}
	data_map = data_map.sort {it.value}
	data_list = map_to_list(data_map)
	return data_list
}
def Map list_to_map(list_in) {
	def Map map_out = [:]
	for (item in list_in) {map_out[item] = null}
	return map_out
}
def List map_to_list(map_in) {
	def List list_out = []
	for (e in map_in) {list_out.add(e.key)}
	return list_out
}
... Darn doors.

Return to “The Wizards' Tower”