In [ ]:
%matplotlib inline
import pyautogui
import numpy as np
from IPython.display import clear_output
from pytesseract import image_to_string
from PIL import Image
import time

import creds #make this yourself
In [ ]:
#Color/bitmap finding routines

def rgb2hsl(x):
    '''converts an [...,3] RGB image to an [...,3] HSL image'''
    hsl = np.empty_like(x,dtype='float32')
    x = np.asarray(x,dtype='float32')/255.0
    m = np.min(x,axis=-1)
    M = np.max(x,axis=-1)
    c = M-m
    dg = c==0
    ndg = ~dg
    r = x[...,0]
    g = x[...,1]
    b = x[...,2]
    hsl[...,2]=(M+m)/2
    hsl[ndg,1]=c[ndg]/(1.0-np.abs(2.0*hsl[ndg,2]-1.0))
    maskr = np.logical_and(np.equal(r,M),ndg)
    hsl[maskr,0] = (g[maskr] - b[maskr]) / c[maskr] / 6.0 + np.where(g[maskr] < b[maskr],1.0,0.0)
    maskg = np.logical_and(np.equal(g,M),ndg)
    hsl[maskg,0] = (b[maskg] - r[maskg]) / c[maskg] / 6.0 + 1.0/3.0
    maskb = np.logical_and(np.equal(b,M),ndg)
    hsl[maskb,0] = (r[maskb] - g[maskb]) / c[maskb] / 6.0 + 2.0/3.0
    hsl[dg,0] = 0.0
    hsl[dg,1] = 0.0
    return hsl

def hsl_val(a,b,a_rgb=True,b_rgb=True):
    '''returns the change in hue,sat,lum for each coordinate in a,b
       a,b can be preconverted to hsl and the *_rgb kwarg set to save time'''
    a = rgb2hsl(a) if a_rgb else a
    b = rgb2hsl(b) if b_rgb else b
    dh = np.abs(a[...,0]-b[...,0])
    dh[dh>0.5] = 1.0 - dh[dh>0.5]
    ds = np.abs(a[...,1]-b[...,1])
    dl = np.abs(a[...,2]-b[...,2])
    return dh,ds,dl
def hsl_cmp(a,b,tol,a_rgb=True,b_rgb=True):
    '''returns a boolean mask for values that satisfy tolerange requirements between a,b
       tolerance requires difference between hue,sat,lum to be separately less than tol
       a,b can be preconverted to hsl and the *_rgb kwarg set to save time'''
    dh,ds,dl = hsl_val(a,b,a_rgb,b_rgb)
    try:
        return np.logical_and(dh < tol[0],np.logical_and(ds < tol[1],dl < tol[2]))
    except TypeError:
        return np.logical_and(dh < tol,np.logical_and(ds < tol,dl < tol))

def dist_val(a,b):
    '''returns the sum of squared RGB color distance for each coordinate of a,b normalized such that dist(black,white)=1.0'''
    return np.sum(np.square(a-b),axis=-1) / (3*255**2.0)
def dist_cmp(a,b,tol):
    '''returns a boolean mask for values that satisfy tolerange requirements between a,b
       tolerance requires the quadrature sum of channel distances to be less than tol'''
    return dist_val(a,b) < tol*tol

def diff_val(a,b):
    '''returns the sum of absolute RGB distance for each coordinate of a,b normalized such that dist(black,white)=1.0'''
    return np.sum(np.abs(a-b),axis=-1) / (3*255)
def diff_cmp(a,b,tol):
    '''returns a boolean mask for values that satisfy tolerange requirements between a,b
       tolerance requires the sum of channel distances to be less than tol'''
    return diff_val(a,b) < tol

def get_val(mode):
    '''return the distance function for the given color mode'''
    if mode == 'diff':
        val = diff_val
    elif mode == 'dist':
        val = dist_val
    elif mode == 'hsl':
        val = hsl_val
    else:
        raise RuntimeError('Unknown tolerance mode: %s'%mode)
    return val
def get_cmp(mode):
    '''return the comparator function for the given color mode'''
    if mode == 'diff':
        cmp = diff_cmp
    elif mode == 'dist':
        cmp = dist_cmp
    elif mode == 'hsl':
        cmp = hsl_cmp
    else:
        raise RuntimeError('Unknown tolerance mode: %s'%mode)
    return cmp

def find_bitmap_prob(bmp,region,mask=None,mode='dist'):
    '''compare to matchTemplate in opencv - returns the distance between bmp and every possible location in region'''
    hr,wr=region.shape[:2]
    hs,ws=bmp.shape[:2]
    val = get_val(mode)
    if mode == 'hsl':
        bmp = rgb2hsl(bmp)
        region = rgb2hsl(region)
        if mask is not None:
            return np.asarray([[np.sum(val(bmp[mask],region[i:i+hs,j:j+ws][mask],a_rgb=False,b_rgb=False)[0]) for j in range(wr-ws)] for i in range(hr-hs)])
        else:
            return np.asarray([[np.sum(val(bmp,region[i:i+hs,j:j+ws],a_rgb=False,b_rgb=False)[0]) for j in range(wr-ws)] for i in range(hr-hs)])
    else:
        if mask is not None:
            return np.asarray([[np.sum(val(bmp[mask],region[i:i+hs,j:j+ws][mask])) for j in range(wr-ws)] for i in range(hr-hs)])
        else:
            return np.asarray([[np.sum(val(bmp,region[i:i+hs,j:j+ws])) for j in range(wr-ws)] for i in range(hr-hs)])

def find_best_bitmap(bmp,region,tol=0.4):
    probs = find_bitmap_prob(bmp,region)
    found = np.asarray(np.nonzero(probs < tol))
    return found[[1,0]].T
        
def find_bitmap(bmp,region,tol=0.01,mask=None,mode='dist'):
    '''similar to find_bitmap_prob but uses the heuristic that each pixel must match better than some tolerance.
       Only returns the coordinates of potential matches.'''
    xs,ys=0,0
    hr,wr=region.shape[:2]
    hs,ws=bmp.shape[:2]
    cmp = get_cmp(mode)
    if mask is None:
        candidates = np.asarray(np.nonzero(cmp(bmp[0,0],region[:-hs,:-ws],tol)))
    else:
        candidates = np.asarray(np.nonzero(np.ones((hr-hs+1,wr-ws+1))))
    for i in np.arange(0,hs):
        for j in np.arange(0,ws):
            if (mask is None and i==0 and j==0) or (mask is not None and not mask[i,j]):
                continue
            view = region[candidates[0]+i,candidates[1]+j,:]
            passed = cmp(bmp[i,j],view,tol)
            candidates = candidates.T[passed].T
        
    return candidates[[1,0],:].T

def find_colors(color,region,tol=0.1,mode='dist'):
    '''finds all instance of color in region'''
    cmp = get_cmp(mode)
    mask = cmp(region,color,tol)
    found = np.argwhere(mask)[:,[1,0]]
    return found

def filter_near(a,b,dist):    
    '''returns all points in a within some distance to a point in b'''
    if len(a) == 0 or len(b) == 0:
        return np.asarray([])
    diffs = np.asarray([(i,np.min(np.sum(np.square(p-b),axis=-1))) for i,p in enumerate(a)])
    return a[diffs[:,1]<dist*dist]

def filter_far(a,b,dist):    
    '''returns all points in a within some distance to a point in b'''
    if len(a) == 0:
        return np.asarray([])
    if len(b) == 0:
        return a
    diffs = np.asarray([(i,np.min(np.sum(np.square(p-b),axis=-1))) for i,p in enumerate(a)])
    return a[diffs[:,1]>dist*dist]

def filter_radius(pts,center,radius):
    '''returns all points in pts within radius of the center point'''
    return pts[np.sum(np.square(pts-center),axis=-1)<radius*radius]

def closest(point,points):
    '''returns the closest value in points to the given point'''
    sorter = np.argsort(np.sum(np.square(points-point),axis=-1))
    return points[np.argmin(sorter)]

def cluster(points,radius=5):
    clusters = np.zeros(len(points),dtype='uint32')
    while True: #loop until all points are clustered
        unclustered = clusters==0
        remaining = np.count_nonzero(unclustered)
        if remaining == 0:
            break 
        # any points near this group (and their points) become a new group
        candidate = points[unclustered][np.random.randint(remaining)] #do this randomly to save time
        dist = np.sum(np.square(points-candidate),axis=1)
        nearby_mask = dist<=radius*radius #importantly includes candidate point
        overlaps = set(list(clusters[nearby_mask])) #groups that were close
        overlaps.remove(0)
        if len(overlaps) == 0:
            G = np.max(clusters)+1 #new cluster
        else:
            G = np.min(list(overlaps)) #prefer smaller numbers
        #set all nearby clusters to index G
        clusters[nearby_mask] = G
        for g in overlaps:
            if g == G or g == 0:
                continue
            clusters[clusters==g] = G
    unique, counts = np.unique(clusters, return_counts=True)
    cluster_points = np.asarray([points[clusters==c] for c in unique],dtype='object')
    return cluster_points,counts
In [ ]:
#bitmap and convenience functions
minimap_mask = np.asarray(Image.open('minimap_mask.png'))[:,:,0] == 255
anchor = np.asarray(Image.open('anchor.png')) #image (always) on the client's banner

# misc useful coordinates
x0,y0 = 0,0 #set by target() used throughout
w,h = 765,503
msxs,msxe,msys,msye = 5,519,5,337
msw,msh = (msxe-msxs+1),(msye-msys+1)
msxc,msyc = msxs+msw/2,msys+msh/2
ivxs,ivxe,ivys,ivye = 560,737,207,460
ivw,ivh = (ivxe-ivxs+1),(ivye-ivys+1)
mmxs,mmxe,mmys,mmye = 548,726,3,165
mmxc,mmyc=647,85

