by mvgulik » Thu Aug 06, 2015 4:33 pm 
			
			"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.