├── offsets.json
├── doc_images
└── bot_img.png
├── readme.md
├── offset.py
├── .gitignore
├── Burrito-bot_OLD
├── README.md
└── bison.py
├── desktop_magic.py
└── bison.py
/offsets.json:
--------------------------------------------------------------------------------
1 | [588, 117]
--------------------------------------------------------------------------------
/doc_images/bot_img.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chriskiehl/Burrito-Bot/HEAD/doc_images/bot_img.png
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | ## Burrito Bot
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/offset.py:
--------------------------------------------------------------------------------
1 | import json
2 |
3 | def load_from_json():
4 | with open('offsets.json', 'rb') as f:
5 | return json.load(f)
6 |
7 | def save_to_json(offsets):
8 | with open('offsets.json', 'wb') as f:
9 | f.write(json.dumps(offsets))
10 |
11 | __offsets = load_from_json()
12 |
13 | x = __offsets[0]
14 | y = __offsets[1]
15 |
16 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.py[cod]
2 |
3 | # C extensions
4 | *.so
5 |
6 | # Packages
7 | *.egg
8 | *.egg-info
9 | dist
10 | build
11 | eggs
12 | parts
13 | bin
14 | var
15 | sdist
16 | develop-eggs
17 | .installed.cfg
18 | lib
19 | lib64
20 | __pycache__
21 |
22 | # Installer logs
23 | pip-log.txt
24 |
25 | # Unit test / coverage reports
26 | .coverage
27 | .tox
28 | nosetests.xml
29 |
30 | # Translations
31 | *.mo
--------------------------------------------------------------------------------
/Burrito-bot_OLD/README.md:
--------------------------------------------------------------------------------
1 | # Burrito Bison bot
2 |
3 | *Edit (05-19-13): This is years old. Keeping it for time capsule purposes..*
4 |
5 | Below are some of the thoughts and failed ideas that I went through while wrtting this thing. All the problems I faced
6 | are most likely really simple and will likely seem trival as I learn more, but I leave them here for those who, like me,
7 | are just starting out.
8 |
9 | Simple little script to 'play' Burrito Bison (found here: http://notdoppler.com/burritobison.php). The code is pretty
10 | weak, this was written just to learn python a little more, and these 'launch' games all seemed mindless enough that
11 | I could easily get a bot to control them.. (it ended up being trickier than I expected)
12 |
13 | The code is pretty crappy, and there are tons of things I'd do differently, and, in fact, if you look at the code you'll
14 | notice that calls start changing little by little and becoming more concise. Which was really the point of this, to
15 | get a little better at constructing a program. So the things I don't like about how it's written now, didn't occur to
16 | me as possible issues when I first started coding, but little by little, better ways of approaching a problem became
17 | clear.
18 |
19 | It's now completely workable, and will play the game from start to finish. There's only one menu that it doesn't catch,
20 | I noticed it when I was recording the final start-to-finish playthrough, but I was too lazy to fix it.
21 |
22 | The bot works by gathering in about the game by taking screen shots and then checking specific pixel locations.
23 | It's a very fragil way to do things, as any difference in browser size ruins the expected pixel values.
24 |
25 | I tried all kinds of things to get around this problem. Being that all important events are different colors from the
26 | main stage and gummies (like the cop for instance), I tried all kinds of funniness with averaging the colors of a
27 | snapshot, assuming that when a new color appeared on screen the average color disrtibution would change. I still think
28 | it's a neat idea for flexibly checking what's on screen, but in practice I couldn't get it to work due to speed issues
29 | (and probably poor code issues). Several variations of this idea were tried in an effort to reduce the number of
30 | calculations needed. A few attempts were made at grayscalling the image first and then getting the colors, others
31 | included taking a full snapshot of the playarea, thumbnailing it to something like 25x25, and then averaging the colors
32 | that way.
33 |
34 | Of all the things I tried (revalting to the getcolors idea) this proved the most reliable way
35 | of noticing when a cop was on screen. Reliable in my case being about (maybe)10% success rate. Even the current
36 | iteration is quite poor, altough, when the bison is moving at slower speeds I'd say it's around a 40% success rate.
37 | Which I was happy enough with to move on. There tons of things with the current implementation that could raise this
38 | number quite a bit (I think). Such as multiprocessing some of the search events so there's not so much time inbetween
39 | calls, turning off all of the other search features that aren't needed anymore (like dialog boxes) would free up a ton
40 | of processing room. They're the old version that takes a unique screen shot instead of 'sharing' one between all
41 | functions.
42 |
43 |
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/desktop_magic.py:
--------------------------------------------------------------------------------
1 | """
2 | Robust functions for grabbing and saving screenshots on Windows.
3 | """
4 |
5 | # TODO: support capture of individual displays (and at the same time with a "single screenshot")
6 | # Use GetDeviceCaps; see http://msdn.microsoft.com/en-us/library/dd144877%28v=vs.85%29.aspx
7 |
8 | import ctypes
9 | import win32gui
10 | import win32ui
11 | import win32con
12 | import win32api
13 |
14 |
15 | class BITMAPINFOHEADER(ctypes.Structure):
16 | _fields_ = [
17 | ('biSize', ctypes.c_uint32),
18 | ('biWidth', ctypes.c_int),
19 | ('biHeight', ctypes.c_int),
20 | ('biPlanes', ctypes.c_short),
21 | ('biBitCount', ctypes.c_short),
22 | ('biCompression', ctypes.c_uint32),
23 | ('biSizeImage', ctypes.c_uint32),
24 | ('biXPelsPerMeter', ctypes.c_long),
25 | ('biYPelsPerMeter', ctypes.c_long),
26 | ('biClrUsed', ctypes.c_uint32),
27 | ('biClrImportant', ctypes.c_uint32)
28 | ]
29 |
30 |
31 |
32 | class BITMAPINFO(ctypes.Structure):
33 | _fields_ = [
34 | ('bmiHeader', BITMAPINFOHEADER),
35 | ('bmiColors', ctypes.c_ulong * 3)
36 | ]
37 |
38 | class GrabFailed(Exception):
39 | """
40 | Could not take a screenshot.
41 | """
42 |
43 | class MonitorSelectionOutOfBounds(Exception):
44 | '''
45 | Argument out of bounds
46 | '''
47 |
48 | class BoundingBoxOutOfRange(Exception):
49 | '''
50 | Coordinates are too large for the current resolution
51 | '''
52 |
53 |
54 | class DIBFailed(Exception):
55 | pass
56 |
57 |
58 |
59 | def _deleteDCAndBitMap(dc, bitmap):
60 | dc.DeleteDC()
61 | win32gui.DeleteObject(bitmap.GetHandle())
62 |
63 | def getMonitorCoordinates(targetMonitor):
64 | '''
65 | Enumerates the available monitor. Return the
66 | Screen Dimensions of the selected monitor.
67 | '''
68 | HMONITOR = 0
69 | HDCMONITOR = 1
70 | SCREENRECT = 2
71 |
72 | try:
73 | monitors = win32api.EnumDisplayMonitors(None, None)
74 |
75 | if targetMonitor > len(monitors)-1:
76 | raise MonitorSelectionOutOfBounds("Monitor argument exceeds attached number of devices.\n"
77 | "There are only %d display devices attached.\n" % len(monitors) +
78 | "Please select appropriate device ( 0=Primary, 1=Secondary, etc..)." )
79 |
80 | left,top,right,bottom = monitors[targetMonitor][SCREENRECT]
81 | width = right - left
82 | height = bottom
83 |
84 | finally:
85 | # I can't figure out what to do with the handle to the Monitor
86 | # that gets returned from EnumDisplayMonitors (the first object in
87 | # the tuple). Trying to close it throws an error.. Does it not need
88 | # cleaned up at all? Most of the winApi is back magic to me...
89 |
90 | # These device context handles were the only things that I could Close()
91 | for monitor in monitors:
92 | monitor[HDCMONITOR].Close()
93 |
94 | return (left, top, width, height)
95 |
96 | def getSecondaryMonitorCoordinates():
97 | '''
98 | Enumerates the available monitors. Return the
99 | Screen Dimensions of the secondary monitor.
100 | '''
101 | HMONITOR = 0
102 | HDCMONITOR = 1
103 | SCREENRECT = 2
104 |
105 | try:
106 | monitors = win32api.EnumDisplayMonitors(None, None)
107 |
108 | # if targetMonitor > len(monitors)-1:
109 | # raise MonitorSelectionOutOfBounds("Monitor argument exceeds attached number of devices.\n"
110 | # "There are only %d display devices attached.\n" % len(monitors) +
111 | # "Please select appropriate device ( 0=Primary, 1=Secondary, etc..)." )
112 |
113 | left,top,right,bottom = monitors[-1][SCREENRECT]
114 | width = right - left
115 | height = bottom
116 |
117 | finally:
118 | # I can't figure out what to do with the handle to the Monitor
119 | # that gets returned from EnumDisplayMonitors (the first object in
120 | # the tuple). Trying to close it throws an error.. Does it not need
121 | # cleaned up at all? Most of the winApi is back magic to me...
122 |
123 | # These device context handles were the only things that I could Close()
124 | for monitor in monitors:
125 | monitor[HDCMONITOR].Close()
126 |
127 | return (left, top, width, height)
128 |
129 |
130 | def getDCAndBitMap(saveBmpFilename=None, bbox=None):
131 | """
132 | Returns a (DC, PyCBitmap). On the returned PyCBitmap, you *must* call
133 | win32gui.DeleteObject(aPyCBitmap.GetHandle()). On the returned DC,
134 | you *must* call aDC.DeleteDC()
135 | """
136 | hwnd = win32gui.GetDesktopWindow()
137 | if bbox:
138 | left, top, width, height = bbox
139 | if (left < win32api.GetSystemMetrics(win32con.SM_XVIRTUALSCREEN) or
140 | top < win32api.GetSystemMetrics(win32con.SM_YVIRTUALSCREEN) or
141 | width > win32api.GetSystemMetrics(win32con.SM_CXVIRTUALSCREEN) or
142 | height > win32api.GetSystemMetrics(win32con.SM_CYVIRTUALSCREEN)):
143 | raise Exception('Invalid bounding box. Range exceeds available screen area.')
144 | width = width - left
145 | height = height - top
146 |
147 | else:
148 | # Get complete virtual screen, including all monitors.
149 | left = win32api.GetSystemMetrics(win32con.SM_XVIRTUALSCREEN)
150 | top = win32api.GetSystemMetrics(win32con.SM_YVIRTUALSCREEN)
151 | width = win32api.GetSystemMetrics(win32con.SM_CXVIRTUALSCREEN)
152 | height = win32api.GetSystemMetrics(win32con.SM_CYVIRTUALSCREEN)
153 | ##print "L", left, "T", top, "dim:", width, "x", height
154 |
155 | # Retrieve the device context (DC) for the entire window.
156 |
157 | hwndDevice = win32gui.GetWindowDC(hwnd)
158 | ##print "device", hwndDevice
159 | assert isinstance(hwndDevice, (int, long)), hwndDevice
160 |
161 | mfcDC = win32ui.CreateDCFromHandle(hwndDevice)
162 | try:
163 | saveDC = mfcDC.CreateCompatibleDC()
164 | saveBitMap = win32ui.CreateBitmap()
165 | # Above line is assumed to never raise an exception.
166 | try:
167 | saveBitMap.CreateCompatibleBitmap(mfcDC, width, height)
168 | saveDC.SelectObject(saveBitMap)
169 | try:
170 | saveDC.BitBlt((0, 0), (width, height), mfcDC, (left, top), win32con.SRCCOPY)
171 | except win32ui.error, e:
172 | raise GrabFailed("Error during BitBlt. "
173 | "Possible reasons: locked workstation, no display, "
174 | "or an active UAC elevation screen. Error was: " + str(e))
175 | if saveBmpFilename is not None:
176 | saveBitMap.SaveBitmapFile(saveDC, saveBmpFilename)
177 | except:
178 | _deleteDCAndBitMap(saveDC, saveBitMap)
179 | # Let's just hope the above line doesn't raise an exception
180 | # (or it will mask the previous exception)
181 | raise
182 | finally:
183 | mfcDC.DeleteDC()
184 |
185 | return saveDC, saveBitMap
186 |
187 |
188 | def getBGR32(dc, bitmap):
189 | """
190 | Returns a (raw BGR str, (width, height)) for C{dc}, C{bitmap}.
191 | Guaranteed to be 32-bit. Note that the origin of the returned image is
192 | in the bottom-left corner, and the image has 32-bit line padding.
193 | """
194 | bmpInfo = bitmap.GetInfo()
195 | width, height = bmpInfo['bmWidth'], bmpInfo['bmHeight']
196 |
197 | bmi = BITMAPINFO()
198 | ctypes.memset(ctypes.byref(bmi), 0x00, ctypes.sizeof(bmi))
199 | bmi.bmiHeader.biSize = ctypes.sizeof(BITMAPINFOHEADER)
200 | bmi.bmiHeader.biWidth = width
201 | bmi.bmiHeader.biHeight = height
202 | bmi.bmiHeader.biBitCount = 24
203 | bmi.bmiHeader.biPlanes = 1
204 |
205 | bufferLen = height * ((width * 3 + 3) & -4)
206 | pbBits = ctypes.create_string_buffer(bufferLen)
207 |
208 | ret = ctypes.windll.gdi32.GetDIBgetits(
209 | dc.GetHandleAttrib(),
210 | bitmap.GetHandle(),
211 | 0,
212 | height,
213 | ctypes.byref(pbBits),
214 | ctypes.pointer(bmi),
215 | win32con.DIB_RGB_COLORS)
216 | if ret == 0:
217 | raise DIBFailed("Return code 0 from GetDIBits")
218 |
219 | assert len(pbBits.raw) == bufferLen, len(pbBits.raw)
220 |
221 | return pbBits.raw, (width, height)
222 |
223 |
224 | def getScreenAsImage(bbox=None):
225 | """
226 | Returns a PIL Image object (mode RGB) of the current screen (incl.
227 | all monitors).
228 |
229 | bbox = boundingBox. Used to snap a subarea of the screen.
230 | A tuple of (x, y, width, height).
231 | """
232 | import Image
233 | dc, bitmap = getDCAndBitMap(bbox=bbox)
234 | try:
235 | bmpInfo = bitmap.GetInfo()
236 | # bmpInfo is something like {
237 | # 'bmType': 0, 'bmWidthBytes': 5120, 'bmHeight': 1024,
238 | # 'bmBitsPixel': 32, 'bmPlanes': 1, 'bmWidth': 1280}
239 | ##print bmpInfo
240 | size = (bmpInfo['bmWidth'], bmpInfo['bmHeight'])
241 |
242 | if bmpInfo['bmBitsPixel'] == 32:
243 | # Use GetBitmapBits and BGRX if the bpp == 32, because
244 | # it's ~15% faster than the method below.
245 | data = bitmap.GetBitmapBits(True) # asString=True
246 | return Image.frombuffer(
247 | 'RGB', size, data, 'raw', 'BGRX', 0, 1)
248 | else:
249 | # If bpp != 32, we cannot use GetBitmapBits, because it
250 | # does not return a 24/32-bit image when the screen is at
251 | # a lower color depth.
252 | try:
253 | data, size = getBGR32(dc, bitmap)
254 | except DIBFailed, e:
255 | raise GrabFailed("getBGR32 failed. Error was " + str(e))
256 | # BGR, 32-bit line padding, origo in lower left corner
257 | return Image.frombuffer(
258 | 'RGB', size, data, 'raw', 'BGR', (size[0] * 3 + 3) & -4, -1)
259 | finally:
260 | _deleteDCAndBitMap(dc, bitmap)
261 |
262 |
263 | def saveScreenToBmp(bmpFilename, bbox=None):
264 | """
265 | Save a screenshot (incl. all monitors) to a .bmp file. Does not require PIL.
266 | The .bmp file will have the same bit-depth as the screen; it is not
267 | guaranteed to be 32-bit.
268 |
269 | bbox = boundingBox. Used to snap a subarea of the screen.
270 | A tuple of (x, y, width, height).
271 | """
272 | dc, bitmap = getDCAndBitMap(saveBmpFilename=bmpFilename, bbox=bbox)
273 | _deleteDCAndBitMap(dc, bitmap)
274 |
275 |
276 | def _demo():
277 | saveNames = ['allMonitors', 'primaryMonitor', 'secondaryMonitor', 'boundingTestOne', 'boundingTestTwo']
278 | params = [None, getMonitorCoordinates(0), getMonitorCoordinates(1), (0,0,100,50), (400,300, 200,200)]
279 |
280 | # for i in range(len(saveNames)):
281 | # saveScreenToBmp( saveNames[i] + '.bmp', params[i])
282 | # im = getScreenAsImage(params[i])
283 | # im.save(saveNames[i] + '.png', format='png' )
284 |
285 |
286 | if __name__ == '__main__':
287 | im = getScreenAsImage((588, 117, 1307, 596))
288 | im.save('testttttttt.png', 'png')
289 |
--------------------------------------------------------------------------------
/Burrito-bot_OLD/bison.py:
--------------------------------------------------------------------------------
1 | """
2 |
3 | All of this is configured to run at 1280x1024 resolution, playing at
4 | http://notdoppler.com/burritobison.php
5 |
6 | Also on chrome. It'll mess up if browser is a different size as it uses
7 | very fragil and poorly designed getpixel() calls to check for things..
8 |
9 | """
10 |
11 | import ImageGrab, ImageOps
12 | import Image
13 | import sys, os
14 | import win32api, win32con
15 | import time
16 | from random import random
17 | from random import randrange
18 | from multiprocessing import Process
19 |
20 | ##GLOBALS
21 | shopping = True
22 | playing = True
23 |
24 | def mousePos(x=(0,0)):
25 | win32api.SetCursorPos(x)
26 | #Temporary position. Eventually this will receive arguments based on
27 | #game logic
28 | tmp = (156, 335)
29 |
30 | def isSpinning():
31 | mousePos((475,620))
32 | expectedVal = (255, 225, 13)
33 | box = (473,377,530,432)
34 |
35 | im = ImageGrab.grab()
36 |
37 | inVal = im.getpixel((500, 390))
38 | ##print inVal
39 | ##print expectedVal
40 | im.save(os.getcwd() + '\\' + 'Spinning.png', "PNG")
41 | if inVal == expectedVal:
42 | print 'Spinning = True'
43 | return True
44 | else:
45 | print 'Not spinning'
46 | return False
47 | ##im.save(os.getcwd() + '\\' + 'text_002.png', "PNG")
48 |
49 | def launcher():
50 |
51 | expectedVal= (250, 152, 135)
52 | im = ImageGrab.grab((455, 435, 501, 467))
53 | inVal = im.getpixel((41,24))
54 | ## print inVal
55 | ## im.save(os.getcwd() + '\\' + 'launcher.png', "PNG")
56 | ## im.putpixel((32,28), (0,0,0))
57 | ## print inVal
58 | if inVal != expectedVal:
59 | leftClick()
60 | im.save(os.getcwd() + '\\' + 'launcher.png', "PNG")
61 | print 'Launch!'
62 | return 1
63 | else:
64 | print 'missed'
65 | launcher()
66 |
67 | def leftClick():
68 | win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN,0,0)
69 | ## time.sleep(.1)
70 | win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP,0,0)
71 | print "MOUSE CLICK!!"
72 | time.sleep(.05)
73 |
74 |
75 | def runFinished():
76 | expectedVal = (42,181,240)
77 | eVal2 = (17,31,75)
78 | box = (181,362,850,452)
79 |
80 | im = ImageGrab.grab(box)
81 |
82 | inVal = im.getpixel((591, 30))
83 | inVal2 = im.getpixel((35, 49))
84 |
85 | if inVal == expectedVal and inVal2 == eVal2:
86 | return True
87 |
88 |
89 | def fuzzCheck(im):
90 | coppa = (99,104,137)
91 | if im.getpixel((randrange(263,290),(randrange(196,223)))) == coppa:
92 | print 'A cop!'
93 | return True
94 | if im.getpixel((randrange(295,320),(randrange(196,223)))) == coppa:
95 | print 'A cop!'
96 | return True
97 |
98 |
99 |
100 | def bubbleCheck(im):
101 | bubble = (252,114,186)
102 | if im.getpixel((randrange(298,325),randrange(100,120))) == bubble:
103 | print 'A Bubble!'
104 | return True
105 | if im.getpixel((randrange(325,350),randrange(80,200))) == bubble:
106 | print 'A Bubble!'
107 |
108 |
109 |
110 | def specialChecker(im):
111 | special = (255,250,240)
112 | if im.getpixel((624,130)) == special:
113 | return(True)
114 |
115 | def spinCheck(im):
116 | launchGuy = (255,242,252)
117 | if im.getpixel((546,90)) == launchGuy:
118 | return True
119 |
120 | def multiClick():
121 | for i in range(14):
122 | leftClick()
123 |
124 | def eventFinder():
125 |
126 | box = (200,500,884,750)
127 | im = ImageGrab.grab(box)
128 |
129 | if specialChecker(im):
130 | print 'Special spotted!\n'
131 | p = Process(target= multiClick())
132 | p.start()
133 | p.join()
134 |
135 |
136 | if bubbleCheck(im):
137 | print "A bubble has appeared!\n"
138 | leftClick()
139 |
140 | ## if specialChecker(im):
141 | ## print 'Special spotted!\n'
142 | ## for i in range(15):
143 | ## leftClick()
144 |
145 | if fuzzCheck(im):
146 | leftClick()
147 |
148 | if specialChecker(im):
149 | print 'Special spotted!\n'
150 |
151 |
152 | if spinCheck(im):
153 | if isSpinning():
154 | launcher()
155 |
156 | print 'searching...'
157 |
158 |
159 |
160 |
161 | def canShop():
162 | im = ImageGrab.grab()
163 |
164 | expectedVal = (242,227,110)
165 | inVal = im.getpixel((695,385))
166 | if expectedVal == inVal:
167 | return True
168 |
169 | def exitShop():
170 | mousePos((840,785))
171 | leftClick()
172 |
173 | def checkSales():
174 | im = ImageGrab.grab()
175 |
176 |
177 | if im.getpixel((275,440))[2] < 150:
178 | print 'Elastic for sale\n'
179 | mousePos((275,525))
180 | leftClick()
181 | time.sleep(.05)
182 | return True
183 |
184 | elif im.getpixel((370,435))[2] < 150:
185 | print 'slip for sale\n'
186 | mousePos((370,435))
187 | leftClick()
188 | time.sleep(.05)
189 | return True
190 |
191 | elif im.getpixel((465,439))[2] < 150:
192 | print 'Pickpocket for sale\n'
193 | mousePos((465,439))
194 | leftClick()
195 | time.sleep(.05)
196 | return True
197 |
198 | elif im.getpixel((458,532))[2] < 150:
199 | print 'Resistance for sale\n'
200 | mousePos((458,532))
201 | leftClick()
202 | time.sleep(.05)
203 | return True
204 |
205 | elif im.getpixel((365,530))[2] < 150:
206 | print 'rocket for sale\n'
207 | mousePos((365,530))
208 | leftClick()
209 | time.sleep(.05)
210 | return True
211 |
212 | elif im.getpixel((270,530))[2] < 150:
213 | print 'Bouncies for sale\n'
214 | mousePos((270,530))
215 | leftClick()
216 | time.sleep(.1)
217 | return True
218 |
219 | elif im.getpixel((272, 635))[2] < 150:
220 | print 'BubbleGum for sale\n'
221 | mousePos((272, 635))
222 | leftClick()
223 | time.sleep(.1)
224 | return True
225 |
226 | elif im.getpixel((367,635))[2] < 150:
227 | print 'Glider for sale\n'
228 | mousePos((367,635))
229 | leftClick()
230 | time.sleep(.1)
231 | return True
232 |
233 | elif im.getpixel((460,635))[2] < 130:
234 | print 'Rocket for sale\n'
235 | mousePos((460,635))
236 | leftClick()
237 | time.sleep(.1)
238 | return True
239 |
240 | elif im.getpixel((270,725))[2] < 150:
241 | print 'Pogo for sale\n'
242 | mousePos((270,725))
243 | leftClick()
244 | time.sleep(.1)
245 | return True
246 |
247 | elif im.getpixel((370,725))[2] < 150:
248 | print 'Pepper for sale\n'
249 | mousePos((370,725))
250 | leftClick()
251 | time.sleep(.1)
252 | return True
253 |
254 | elif im.getpixel((463,725))[2] < 150:
255 | print 'general for sale\n'
256 | mousePos((463,725))
257 | leftClick()
258 | time.sleep(.1)
259 | return True
260 |
261 | else:
262 | return False
263 |
264 |
265 | def buy():
266 | mousePos((745,535))
267 | leftClick()
268 |
269 | def retry():
270 | mousePos((780,415))
271 | leftClick()
272 |
273 | def clickInfo():
274 | mousePos((195,424))
275 | leftClick()
276 |
277 | def infoBoxLeft():
278 | expectedVal = (46,195,251)
279 | eVal2 = (251,223,114)
280 | box = (160,339,460,652)
281 |
282 | im = ImageGrab.grab(box)
283 |
284 | inVal2 = im.getpixel((92,84))
285 | inVal = im.getpixel((24,82))
286 |
287 | if inVal == expectedVal and inVal2 == eVal2:
288 | print "an InfoBox is on screen"
289 | return True
290 |
291 | def infoBoxMid():
292 | expectedVal = (28,184,250)
293 | eVal2 = (251,223,114)
294 | box = (160,339,460,652)
295 |
296 | im = ImageGrab.grab(box)
297 |
298 | inVal2 = im.getpixel((230,164))
299 | inVal = im.getpixel((178,166))
300 |
301 | if inVal == expectedVal and inVal2 == eVal2:
302 | print "mis-screen InfoBox showing"
303 | return True
304 |
305 | def infoExplosive():
306 | box = (160,339,460,652)
307 | im = ImageGrab.grab()
308 |
309 | expectedVal = (33,175,235)
310 | inVal = im.getpixel((389,442))
311 |
312 | eVal2 = (241,216,117)
313 | inVal2 = im.getpixel((445,440))
314 |
315 | if inVal == expectedVal and inVal2 == eVal2:
316 | print "InfoExplosion Dialog On screen"
317 | return True
318 |
319 | def infoBubble():
320 | im = ImageGrab.grab()
321 |
322 | inPix = (59,195,246)
323 | if im.getpixel((385,440)) == inPix:
324 | return True
325 |
326 |
327 |
328 |
329 | boxes = [1,1,1,1,1,1]
330 | def play():
331 | shopping = False
332 | count =0
333 |
334 | while True:
335 | if shopping == False:
336 | if infoBoxLeft() == True:
337 | clickInfo()
338 | boxes[0]=0
339 |
340 | elif infoBoxMid() == True:
341 | mousePos((345,505))
342 | leftClick()
343 |
344 | elif infoExplosive() == True:
345 | mousePos((395,440))
346 | leftClick()
347 | if infoBubble():
348 | mousePos((385,440))
349 | leftClick()
350 |
351 | else:
352 | eventFinder()
353 | count +=1
354 | print count
355 | if count >15:
356 | leftClick()
357 | count=0
358 | eventFinder()
359 |
360 | if runFinished() == True:
361 | if canShop() == True:
362 | mousePos((695,385))
363 | leftClick()
364 | shopping = True
365 | else:
366 | retry()
367 | time.sleep(2)
368 |
369 |
370 |
371 | else:
372 |
373 | while checkSales() == True:
374 | buy()
375 | exitShop()
376 | time.sleep(2)
377 | play()
378 |
379 |
380 |
381 | def main():
382 | ## pass
383 | time.sleep(2)
384 | play()
385 |
386 | if __name__ == '__main__':
387 | main()
388 |
389 |
390 |
391 |
392 |
--------------------------------------------------------------------------------
/bison.py:
--------------------------------------------------------------------------------
1 | """
2 | A bot to automatically play Burrito Bison.
3 |
4 | This was my first big project that I tackled in Python. It has been
5 | one year since I wrote it, and it still gets forked every now and
6 | again. So, high time for a refactoring session!
7 |
8 | The original bison.py will remain. It's like a time capsule now.
9 | """
10 |
11 | import os
12 | import csv
13 | import sys
14 | import time
15 | import Image
16 | import offset
17 | import win32api
18 | import win32con
19 | import ImageOps
20 | import ImageGrab
21 | from ctypes import *
22 | from random import random
23 | from random import randrange
24 | from multiprocessing import Process
25 | from desktop_magic import getMonitorCoordinates
26 | from desktop_magic import getScreenAsImage as grab
27 |
28 | def get_play_area(monitor):
29 | '''
30 | Snaps an image of the chosen monitor (zero indexed).
31 | Loops through the RGB pixels looking for the value
32 | (244,222,176), which corresponds to the top left
33 | most pixel of the game.
34 |
35 | It returns the coordinates of the playarea.
36 | '''
37 |
38 | TOP_LEFT_PIXELS = (204,204,204)
39 | GREY_BORDER = (204,204,204)
40 | SCREEN_WIDTH = 719
41 | SCREEN_HEIGH = 479
42 |
43 | monitor_coords = getMonitorCoordinates(0) #set to whatever monitor you have the game screen on
44 | im = grab(monitor_coords)
45 | imageWidth, imHeight = im.size
46 | imageArray = im.getdata()
47 |
48 | for index, pixel in enumerate(imageArray):
49 | if pixel == TOP_LEFT_PIXELS:
50 | # getdata returns a flat array, so the below figures out
51 | # the 2d coords based on the index position.
52 | top = (index / imageWidth)
53 | left = (index % imageWidth)
54 | if (im.getpixel((left + 1, top + 1)) == GREY_BORDER and
55 | im.getpixel((left + 2, top + 2)) == GREY_BORDER):
56 | top += 5
57 | left += 5
58 |
59 | return (left, top, left + SCREEN_WIDTH, top + SCREEN_HEIGH)
60 |
61 | raise Exception("Play area not in view."
62 | "Make sure the game is visible on screen!")
63 |
64 |
65 | def _getLocationOffsetAndPixel():
66 | playArea = get_play_area()
67 | offset.x = playArea[0]
68 | offset.y = playArea[1]
69 |
70 | snapshot = ImageGrab.grab(playArea)
71 |
72 | pos = list(win32api.GetCursorPos())
73 | pos[0] = pos[0] - offset.x
74 | pos[1] = pos[1] - offset.y
75 | pixelAtMousePos = getPixel(pos[0], pos[1])
76 |
77 | print pos, pixelAtMousePos
78 |
79 | def _dumpDataToExcel(data):
80 | '''
81 | dump frequency and bin information to a csv
82 | file for Histogram creation.
83 | '''
84 | data.sort()
85 | bins = _createBins(data)
86 | with open('histogram.csv', 'wb') as csvfile:
87 | writer = csv.writer(csvfile, delimiter=',')
88 | writer.writerow(['Frequency', 'Bins'])
89 | for i in range(len(data)):
90 | if i < len(bins):
91 | writer.writerow([data[i], bins[i]])
92 | else:
93 | writer.writerow([data[i]])
94 |
95 | def _createBins(data, binNum=15):
96 | '''
97 | Generates equally sized bins for
98 | histogram output
99 | '''
100 | minVal = data[0]
101 | maxVal = data[-1]
102 | dataRange = maxVal - minVal
103 | binRange = dataRange/binNum
104 | bins = []
105 | for i in range(binNum):
106 | bins.append(minVal)
107 | minVal += binRange
108 | return bins
109 |
110 |
111 | def getPixel(x,y):
112 | offset.x
113 | offset.y
114 |
115 |
116 | gdi= windll.gdi32
117 | RGBInt = gdi.GetPixel(windll.user32.GetDC(0),
118 | offset.x + x, offset.y + y)
119 |
120 | red = RGBInt & 255
121 | green = (RGBInt >> 8) & 255
122 | blue = (RGBInt >> 16) & 255
123 | return (red, green, blue)
124 |
125 | def check_pixel(location, color):
126 | pixel = getPixel(location[0], location[1])
127 | print 'input color: ', color
128 | print 'check pixel color:', pixel
129 | if pixel in [color]:
130 | return True
131 | return False
132 |
133 | def is_spinner_screen():
134 | STAR_LOCATION = (339, 47)
135 | GOLD_STAR_COLOR = (255, 225, 13)
136 |
137 | return check_pixel(STAR_LOCATION, GOLD_STAR_COLOR)
138 |
139 | def wait_for_needle():
140 | NEEDLE_CENTER = (327, 121)
141 | BOARD_COLOR = (250,114,95)
142 |
143 | s = time.time()
144 | hit_count = 0
145 | while time.time() - s < 15: #If STILL not found after 15 sec. Prob on wrong screen
146 | if not check_pixel(NEEDLE_CENTER, BOARD_COLOR):
147 | hit_count += 1
148 | if hit_count > 30:
149 | return True
150 |
151 |
152 | def set_mouse_pos(pos=(0,0)):
153 | x,y = pos
154 | x = x + offset.x
155 | y = y + offset.y
156 | win32api.SetCursorPos((x,y))
157 |
158 | def launcher():
159 |
160 | expectedVal= (250, 152, 135)
161 | im = ImageGrab.grab((455, 435, 501, 467))
162 | inVal = im.getpixel((41,24))
163 | ## print inVal
164 | ## im.save(os.getcwd() + '\\' + 'launcher.png', "PNG")
165 | ## im.putpixel((32,28), (0,0,0))
166 | ## print inVal
167 | if inVal != expectedVal:
168 | left_click()
169 | im.save(os.getcwd() + '\\' + 'launcher.png', "PNG")
170 | print 'Launch!'
171 | return 1
172 | else:
173 | print 'missed'
174 | launcher()
175 |
176 |
177 |
178 |
179 | def runFinished():
180 | expectedVal = (42,181,240)
181 | eVal2 = (17,31,75)
182 | box = (181,362,850,452)
183 |
184 | im = ImageGrab.grab(box)
185 |
186 | inVal = im.getpixel((591, 30))
187 | inVal2 = im.getpixel((35, 49))
188 |
189 | if inVal == expectedVal and inVal2 == eVal2:
190 | return True
191 |
192 |
193 | def fuzzCheck(im):
194 | coppa = (99,104,137)
195 | if im.getpixel((randrange(263,290),(randrange(196,223)))) == coppa:
196 | print 'A cop!'
197 | return True
198 | if im.getpixel((randrange(295,320),(randrange(196,223)))) == coppa:
199 | print 'A cop!'
200 | return True
201 |
202 |
203 |
204 | def bubbleCheck(im):
205 | bubble = (252,114,186)
206 | if im.getpixel((randrange(298,325),randrange(100,120))) == bubble:
207 | print 'A Bubble!'
208 | return True
209 | if im.getpixel((randrange(325,350),randrange(80,200))) == bubble:
210 | print 'A Bubble!'
211 |
212 |
213 |
214 | def specialChecker(im):
215 | special = (255,250,240)
216 | if im.getpixel((624,130)) == special:
217 | return(True)
218 |
219 | def spinCheck(im):
220 | launchGuy = (255,242,252)
221 | if im.getpixel((546,90)) == launchGuy:
222 | return True
223 |
224 | def multiClick():
225 | for i in range(14):
226 | left_click()
227 |
228 | def eventFinder():
229 |
230 | box = (200,500,884,750)
231 | im = ImageGrab.grab(box)
232 |
233 | if specialChecker(im):
234 | print 'Special spotted!\n'
235 | p = Process(target= multiClick())
236 | p.start()
237 | p.join()
238 |
239 |
240 | if bubbleCheck(im):
241 | print "A bubble has appeared!\n"
242 | left_click()
243 |
244 | ## if specialChecker(im):
245 | ## print 'Special spotted!\n'
246 | ## for i in range(15):
247 | ## left_click()
248 |
249 | if fuzzCheck(im):
250 | left_click()
251 |
252 | if specialChecker(im):
253 | print 'Special spotted!\n'
254 |
255 |
256 | if spinCheck(im):
257 | if isSpinning():
258 | launcher()
259 |
260 | print 'searching...'
261 |
262 |
263 |
264 |
265 | def can_shop():
266 | SHOP_BUTTON = (497, 55)
267 | BUTTON_COLOR = (39, 178, 237)
268 |
269 | if not check_pixel(SHOP_BUTTON, BUTTON_COLOR):
270 | return True
271 | return False
272 |
273 | def enter_shop():
274 | SHOP_BUTTON = (497, 55)
275 | set_mouse_pos(SHOP_BUTTON)
276 | left_click()
277 |
278 | def exitShop():
279 | set_mouse_pos((685, 446))
280 | left_click()
281 |
282 | def check_sales_and_purcahse():
283 | shop_items = {
284 | 'elastic_cables': [(116, 99), (236, 138, 207)],
285 | 'slippery_lotion': [(209, 104), (228, 132, 200)],
286 | 'pickpocket': [(304, 101), (234, 136, 205)],
287 | 'bounciness': [(112, 191), (235, 136, 206)],
288 | 'rocket_slam': [(207, 188), (234, 136, 205)],
289 | 'resistance': [(303, 191), (237, 138, 208)],
290 | 'bubble_gummies': [(115, 293), (232, 133, 203)],
291 | 'glider_gummies': [(206, 296), (235, 136, 206)],
292 | 'rocket_gummies': [(303, 295), (227, 131, 199)],
293 | 'pogostick': [(111, 381), (235, 136, 206)],
294 | 'pepper_gummies': [(210, 383), (234, 136, 205)],
295 | 'general_goods': [(306, 380), (233, 134, 204)]
296 | }
297 |
298 | while True:
299 | item_available = get_available_items(shop_items)
300 | if item_available is None:
301 | break
302 | purchase_item(item_available)
303 | print 'Done shopping'
304 |
305 | def get_available_items(shop_items):
306 | for k, v in shop_items.iteritems():
307 | item_location = v[0]
308 | item_color = v[1]
309 | print 'checking:', k
310 |
311 | if not check_pixel(item_location, item_color):
312 | print 'purchasing item:', k
313 | return item_location
314 | return None
315 |
316 | def purchase_item(item_location):
317 | set_mouse_pos(item_location)
318 | left_click()
319 |
320 | BUY_BUTTON = (582, 193)
321 | set_mouse_pos(BUY_BUTTON)
322 | left_click()
323 | time.sleep(1)
324 |
325 | def on_retry_screen():
326 | RETRY_LOC, RETRY_COLOR = [(637, 56), (35, 175, 243)]
327 | if check_pixel(RETRY_LOC, RETRY_COLOR):
328 | return True
329 | return False
330 |
331 | def infoBoxLeft():
332 | expectedVal = (46,195,251)
333 | eVal2 = (251,223,114)
334 | box = (160,339,460,652)
335 |
336 | im = ImageGrab.grab(box)
337 |
338 | inVal2 = im.getpixel((92,84))
339 | inVal = im.getpixel((24,82))
340 |
341 | if inVal == expectedVal and inVal2 == eVal2:
342 | print "an InfoBox is on screen"
343 | return True
344 |
345 | def infoBoxMid():
346 | expectedVal = (28,184,250)
347 | eVal2 = (251,223,114)
348 | box = (160,339,460,652)
349 |
350 | im = ImageGrab.grab(box)
351 |
352 | inVal2 = im.getpixel((230,164))
353 | inVal = im.getpixel((178,166))
354 |
355 | if inVal == expectedVal and inVal2 == eVal2:
356 | print "mis-screen InfoBox showing"
357 | return True
358 |
359 | def infoExplosive():
360 | box = (160,339,460,652)
361 | im = ImageGrab.grab()
362 |
363 | expectedVal = (33,175,235)
364 | inVal = im.getpixel((389,442))
365 |
366 | eVal2 = (241,216,117)
367 | inVal2 = im.getpixel((445,440))
368 |
369 | if inVal == expectedVal and inVal2 == eVal2:
370 | print "InfoExplosion Dialog On screen"
371 | return True
372 |
373 | def infoBubble():
374 | im = ImageGrab.grab()
375 |
376 | inPix = (59,195,246)
377 | if im.getpixel((385,440)) == inPix:
378 | return True
379 |
380 |
381 |
382 |
383 | boxes = [1,1,1,1,1,1]
384 | def play():
385 | shopping = False
386 | count =0
387 |
388 | while True:
389 | if shopping == False:
390 | if infoBoxLeft() == True:
391 | clickInfo()
392 | boxes[0]=0
393 |
394 | elif infoBoxMid() == True:
395 | set_mouse_pos((345,505))
396 | left_click()
397 |
398 | elif infoExplosive() == True:
399 | set_mouse_pos((395,440))
400 | left_click()
401 | if infoBubble():
402 | set_mouse_pos((385,440))
403 | left_click()
404 |
405 | else:
406 | eventFinder()
407 | count +=1
408 | print count
409 | if count >15:
410 | left_click()
411 | count=0
412 | eventFinder()
413 |
414 | if runFinished() == True:
415 | if canShop() == True:
416 | set_mouse_pos((695,385))
417 | left_click()
418 | shopping = True
419 | else:
420 | retry()
421 | time.sleep(2)
422 |
423 |
424 |
425 | else:
426 |
427 | while checkSales() == True:
428 | buy()
429 | exitShop()
430 | time.sleep(2)
431 | play()
432 |
433 | def left_click():
434 | win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN,0,0)
435 | win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP,0,0)
436 | print "MOUSE CLICK!!"
437 | time.sleep(.05)
438 |
439 | def main():
440 | play_area = get_play_area(0)
441 | # print play_area
442 | offset.save_to_json((play_area[0], play_area[1]))
443 | reload(offset)
444 | # print offset.x, offset.y
445 |
446 | im = grab(play_area)
447 | im.save('adfsadsf.png', 'png')
448 | # # print is_spinner_screen()
449 | # # set_mouse_pos((720, 270))
450 | # # wait_for_needle()
451 | # # left_click()
452 |
453 | # if can_shop():
454 | # enter_shop()
455 |
456 | # time.sleep(3)
457 |
458 | # for i in range(12):
459 | # time.sleep(3)
460 | pos = win32api.GetCursorPos()
461 | x = pos[0] - offset.x
462 | y = pos[1] - offset.y
463 | print '[(%d, %d), %s]' % (x,y, str(getPixel(x,y)))
464 | print
465 |
466 | print on_retry_screen()
467 | # print on_retry_screen()
468 | # check_sales_and_purcahse()
469 | # print getPixel(631, 54)
470 |
471 | bot_logo = '''
472 |
473 |
474 |
475 | ____ _ _
476 | | _ \ (_)| |
477 | | |_) | _ _ _ __ _ __ _ | |_ ___
478 | | _ < | | | || '__|| '__|| || __| / _ \
479 | | |_) || |_| || | | | | || |_ | (_) |
480 | |____/ \__,_||_| |_| |_| \__| \___/
481 | ____ _
482 | | _ \ | |
483 | | |_) | ___ | |_
484 | | _ < / _ \ | __|
485 | | |_) || (_) || |_
486 | |____/ \___/ \__|
487 |
488 |
489 |
490 | 1. Start Bot
491 | 2. Quit
492 | '''
493 |
494 | if __name__ == '__main__':
495 | print bot_logo
496 | c = input('Select an option:')
497 |
498 |
499 |
500 |
501 |
--------------------------------------------------------------------------------