def target():
    '''looks for the client and caches its location'''
    global x0,y0
    desktop = np.asarray(pyautogui.screenshot())
    pts = find_bitmap(anchor,desktop)
    assert len(pts)==1,'window ambiguious or not found'
    x0,y0 = pts[0]+[0,anchor.shape[1]]

#functions to grab images of client - smaller region is faster maybe?
def get_client():
    return np.asarray(pyautogui.screenshot(region=(x0,y0,w,h)))
def get_mainscreen():
    return np.asarray(pyautogui.screenshot(region=(x0+msxs,y0+msys,msxe-msxs+1,msye-msys+1)))
def get_uptext(width=400):
    return np.asarray(pyautogui.screenshot(region=(x0+7,y0+7,width-7+1,23-7+1)))
def get_minimap():
    return np.asarray(pyautogui.screenshot(region=(x0+mmxs,y0+mmys,mmxe-mmxs+1,mmye-mmys+1)))
def get_compass():
    return np.asarray(pyautogui.screenshot(region=(x0+mmxs,y0+mmys,37,35)))
def get_inventory():
    return np.asarray(pyautogui.screenshot(region=(x0+ivxs,y0+ivys,ivxe-ivxs+1,ivye-ivys+1)))

def get_compass_angle():
    compass = get_compass()
    red = find_colors([238,0,0],compass,0.2)-np.asarray(compass.shape)[[1,0]]/2
    clusters,counts = cluster(red,radius=5)
    tips = clusters[counts<5]
    meanxy = np.asarray([np.mean(tip.T,axis=1) for tip in clusters[counts<5]])
    meanxy = np.mean(meanxy.T,axis=1)
    direction = [-1,1]*meanxy/np.sqrt(np.sum(np.square(meanxy)))
    return np.mod(-np.arctan2(direction[1],direction[0])/np.pi*180+90,360)

def polish_minimap(min_same=28,horizontal=True,bounds=30,click=True):
    if click:
        click_mouse(mmxc,mmyc)
    bestn = 0
    left = True
    pyautogui.PAUSE = 0.001
    while True:
        deg = get_compass_angle()
        left = np.random.random() < 0.5
        if deg < 360-bounds and deg > 180:
            left = False
        if deg < 180 and deg > bounds:
            left = True
        if left:
            pyautogui.keyDown('left')
            time.sleep(0.1*np.random.random())
            pyautogui.keyUp('left')
        else:
            pyautogui.keyDown('right')
            time.sleep(0.1*np.random.random())
            pyautogui.keyUp('right')
            
        minimap = get_minimap()
        walls = find_colors([238,238,238],minimap,tol=0.05)
        vals,counts = np.unique(walls[:,1 if horizontal else 0],return_counts=True)
        maxn = np.max(counts)
        print(maxn)
        if maxn >= min_same and (deg > 360-bounds or deg < bounds):
            break
    pyautogui.PAUSE = 0.1

def flag_wait(init=2.0,step=0.2,post=1.5,imax=50):
    '''sleeps the init time, then each step while the flag stem is visible up to imax times, finally sleeping post'''
    time.sleep(init)
    i = 0
    while True:
        minimap = get_minimap()
        i = i+1
        if i > imax:
            break
        if len(find_bitmap(flag,minimap)) == 0:
            time.sleep(post)
            break
        time.sleep(step)

def uptext_mask(uptext,width=None):
    '''provides a black-on-white mask of an uptext image for OCR'''
    uptext = uptext[:,:width] if width is not None else uptext
    white = find_colors([225,225,225],uptext,tol=0.1)
    cyan = find_colors([0,225,225],uptext,tol=0.1)
    yel = find_colors([225,225,0],uptext,tol=0.1)
    thresh = np.full_like(uptext,255)
    
    for c in [white,cyan,yel]:
        thresh[c[:,1],c[:,0]] = [0,0,0]

    return uptext,thresh

def move_mouse(x,y,speed=1.0):
    '''moves the mouse to a point'''
    cx,cy = pyautogui.position()
    ex,ey = x+x0,y+y0
    dt = np.sqrt((cx-x)**2.0+(cy-y)**2.0)/(speed*1000)
    pyautogui.moveTo(ex,ey,dt,pyautogui.easeOutQuad)

def click_mouse(x,y,left=True,speed=1.0):
    '''moves to and clicks a point'''
    move_mouse(x,y,speed=speed)
    pyautogui.click(button='left' if left else 'right')
    
def send_keys(text,speed=1.0):
    '''sends text to the client (\n for enter)'''
    pyautogui.typewrite(text,interval=0.05*speed)
In [ ]:
flag = np.asarray(Image.open('flag.png'))
loginscreen = np.asarray(Image.open('loginscreen.png'))
existinguser = np.asarray(Image.open('existinguser.png'))
use_booth = np.asarray(Image.open('use_booth.png'))
bank_window = np.asarray(Image.open('bank_window.png'))
store_all = np.asarray(Image.open('store_all.png'))
crumbling = np.asarray(Image.open('crumbling.png'))
minerocks,minerocks_mask = uptext_mask(np.asarray(Image.open('minerocks.png')))

west_road = [122,117,70]
east_road = [121,119,97]
wall_color = [190,184,155]
inner_wall_color = [60,60,50]
outer_wall_color = [73,64,41]

copper_color = [174,126,81]
tin_color = [149,138,138]
iron_color = [60,35,28]
gold_color = [251,204,31]
silver_color = []
In [ ]:
#higher level routines

def login():    
    '''basic login routine - assumes current state is login window'''
    print('logging in')
    if len(find_bitmap(existinguser,client)) > 0:
        click_mouse(463,291)
        time.sleep(2.0)
    click_mouse(355,240)
    time.sleep(2.0)
    send_keys('%s\n%s'%(creds.username,creds.password))
    time.sleep(1.0)
    click_mouse(305,326)
    time.sleep(5.0)
    click_mouse(401,335)
    time.sleep(5.0)

def count_inv(mask=False,color=[1,0,0],tol=0.02):
    '''counts the number of items with the given color (default is shadow, so all) in the inventory'''
    inventory = get_inventory()
    w,h = 42,36
    grid = [[len(find_colors(color,inventory[h*i:h*i+h,w*j:w*j+w],tol=tol))>0 for i in range(7)] for j in range(4)]
    return grid if mask else np.count_nonzero(grid)

def count_rocks(weighted=True,rocks=None):
    '''finds the weighted count of each rock in the inventory for each rock the rocks list'''
    count_inv
    raw_counts = np.asarray([(count_inv(color=invc,tol=tol),weight) for weight,color,tol,invc in rocks])
    return raw_counts[:,0]/raw_counts[:,1] if weighted else raw_counts[:,0]


bank_floor_colors = [[130,60,47],[170,104,80]]
def open_bank():
    '''opens bank window if not already open - FALADOR WEST ONLY
       bank is found by proximity of npc points to a unique bank floor color
       booth is found by proximity of two colors on the booth (dark top and light mid area)
       right clicks booth and checks for Use Quickly, tries next option if not found'''
    mainscreen = get_mainscreen()
    if len(find_bitmap(bank_window,mainscreen)) > 0:
        return True
    minimap = get_minimap()
    npc_points = find_colors([255,255,0],minimap,tol=0.05,mode='hsl')
    bank_points = np.concatenate([find_colors(bank_floor,minimap,tol=0.085,mode='hsl') for bank_floor in bank_floor_colors])
    print('Bank points:',len(bank_points))
    clusters,counts = cluster(bank_points)
    if len(counts) < 1 or np.count_nonzero(counts>20) < 1:
        bank_points = np.asarray([])
    else:
        bank_points = clusters[np.random.choice(np.nonzero(counts>20)[0])]
    print('Clustered bank points:',len(bank_points))
    bank_points = filter_near(npc_points,bank_points,6)
    print('Points near NPCs:',len(bank_points))
    np.random.shuffle(bank_points)
    if len(bank_points) < 15:
        return False
    click_mouse(*(bank_points[0]+[mmxs,mmys-8]))
    flag_wait()
    flag_wait()
    mainscreen = get_mainscreen()
    pa = find_colors([74,70,70],mainscreen,tol=0.02,mode='hsl')
    pb = find_colors([118,96,68],mainscreen,tol=0.02,mode='hsl')
    points = filter_near(pa,pb,20)
    np.random.shuffle(points)
    if len(points) > 1:
        minidx = np.argmin(np.sum(np.square(points-[msxc-msxs,msyc-msys]),axis=1))
        points[-1],points[minidx] = points[minidx],points[-1]
    for point in points[-5:]:
        click_mouse(*point,left=False)
        time.sleep(0.05)
        use = find_bitmap(use_booth,get_mainscreen())
        if len(use) > 0:
            click_mouse(*(use[0]+[10,10]))
            flag_wait()
            return True
        move_mouse(*(point+[0,-25]))
    return False
            
def deposit_all():
    '''searches for border colors in inventory and deposits them all to bank
       assumes bank window already open'''
    mainscreen = get_mainscreen()
    while len(find_bitmap(bank_window,mainscreen)) > 0:
        inventory = get_inventory()
        found = find_colors([1,0,0],inventory)
        if len(found):
            np.random.shuffle(found)
            click_mouse(*found[0]+[ivxs,ivys],left=False)
            time.sleep(0.5)
            client = get_client()
            found = find_bitmap(store_all,client)
            if len(found):
                click_mouse(*found[0]+[10,10])
                time.sleep(1.0)
        else:
            break
        mainscreen = get_mainscreen()
    
tabs = {'settings':[681,484],'inventory':[645,187],'stats':[584,190]}
def open_tab(tab):
    if tab not in tabs:
        raise RuntimeException('Unknown tab %s'%tab)
    click_mouse(*tabs[tab])
    time.sleep(0.5)

run_already_on = np.asarray(Image.open('run_on.png'))[...,:3]
def run_on(restore_tab='inventory'):
    open_tab('settings')
    inventory = get_inventory()
    if len(find_bitmap(run_already_on,inventory,tol=0.02)) == 0:
        click_mouse(646,435)
        time.sleep(0.5)
    open_tab(restore_tab)
    
In [ ]:
#Seer's Flax picker and spinner - UNFINISHED

bank_floor = [141,134,131]
party_room_gray = [165,156,152]
party_room_blue = [99,115,147]
mm_flax = [93,93,163]
mm_ladder = [82,33,0]


inv_flax = np.asarray(Image.open('flax.png'))
inv_bowstring = np.asarray(Image.open('bowstring.png'))


def pick_flax():
    print('trying to pick')
    return False

inventory = get_inventory()
nf = len(find_best_bitmap(inv_flax,inventory,tol=0.2))
nbs = len(find_best_bitmap(inv_bowstring,inventory,tol=0.2))
nrem = 28 - count_inv()

if nrem > 0:
    if nf > 0:
        state = 'picking'
    else:
        state = 'to_flax'
else:
    if nf > 0:
        if nbs > 0:
            state = 'spinning'
        else:
            state = 'to_spin'
    else:
        minimap = get_minimap()
        bank = find_best_bitmap(bank_icon,minimap,tol=0.05)
        spin = find_best_bitmap(spin_icon,minimap,tol=0.05)
        if len(spin) > 0:
            state = 'exit_house'
        else:
            state = 'to_bank'


a = find_colors(bank_floor,minimap,tol=(0.5,0.03,0.03),mode='hsl')
b = find_colors(party_room_gray,minimap,tol=(0.5,0.03,0.03),mode='hsl')
c = find_colors(party_room_blue,minimap,tol=(0.05,0.03,0.03),mode='hsl')
d = find_colors([238,0,0],minimap,tol=(0.05,0.03,0.03),mode='hsl')
e = find_colors(mm_ladder,minimap,tol=(0.05,0.03,0.03),mode='hsl')
spindoor = filter_near(d,e,10)
party = filter_near(b,c,5)
npc = find_colors([238,238,0],minimap,tol=(0.05,0.2,0.2),mode='hsl')
flax = find_colors(mm_flax,minimap,tol=(0.05,0.2,0.2),mode='hsl')
bank = a

if state == 'picking':
    pick_flax()
elif state == 'spinning':
    time.sleep(1.0)
elif state == 'to_flax':
    if len(flax) > 0:
        np.random.shuffle(flax)
        click_mouse(*(flax[0]+[mmxs,mmys]))
        flag_wait()
        pick_flax()
        continue
    if len(party) > 0:
        minx = np.min(party[:,0])
        click_mouse(*([minx-10,mmcy+40]))
        flag_wait()
elif state == 'to_bank':
    if len(bank) > 0:
        click_mouse(*(bank+[mmxs,mmys]))
        flag_wait()
        #open bank
        deposit_all()
    else:
        print('no bank!')
elif state == 'to_spin':
    if len(party) > 0:
        minx = np.min(party[:,0])
        click_mouse(*([minx-10,mmcy-40]))
        flag_wait()
    else:
        print('no party room!')
In [ ]:
#Air rune crafter falador east

ess = np.asarray(Image.open('pure_essence.png'))[...,:3]
air_rune = np.asarray(Image.open('air_rune.png'))[...,:3]

mm_bank = [185,174,147]
mm_north_road = [132,125,105]
mm_south_road = [113,105,105]
mm_altar_dirt = [127,108,72]

use_tiara = True

target()
total_trips = 0
last_craft = time.monotonic()
logins = 0
while True:
    client = get_client()
    if len(find_bitmap(loginscreen,client)) > 0:
        logins = logins + 1
        if logins > 10:
            raise RuntimeError('Too many logins! Bailing out before we get fishy!')
        login()
        continue
    if time.monotonic()-last_craft > 10*60:
        raise RuntimeError('Took more than 10min to craft, something is wrong.')

    inv = count_inv()
    minimap = get_minimap()
    dirt = find_colors(mm_altar_dirt,minimap,mode='hsl',tol=(0.05,0.08,0.08))
    dirt = filter_radius(dirt,[mmxc-mmxs,mmyc-mmys],65)
    
    print('dirt',len(dirt))
    if len(dirt) > 2000: #at altar
        if inv == 28: #craft
            mainscreen = get_mainscreen()
            found = find_colors([64,64,64],mainscreen,tol=(0.5,0.1,0.1),mode='hsl')
            np.random.shuffle(found)
            for trial in range(15):
                move_mouse(*(found[-trial]+[msxs,msys]))
                uptext,mask = uptext_mask(get_uptext())
                txt = image_to_string(mask)
                print('tesseract say:',txt)
                if 'mu.' in txt or ' 1W' in txt or 'Curran' in txt or 'Cum.' in txt or 'Am.' in txt or 'am.' in txt or 'cmmuna' in txt:
                    click_mouse(*(found[-trial]+[msxs,msys]))
                    flag_wait()
                    last_craft = time.monotonic()
                    time.sleep(2.0)
                    break
        else: #return
            clusters,counts = cluster(dirt,radius=2)
            print('dirt clusters',counts)
            if np.count_nonzero(counts<1000):
                exit = np.concatenate(clusters[counts<1000])
                np.random.shuffle(exit)
                click_mouse(*(exit[0]+[mmxs,mmys]))
                flag_wait()                    
                mainscreen = get_mainscreen()
                portal = find_colors([215,212,174],mainscreen,tol=0.08,mode='hsl')
                if len(portal) > 0:
                    np.random.shuffle(portal)
                    click_mouse(*(portal[0]+[msxs,msys]))
                    flag_wait()
                    continue
                else:
                    print('no portal!')
    else: #banking or going to altar
        north = find_colors(mm_north_road,minimap,mode='hsl',tol=(0.05,0.08,0.08))
        north = filter_radius(north,[mmxc-mmxs,mmyc-mmys],65)
        south = find_colors(mm_south_road,minimap,mode='hsl',tol=(0.05,0.08,0.08))
        south = filter_radius(south,[mmxc-mmxs,mmyc-mmys],65)
        bank = find_colors(mm_bank,minimap,mode='hsl',tol=(0.05,0.2,0.08))
        bank = filter_radius(bank,[mmxc-mmxs,mmyc-mmys],65)
        print('north',len(north),'south',len(south),'bank',len(bank))
        npc = find_colors([238,238,0],minimap,mode='hsl',tol=0.15)
        clusters,counts = cluster(npc,radius=5)
        if len(bank) and len(counts) and np.max(counts) > 50:
            npc = clusters[np.argmax(counts)]
            bank = filter_near(npc,bank,5)
        else:
            bank = []

        if inv == 28: #go craft
            if len(south) > 0:
                walls = find_colors([238,238,238],minimap,tol=0.15)
                border = filter_near(south,walls,5)
                border = filter_far(border,[[mmxc-mmxs,mmyc-mmys]],10)
                print('border',len(border))
                if len(border) > 100:
                    mainscreen = get_mainscreen()
                    a = find_colors([74,72,70],mainscreen,tol=(0.07,0.1,0.1),mode='hsl')
                    b = find_colors([64,64,64],mainscreen,tol=(0.07,0.1,0.1),mode='hsl')
                    altar = filter_near(a,b,10)
                    clusters,counts = cluster(altar)
                    if len(counts) > 5 and np.max(counts) > 1000:
                        print('altar located')
                        click_mouse(mmxc,mmyc)
                        flag_wait()
                        mainscreen = get_mainscreen()
                        a = find_colors([74,72,70],mainscreen,tol=(0.07,0.1,0.1),mode='hsl')
                        b = find_colors([64,64,64],mainscreen,tol=(0.07,0.1,0.1),mode='hsl')
                        altar = filter_near(a,b,10)
                        clusters,counts = cluster(altar)
                        if use_tiara is False:
                            click_mouse(586,226)
                            time.sleep(0.05)
                        found = clusters[np.argmax(counts)]
                        np.random.shuffle(found)
                        click_mouse(*(found[0]+[msxs,msys]))
                        flag_wait()
                        time.sleep(1.0)
                        continue
                    walkto = border[np.argmin(border[:,0])]-[15,55]
                    vec = walkto-[mmxc-mmxs,mmyc-mmys]
                    veclen = np.sqrt(np.sum(np.square(vec)))
                    if veclen > 65:
                        walkto = [mmxc-mmxs,mmyc-mmys] + vec/veclen*65

                else:
                    walkto = south[np.argmax(south[:,1])]
            elif len(north) > 0:
                walkto = north[np.argmax(north[:,1]-north[:,0])]
            else:
                print('really lost...')
                continue
            print('heading south')
            click_mouse(*(walkto+[mmxs,mmys]))
            time.sleep(1.5)
        else: #go bank
            if len(bank) > 0:
                np.random.shuffle(bank)
                click_mouse(*(bank[0]+[mmxs,mmys-10]))
                flag_wait()
                time.sleep(2.0)
                mainscreen = get_mainscreen()
                a = find_colors([125,101,71],mainscreen,tol=0.02,mode='hsl')
                b = find_colors([143,116,82],mainscreen,tol=0.02,mode='hsl')
                points = filter_near(a,b,40)
                np.random.shuffle(points)
                if len(points) > 1:
                    minidx = np.argmin(np.sum(np.square(points-[msxc-msxs,msyc-msys]),axis=1))
                    points[-1],points[minidx] = points[minidx],points[-1]
                for point in points[-5:]:
                    click_mouse(*point,left=False)
                    time.sleep(0.05)
                    use = find_bitmap(use_booth,get_client())
                    if len(use) > 0:
                        click_mouse(*(use[0]+[10,10]))
                        flag_wait()
                        time.sleep(2.0)
                        while True:
                            inv = get_inventory()
                            found = find_best_bitmap(air_rune,inv,tol=0.05)
                            if len(found) > 0:
                                np.random.shuffle(found)
                                click_mouse(*(found[0]+[ivxs,ivys]),left=False)
                                time.sleep(0.5)
                                client = get_client()
                                found = find_bitmap(store_all,client)
                                if len(found):
                                    click_mouse(*found[0]+[10,10])
                                    time.sleep(1.0)
                            else:
                                break
                        mainscreen = get_mainscreen()
                        found = find_best_bitmap(ess,mainscreen,tol=0.05)
                        if len(found) > 0:
                            np.random.shuffle(found)
                            click_mouse(*(found[0]+[msxs,msys]),left=False)
                            time.sleep(1.0)
                            click_mouse(*(found[0]+[msxs,msys+87]))
                            time.sleep(1.0)
                            send_keys('28')
                            time.sleep(0.5)
                            send_keys('\n')
                            time.sleep(0.5)
                        else:
                            raise RuntimeError('out of materials!')
                        click_mouse(488,43)
                        if np.random.random() < 0.2:
                            polish_minimap()
                        clear_output()
                        total_trips += 1
                        print('completed %i inventories'%total_trips)
                        time.sleep(1.0)
                        run_on()
                        break
                    move_mouse(*(point+[0,-25]))
                continue
            if len(north) > 100:
                walkto = north[np.argmin(north[:,1]+0.5*north[:,0])]
            else:
                walkto = np.asarray([mmxc-mmxs+20,mmyc-mmys-40])#south[np.argmin(south[:,1]-south[:,0])]
            print('heading north')
            click_mouse(*(walkto+[mmxs,mmys]))
            time.sleep(1.5)
            
            
In [ ]:
#Aubury essence miner varrock

mm_dirt_road = [140,132,95]
mm_bank_floor = [136,134,126]

travel_icon = np.asarray(Image.open('travel_icon.png'))[...,:3]
magic_icon = np.asarray(Image.open('magic_shop.png'))[...,:3]
teleport = np.asarray(Image.open('teleport.png'))[...,:3]

target()
total_trips = 0
last_mine = time.monotonic()
logins = 0
while True:
    client = get_client()
    if len(find_bitmap(loginscreen,client)) > 0:
        logins = logins + 1
        if logins > 10:
            raise RuntimeError('Too many logins! Bailing out before we get fishy!')
        login()
        continue
    if time.monotonic()-last_mine > 10*60:
        raise RuntimeError('Bailing out, wandered around for 10 minutes, definitely lost.')
        
    minimap = get_minimap()
    black = find_colors([0,0,0],minimap,tol=0.05)
    inv = count_inv()
    
    if len(black) > 1000: #in mine
        border = filter_far(black,[[mmxc-mmxs,mmyc-mmys]],40)
        if len(border) > 9000: #we're in a wing
            if inv == 28: #full, leave
                mainscreen = get_mainscreen()
                portal = find_colors([215,212,174],mainscreen,tol=0.08,mode='hsl')
                if len(portal) > 0:
                    np.random.shuffle(portal)
                    click_mouse(*(portal[0]+[msxs,msys]))
                    flag_wait()
                    continue
                else:
                    print('no portal!')
                    travel = find_best_bitmap(travel_icon,minimap,tol=0.05)
                    if len(travel) > 0:
                        np.random.shuffle(travel)
                        click_mouse(*(travel[0]+[mmxs,mmys]))
                        flag_wait()
            else: #mine
                flag_wait(init=0,post=0)
                did_something = False
                for trial in range(15):
                    x,y = np.random.randint(msxs,msxs+msw),np.random.randint(msys,msys+msh)
                    move_mouse(x,y)
                    uptext,mask = uptext_mask(get_uptext())
                    txt = image_to_string(mask)
                    print('tesseract say:',txt)
                    if 'Runa' in txt or '1.“' in txt:
                        did_something = True
                        click_mouse(x,y)
                        flag_wait()
                        i = 0
                        while True:
                            new_inv = count_inv()
                            if new_inv != inv:
                                i = 0
                                inv = new_inv
                            if inv == 28:
                                break
                            if i > 10:
                                break
                            i += 1
                            time.sleep(0.5)
                        break
                if did_something:
                    last_mine = time.monotonic()
                    continue
            
            print('trying new area...')
            area = find_colors([200,200,200],minimap,mode='hsl',tol=0.3)
            area = filter_radius(area,[mmxc-mmxs,mmyc-mmys],70)
            area = filter_far(area,black,20)
            if len(area) > 0:
                np.random.shuffle(area)
                click_mouse(*(area[0]+[mmxs,mmys]))
                flag_wait()
            else:
                print('hopelessly lost')
        else:
            print('moving to essence')
            area = find_colors([200,200,200],minimap,mode='hsl',tol=0.3)
            area = filter_radius(area,[mmxc-mmxs,mmyc-mmys],65)
            if len(area) > 0:
                point = area[np.argmin(-area[:,0]-area[:,1])]
                click_mouse(*(point+[mmxs,mmys]))
                time.sleep(3.0)
            else:
                print('hopelessly lost')
                    
    else: # in varrock
        road = find_colors(mm_dirt_road,minimap,tol=(0.05,0.07,0.05),mode='hsl')
        road = filter_radius(road,[mmxc-mmxs,mmyc-mmys],65)
        print('road',len(road))
        if inv == 28: #go bank
            bank_floor = find_colors(mm_bank_floor,minimap,mode='hsl',tol=(0.06,0.08,0.09))
            npcs = find_colors([238,238,0],minimap,mode='hsl',tol=0.1)
            clusters,counts = cluster(npcs,radius=4)
            print('bank_clusters',counts)
            if len(counts) > 0 and np.max(counts) > 59:
                bank_points = clusters[np.argmax(counts)]
                bank_points = filter_near(npcs,bank_points,4)
                print('bank',len(bank_points))
                if len(bank_points) > 5:
                    np.random.shuffle(bank_points)
                    click_mouse(*(bank_points[0]+[mmxs,mmys]))
                    flag_wait(imax=200)
                    mainscreen = get_mainscreen()
                    a = find_colors([96,83,45],mainscreen,mode='hsl',tol=0.1)
                    b = find_colors([52,43,65],mainscreen,mode='hsl',tol=0.1)
                    points = filter_near(a,b,40)
                    np.random.shuffle(points)
                    if len(points) > 1:
                        minidx = np.argmin(np.sum(np.square(points-[msxc-msxs,msyc-msys]),axis=1))
                        points[-1],points[minidx] = points[minidx],points[-1]
                    for point in points[-5:]:
                        click_mouse(*point,left=False)
                        time.sleep(0.05)
                        use = find_bitmap(use_booth,get_mainscreen())
                        if len(use) > 0:
                            click_mouse(*(use[0]+[10,10]))
                            flag_wait()
                            time.sleep(2.0)
                            deposit_all()
                            click_mouse(488,43)
                            time.sleep(1.0)
                            run_on()
                            if np.random.random() < 0.2:
                                polish_minimap()
                            break
                        move_mouse(*(point+[0,-25]))
                    continue
            print('heading north')
            walkto = road[np.argmin(road[:,1]-road[:,0])]
        else: #go aubury
            magic = find_best_bitmap(magic_icon,minimap,tol=0.11)
            if len(magic) > 0:
                np.random.shuffle(magic)
                click_mouse(*(magic[0]+[mmxs+5,mmys+5]))
                flag_wait()
                print('search for aubury')
                for i in range(20):
                    mainscreen = get_mainscreen()
                    a = find_colors([251,220,32],mainscreen,tol=0.18)
                    b = find_colors([240,240,240],mainscreen,tol=0.18)
                    aubury = filter_near(a,b,30)
                    if len(aubury) > 0:
                        np.random.shuffle(aubury)
                        move_mouse(*(aubury[0]+[msxs,msys]))
                        uptext = get_uptext()
                        yellow = find_colors([238,238,0],uptext,mode='hsl',tol=0.18)
                        if len(yellow) > 100:
                            click_mouse(*(aubury[0]+[msxs,msys]),left=False)
                            mainscreen = get_mainscreen()
                            clickme = find_bitmap(teleport,mainscreen)
                            if len(clickme) == 1:
                                click_mouse(*(clickme[0]+[msxs+15,msys+3]))
                                time.sleep(5.0)
                                break
                continue
            print('heading south')
            walkto = road[np.argmax(road[:,1]+0.35*road[:,0])]
        click_mouse(*(walkto+[mmxs,mmys]))
        time.sleep(1.0)
In [ ]:
#Tree copper and shaft fletcher

logs = np.asarray(Image.open('oak_logs.png'))[:,:,:3]
knife = np.asarray(Image.open('knife.png'))[:,:,:3]

target()
while True:
    client = get_client()
    if len(find_bitmap(loginscreen,client)) > 0:
        logins = logins + 1
        if logins > 10:
            raise RuntimeError('Too many logins! Bailing out before we get fishy!')
        login()
        continue
            
    mainscreen = get_mainscreen()
    
    if count_inv() > 26: #fletch (or fire)
        print('time to fletch')
        inventory = get_inventory()
        k = find_best_bitmap(knife, inventory, tol=0.2)
        l = find_best_bitmap(logs, inventory, tol=0.2)
        print(len(l))
        if len(k) > 0 and len(l) > 0:
            np.random.shuffle(k)
            np.random.shuffle(l)
            click_mouse(*(k[0]+[ivxs,ivys]))
            time.sleep(1.0)
            click_mouse(*(l[0]+[ivxs,ivys]))
            time.sleep(1.0)
            click_mouse(76,405,left=False)
            time.sleep(1.0)
            click_mouse(55,477)
            time.sleep(1.0)
            send_keys('9999')
            time.sleep(1.0)
            send_keys('\n')
            i = 0
            last_len = len(l)
            while True:
                inventory = get_inventory()
                new_len = len(find_best_bitmap(logs, inventory, tol=0.2))
                if new_len == 0:
                    break
                if last_len != new_len:
                    last_len = new_len
                    i = 0
                i=i+1
                if i > 4:
                    print('timed out')
                    break
                time.sleep(0.5)
        else:
            print('missing knife or logs')

    a = find_colors([0,10,0],mainscreen,tol=0.05,mode='hsl')
    c = find_colors([150,170,100],mainscreen,tol=0.05,mode='hsl')
    trees = filter_near(a,c,20)
    found = False
    if len(trees) > 0:
        np.random.shuffle(trees)
        print('trying trees')
        for tree in trees[-10:]:
            move_mouse(*(tree+[msxs,msys]))
            time.sleep(0.1)
            uptext,mask = uptext_mask(get_uptext())
            txt = image_to_string(mask)
            print('tesseract say:',txt)
            if 'unTan' in txt or 'm. 1.' in txt or '1.22' in txt or 'm. I.' in txt or 'm 1.' in txt or 'dnunTma' in txt or 'dnunTva' in txt:
                print('chop it down!')
                click_mouse(*(tree+[msxs,msys]))
                found = True
                inv = count_inv()
                flag_wait()
                i = 0
                while inv == count_inv():
                    i += 1
                    if i > 10:
                        print('timed out')
                        break
                    time.sleep(0.5)
                else: #didn't timeout
                    break
    if found:        
        continue
    t = find_colors([55,79,25],minimap,mode='hsl',tol=0.05)
    if np.random.random() > 0.1:
        t = t[t[...,1]>mmyc-mmys]
    if len(t) > 0:
        np.random.shuffle(t)
        click_mouse(*(t[0]+[mmxs,mmys]))
        flag_wait()
In [ ]:
#Chicken killer + bone burrier + feather grabber

bones_inv = np.asarray(Image.open('bones_inv.png'))
raw_chicken = np.asarray(Image.open('raw_chicken.png'))[...,:3]
drop_txt = np.asarray(Image.open('drop.png'))[...,:3]

target()
total_chickens = 0
logins = 0
while True:
    client = get_client()
    if len(find_bitmap(loginscreen,client)) > 0:
        logins = logins + 1
        if logins > 10:
            raise RuntimeError('Too many logins! Bailing out before we get fishy!')
        login()
        continue
            
    mainscreen = get_mainscreen()
    hp_r = find_colors([255,0,0],mainscreen,tol=0.01,mode='hsl') - [msxc-msxs,msyc-msys]
    hp_g = find_colors([0,255,0],mainscreen,tol=0.01,mode='hsl') - [msxc-msxs,msyc-msys]
    
    if len(filter_radius(np.concatenate([hp_r]),[0,0],100)) > 10: #in combat
        time.sleep(1.0)
        continue
        
    mainscreen = get_mainscreen()
    a = find_colors([185,149,147],mainscreen,tol=0.05,mode='hsl')
    c = find_colors([225,225,225],mainscreen,tol=0.1,mode='hsl')
    bones = filter_near(a,c,10)
    if len(bones) > 0:
        print('collecting white stuff...')
        for i in range(4):
            if i > 0:
                mainscreen = get_mainscreen()
                a = find_colors([185,149,147],mainscreen,tol=0.05,mode='hsl')
                c = find_colors([225,225,225],mainscreen,tol=0.1,mode='hsl')
                bones = filter_near(a,c,10)
            np.random.shuffle(bones)
            if len(bones) == 0:
                continue
            move_mouse(*(bones[0]+[msxs,msys]))
            time.sleep(0.2)
            uptext = get_uptext()
            orange = find_colors([230,140,60],uptext,mode='hsl',tol=0.2)
            print('bones:',len(orange))
            if len(orange) > 50:
                click_mouse(*(bones[0]+[msxs,msys]))
                flag_wait(init=1.0,post=0.5)
            
    if count_inv() > 25: #time to bury
        print('dropping chicken...')
        while True:
            inventory = get_inventory()
            drop = find_best_bitmap(raw_chicken,inventory,tol=0.2)
            if len(drop) > 0:
                np.random.shuffle(drop)
                click_mouse(*(drop[0]+[ivxs,ivys]),left=False)
                time.sleep(0.2)
                client = get_client()
                found = find_bitmap(drop_txt,client,tol=0.02)
                if len(found) > 0:
                    click_mouse(*(found[0]+[10,5]))
                else:
                    move_mouse(*(drop[0]+[ivxs,ivys-10]))
                time.sleep(0.5)
            else:
                break
        print('burying bones...')
        while True:
            inventory = get_inventory()
            bury = find_best_bitmap(bones_inv,inventory,tol=0.2)
            if len(bury) > 0:
                np.random.shuffle(bury)
                click_mouse(*(bury[0]+[ivxs,ivys]))
                time.sleep(0.1)
            else:
                break
                
    mainscreen = get_mainscreen()
    a = find_colors([135,27,14],mainscreen,tol=0.1,mode='hsl') #beak
    a,counts = cluster(a)
    valid = counts<20
    if np.count_nonzero(valid) == 0:
        print('no chickens!')
        time.sleep(0.5)
        continue
    a = np.concatenate(a[valid])
    b = np.concatenate([find_colors(c,mainscreen,tol=(0.05,0.05,0.05),mode='hsl') for c in [[118,91,55],[183,167,124]]])
    veto = find_colors([88,104,133],mainscreen,tol=0.1,mode='hsl') #water
    if len(a) == 0 or len(b) == 0:
        continue
    chickens = filter_near(b,a,20)
    if len(veto) > 0:
        chickens = filter_far(chickens,veto,10)
        
    if len(chickens) > 0:
        np.random.shuffle(chickens)
        #dist = np.sqrt(np.sum(np.square(cows-[msw/2,msh/2]),axis=1))
        #dist += 50*(2.0*np.random.random(dist.shape)-1.0)
        #sorter = np.argsort(dist)
        
        move_mouse(*(chickens[0]+[msxs,msys]))
        time.sleep(0.1)
        uptext = get_uptext()
        greentxt = find_colors([0,225,0],uptext,tol=0.05,mode='hsl')
        if len(greentxt) > 10:
            total_chickens += 1
            print('Attacking chicken %i'%total_chickens)
            click_mouse(*(chickens[0]+[msxs,msys]))
            flag_wait(init=1.0,post=1.0)
            continue
In [ ]:
#Cow killer + bone burrier

bones_inv = np.asarray(Image.open('bones_inv.png'))

target()
total_cows = 0
logins = 0
while True:
    client = get_client()
    if len(find_bitmap(loginscreen,client)) > 0:
        logins = logins + 1
        if logins > 10:
            raise RuntimeError('Too many logins! Bailing out before we get fishy!')
        login()
        continue
            
    mainscreen = get_mainscreen()
    hp_r = find_colors([255,0,0],mainscreen,tol=0.01,mode='hsl') - [msxc-msxs,msyc-msys]
    hp_g = find_colors([0,255,0],mainscreen,tol=0.01,mode='hsl') - [msxc-msxs,msyc-msys]
    
    if len(filter_radius(np.concatenate([hp_r]),[0,0],100)) > 10: #in combat
        time.sleep(1.0)
        continue
        
    mainscreen = get_mainscreen()
    a = find_colors([158,33,17],mainscreen,tol=0.05,mode='hsl')
    c = find_colors([225,225,225],mainscreen,tol=0.1,mode='hsl')
    bones = filter_near(a,c,10)
    if len(bones) > 0:
        print('collecting bones...')
        np.random.shuffle(bones)
        move_mouse(*(bones[0]+[msxs,msys]))
        time.sleep(0.5)
        uptext = get_uptext()
        orange = find_colors([225,128,50],uptext,mode='hsl',tol=(0.03,0.2,0.1))
        print('bones:',len(orange))
        if len(orange) > 50:
            click_mouse(*(bones[0]+[msxs,msys]))
            flag_wait()
            
    if count_inv() > 25: #time to bury
        print('burying bones...')
        while True:
            inventory = get_inventory()
            bury = find_best_bitmap(bones_inv,inventory,tol=0.2)
            if len(bury) > 0:
                np.random.shuffle(bury)
                click_mouse(*(bury[0]+[ivxs,ivys]))
                time.sleep(1.0)
            else:
                break
    
    mainscreen = get_mainscreen()
    a = find_colors([88,70,59],mainscreen,tol=0.08,mode='hsl')
    b = find_colors([33,29,13],mainscreen,tol=0.08,mode='hsl')
    c = find_colors([200,200,200],mainscreen,tol=0.2,mode='hsl')
    a = filter_near(a,c,50)
    b = filter_near(b,c,50)
    if len(a) == 0 and len(b) == 0:
        continue
    elif len(a) == 0:
        cows = b
    elif len(b) == 0:
        cows = a
    else:
        cows = np.concatenate([a,b])
        
    if len(cows) > 0:
        cows = cows[cows[:,0]<msw-1]#filter off edge...
        np.random.shuffle(cows)
        #dist = np.sqrt(np.sum(np.square(cows-[msw/2,msh/2]),axis=1))
        #dist += 50*(2.0*np.random.random(dist.shape)-1.0)
        #sorter = np.argsort(dist)
        
        move_mouse(*(cows[0]+[msxs,msys]))
        time.sleep(0.1)
        uptext = get_uptext()
        greentxt = find_colors([0,225,0],uptext,tol=0.05,mode='hsl')
        if len(greentxt) > 10:
            total_cows += 1
            print('Attacking cow %i'%total_cows)
            click_mouse(*(cows[0]+[msxs,msys]))
            time.sleep(5.0)
            continue
In [ ]:
#Smither for varock west anvils

mm_floor = [94,87,54]
mm_ew_road = [124,122,115]
mm_s_road = [131,123,89]

final = np.asarray(Image.open('iron_plate.png'))
raw_req = 5

#final = np.asarray(Image.open('iron_arrowheads.png'))[...,:3]
#raw_req = 1

#final = np.asarray(Image.open('iron_bolts.png'))[...,:3]
#raw_req = 1

raw = np.asarray(Image.open('iron_bar.png'))
bmp_tol = 0.3

target()
total_trips = 0
logins = 0
last_smith = time.monotonic()
while True:
    client = get_client()
    if len(find_bitmap(loginscreen,client)) > 0:
        logins = logins + 1
        if logins > 10:
            raise RuntimeError('Too many logins! Bailing out before we get fishy!')
        login()
        continue
    if time.monotonic() - last_smith > 10*60:
        raise RuntimeError('Sorry folks, got lost somehow and now we\'re done.')
    minimap = get_minimap()
    masked = np.full_like(minimap,0)
    masked[minimap_mask] = minimap[minimap_mask]
    minimap = masked
    inv_full = count_inv() == 28
    a = find_colors(mm_ew_road,minimap,tol=(0.02,0.03,0.03),mode='hsl') #mm_ew_road
    b = find_colors(mm_s_road,minimap,tol=(0.02,0.03,0.03),mode='hsl') #mm_s_road
    c = find_colors(mm_floor,minimap,tol=(0.02,0.03,0.03),mode='hsl') #mm_floor

    anvil_bldg = filter_near(filter_near(c,a,10),b,10)
    bankers = filter_far(filter_near(find_colors([255,255,0],minimap,tol=0.05,mode='hsl'),c,2),b,30)
    
    inventory = get_inventory()
    raw_points = find_best_bitmap(raw,inventory,tol=bmp_tol)
    
    if inv_full or len(raw_points) > 1.5*raw_req: #go smith
        if len(anvil_bldg) == 0:
            print('can\'t find anvil building!')
            continue
        np.random.shuffle(anvil_bldg)
        click_mouse(*(anvil_bldg[0]+[mmxs+5,mmys+5]))
        flag_wait()
        if len(raw_points):
            np.random.shuffle(raw_points)
            click_mouse(*(raw_points[0]+[ivxs,ivys]))
            mainscreen = get_mainscreen()
            a = find_colors([50,50,50],mainscreen,tol=0.05,mode='hsl')
            b = find_colors([100,100,100],mainscreen,tol=0.05,mode='hsl')
            points = filter_near(b,a,10)
            np.random.shuffle(points)
            for point in points[-5:]:
                move_mouse(*(point+[msxs,msys]))
                time.sleep(0.5)
                uptext,mask = uptext_mask(get_uptext())
                txt = image_to_string(mask)
                print(txt)
                if 'flmnl' in txt or 'nml' in txt or 'nwl' in txt or 'nyml' in txt:
                    click_mouse(*(point+[msxs,msys]))
                    flag_wait()
                    mainscreen = get_mainscreen()
                    smith_pos = find_best_bitmap(final,mainscreen,tol=0.27)
                    if len(smith_pos) ==0:
                        break
                    np.random.shuffle(smith_pos)
                    click_mouse(*(smith_pos[0]+[msxs,msys]),left=False)
                    time.sleep(2.0)
                    print('make 10')
                    click_mouse(*(smith_pos[0]+[msxs,msys+58]))
                    last_smith = time.monotonic()
                    polish_minimap(click=False)
                    raw_num = len(raw_points)
                    i = 0
                    while True:
                        i = i+1
                        inventory = get_inventory()
                        new_raw_num = len(find_best_bitmap(raw,inventory,tol=bmp_tol))
                        print('remaining:',new_raw_num)
                        if new_raw_num != raw_num:
                            raw_num = new_raw_num
                            i = 0
                        if i > 5:
                            break
                        if new_raw_num < raw_req:
                            break
                        time.sleep(0.5)
                    break
        else:
            print('no raw material found!')
    else: #go bank
        #open bank    
        mainscreen = get_mainscreen()
        if len(find_bitmap(bank_window,mainscreen,tol=0.02)) == 0:
            print('going to bank')
            if len(bankers) == 0:
                continue
            np.random.shuffle(bankers)
            click_mouse(*(bankers[0]+[mmxs,mmys]))
            flag_wait()
            
            mainscreen = get_mainscreen()
            a = find_colors([60,60,60],mainscreen,tol=0.05,mode='hsl')
            b = find_colors([55,45,87],mainscreen,tol=0.05,mode='hsl')
            points = filter_near(a,b,50) 
            print(len(a),len(b),len(points))
            np.random.shuffle(points)
            for point in points[-5:]:
                click_mouse(*point,left=False)
                time.sleep(0.5)
                use = find_bitmap(use_booth,get_mainscreen())
                if len(use) > 0:
                    click_mouse(*(use[0]+[10,10]))
                    time.sleep(1.0)
                    flag_wait()
                    print('bank opened')
                    time.sleep(1.0)
                    break
                move_mouse(*(point+[0,-25]))
            continue
        else:
            inventory = get_inventory()
            final_points = find_best_bitmap(final,inventory,tol=bmp_tol)
            if len(final_points):
                print('depositing product')
                np.random.shuffle(final_points)
                click_mouse(*final_points[0]+[ivxs,ivys],left=False)
                time.sleep(0.5)
                client = get_client()
                found = find_bitmap(store_all,client)
                if len(found):
                    click_mouse(*found[0]+[10,10])
                    time.sleep(1.0)
                    continue
            mainscreen = get_mainscreen()        
            raw_points = find_best_bitmap(raw,mainscreen,tol=bmp_tol)
            if len(raw_points):
                print('withdrawing raw')
                np.random.shuffle(raw_points)
                click_mouse(*(raw_points[0]+[msxs,msys]),left=False)
                time.sleep(1.0)
                click_mouse(*(raw_points[0]+[msxs,msys]+[0,87]))
                time.sleep(1.0)
                send_keys('28\n')
                time.sleep(1.0)
In [ ]:
west_of_wall()
In [ ]:
#Mining script requires agility shortcut Falador west

#rocks = [(1,copper_color,0.025,[223,129,59]),(1,tin_color,0.025,[139,130,129])] #copper&tin
rocks = [(1,iron_color,0.015,[78,48,36])] #iron
mm_rocks = [159,103,59]#[127,77,42]

mm_rock_tol = (0.07,0.08,0.06)
mm_east_tol = (0.07,0.08,0.08)
mm_west_tol = (0.07,0.1,0.08)

mine_icon = np.asarray(Image.open('mine_icon.png'))[...,:3]
agility_icon = np.asarray(Image.open('agility_icon.png'))[...,:3]

def mine(rocks=rocks):
    '''mines the next rock based on weights in rocks structure
       finds rock based on color of ore plus proximity to generic rock color
       confirms uptext hovering over rock before mining
       waits for rock to appear in inventory before proceeding'''
    counts = count_rocks(rocks=rocks)
    print('Weighted totals:',counts)
    minidx = np.argmin(counts)
    weight,color,tol,bmp = rocks[minidx]
    mainscreen = get_mainscreen()
    found = find_colors(color,mainscreen,tol=tol,mode='hsl')
    b = find_colors(np.asarray([107,88,28]),mainscreen,tol=0.02)
    found = filter_near(found,b,10)
    if len(found) == 0:
        return False
    point = closest([msw/2,msh/2-20],found)
    move_mouse(*(point+[msxs,msys]))
    time.sleep(0.2)
    uptext,mask = uptext_mask(get_uptext(width=80))
    txt = image_to_string(mask)
    if 'Ru(k' in txt:
        click_mouse(*(point+[msxs,msys]))
    else:
        return False
    for i in range(100):
        time.sleep(0.05)
        if np.any(count_rocks(rocks=rocks) != counts):
            time.sleep(0.2)
            return True
    return False

def west_of_wall():
    '''returns true if character is closer to west road or mine colors than east road or mine colors'''
    minimap = get_minimap()
    if len(find_best_bitmap(mine_icon,minimap,0.05)) > 0:
        print('at mine')
        return True
    west = find_colors(west_road,minimap,tol=mm_west_tol,mode='hsl')
    clusters,counts = cluster(west,radius=2)
    if len(counts) > 0 and np.max(counts) > 100:
        west = np.concatenate(clusters[counts > 25])
    else:
        west = []
    npc_points = find_colors([255,255,0],minimap,tol=0.05,mode='hsl')
    bank_points = np.concatenate([find_colors(bank_floor,minimap,tol=0.085,mode='hsl') for bank_floor in bank_floor_colors])
    clusters,counts = cluster(bank_points)
    if len(counts) < 1 or np.count_nonzero(counts>20) < 1:
        bank_points = np.asarray([])
    else:
        bank_points = clusters[np.random.choice(np.nonzero(counts>20)[0])]
    bank_points = filter_near(bank_points,npc_points,6)
    if len(bank_points) < 10:
        rocks = find_colors(mm_rocks,minimap,tol=mm_rock_tol,mode='hsl')
        if len(west) > 0:
            west = np.concatenate([rocks,west])
        else:
            west = rocks
    east = find_colors(east_road,minimap,tol=mm_east_tol,mode='hsl')
    clusters,counts = cluster(east,radius=2)
    if len(counts) > 0 and np.max(counts) > 100:
        east = np.concatenate(clusters[counts > 10])
    else:
        east = []
    print('Locating... E:',len(east),'W:',len(west),'B',len(bank_points))
    west_best = 9001 if len(west) == 0 else np.min(np.sum(np.square(west-[mmxc-mmxs,mmyc-mmys]),axis=-1))
    east_best = 9001 if len(east) == 0 else np.min(np.sum(np.square(east-[mmxc-mmxs,mmyc-mmys]),axis=-1))
    if west_best <= east_best:
        print('west of wall')
        return True
    else:
        print('east of wall')
        return False
            
            
def jump_wall():
    '''The Donald can't stop us!
       tries to get as close as possible to boundary between east and west road colors on minimap
       looks for proximity of wall color, east, and west road colors on mainscreen
       attempts to confirm uptext hovering over possible wall locations
       returns true if successfully jumped'''
    minimap = get_minimap()
    east = find_colors(east_road,minimap,tol=mm_east_tol,mode='hsl')
    west = find_colors(west_road,minimap,tol=mm_west_tol,mode='hsl')
    print('Road points... E:',len(east),'W:',len(west))
    if len(west) == 0 or len(east) == 0:
        return False
    border = filter_near(east,west,3)
    print('Boundary:',len(border))
    if len(border) <= 3: #try the agility icon
        agility = find_best_bitmap(agility_icon,minimap,tol=0.05)
    else:
        agility = None
    np.random.shuffle(border)
    if len(border) > 3 or len(agility) > 0:
        border = border[0] if len(border) > 3 else (agility[np.random.randint(len(agility))]+[5,5])
        click_mouse(*(border+[mmxs,mmys]))
        flag_wait()
        mainscreen = get_mainscreen()
        wall_points = find_colors(wall_color,mainscreen,tol=0.07,mode='hsl')
        inner_wall_points = find_colors(inner_wall_color,mainscreen,tol=0.07,mode='hsl')
        outer_wall_points = find_colors([73,64,41],mainscreen,tol=0.07,mode='hsl')
        wall_points = filter_near(filter_near(wall_points,inner_wall_points,10),outer_wall_points,10)
        np.random.shuffle(wall_points)
        for point in wall_points[-5:]:
            move_mouse(*(point+[msxs,msys]))
            time.sleep(0.2)
            uptext,mask = uptext_mask(get_uptext(width=80))
            txt = image_to_string(mask)
            print(txt)
            if 'Clumb' in txt or 'timb' in txt:
                click_mouse(*(point+[msxs,msys]))
                time.sleep(5.0)
                return True
    return False

target()
miss = 0
total_trips = 0
last_mine = time.monotonic()
while True:
    client = get_client()
    if len(find_bitmap(loginscreen,client)) > 0:
        login()
        continue
    if time.monotonic()-last_mine > 10*60:
        raise RuntimeError('Haven\'t mined in 10 minutes, giving up because something ain\'t right.')
    inv_full = count_inv() == 28
    print('Total items:',count_inv())
    if inv_full:
        if west_of_wall():
            if not jump_wall():
                minimap = get_minimap()
                west = filter_radius(find_colors(west_road,minimap,tol=mm_west_tol,mode='hsl'),[mmxc-mmxs,mmyc-mmys],70)
                print('Moving east:',len(west))
                if len(west):
                    click_mouse(*(west[np.argsort(west[:,0])[-1]]+(mmxs,mmys)))
                    time.sleep(2.0)
            else:
                print('Crossed wall west->east')
        else: 
            if open_bank():
                deposit_all()
                total_trips = total_trips + 1
                clear_output()
                if np.random.random() < 0.5:
                    polish_minimap(min_same=35,horizontal=False)
                print('Completed %i inventories'%total_trips)
                continue
    else:
        if west_of_wall():
            if not mine(rocks):
                print('No rock found!')
                miss = miss + 1
                if miss < 5:
                    time.sleep(0.5)
                    continue
                print('Trying new position...')
                minimap = get_minimap()
                mine_loc = find_colors(mm_rocks,minimap,tol=mm_rock_tol,mode='hsl')
                mine_loc = filter_radius(mine_loc,[mmxc-mmxs,mmyc-mmys],50)
                if len(mine_loc):
                    np.random.shuffle(mine_loc)
                    click_mouse(*(mine_loc[-1]+(mmxs,mmys)))
                    flag_wait()
                    continue
                west = find_colors(west_road,minimap,tol=mm_west_tol,mode='hsl')
                west = filter_radius(west,[mmxc-mmxs,mmyc-mmys],70)
                print('Moving west:',len(west))
                if len(west):
                    click_mouse(*(west[np.argsort(west[:,0])[0]]+(mmxs,mmys)))
                    time.sleep(2.0)
                else:
                    print('Got lost going to mine!')
            else:
                last_mine = time.monotonic()
                miss = 0
        else: 
            if not jump_wall():
                minimap = get_minimap()
                east = filter_radius(find_colors(east_road,minimap,tol=mm_east_tol,mode='hsl'),[mmxc-mmxs,mmyc-mmys],70)
                print('Moving west:',len(east))
                if len(east):
                    click_mouse(*(east[np.argsort(east[:,0]-east[:,1])[0]]+(mmxs,mmys)))
                    time.sleep(2.0)
                else:
                    print('Got lost going to wall!')
            else:
                miss = 9999 #to move west immediately
                run_on()
                print('Crossed wall east->west')
In [ ]:
#Gold miner for Rimmington (falador shortcut south)

rimm_rock_color = [141,96,17]

mm_rock = [105,90,98]
mm_mine_colors = [[135,109,13]]

falador_wall = [189,175,152]
agility_color = [18,155,62]
tunnel_color = [60,9,0]
rimm_road = [117,109,108]

road_tol = 0.10


def to_mine(rr,minmap):
    mainscreen = get_mainscreen()
    i = find_colors(iron_color,mainscreen,mode='hsl',tol=0.05)
    g = find_colors(gold_color,mainscreen,mode='hsl',tol=0.07)
    r = find_colors(rimm_rock_color,mainscreen,mode='hsl',tol=0.05)
    i = filter_near(i,r,5)
    g = filter_near(g,r,5)
    found = g if len(g) else i
    if len(found) and (len(g) > 0 or np.random.random() < 0.75): #occasionally move to find gold
        point = closest([msw/2,msh/2-20],found)
        move_mouse(*(point+[msxs,msys]))
        time.sleep(0.2)
        uptext,mask = uptext_mask(get_uptext(width=80))
        txt = image_to_string(mask)
        if 'Ru(k' in txt:
            inv = count_inv()
            click_mouse(*(point+[msxs,msys]))
            for i in range(100 if len(g) == 0 else 1000):
                time.sleep(0.05)
                if np.any(count_inv() != inv):
                    time.sleep(1.0)
                    return True
    minimap = get_minimap()
    a = find_colors(mm_rock,minimap,tol=0.04,mode='hsl')
    c = np.concatenate([find_colors(mm_mine,minimap,tol=0.1,mode='hsl') for mm_mine in mm_mine_colors])
    locations = filter_near(a,c,10)
    print('rocks:',len(a),'mine:',len(c),'loc:',len(locations))
    locations = filter_far(locations,[mmxc-mmxs,mmyc-mmys],15)
    if len(locations) > 2:
        np.random.shuffle(locations)
        click_mouse(*(locations[0]+[mmxs,mmys]))
        flag_wait()
    else:
        order = np.argsort(-2*rr[:,1]-rr[:,0]) #sort by -2*y-x (sse-most)
        walkto = rr[order[0]]
        click_mouse(*(walkto+[mmxc,mmyc]))
        flag_wait()

target()
total_trips = 0
logins = 0
while True:
    client = get_client()
    if len(find_bitmap(loginscreen,client)) > 0:
        logins = logins + 1
        if logins > 10:
            raise RuntimeError('Too many logins! Bailing out before we get fishy!')
        login()
        continue
    minimap = get_minimap()
    masked = np.full_like(minimap,0)
    masked[minimap_mask] = minimap[minimap_mask]
    minimap = masked
    inv_full = count_inv() == 28
    rr = find_colors(rimm_road,minimap,tol=road_tol,mode='hsl') - [mmxc-mmxs,mmyc-mmys]
    fw = find_colors(falador_wall,minimap,tol=0.15,mode='hsl') - [mmxc-mmxs,mmyc-mmys]
    bank = np.concatenate([ind_colors(bank_floor,minimap,tol=0.08,mode='hsl') for bank_floor in bank_floor_colors])
    if len(bank) < 20:
        agility = find_colors(agility_color,minimap,tol=0.1,mode='hsl') - [mmxc-mmxs,mmyc-mmys]
    else:
        agility = []
    print('Locating...','R:',len(rr),'F:',len(fw),'B:',len(bank),'A:',len(agility))
    if len(fw) > 250: # inside falador either traveling or banking
        north_of_wall = None
        if len(agility) > 5 and len(filter_radius(agility,[0,0],30)) > 5: #close to hole
            near_wall = filter_radius(fw,[0,0],15)
            print('near wall',len(near_wall))
            if len(near_wall) > 5:
                north_of_wall = np.mean(near_wall[:,1]) > 0 #mean of y position of wall within 30 px of character
        if north_of_wall is None:
            sw_wall_count = np.count_nonzero(np.logical_and(fw[:,0] < 0,fw[:,1] > 0))
            print('sw wall',sw_wall_count)
            north_of_wall = sw_wall_count > 15 #more than 20 wall px in s or w 
        print('north' if north_of_wall else 'south','of wall')
        if len(agility) > 5 and (north_of_wall ^ inv_full): #if we haven't gone under wall yet
            order = np.argsort(-2*fw[:,1]+fw[:,0]) #sort by -2*y+x (ssw-most)
            walkto = fw[order[0]]+[20,0]
            click_mouse(*(walkto+[mmxc,mmyc]))
            flag_wait()
            mainscreen = get_mainscreen()
            tunnel = find_colors(tunnel_color,mainscreen,mode='hsl',tol=0.08)
            if len(tunnel)>20:
                np.random.shuffle(tunnel)
                click = tunnel[0]
                if north_of_wall:
                    click = tunnel[0]-[0,75]
                click_mouse(*(click+[msxs,msys]))
                time.sleep(10.0)
                if north_of_wall:
                    run_on()
                continue
        if inv_full: #definitely going north
            if open_bank(): #try to go to and open bank
                deposit_all()
                total_trips = total_trips + 1
                print('Completed %i inventories'%total_trips)
                continue    
            npc_points = find_colors([255,255,0],minimap,tol=0.05,mode='hsl')
            bank_points = filter_near(npc_points,bank,6)
            if len(bank_points) < 100:
                if north_of_wall: #otherwise if inside falador go north
                    order = np.argsort(2*fw[:,1]+fw[:,0]) #sort by -2*y+x (nnw-most)
                    walkto = fw[order[0]]+[20,0]
                    click_mouse(*(walkto+[mmxc,mmyc]))
                    flag_wait()
                else: #gotta get to hole
                    order = np.argsort(-2*fw[:,1]+fw[:,0]) #sort by -2*y+x (ssw-most)
                    walkto = fw[order[0]]+[20,0]
                    click_mouse(*(walkto+[mmxc,mmyc]))
                    flag_wait()
            else:
                print('must have missed bank...')
        elif north_of_wall: # inside falador, north of wall, and inv empty: go south
            order = np.argsort(-2*fw[:,1]+fw[:,0]) #sort by -2*y+x (ssw-most)
            walkto = fw[order[0]]+[20,0]
            click_mouse(*(walkto+[mmxc,mmyc]))
            flag_wait()
        else: #gotta get to mine
            to_mine(rr,minimap)
    elif inv_full: # full inventory travelin to bank
        if len(agility) > 5:
            np.random.shuffle(agility)
            walkto = agility[0]
        elif len(rr) > 0:
            order = np.argsort(4*rr[:,1]+rr[:,0]) #sort by 2*y+x (nnw-most)
            walkto = rr[order[0]]
        else:
            walkto = np.asarray([-20,-40])
        click_mouse(*(walkto+[mmxc,mmyc]))
        flag_wait()
    else: #mining or traveling to mine
        to_mine(rr,minimap)
    
In [ ]:
#Smelting script banks Falador west and uses Falador furnace

#for gold
#bar = np.asarray(Image.open('gold_bar.png'))[:,:,:3]
#ore = np.asarray(Image.open('gold_ore.png'))[:,:,:3]
#inputs = [(1,ore)]
#bar_pos = np.asarray([310,405])

#for iron
bar = np.asarray(Image.open('iron_bar.png'))[:,:,:3]
ore = np.asarray(Image.open('iron_ore.png'))[:,:,:3]
inputs = [(1,ore)]
bar_pos = np.asarray([160,405])

#for bronze - update to bitmaps
#rocks = [(1,[94,80],0.025,[223,129,59]),(1,[143,80],0.025,[139,130,129])] #num_per_bar,bank_coords,tolerance,item_color
#bar_pos = np.asarray([50,405]) #position of bar on furnace menu 

def count_inputs():
    inventory = get_inventory()
    return np.asarray([len(find_best_bitmap(bmp,inventory,tol=0.02))//unit for unit,bmp in inputs])
        
furnace_icon = np.asarray(Image.open('furnace_icon.png'))[:,:,:3]
def go_smelt():
    '''finds furnace icon on minimap and walks to it, then locates furnace by proximity of metal and fire colors
       if found, starts smelting and waits until out of rocks or timed out'''
    minimap = get_minimap()
    icon = find_best_bitmap(furnace_icon,minimap,tol=0.04)#find_colors(np.asarray([255,115,41]),minimap,tol=0.05,mode='hsl')
    icon = filter_radius(icon,[mmxc-mmxs,mmyc-mmys],70) 
    np.random.shuffle(icon)
    print('Furnace icon points:',len(icon))
    if len(icon) == 1:
        click_mouse(*(icon[0]+(mmxs+4,mmys)))
        flag_wait()    
        mainscreen = get_mainscreen()
        fire = find_colors([192,79,48],mainscreen,mode='hsl',tol=0.04)
        furnace = find_colors([192,79,48],mainscreen,mode='hsl',tol=0.04)
        furnace = filter_near(furnace,fire,10)
        np.random.shuffle(furnace)
        if len(furnace) > 0:
            print('Found furnace, starting smelting...')
            click_mouse(*(furnace[-1]+[msxs+20,msys]))
            time.sleep(5.0)
            click_mouse(*bar_pos,left=False)
            time.sleep(1.0)
            click_mouse(*(bar_pos+[0,70]))
            time.sleep(1.0)
            send_keys('99\n')
            time.sleep(1.0)
            inv = count_inputs()
            polish_minimap(min_same=35,horizontal=False,click=False)
            i = 0
            while True:
                time.sleep(0.5)
                i = i+1
                cur_inv = count_inputs()
                if np.any(cur_inv != inv):
                    inv = cur_inv
                    i = 0
                if np.sum(cur_inv) == 0:
                    print('Success, getting more materials!')
                    run_on()
                    return True
                if i > 10:
                    print('Timed out, trying again')
                    return True
        return True # didn't smelt but don't run away...
    return False
    

target()
done = False
total_trips = 0
last_smelt = time.monotonic()
while True:
    client = get_client()
    if len(find_bitmap(loginscreen,client)) > 0:
        login()
        continue
    if time.monotonic() - last_smelt > 10*60:
        raise RuntimeError('Been a loooong time since a smelt. Probably horribly lost. Maybe.')
        
    inv = count_inputs()
    if np.all(inv != 0): #ready to smelt
        done = False
        if go_smelt():
            last_smelt = time.monotonic()
        else:
            minimap = get_minimap()
            east = filter_radius(find_colors(east_road,minimap,tol=0.08),[mmxc-mmxs,mmyc-mmys],70)
            print('Moving east:',len(east))
            if len(east):
                click_mouse(*(east[np.argsort(-east[:,0]+np.abs(east[:,1]-mmxc+mmxs)*0.1)[0]]+(mmxs,mmys)))
                time.sleep(1.5)
            else:
                print('Lost looking for furnace!')
    else: #go to bank
        if done:
            break
        if open_bank():
            deposit_all()
            clear_output()
            total_trips = total_trips + 1
            print('Completed %i invetories'%total_trips)
            done = True
            time.sleep(0.5)
            mainscreen = get_mainscreen()
            batch = np.sum([unit for unit,_ in inputs])
            for unit,bmp in inputs:
                coords = find_best_bitmap(bmp,mainscreen,tol=0.2)
                print('raw found:',len(coords))
                np.random.shuffle(coords)
                if len(coords) > 0:
                    click_mouse(*(coords[0]+[msxs,msys]),left=False)
                    time.sleep(1.0)
                    click_mouse(*(coords[0]+[msxs,msys]+[0,87]))
                    time.sleep(1.0)
                    send_keys('%i\n'%(unit*(28//batch)))
                    time.sleep(1.0)
                else:
                    print('Out of supplies!')
        else:                
            minimap = get_minimap()
            east = filter_radius(find_colors(east_road,minimap,tol=0.08,mode='hsl'),[mmxc-mmxs,mmyc-mmys],70)
            print('Moving west:',len(east))
            if len(east):
                click_mouse(*(east[np.argsort(east[:,0]+np.abs(east[:,1]-mmxc+mmxs)*0.1)[0]]+(mmxs,mmys)))
                time.sleep(1.5)
            else:
                print('Lost looking for bank!')
In [ ]:
# Echos coords and colors under mouse
try:
    while True:
        time.sleep(1)
        target()
        x,y = pyautogui.position()
        print('%i,%i [%i,%i,%i]'%(x-x0,y-y0,*np.asarray(pyautogui.screenshot(region=[x,y,1,1]))[0,0]))
except KeyboardInterrupt:
    pass
In [ ]:
while True: #buy feathers
    click_mouse(380,79,left=False)
    time.sleep(0.2)
    click_mouse(386,154)
    time.sleep(0.1)
In [ ]:
while True: #make arrows
    click_mouse(580,228) #inv1
    time.sleep(0.5)
    click_mouse(625,236) #inv2
    time.sleep(0.5)
    click_mouse(250,420,left=False)
    time.sleep(0.5)
    click_mouse(237,480)
    time.sleep(10.0)
In [ ]:
while True: #make bolts
    click_mouse(580,228) #inv1
    time.sleep(0.2)
    click_mouse(625,236) #inv2
    time.sleep(0.1)
In [ ]:
target() #buy runes
topleft = np.asarray([95,85])
offset = np.asarray([144-95,0])
idx = np.asarray([0,0]) #rune to buy
for i in range(100):
    click_mouse(*(topleft+offset*idx),left=False)
    time.sleep(0.1)
    click_mouse(*((topleft+offset*idx)+[0,154-79]))
    time.sleep(0.05)
In [ ]: