from collections import OrderedDict from PIL import Image, ImageChops, ImageDraw import time import json import os import os.path try: import pymongo except: pass import math try: from bson.objectid import ObjectId except: pass from image_util import load_image, image_to_string_format,\ reduce_to_colors try: conn = pymongo.Connection('localhost') db = conn.ztrans except: pass def replace_color(im, color1, color2): mode = im.mode im = im.convert("P", palette=Image.ADAPTIVE) p = im.getpalette() new_p = list() for i in range(256): r = p[3*i] g = p[3*i+1] b = p[3*i+2] if r == color1[0] and g == color1[1] and b == color1[2]: new_p.extend(color2[:3]) else: new_p.extend([r,g,b]) im.putpalette(new_p) return im.convert(mode) class TileSetParser: @classmethod def parse_images(cls, image_list, seed_list, seed_fails, tilesize): x = None y = None tiles = OrderedDict() fail_tiles = OrderedDict() seed_tiles = OrderedDict() for ii, im in enumerate(seed_list): #print(ii, len(seed_list)) if x is None: x,y = TileTools.find_tileset_offset(im, tilesize) these_tiles = TileTools.get_tiles(im, x, y, tilesize) for t in these_tiles: seed_tiles[t] = seed_tiles.get(t,0)+these_tiles[t] for im in seed_fails: these_tiles = TileTools.get_tiles(im, x, y, tilesize) for t in these_tiles: fail_tiles[t] = fail_tiles.get(t,0)+these_tiles[t] maps = 0 for ii, image in enumerate(image_list): #print("tt--", ii) these_tiles = TileTools.get_tiles(image, x,y, tilesize) c = 0 for t in these_tiles: if t in fail_tiles: c+=these_tiles[t] for t in these_tiles: if t in fail_tiles and c > 10: for s in these_tiles: if s not in tiles: fail_tiles[s] = 1 break else: print("succ") #test for success tiles... succ = 0 ox, oy = TileTools.find_tileset_offset(image, tilesize) if ox == x and oy == y: image.save("maps_"+str(maps)+".png") maps+=1 for s in these_tiles: tiles[s] = tiles.get(s,0)+these_tiles[s] width = 16*tilesize height = int(len(tiles)/tilesize+1)*tilesize nim = Image.new("RGB", (width, height)) wx = 0 wy = 0 for key in tiles: subi = load_image(key) draw = ImageDraw.Draw(subi) draw.line((0,0, subi.width,0), fill = 128) draw.line((0,0, 0, subi.height), fill=128) nim.paste(subi, (wx,wy)) wx+=tilesize if wx >= width: wx = 0 wy+=tilesize nim.save("t.png") #import pdb #pdb.set_trace() return {"tileset": nim, "tiles": tiles, "fail_tiles": fail_tiles, "off_x": x, "off_y": y, "tilesize": tilesize} def main(): start_image_id = ObjectId("5df9d8208ac3d956387c0941") doc = db.ocr_images.find_one({"_id": start_image_id}) game_id = doc['game_id'] user_id = doc['user_id'] seed_list_ids = [ObjectId("5df9d8df8ac3d956387c0957"), ObjectId("5df9d9008ac3d956387c095d"), ] seed_fail_ids = [] seed_list = list() fail_list = list() for seed_id in seed_list_ids: doc = db.ocr_images.find_one({"_id": seed_id}) img = load_image(doc['image_data']) seed_list.append(img) for fail_id in seed_fail_ids: doc = db.ocr_images.find_one({"_id": fail_id}) img = load_image(doc['image_data']) fail_list.append(img) image_list = [Image.open("text"+str(i)+".png") for i in range(7)] f = ParseScreenText.get_font(image_list) start_image_id = ObjectId("5df9d8208ac3d956387c0941") doc = db.ocr_images.find_one({"_id": start_image_id}) game_id = doc['game_id'] user_id = doc['user_id'] image_list = list() c = 0 for image in db.ocr_images.find({"user_id": user_id, "game_id": game_id}, sort=[("_id", pymongo.ASCENDING)]): im = load_image(image['image_data']) tex = ParseScreenText.parse_screen(im, f) c+=1 if image['_id'] in [ObjectId('5e3e44e48ac3d94113fa1361'), ObjectId('5e3e44e68ac3d94112f910c6'), ObjectId('5e3e44e88ac3d94113fa1363'), ObjectId('5e3e44ff8ac3d94113fa1366')]: im.paste(im.crop((0,0, 160, im.height)), (32,0)) if not tex: image_list.append(im) res = TileSetParser.parse_images(image_list, seed_list, fail_list, tilesize=16) ts = ["grass", "woods", "wall", "castle", "water", "town", "port", "building","inn", "tree", "path", "door", "fence", "armor shop", "weapon shop", "foutain", "well", "bridge", "item shop", "clinic", "swamp", "rock", "ruins", "black magic shop", "white magic shop", "tile", "stairs up", "column", "statue", "fireplace", "chair", "table", "bed", "stairs down", "throne", "chest", "orb", "cave", "skull", "vase", "desert", "ship", "river", "meadow", "tombstone", "ladder down", "ladder up", "dirt","hammer", "sword", "anvil", "lid", "alter", "exit", "hole", "poison", "candles", "volcano","fairy", "submarine", "tower", "computer", "runes", "teleporter up", "teleporter down", "fire", "door", "king" ] res['tileset'].save("tileset__.png") res['tileset'].show() import pdb pdb.set_trace() sounds = [] obss = [0,0,1,2,1, 2,2,1,3,1, 0,0,1,3,3, 1,1,2,3,3, 0,1,2,3,3, 0,2,1,1,1, 0,1,1,2,1, 2,3,2,0,1, 0,2,1,0,1, 2,2,0,1,1, 1,3,1,2,2, 0,1,2,3,2, 2,1,1,2,2, 1,3,3 ]#0-no obs, 1-obst, 2-no obst special, 3-special obst mapp = [ 1, 1, 1, 0, 2, 3, 3, 3, 2, 2, 4, 2, 5, 0, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 1, 1, 1, 0, 4, 0, 6, 6, 6, 4, 4, 6, 6, 2, 2, 2, 2, 2, 2, 7, 8, 0, 9, 10, 0, 4, 2,11, 0,12,-1,10,-1, 9, 2, 2, 2, 7,-1, -1, 7,-1,-1,10, 2, 2,13,14,10,-1,-1,-1,-1,15, 0, -1,-1,-1,-1,-1,16, 7,-1,-1,17,-1,18, 4,-1, 4,17, 7,19,-1,-1,-1,-1, 0, 1, 0, 4,20,20,20,21,21,21, 21,21,20,20,21,21,22,22, 0,22,22, 0,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,23,24,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,25,-1, 2, 2, 0, 2,26,27, 2, 2, 2, 2, 2, 2, 2, 2, 2,11,-1, 2,-1, 2, 2, 2, 2, 28,29,28, 2,30,31,30,-1,31,-1,25, 2,25, 2,11,32, -1, 2,-1,-1,25,-1, 2,33,34,34,34,34,67,34,25, 2, 66,27, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,25, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,11,35,28,-1,-1,-1, 25,28,-1,-1,-1,28,-1,25, 2,-1, 2,-1,27, 2,26,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,36, 2,-1,-1,-1,-1, 17, 4, 4,21,21,37, 2, 2, 2, 2, 2, 2,26, 2,11,25, 2, 2, 2, 2,-1,-1,38,-1,-1,25, 2, 2, 2, 2,-1, 2, 11, 2,-1,39,-1,-1,31,-1,-1,-1,-1,-1,-1,-1,-1, 0, 40, 0, 0, 0, 2, 5, 2, 2,10,-1,10,-1, 2, 2, 2,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,41,42,42,43,43,43,43, 3, 3,43, 5, 3, 3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,28,32,-1, -1,44,42,54,-1,25,27,26,25,-1,25,25,-1,25, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,66,25,27, 2, 2, 2, 2, 2, 46, 2,25, 2, 2,11,27,33,35,26,47,11,-1, 2, 2, 2, 25, 2, 2, 2, 2, 2, 2,27,25,26, 2, 2, 2, 2, 2, 2, 25, 2, 2,11,11,-1,-1,25,25,27,25,-1,28,-1,25,25, -1,-1,-1,25,-1,-1,34,-1,35,34,34,-1,-1,-1,-1,-1, 2,-1, 2, 2, 2,-1,-1,28,-1,30,-1,30,31,-1,30,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 0,47,21, 2, 2, 2,-1, 2,-1,-1,-1, 2, 2, 2, 2, 2, 2,-1,-1, -1,-1,21, 2, 2, 2, 2,-1, 2,-1,30, 2,25, 2, 2,-1, -1,29,48,49,50, 5, 0,40,10,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,40,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,21,47,26, 2, 2, 2, 2, 2,47,-1,-1,47,21,47, 2, 2, 2, 2, 2, 2,25, 2, 2,11,11,47,-1,-1,-1,-1,47, -1, 2, 2, 2, 2,33, 2,47,47,-1,-1, 2, 2, 2, 2, 2, 2, 2, 2, 2,-1,47,-1,-1,-1,-1, 2, 2,-1, 2,26,21, -1,51,47,21,-1,47,26, 2, 2, 2, 2, 2, 2,-1,47, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,25, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,29,32,-1,32,-1, 2, 2, 2, 2,35, 2, 2, 2,-1, 2, 2,25, 2, 2, 2,35,47, 47,47,47,47,-1,-1,-1,-1,-1,-1,-1,-1,-1, 2, 2, 2, 2, 2, 2,52, 2,-1,36, 2,53, 5, 0,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1, 2, 2, 2,47,21,33, 2, 2, 2, 2, 2, 2, 2, 2,54, 2,21, 2, 2, 2, 2,25, 2, 2, 2, 2, 2,55, 2, 2, 2,-1,-1,-1,-1,-1,47, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,47, 2, 2, 2, 2,-1, 2,-1, 2,25, 2,-1,-1,-1,-1,-1,-1,-1,-1, 2, 2, 2, 2,-1,-1,-1,-1,16,-1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,25, 2, 2, 2, 2,56,-1,-1, 2, 2, 2,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,10,-1,-1,-1,-1, -1, 9,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1, 9,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1, 9,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 2, 2, 47, 2,47,47,47,-1,-1,-1,-1,-1,57,57,57,57,21,21, 47,55,26,33, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,25, 2, 2, 2, 2,47,55,26, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,33,21,21, 2, 2, 2,47,47, 2, 2, 2, 2,25, 2, 2, 2, 2, 2, 2, 2,-1,36, 2, 2, 2, 2, 2, 2, 2, 2,53, 2, 2,52, 2,25, 2, 2, 2,11, -1,-1,-1,-1,58,59, 2, 2,25, 2, 2, 2, 4,59, 2, 2, 2, 2, 2,27, 2, 2,66,47,47, 2, 2, 2, 2,35, 2, 2, 25, 2, 2,11,33,26, 4,25,33, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,66, 2, 2, 2, 2, 2, 2,25, 2,11,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1, 2, 2, 2, 2,66, 2,26, 33,53, 2,52, 2,28,-1,28,36,10,-1,-1,10,-1,-1,10, -1,-1,-1,60,60,40, 2, 2, 2, 2,25,66, 2, 2, 2, 2, 26,33,27,25, 2, 2,11, 2, 2,11, 2, 2, 2,26,33, 2, 2, 2,61,61,-1,-1,-1, 2, 2,27, 2,-1,-1, 2, 2,-1, -1,-1,-1,-1,-1, 2,27,61, 2,61, 2, 2, 2, 2,25,33, 2, 2, 2, 2, 2, 2, 2, 2, 2,66, 2, 2,28, 2,62, 2, 2,-1, 2,25,25, 2, 2,25, 2, 2, 2, 2, 2, 2, 2, 2, 62, 2, 2,25,66, 2, 2, 2, 2, 2, 2, 2, 2,35,11,63, 64,-1,-1,-1,61,61,30,61,62, 2,52, 2,-1,36,53,36, -1,-1,66,28,36,-1,-1,-1,28,-1,-1,-1,-1,25,27, 2, 2, 2, 2, 2, 2,25, 2, 2, 2, 2, 2,27, 2,52, 2,53, 45,53,51,26,46, 2, 2, 2,62,11, 2, 2,65,65,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,26,41,41,41 ] lud = dict() person_dict = dict() person_box = (6, 5, 10,11) person_tiles = list() fail_person_tiles = list() fail_person_dict = dict() for i, key in enumerate(res['tiles']): if i >= len(mapp): continue elif mapp[i] >= 0: num = mapp[i] typ = ts[num] obs = obss[num] subi = load_image(key) subi_key = image_to_string_format(subi, "BMP") lud[subi_key] = {"type": typ, "obs": obs, "num": num, "raw_i": i} elif mapp[i] == -1: #this is a person tile, so put it into the person-sets. #go through all (regular) tiles and find the one with the lowest #difference with this tile. max_c = 0 succ_tile = None diff_tile = None for j, tile in enumerate(res['tiles']): if j= 0: dd = ImageChops.difference(load_image(key), load_image(tile)) for c in dd.convert("RGBA").getcolors(): if c[1][:3] == (0,0,0): val = c[0] if val > max_c: max_c = val succ_tile = tile diff_tile = dd if succ_tile: cropped1 = load_image(succ_tile).crop(person_box) cropped2 = load_image(key).crop(person_box) dd = ImageChops.difference(cropped1, cropped2).convert("RGBA") cc = None for cc in dd.getcolors(): if cc[1][:3] == (0,0,0): break if (cc and cc[0] < cropped1.width*cropped1.height/2) or cc is None: if cc: print([cc[0], 64]) pkey = image_to_string_format(cropped2, "BMP") person_dict[key] = pkey person_tiles.append(key) else: pkey = image_to_string_format(cropped2, "BMP") fail_person_tiles.append(key) fail_person_dict[key] = pkey #...a tilesize = 16 width = 8*tilesize height = int(len(person_tiles)/8+1)*tilesize pim = Image.new("RGB", (width, height)) wx = 0 wy = 0 for key in person_tiles: subi = load_image(key).crop((0,0,tilesize-1, tilesize-1)) pim.paste(subi, (wx,wy)) wx+=tilesize if wx >= width: wx = 0 wy+=tilesize pim.save("p.png") pim.show() wx=0 wy=0 width = 8*tilesize height = int(len(fail_person_tiles)/8+1)*tilesize pim2 = Image.new("RGB", (width, height)) for key in fail_person_tiles: subi = load_image(key).crop((0,0,tilesize-1, tilesize-1)) pim2.paste(subi, (wx,wy)) wx+=tilesize if wx >= width: wx = 0 wy+=tilesize pim2.save("p_f.png") pim2.show() #fix p.png stuff here below--v !!! pmap = [ 0, 0, 0, 1, 1, 2, 1, 0, 3, 0, 2, 0, 2, 2, 2, 1, 2, 1, 2, 2, 1, 1, 2, 4, 1, 5, 4, 5, 4, 4, 1, 0, 3, 3, 0, 3, 0, 3, 0, 3, 6, 6, 7, 0, 6, 6, 6, 6, 6,10,10,10,11,10,10,11, 10,10,12,12,12,12,13,13, 13,13, 0,13, 0,12, 0,12, 0, 5, 5, 5,13, 5,13,14, 14,14,14,14,14,14,14,14, 10,10,10,14, 6, 6, 6, 6, 5, 1, 5, 7, 0, 7, 0,16, 16,16,16,16,16,16,12,12, 12,12,12, 0,12,12,12,16, 12, 5,16, 5,16,16, 0,16, 7, 7,12, 7,12, 7,17,18, 18, 5, 5, 0, 0, 0, 0,12, 12,19,19,19,20,20,20,20, 20,20,20,20,20,12,12,12, 12, 7, 2, 7, 7, 2, 7, 2, 7, 7,10, 2, 2,10,10,10, 11,10,11,10, 2, 2, 2, 4, 4,12, 4, 4, 4, 0, 0, 0, 4, 0,21,21,21, 2,13, 2, 2,13,13, 1,13, 1, 1, 2, 2,13,21,21,13,13,12,21, 12,21, 5, 1, 2, 5, 2,11, 11, 0, 0, 0, 0, 0, 0,20, 20,20,22,22,19,19,19,23, 23,23,23,23,24,24,24,24, 24,22,22,22,25,25,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1 ] pmapf = [-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, 1,-1,-1,-1,-1,-1,25,25, -1,-1,-1, 9,25,-1,25,25, 25,-1, 9,-1,25,25,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,13,-1, 13,-1,13,-1,21,-1,-1,-1, -1,21,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,25,25, -1,-1,-1,-1,25,25,25,-1, 25,25,-1,15,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,12, -1, 0,12,-1,-1,-1, 0,-1, 0,-1, 0,-1,-1, 0,-1,-1, 12,-1,-1,12,-1,-1,-1,-1, 0,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,16,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,16,-1,-1, -1,-1,25,-1,-1,-1,-1,25, -1,-1,-1,25,-1,25,-1,25, -1,25,25,-1,25,25,25,-1, 25,-1,25,-1,-1,-1,-1,-1, -1,19,19,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, 2,-1,-1,-1,-1, 2,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1, 0, -1,-1,21,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,21,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,20, -1,-1,-1,25,25,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,22,22,-1,-1,-1, 22,-1,-1,-1,22,22,-1,-1, 25,-1,-1,-1,-1,25,-1, 9, 9,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1 ] persons = ["woman", "guard", "dancer", "boy", "old woman", "old man", "girl", "scholar", "king", "garland", "broom", "witch", "man", "punk", "elf", "astros", "dwarf", "vampire", "monster", "airship", "dragon", "pirate","robot", "mermaid", "robed", "bat", ] plud = {"person_box": person_box, "person_dict": {}} for i, key in enumerate(person_tiles): print(("p", i,key)) if pmap[i] >= 0: cropped_pic = person_dict[key] plud['person_dict'][cropped_pic] = { "num": pmap[i], "type": persons[pmap[i]], "obs": 1, "raw_i": i } for i, key in enumerate(fail_person_tiles): print(("pp", i,key)) if pmapf[i] >= 0: cropped_pic = fail_person_dict[key] plud['person_dict'][cropped_pic] = { "num": pmapf[i], "type": persons[pmapf[i]], "obs": 1, "raw_i": i, "fail_set": True, } tile_info = {"off_x": res['off_x'], "off_y": res['off_y'], "tilesize": res['tilesize'] } saved_data = {"tile_info": tile_info, "lud": lud, "plud": plud} file_w = open("ff1_data.lud", "w") file_w.write(json.dumps(saved_data)) for i in range(10): im = Image.open("maps_"+str(2+i)+".png") t = time.time() k, map_data = ParseScreenObstructions.parse_screen(im, tile_info, lud, plud, partial_center=True) print((time.time()-t)) import pdb pdb.set_trace() class PathFinder: persons_set = {"woman", "guard", "dancer", "boy", "old woman", "old man", "girl", "scholar", "king", "garland", "broom", "witch", "man", "punk", "elf", "astros", "dwarf", "vampire", "monster", "airship", "dragon", "pirate","robot", "mermaid", "robed"} dont_expand_types = ['stairs up', 'stairs down', 'ladder up', 'ladder down', "teleporter up", "teleporter down", "hole"] @classmethod def find_paths(cls, map_data, y, x): def valid(y,x): if map_data['tiles'][y][x]['obs'] in ob or map_data['tiles'][y][x]['type'] in cls.persons_set: return True return False def dont_expand(y,x): if map_data['tiles'][y][x]['obs'] in obs or map_data['tiles'][y][x]['type'] in cls.persons_set or map_data['tiles'][y][x]['type'] in cls.dont_expand_types: return True return False marked = {(y,x): (0,0)} last_marked = [(y,x)] ob = [0,2,3] obs = [3] print(map_data) try: while last_marked: new_marked = list() for y,x in last_marked: if map_data['tiles'][y][x] and dont_expand(y,x): continue #mark up if y > 0 and (y-1,x) not in marked and valid(y-1,x): new_marked.append((y-1,x, 1, 0)) marked[(y-1, x)] = (-1,0) #mark down if y < len(map_data['tiles'])-1 and (y+1,x) not in marked and valid(y+1,x): new_marked.append((y+1,x, -1,0)) marked[(y+1,x)] = (1,0) #mark left if x > 0 and (y,x-1) not in marked and valid(y,x-1): new_marked.append((y, x-1, 0,1)) marked[(y,x-1)] = (0,-1) #mark right if x < len(map_data['tiles'][0])-1 and (y,x+1) not in marked and valid(y,x+1): new_marked.append((y, x+1, 0,-1)) marked[(y,x+1)] = (0,1) last_marked = list() for y,x,vy,vx in new_marked: last_marked.append((y,x)) except: return None return marked @classmethod def find_path(cls, marked, y,x): if not (y,x) in marked: return None path = list() py,px = y,x while marked[(py, px)] not in [(0,0), None]: vy, vx = marked[(py,px)] path.append((py,px, vy,vx)) py-=vy px-=vx print(("path", path[-1])) path = path[::-1] return path class PackageOutput: def __init__(self, filename, enemy_filename): ScreenSelector._load_content(None, None, None, filename, enemy_filename) self.memory = list() self.pause_mode = {"active": False, "goal": None} self.press_mem = {} self.state_mem = {} def get_output(self, im, state_dict): typ, k, map_data = ScreenSelector.parse_whole_screen(im) path_data = PathFinder.find_paths(map_data, 6,7) #for key in state_dict: # if key in ['up', 'down', 'left', 'right'] and state_dict.get(key) == 1: # self.pause_mode['active'] = False # self.pause_mode['goal'] = 'menu' #print(k) #print(typ, '-----') mem = self.memory if self.state_mem.get('paused') != state_dict.get("paused"): mem = dict() output = list() press_output = list() mem_dont = False if typ == "world": if state_dict.get("paused") == 0 or True: if not k: mem_dont = True for entry in k: #if entry not in mem: output.append(entry) else: #maybe not? for entry in k: output.append(entry) elif typ == 'map': #print(state_dict) specials = dict() specials_list = list() if state_dict.get('paused')==0: special_flag = False for entry in k: if entry == "special": special_flag = True elif special_flag: sp = entry.split(" ") spec = sp[0] for i in range(len(sp)): if sp[i].replace("-", "").isdigit(): spec = " ".join(sp[:i]) break if spec not in " ".join(mem): print(("spec", spec)) print((" ".join(mem).split())) specials[spec] = 1 else: sp = entry.split(" ") if len(sp) > 3: sp[2] = " ".join(sp[2:]) if len(sp) > 2 and sp[2] in ['grass', 'woods', 'dirt', 'desert', 'swamp', 'tile', 'meadow']: continue output.append(sp[0]+" "+sp[2]+",") if not output: output.append("None") if specials: print(("____++", mem)) output.append("special,") for key in specials: output.append(key+",") if output and output[-1] and output[-1][-1] == ",": output[-1] = output[-1][:-1] for key in ['west', 'east', 'south', 'north']: if key+" unknown" not in output and\ key+" unknown," not in output: break else: output = [" "] mem_dont = True else: special = False dir_seen = dict() mem_seen = dict() try: mem[5:] except: mem = list() for entry in k: if special is False and entry.split(" ")[0].lower() in ['west','east','north','south']: output.append(entry+",") elif entry == 'special': special = True output.append(entry+",") else: #for the ai menu... specials_list.append(entry) sp = entry.split(" ") seen = [] #convert from coordinates here to west/east directions count = 0 res = list() for i, ent in enumerate(sp): if ent.replace("-", "").isdigit(): if count == 0: if int(ent) > 0: res.append("east "+ent) else: res.append("west "+ent.replace("-", "")) count+=1 else: if int(ent) > 0: res.append("north "+ent) else: res.append("south "+ent.replace("-", "")) else: res.append(ent) entry = " ".join(res) if entry not in mem_seen: seen.append(entry) if len(seen) > 0: output.append(" ".join(seen)+",") if output[-1] in ['special', 'special,']: output = output[:-1] if output and output[-1] and output[-1][-1] == ",": output[-1] = output[-1][:-1] elif typ == 'text': for entry in k: if entry not in mem: output.append(entry) elif typ == 'menu': for entry in k: if entry not in mem: output.append(entry) elif typ == 'shop': if type(k) != type(mem): output = [k['title'], k['text'], k['menu']] else: output = list() for key in ['title', 'text', 'menu']: if mem.get(key) != k[key]: output.append(k[key]) elif typ == 'battle': output = list() if state_dict.get("paused", 0) == 0: for key in ['enemy_string', 'status', 'character', 'menu']: if key == "status": if type(k) != type(mem) and k[key]: output.extend(k[key]) elif k[key]: for entry in k[key]: if entry not in mem.get(key,[]): output.append(entry) elif (type(k) != type(mem) or mem.get(key) != k.get(key)) and k.get(key): if type(k[key]) == list: output.extend(k[key]) else: output.append(k[key]) else: for key in ['enemy_string', 'status', 'textbox', 'character', 'menu']: if k[key]: if type(k[key]) == list: output.extend(k[key]) else: output.append(k[key]) if mem_dont == False: self.memory = k self.state_mem = state_dict clicked = dict() for key in state_dict: if state_dict[key] and not self.press_mem.get(key): self.press_mem[key] = True clicked[key] = True print(clicked) for key in self.press_mem: if not state_dict.get(key): self.press_mem[key] = False if state_dict.get("paused") == 1: if self.pause_mode['active'] is True: output = list() print((self.pause_mode)) if self.pause_mode['active'] is False and clicked.get('start'): self.pause_mode['active'] = True self.pause_mode['goal'] = "menu" self.pause_mode['select'] = 0 output = ["AI Menu"] if typ == "map": self.pause_mode['menu'] = [str(i+1)+": "+" ".join(x.strip().split(" ")[:-2])+", " for i,x in enumerate(specials_list)] self.pause_mode['total'] = len(self.pause_mode['menu']) #output.extend(self.pause_mode['menu']) elif clicked.get("start") and self.pause_mode['goal'] == "menu": #activate menu selection output = ["Going to: "+self.pause_mode['menu'][self.pause_mode['select']].partition(": ")[2]] self.pause_mode['goal'] = self.pause_mode['menu'][self.pause_mode['select']] elif self.pause_mode['active'] and state_dict.get("start") and self.pause_mode['goal'] != "menu": pass elif self.pause_mode['active'] and not state_dict.get("start") and self.pause_mode['goal'] != "menu": print((self.pause_mode['goal'])) press_output = ["unpause"] elif self.pause_mode['active'] and self.pause_mode['total'] > 0: if state_dict.get("a"):#clicked.get("a"): self.pause_mode['select'] += 1 if state_dict.get("b"):#clicked.get("b"): self.pause_mode['select'] -= 1 if self.pause_mode['select'] < 0: self.pause_mode['select'] += self.pause_mode['total'] if self.pause_mode['select'] >= self.pause_mode['total']: self.pause_mode['select'] -= self.pause_mode['total'] if self.pause_mode['active'] and self.pause_mode['goal'] == "menu": if self.pause_mode['total'] > 0: output.append("Go to: "+self.pause_mode['menu'][self.pause_mode['select']]) else: if self.pause_mode['active'] and self.pause_mode['goal'] != "menu": #move to target #find shortest path to target here... #aaa AAA goal = self.pause_mode['goal'] num = int(goal.partition(": ")[0])-1 target = goal.partition(": ")[2] count = 0 x, y = None, None special_flag = False print(k) for entry in k: ee = target.partition(",")[0] if "special" in entry: special_flag = True if ee in entry and special_flag: count+=1 coords = entry.partition(ee)[2].strip().split(" ") x, y = int(coords[0]), int(coords[1]) if count == num: break if path_data and x is not None and y is not None: path = PathFinder.find_path(path_data, 6-y,7+x) print(("X Y ",x,y,target, num, goal)) if path: vy = -1*path[0][2] vx = path[0][3] if vx != None: if vy < 0: press_output.append("down") elif vy > 0: press_output.append("up") elif vx < 0: press_output.append("left") elif vx > 0: press_output.append("right") print(("AAAA ", map_data['tiles'][6-vy][7+vx]['type'], target)) if map_data['tiles'][6-vy][7+vx]['type'] == target.replace(",", "").strip(): press_output.append("a") output = list() if "unknown" not in" ".join(k).partition("special")[0] and (count == 0 or abs(x)+abs(y) <= 1): self.pause_mode['active'] = False self.pause_mode['goal'] = 'menu' else: output = list() else: self.pause_mode['active'] = False self.pause_mode['goal'] = 'menu' output = ['No path available'] else: output = list() elif self.pause_mode['active']: if self.pause_mode['goal'] == "menu": self.pause_mode['active'] = False else: pass if typ != "map": self.pause_mode['active'] = False self.pause_mode['goal'] = 'menu' return output, press_output def run(self, im, state_dict): new_out = self.get_output(im, state_dict) return new_out def main_b(): doc = json.loads(open("ff1_data.lud", "r").read()) tile_info = doc['tile_info'] lud = doc['lud'] plud = doc['plud'] for i in range(10): im = Image.open("maps_"+str(2+i)+".png") t = time.time() k, map_data = ParseScreenObstructions.parse_screen(im, tile_info, lud, plud, partial_center=True) print(( time.time()-t)) import pdb pdb.set_trace() def main_c(): po = PackageOutput("ff1_data.lud", "enemy_lookup.dat") for i in range(10): im = Image.open("maps_"+str(2+i)+".png") t = time.time() print(("--", po.memory)) print((po.run(im))) print((time.time()-t)) import pdb pdb.set_trace() class ParseScreenObstructions: @classmethod def parse_screen(cls, im, tile_info, lud, plud, partial_center=False): off_x = tile_info['off_x']#0 off_y = tile_info['off_y']#8 tilesize = tile_info['tilesize'] map_data = {"center": [6,7], "tiles": []} #AAAAAAAAaaaaaaaaaaa #-start at center of the screen, go out in 4 directions and # get the tiles screen = TileTools.parse_tiles(im, off_x, off_y, tilesize, partial_center=partial_center) horizontal = list() vertical = list() special = list() unknown_limit = 32 unknown_count = 0 for y, row in enumerate(screen): map_data['tiles'].append([]) for x, tile in enumerate(row): person = None if partial_center == True and x == 7 and y == 5: doc = None for key in lud: #bmps are stored upside down, so do endswith here.. if key.endswith(tile[int(-len(tile)*3/4):]): doc = lud.get(key) break else: doc = lud.get(tile) if doc is None and tile is not None: #check person tiles pt = load_image(tile) cropped = pt.crop(plud['person_box']) pkey = image_to_string_format(cropped, "BMP") if pkey in plud['person_dict']: person = plud['person_dict'][pkey] doc = {"obs": person['obs'], "type": person['type'], "num": person['num'], "raw_i": person['raw_i']} else: #handle tiles that are overlayed a bit with a #sprite below them for key in lud: #bmps are stored upside down, so do endswith here.. if key.endswith(tile[int(-len(tile)*3/4):]): doc = lud.get(key) break else: unknown_count+=1 if y == 6: horizontal.append(doc) if x == 7: vertical.append(doc) map_data['tiles'][-1].append(doc) if doc and (doc['obs'] in [2,3] or person): if doc['type'] != 'bat': special.append([x,y, doc, tile]) if unknown_count > unknown_limit: horizontal = [None for x in horizontal] vertical = [None for x in vertical] special_groups = dict() for tup in sorted(special, key=lambda x:(x[0],x[1])): if tup[2]['type'] not in special_groups: special_groups[tup[2]['type']] = [[tup]] else: for entry_tup in special_groups[tup[2]['type']]: for e_tup2 in entry_tup: if abs(tup[0]-e_tup2[0])+abs(tup[1]-e_tup2[1])<2: entry_tup.append(tup) break else: continue break else: special_groups[tup[2]['type']].append([tup]) new_special = list() for ent_group in special_groups: for ent in special_groups[ent_group]: num = 0 sx=0 sy=0 for tup in ent: sx+=tup[0] sy+=tup[1] num+=1 ent[0][0] = int(sx/num) ent[0][1] = int(sy/num) new_special.append(ent[0]) special = new_special results = {"horizontal": horizontal, "vertical": vertical, "special": special, "im": im} return cls.output_to_text(results), map_data #-compute the tile types (obstruction or not, special or not). #--have sound types for wood, brick, water, etc. #-convert to sound info. #--if no info found, assume that the play moved a bit. pass @classmethod def output_to_text(cls, results): west_obs = None east_obs = None south_obs = None north_obs = None for i, doc in enumerate(results['horizontal']): if doc and i != 7 and doc['obs']%2 == 1: if i < 7: west_obs = 6-i; if i > 7 and east_obs == None: east_obs = i-8; for j, doc in enumerate(results['vertical']): if doc and j != 6 and doc['obs']%2 == 1: if j < 6: north_obs = 5-j; if j > 6 and south_obs == None: south_obs = j-7; west_tile = results['horizontal'][6] if west_tile is not None: west_tile = west_tile['type'] else: west_tile = "unknown" east_tile = results['horizontal'][8] if east_tile is not None: east_tile = east_tile['type'] else: east_tile = "unknown" south_tile = results['vertical'][7] if south_tile is not None: south_tile = south_tile['type'] else: south_tile = "unknown" north_tile = results['vertical'][5] if north_tile is not None: north_tile = north_tile['type'] else: north_tile = "unknown" outputs = ["west "+str(west_obs)+" "+west_tile, "north "+str(north_obs)+" "+north_tile, "east "+str(east_obs)+" "+east_tile, "south "+str(south_obs)+" "+south_tile] sp = dict() sp_a = list() for k, doc in enumerate(results['special']): x,y = doc[0]-7, doc[1]-6 angle = math.atan2(-y,x) while angle < 0: angle+=math.pi*2 while angle > math.pi*2: angle-=math.pi*2 if math.pi/8 <= angle <= 3*math.pi/8: dr = "northeast" elif 3*math.pi/8 < angle <= 5*math.pi/8: dr = "north" elif 5*math.pi/8 < angle <= 7*math.pi/8: dr = "northwest" elif 7*math.pi/8 < angle <= 9*math.pi/8: dr = "west" elif 9*math.pi/8 < angle <= 11*math.pi/8: dr = "southwest" elif 11*math.pi/8 < angle <= 13*math.pi/8: dr = "south" elif 13*math.pi/8 < angle <= 15*math.pi/8: dr = "southeast" elif angle < math.pi/8 or angle > 15*(math.pi/8): dr = "east" """ if math.pi/4 <= angle <= 3*math.pi/4: dr = "north" elif 3*math.pi/4 < angle <= 5*math.pi/4: dr = "west" elif 5*math.pi/4 < angle <= 7*math.pi/4: dr = "south" elif angle < math.pi/4 or angle > 7*(math.pi/4): dr = "east" """ sp_a.append(doc[2]['type']+" "+str(x)+" "+str(-1*y)+" ") if dr not in sp: sp[dr] = OrderedDict() sp[dr][doc[2]['type']] = 1 if sp: outputs.append("special") outputs.extend(sp_a) """ for key in ['west', 'northwest', 'north', 'northeast', 'east', 'southeast', 'south', 'southwest']: if sp.get(key): outputs.append(key) for subkey in sp[key]: outputs[-1] = outputs[-1]+" "+subkey """ return outputs class ParseScreenText: @classmethod def get_font(cls, text_image_list): found_tiles = OrderedDict() for image in text_image_list: for j in range(int(image.height/8)): for i in range(int(image.width/8)): subi = image.crop((i*8, j*8, i*8+8, j*8+8)) ss = image_to_string_format(subi, "BMP") found_tiles[ss] = found_tiles.get(ss,0)+1 seen = OrderedDict() c=0 for i, ch in enumerate(found_tiles): ss = image_to_string_format(reduce_to_colors(load_image(ch).convert("P", palette=Image.ADAPTIVE), ["FFFFFF"], 32), "BMP") if ss not in seen: c+=1 seen[ss] = ch im = Image.new("RGB", (8*c, 8)) for c, k in enumerate(seen): ch = seen[k] im.paste(load_image(ch), (c*8, 0)) kk = list(found_tiles.keys()) stra = [x for x in " >>ABCDEFGHIJ KLMNOPQRSTUVWXYZ',.123456789abcdefghijklmnopqrstuvwxyz-"] stra.extend(["..", "!", "?", " "," "," "," "," "," "," "," ",">",">"," "," ", "Mail", "Rod", " ", "Sword", " ", " "," "," "," "," "," ","Nunchucks", " ", " ","Hammer", " ", " ", " ", "Level", "/", "Weapon", " ", " ", " ", " ", "Status", " ", " ", " ", " ", " ", " ", ">", ">", " ", "E", ">", ">", "Fight", " ", " ", " "," ", " ", "Magic", " ", " ", " ", "Drink", " ", " ", " "]) output_dict = OrderedDict() kk2 = [seen[x] for x in list(seen.keys())] for i, ch in enumerate(kk2): subi = load_image(ch) new_subi = reduce_to_colors(subi.convert("P", palette=Image.ADAPTIVE), ["FFFFFF"], 32) str_image = image_to_string_format(new_subi, "BMP") if i < len(stra) and str_image not in output_dict: output_dict[str_image] = stra[i] return output_dict @classmethod def parse_screen(cls, im, font_dict): im = reduce_to_colors(im.convert("P", palette=Image.ADAPTIVE), ["FFFFFF"], 32).convert("RGB") text = [[]] for j in range(int(im.height/8)): for i in range(int(im.width/8)): subi = im.crop((i*8, j*8, i*8+8, j*8+8)) subi_key= image_to_string_format(subi, "BMP") value = font_dict.get(subi_key, " ") text[-1].append(value) text.append([]) output = list() current_output = "" si = 0 sj = 0 for j, line in enumerate(text): for i, ch in enumerate(line): if ch.strip() or current_output: if not current_output: current_output = ch si = i sj = j elif ch == ">" and current_output[-1] != ">": output.append([(si, sj), current_output]) current_output = ">" si = i sj = j elif ch == " " and current_output[-1] == " " and current_output[-2] == " ": output.append([(si,sj), current_output]) current_output = "" else: current_output += ch if current_output: output.append([(si, sj), current_output.replace("_","..")]) current_output = "" return output class TileTools: @classmethod def parse_tiles(cls, im, off_x, off_y, tilesize, partial_center=False): cx = off_x cy = off_y res = OrderedDict() rr = [[]] while True: if cx+tilesize < im.size[0]: sim= im.crop((cx, cy, cx+tilesize,cy+tilesize)) s = image_to_string_format(sim, format_type="BMP") if cy in [88, 104] and cx == 112: #if cy == 104 or partial_center == False: if partial_center == False: s = None rr[-1].append(s) cx+=tilesize elif cy+tilesize < im.size[1]-tilesize: cx= off_x cy+=tilesize rr.append([]) else: break return rr @classmethod def get_tiles(cls, im, off_x, off_y, tilesize): rr = cls.parse_tiles(im, off_x, off_y, tilesize) res = OrderedDict() for y, row in enumerate(rr): for x, tile in enumerate(row): if tile: res[tile] = res.get(tile,0)+1 return res @classmethod def find_tileset_offset(cls, im, tilesize): ress = list() for x in range(tilesize): for y in range(tilesize): tiles = cls.get_tiles(im, x,y, tilesize) ress.append([x,y,len(tiles), tiles]) ress.sort(key=lambda x: x[2]) return ress[0][0:2] def to_image_key(img): if isinstance(img, str): img = load_image(img) key = image_to_string_format(img, "BMP") return key class ScreenSelector: shop_image = load_image("iVBORw0KGgoAAAANSUhEUgAAAKAAAAAYCAIAAADyNGFiAAAAhUlEQVR4nO3UMQ6AIAxGYTTqGekJ6Rl1cSAQNnCqbd43Mf7hBVICAAAAAAAAAHOb9QA3cs7WEz5Q1Xog8JJat5RiPWSJiKTWmMBzY916d3827lTV3XqPD17qpjayfzaH6RhP6sWdelsPmXjyJSI9MC84OAIHR+DgCBwcgYMjcHAEDo7Awb3rRh8l+sp+JAAAAABJRU5ErkJggg==") battle_image = to_image_key("iVBORw0KGgoAAAANSUhEUgAAAQAAAAAICAIAAACZNLboAAAAgklEQVR4nO3UMRKAIAwEQHR8ZPJCeKZFGiQClUxObkuhOG4SUyIiIiLazjG9ISILcpAppTRfsPr3+YObLIC1n3NeEmZ3qpqeM4TVv88f32gB6vbtbfSdumebIaz+fX4I5/gYpf0fsJKbnz1Q/6/547umN+B2GpSIqKofIJT+e/mDuwF7dj4gb9hPPAAAAABJRU5ErkJggg==") char_select = to_image_key("iVBORw0KGgoAAAANSUhEUgAAAQAAAAAgCAIAAAByyzGzAAAAjklEQVR4nO3W0QlCMRAEwCiWpL3kKkx60aL8CMorIK7wmGlguT0upDUAAAAAAAAAAAAAAAAAAAAAAAAAgL+5xJJ677GsvDlnOFGfW4QOYG1rjJGJC6uqlr0Bfe6SOIDjttZsZ3KcK7MzfW50/XXActZttc9Q4cdYn7vcMjHte9PPeywxoz9eVZX/jehzizf4UD4gJtsg3gAAAABJRU5ErkJggg==") empty_orb = to_image_key("iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAAdUlEQVR4nJVSwRGAMAijPTdxBd1FdnKPuIsO5cM7jIjU5lcuITnSIuMqPRjeo2U++Lnt06fAqADuqSrLikVyi1mppKl54ovKhjVZzxrjNBxctg6BIThrkuqvAwAfybXj2MxpR6I8zx4SEwmbNuR/KRDk6O7hBC14K/+LWlBvAAAAAElFTkSuQmCC") item_sub_menu = to_image_key("iVBORw0KGgoAAAANSUhEUgAAAQAAAABcCAIAAAAOK/wJAAAAuklEQVR4nO3WsQ0CMQwF0IAYCXaJJ0x2gaEorrkqvuKIdOS92rJc/K+kFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABggls6UWudcAf8Qu99PJAUYEt/a+20i2CWiChZB0YF2Kd/2wVXsc/toAP341vgQrbQpp+Xx8FF/f085SyYo74+EZEWIHkB4L8pAEtTAJamACztC+hvHx3TeOZ7AAAAAElFTkSuQmCC") formation_menu = to_image_key("iVBORw0KGgoAAAANSUhEUgAAAQAAAAAwCAIAAABxHTMoAAAAqElEQVR4nO3VwQ0CIRRFUTSWpL1AhdCLFuUCF7OcmEl+4J9TwQvDHUoBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALjcLXpAmFpr9ISFjTGiJ1wjaQDz9vfeo4csqbVWdmkgYwDH2z+/Jecdz22DBu7RA2K4/X+bh7bN4/mIHhDm9w97P6OHLKa+Pq21bQJI+gLAJABSEwCpCYDUBEBqAiA1AZCaAEjtC0NpHyXvFRJOAAAAAElFTkSuQmCC") empty_battle_char = to_image_key("iVBORw0KGgoAAAANSUhEUgAAABAAAAAYCAIAAAB8wupbAAAAEklEQVR4nGNgGAWjYBSMgsEFAASYAAHgYt7ZAAAAAElFTkSuQmCC") empty_battle_char = to_image_key("iVBORw0KGgoAAAANSUhEUgAAAAgAAAAYCAIAAABIuytHAAAAD0lEQVR4nGNgGAWjgPoAAAJYAAGgxYwDAAAAAElFTkSuQmCC") battle_enemies_dict = dict() font_dict = dict() luds = dict() @classmethod def _load_content(cls, fonts, tilesets, spritesets, filename_lud, enemy_filename): if enemy_filename: cls.battle_enemies_dict = json.loads(open(enemy_filename).read()) else: for filename in os.listdir("./"): if filename.startswith("enemy_") and filename.count("_") > 1: n = filename.partition("enemy_")[2].partition(".png")[0].partition("_")[0] key = to_image_key(Image.open(filename)) cls.battle_enemies_dict[key] = cls._parse_enemy_name(n) ff = open("./enemy_lookup.dat", "w") ff.write(json.dumps(cls.battle_enemies_dict)) ff.close() cls.luds = json.loads(open(filename_lud).read()) #images have different bmp headers sometimes, so reformat them here. new_dict = dict() for key, val in list(cls.luds['plud']['person_dict'].items()): new_dict[image_to_string_format(load_image(key),"BMP")] = val cls.luds['plud']['person_dict'] = new_dict new_dict = dict() for key, val in list(cls.luds['lud'].items()): new_dict[image_to_string_format(load_image(key), "BMP")] = val cls.luds['lud'] = new_dict image_list = [Image.open("text"+str(i)+".png") for i in range(7)] cls.font_dict = ParseScreenText.get_font(image_list) cls._load_worldmap() @classmethod def _parse_enemy_name(cls, n): n = n.lower() if n == "blue d": return "blue dragon" elif n == "frost d": return "frost dragon" elif n[:2] == "fr" and len(n)>4: return "frost "+n[2:] elif n == "gas d": return "gas dragon" elif n == "grey w": return "grey worm" elif n[:2] == "gr" and len(n)>4: return "greater "+n[2:] elif n == "irongol": return "iron golem" elif n == "manticor": return "manticore" elif n == "mudgol": return "mud golem" elif n == "r.goyle": return "red gargoyle" elif n == "red d": return "red dragon" elif n[:2] == "r." and len(n)>4: return "red "+n[2:] elif n == "rockgol": return "rock golem" elif n == "saber t": return "saber tooth" elif n == "sand w": return "sand worm" elif n == "tyro": return "t rex" elif n == "wzvamp": return "vampire wizard" elif n[:2] == "wz" and len(n)>4: return n[2:]+" wizard" elif n == "zombied": return "zombie dragon" elif n == "zombull": return "zombie bull" else: return n @classmethod def parse_whole_screen(cls, image): #image_list = [Image.open("text"+str(i)+".png") for i in range(7)] #f = ParseScreenText.get_font(image_list) map_data = dict() text = ParseScreenText.parse_screen(image, cls.font_dict) if text: if cls.is_shop(image): return 'shop', cls.shop_parse(image, text), map_data elif cls.is_battle(image): return 'battle', cls.battle_parse(image, text), map_data elif cls.is_menu(image, text): return 'menu', cls.menu_parse(image, text), map_data else: return 'text', cls.text_box(image, text), map_data else: if cls.is_world_map(image): return 'world', cls.world_map_parse(image), map_data else: k, map_data=ParseScreenObstructions.parse_screen(image, cls.luds['tile_info'], cls.luds['lud'], cls.luds['plud'], partial_center=True) return 'map', k, map_data world_map_title = to_image_key('iVBORw0KGgoAAAANSUhEUgAAAIAAAAAgCAIAAABVQOdyAAAD80lEQVR4nO1avXHzMAxFfGlTaRAtoMqdh/B5sK/SaQh3rryABnHl3vcVjJFn/JGiLKbJuxQ5EgRIgCLAR39Q94+2x/F2jgWm7mCKpXatB9vFKLNL6MnOypTfAp8NbKR1jvOAjaf++tLYn9Oax3k49VduH+m+238Zep7y3MgKp71hlxvjWf3gqX9r7LY24Hl/nAds1I5IDvX0jPPA+zc1JoU8KuNfyyhajAe+EZsHgJ7bE/+ClWf1EHw9ycs8/NRfcdvqeAjglHRX4epWokUACI5UdD17c+oOJQsOZFKXODRejjK1o6fuYB4yKR7NckCLAOz2X8GBkJaaXbB2rqeQIXr1R2DOygvMRtg8AObeZ5z66+NyF42BW3VXOvo95fiPGY9mZ72HRkeQiazjYqB/9ZAUeDOT4wTKZ7sRfjMApuPeC+HibK3VHu0CYC51nAcu88uViGPH3Mi42VEA23/d+9S4Clq5YE4nQfmISH4XkhyMxsnWQ7ubcMKaGHi1vMgl2tzUHY63M1elScAsq4jocbnjJLcO0sfWXJAoNtgLvEhB3eg7mqAcRC82evWu2R4XxyhWvNYaNLoJi/+TW8UhEHhf68Fe8VWZQRKS+kTSaFAjUJsjyKsRs5LeKaF7v7useJhKMJ14026TITY/gv4QY9UXUMjyC2FvZ5Vz/d4DgGei3LQ3eXJSd1ZzFvUB0Ec2vfJfRAZrTxY1LwRirt/InL2836KJZaYRvfT4OA/4TmDOeSkqj6Ai7xORVWzoukK7ICVYYcVs1MDUnTXtrQXnL8S8Z4O6eqmmCkpTERR/zPJnqfmlXD+pG5YnljUttPE0dvsv4VOsesX7T3W9VF+GYhHpsfy8gJiap3ABom7hxwN+wiQoGfU5kDXtdR1v5zjJveW+tuoekE3CjJiaX8r16wecYP2xaUEZ8aWa/8cwaGqPWx6Xu+bVS1CZhHlre9tZZEL2KTMHOh+aXL9WblYjAbKmMcnr4Yku9HIewSdI9H0RWYSaLyBevGb5Kz7PmOvHF/kYhb9G0XNe+lBcTe29n4rwbvBihXUfrKdtkXDJTwLilwM8psqnYWJtAEpY/hJqnuCLznL95nBuxPZFpk14uf1dWBWA8mnF1Dy9kjMlXD8Oj8m47KuAKWOStdrWerZu1U2YXqtsTyYhoOY9aK4f21EtFiqn/krdYZFp062sitv59hPMeSkqA4A3zBF+TPizfdSV1SQDcBRrS10l6zRjMz29L86xrGlTlbZoJ+f294BClh8RUPOFXL8ebo4yFRaa1qoEOEvx17kmQ9RzQbrRYwq1AHZNr8cFSgqx2Lqnf6lpcy2kaKWE9Sn67z1gAbK/nq/Afw+oxUTPNFf0AAAAAElFTkSuQmCC') @classmethod def is_world_map(cls, image): if to_image_key(image.crop((64,16,192,48))) == cls.world_map_title: return True return False @classmethod def _load_worldmap(cls): cls.world_mask = load_image("iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAIAAABMXPacAAAAxklEQVR4nO3cMQ6DMAwFUNT739kduiCVoQ0h/IT3dkSIDRgD2TYAAAAAgOlU1b+bvBIGsYbHHjgAAAxXVQpwZnOYsxI5gjAAXahPftG/Hd3sO1oh8QsZBsDTuRwDAAAAAABxfJkAAACw5xEJOEmzBQAAAADW16UJGLRayly0YLmS/GJ1I3Pc+XRg2KvEz17E4DamHgA4L3ZxWwC4ilsdrZpzR9KRR1YCACxPyQcAQDqr5tzM7M+ag/4RAwCAnRmLegAAAPK9Aa6QfYsCj718AAAAAElFTkSuQmCC").convert("RGB") cls.locals = list() for i in range(cls.world_mask.width): for j in range(cls.world_mask.height): if cls.world_mask.getpixel((i,j)) == (255,255,255): cls.locals.append((i,j)) new_output = list() for x1,y1 in cls.locals: for tup in new_output: for x,y in tup: if abs(x1-x)+abs(y-y1) < 3: tup.append((x1,y1)) break else: continue break else: new_output.append([(x1,y1)]) new_output2 = list() for tup in new_output: cx = 0 cy = 0 cc = 0 for x,y in tup: cx+=x cy+=y cc+=1 cx = int(cx/float(cc)) cy = int(cy/float(cc)) new_output2.append([cx,cy,cc]) landmark_types = ["Gaint's cave", "Sage's cave", "Gaint's cave", "Waterfall", "Onrac", "Earth cave", "Cardia", "Melmond", "Cardia", "Cardia", "Cardia", "Dwarf cave", "Northwest castle", "Marsh cave", "Cardia", "Cardia", "Castle of Ordeal", "Temple of Fiends", "Elfhland","Corneria", "Matoya's cave", "Guru volcano", "Mirage Tower", "Ice cave", "Pravoka", "Crescent lake", "Gaia", "Lefein" ] for i, tup in enumerate(new_output2): tup.append(landmark_types[i]) tup.extend([[110, 118, "Desert"], [108, 25, "Landing spot"], [20,39,"Landing spot"], [60,18,"Landing spot"]]) cls.world_landmarks = new_output2 @classmethod def world_map_parse(cls, image): cropped = image.crop((64, 48, 192, 176)).convert("P", palette=Image.ADAPTIVE) p = cropped.getpalette() new_palette = list() default_color = (0,0,0) threshold = 32 for i in range(256): r = p[3*i] g = p[3*i+1] b = p[3*i+2] for cc in [(0,19,155), (0, 120,82), (17, 209, 164), (233,211,134)]: val = (cc[0]-r)**2+(cc[1]-g)**2+(cc[2]-b)**2 if val <= threshold**2: new_palette.extend(default_color) break else: new_palette.extend((255,255,255)) cropped.putpalette(new_palette) cropped = cropped.convert("RGB") outputi = ImageChops.difference(cropped.convert("RGB"), cls.world_mask.convert("RGB")) for c in outputi.convert("RGB").getcolors(): if c[1] == (255,255,255): if c[0] > 0: break else: return [] cx = 0 cy = 0 n = 0 for i in range(outputi.width): for j in range(outputi.height): if outputi.getpixel((i,j)) == (255,255,255): cx+=i cy+=j n+=1 cx = int(cx/float(n)) cy = int(cy/float(n)) output = list() output.append("location: "+str(cx*2)+", "+str((outputi.height-cy)*2)+", ") for entry in cls.world_landmarks: if abs(entry[0]-cx)+abs(entry[1]-cy) < 32: zx = entry[0]-cx zy = cy-entry[1] zc = entry[2] z_name = entry[3] #if zc > 1: # typ = "major" #else: # typ = "minor" typ = z_name string = typ+", "+str(zx*2)+", "+str(zy*2)+"," output.append(string) print(output) return output @classmethod def is_battle(cls, image): #check for battle backgrounds color1 = image.getpixel((0,0)) crop = image.crop((0,0,256, 8)) crop = replace_color(crop, color1, (0,0,0)) key = to_image_key(crop) if key == cls.battle_image: return True return False @classmethod def battle_parse(cls, image, text): textbox = list() player_names = ["" for x in range(4)] player_hps = ["" for x in range(4)] for tup, string in text: x,y = tup if x >= 26 and y< 26: textbox.append(string) if y == 4: player_names[0] = string.strip() elif y == 7: player_hps[0] = string.strip() elif y == 10: player_names[1] = string.strip() elif y == 13: player_hps[1] = string.strip() elif y == 16: player_names[2] = string.strip() elif y == 19: player_hps[2] = string.strip() elif y == 22: player_names[3] = string.strip() elif y == 25: player_hps[3] = string.strip() textbox = " ".join(textbox) enemy_names = list() for tup, string in text: x,y = tup if x == 3 and y >= 19: enemy_names.append(string.strip()) enemies = list() coords = [(16, 40, 32, 32)] enemy_count = OrderedDict() boxes_to_check = list() for i in range(3): for j in range(3): x = 16+32*i y = 40+32*j w = 32 h = 32 boxes_to_check.append(((x,y,w, h), (i,j), i*3+j+1)) #check for big enemy plus 3 small for i in range(3): for j in range(3): x = 32+32*i y = 40+32*j w = 32 h = 32 boxes_to_check.append(((x,y,w,h), (i,j), j+1)) #check for garland box #boxes_to_check.append(((64, 72, 32, 32), (1,1), 1)) #check for big enemies v1 for i in range(2): for j in range(2): x = 16+64*i y = 40+48*j w = 48 h = 48 boxes_to_check.append(((x,y,w,h), (i*2,j), i*2+j+1)) #check for big enemies v2 for i in range(1): for j in range(2): x = 16+48*1 y = 40+48*j w = 48 h = 48 boxes_to_check.append(((x,y,w,h), (i,j), i*2+j+1)) #boss box check boxes_to_check.append(((16+24, 40+24, 48, 48), (1,1), 1)) #chaos box check boxes_to_check.append(((16, 40, 96, 96), (1,1), 1)) for box, coord, num in boxes_to_check: x,y,w,h = box subi = image.crop((x,y,x+w,y+h)) res = cls.battle_enemies_dict.get(to_image_key(subi)) if res: i,j = coord enemies.append((i,j, res, num)) enemy_count[res] = enemy_count.get(res,0)+1 enemy_string = "" for ekey in enemy_count: enemy_string = enemy_string+" "+str(enemy_count[ekey])+" "+ekey enemy_string = enemy_string.strip() status = [] attacker = "" defender = "" attack_type = "" exp_string = "" status_text = "" for tup, string in text: x,y = tup if (2,20) == tup: attacker = cls._parse_enemy_name(string.strip()) elif (2,23) == tup: defender = cls._parse_enemy_name(string.strip()) elif (2,26) == tup: status_text = string.strip() elif (12,23) == tup: attack_type = string.strip() elif (12,20) == tup: exp_string = string.strip() if "DMG" in attack_type: attack_type = attack_type.partition("DMG")[0]+" Damage" if attacker and defender: if attacker.lower().strip() == "exp up" and\ defender.lower().strip() == "gold": status = ["Exp Up: "+exp_string] if attack_type: status.append("Gold gained: "+attack_type) elif attacker.lower().startswith("lev. up!") and\ defender.lower().strip() == "hp max": if attack_type.strip(): status = ["Level up! "+attacker[8:]+" ", "HP Max: "+attack_type.partition("pts.")[0]+" points."] else: status = ["Level up! "+attacker[8:]+" "] else: if exp_string.strip() and not "hits" in exp_string.lower(): status = [attacker+" uses "+exp_string+" on "+defender] if attack_type: if "DMG" in attack_type: status.append(attack_type.partition("DMG")[0]+" Damage") else: status.append(attack_type) else: status = [attacker+" attacks "+defender] if attack_type: status.append(attack_type) elif attacker and exp_string and attacker.strip() in player_names: status = [attacker+" uses "+exp_string] if status_text: lookup = { "str. up": "Strength up.", "agi. up": "Agility up.", "vit. up": "Vitality up.", "int. up": "Intelligence up." } status.append(lookup.get(status_text.lower(), status_text)) menu = "" #print(text) magic = False for tup, string in text: x,y = tup if 2 <= x <= 21 and 19 <= y <= 25: if ">" in string: menu = string.partition(">")[2].strip().split(" ")[0] for tup2, string2 in text: x2,y2 = tup2 if y2 == y and x2 == 21 and menu: menu += " left "+string2 elif y2 == y and x2 <= 21 and menu and (string2.strip().split(" ")[-1].isdigit() or string2.strip().split(" ")[-1] == "O"): menu += " left "+string2.strip().split(" ")[-1] elif 0 <= x <= 8 and 5 <= y <= 13: i = int(x/4) j = int((y-5)/4) c = (3*i+j)+1 for tup_x, tup_y, enemy, num in enemies: if (tup_x, tup_y) == (i,j): menu = enemy+" "+str(num) enemy_string = "" break elif 15 <= x <= 20 and 6 <= y <= 18: if ">" in string: if y == 6: menu = player_names[0]+" hp "+player_hps[0] elif y == 9: menu = player_names[1]+" hp "+player_hps[1] elif y == 12: menu = player_names[2]+" hp "+player_hps[2] elif y == 15: menu = player_names[3]+" hp "+player_hps[3] curr_selected = -1 for i in range(4): ii = image.crop((160, 41+i*24, 168, 41+(i+1)*24)) if image_to_string_format(ii, "BMP") != cls.empty_battle_char: curr_selected = i character = "" if curr_selected >=0 and menu.replace(">","").strip() in ["Fight", "Magic", "Drink", "ITEM", "RUN"]: character = player_names[curr_selected] #print(enemy_names, ":::") if not menu.strip() or not " ".join(enemy_names).strip() or ">" in " ".join(enemy_names): enemy_string = "" if status: enemy_string = "" res = {"textbox": textbox, "enemies": enemies, "status": status, "enemy_string": enemy_string, "menu": menu, "enemy_names": enemy_names, "character": character} #print(res) return res @classmethod def is_menu(cls, image, text): raw_text = " ".join([x[1] for x in text]) #test main menu if not raw_text: return False elif "CONTINUE" in raw_text and "NEW GAME" in raw_text\ and "RESPOND RATE" in raw_text: return "main_menu" elif cls.char_select == image_to_string_format(image.crop((0,0,image.width, 32)), "BMP"): return "char_select" elif ("A B C D E F G H I J" in raw_text \ or "K L M N O P Q R S T" in raw_text)\ and "SELECT NAME" in raw_text: return "name_select" elif "ARMOR" in raw_text and "Weapon" in raw_text and\ "Status" in raw_text: return "player_menu" elif "ITEM" in raw_text and text[0][0] == (2,2): return "item_menu" elif cls.item_sub_menu == image_to_string_format(image.crop((0,0,image.width, 92)), "BMP"): return "item_sub_menu" elif "L1" in raw_text and "L2" in raw_text and\ "L3" in raw_text and "L4" in raw_text and "L5" in raw_text and\ "L6" in raw_text and "L7" in raw_text and "L8" in raw_text and\ raw_text.count("/") > 7: return "magic_menu" elif text and text[0][0] == (2,2) and text[0][1].strip() == "Weapon": return "weapon_menu" elif text and text[0][0] == (2,2) and text[0][1].strip() == "ARMOR": return "armor_menu" elif "EXP.POINTS" in raw_text and "FOR LEV UP" in raw_text: return "status_menu" elif cls.formation_menu == image_to_string_format(image.crop((0,0,image.width, 48)), "BMP"): return "formation_menu" else: pass #import pdb #pdb.set_trace() return False @classmethod def menu_parse(cls, image, text): menu_type = cls.is_menu(image, text) output = list() if menu_type == "main_menu": for i, (pos, entry) in enumerate(text): if ">" in entry: output.append(text[i+1][1]) if entry.strip() not in ['CONTINUE', 'NEW GAME']: output.append(entry) elif menu_type == "char_select": output = list() cursor = 0 trans_dict = {"Bl.BELT": "black belt", "RedMAGE": "red mage", "Wh.MAGE": "white mage", "Bl.MAGE": "black mage"} for pos, entry in text: if ">>" in entry: if pos == (6,7): cursor = 1 elif pos == (20, 7): cursor = 2 elif pos == (6,19): cursor = 3 elif pos == (20, 19): cursor = 4 if cursor > 0: cc = 0 char_type = 0 for pos, entry in text: if entry.strip() in ["FIGHTER", "THIEF", "Bl.BELT", "RedMAGE", "Wh.MAGE", "Bl.MAGE"]: cc+=1 if cursor == cc: char_type = trans_dict.get(entry.strip(), entry) char_type = char_type.strip().lower() output.append("Character "+str(cursor)) output.append(char_type) else: chars = list() pos_names = list() for pos, entry in text: if entry.strip() in ["FIGHTER", "THIEF", "Bl.BELT", "RedMAGE", "Wh.MAGE", "Bl.MAGE"]: char_type = trans_dict.get(entry.strip(), entry) char_type = char_type.strip().lower() chars.append(char_type) else: the_name = entry.strip() if pos[1] == 11 and pos[0] < 20: pos_names.append([the_name, 1]) elif pos[1] == 11 and pos[0] > 20: pos_names.append([the_name, 2]) elif pos[0] < 20: pos_names.append([the_name, 3]) else: pos_names.append([the_name, 4]) for i in range(4): for _, c in pos_names: if i+1 == c: break else: pos_names.append(["blank", i+1]) pos_names.sort(key=lambda x: x[1]) names = [x[0] for x in pos_names] for i in range(len(names)): output.append(chars[i]+" "+names[i]) elif menu_type == "name_select": name = "" current_char = "" lookup = {"'": "apostrophe", ",": "comma", ".": "period", "": "space", "-": "dash", "..": "dot dot", "!": "exclamation mark", "?": "question mark"} for pos, entry in text: if pos[1] == 3: name = entry[:-2] if ">" in entry: char = entry.split(">")[-1].split(" ")[0] if char == "O": if pos[1] == 15: char = "0" if char.isupper(): char = "uppercase "+char.lower() elif char.islower(): char = "lowercase "+char.lower() elif char.isdigit(): pass else: char = lookup.get(char, char) current_char = char output.append("Input character name") output.append(name) output.append("selected character: ") output.append(current_char) elif menu_type == "player_menu": orbs = 0 for x in range(2): for y in range(2): orb=image.crop((32+x*16,24+y*16, 32+16*(x+1), 24+(y+1)*16)) orb_bmp = image_to_string_format(orb, "BMP") if orb_bmp != cls.empty_orb: orbs+=1 orbs = str(orbs)+" orbs" gold = "" menu = "" curr = -1 names = ["" for x in range(4)] for pos,string in text: if pos[1] == 11 and pos[0] < 8: gold = string.replace("G", "Gold") if ">" in string and string.replace(">","").strip(): menu = string.replace(">", "") elif ">" in string: if pos == (10, 1): curr = 0 elif pos == (19, 1): curr = 1 elif pos == (10,15): curr = 2 elif pos == (19,15): curr = 3 elif pos[1] == 2: if 12 <= pos[0] <= 16: names[0] = string.strip() elif 22<= pos[0] <= 26: names[1] = string.strip() elif pos[1] == 16: if 12 <= pos[0] <= 16: names[2] = string.strip() elif 22<=pos[0]<=26: names[3] = string.strip() if not menu: if curr>= 0: menu = names[curr] output.extend(["Player Menu", orbs, gold, menu]) elif menu_type == "item_menu": menu = "" for pos, string in text: if ">>" in string: menu = string.partition(">>")[2].split(" ")[:2] menu = " ".join(menu).strip() output.extend(['Item Menu', menu]) elif menu_type == "item_sub_menu": des = "" seek = None names = list() hp1 = list() hp2 = list() curr = -1 for pos, string in text: if pos[1] == 12: if ">" in string: curr = len(names) names.append(string.strip()) elif pos[1] == 15: hp1.append(string.strip()) elif pos[1] == 16: hp2.append(string.strip().replace("/", "of ")) if pos[1] >= 22: des+=string+" " if des: output.append(des) if curr>= 0: output.append(names[curr]+" hp "+hp1[curr]+" "+hp2[curr]) else: for i in range(4): output.append(names[i]+" "+hp1[i]) elif menu_type == "magic_menu": name = "" curr = -1 levels = ["" for x in range(8)] des = "" for pos, string in text: if pos[0] == 3: if pos[1] == 2: name = string.strip() elif "/" in string and string[0] == "L": num = (pos[1]-4)/2 levels[num] = string.partition(" ")[2].strip() elif ">" in string: curr = (pos[1]-4)/2 magic = string.replace(">","").strip() elif pos[1] >= 23: des+=string.strip()+" " des = des.strip() output.append(name) if des: output.append(des) if curr >= 0: output.append(magic+" "+levels[curr].replace("/", " of ")) else: output.append("no spells available") elif menu_type in ["weapon_menu", "armor_menu"]: names = ["" for x in range(4)] menu = "" curr = -1 for pos,string in text: if pos[0] <= 7 and pos[1] in [6,12,18,24]: names[(pos[1]-6)/6] = string elif pos[1] == 2 and pos[0] >= 9 and ">" in string: menu = string.partition(">>")[2].split(" ")[0].strip() elif ">" in string: if 6 <= pos[1] < 12: curr = 0 elif 12 <= pos[1] < 18: curr = 1 elif 18 <= pos[1] < 24: curr = 2 elif 24 <= pos[1]: curr = 3 if string.replace(">", "")[:2] == "E-": menu = "equiped "+string.replace(">", "")[2:].strip() else: menu = string.replace(">", "").strip() output.append(menu_type.replace("_", " ")) if curr>=0: output.append(names[curr]) if menu: output.append(menu) elif menu_type == "status_menu": lud = {"STR.": "strength", "AGL.": "agility", "INT.": "Intelligence", "VIT.": "vitality"} lud2 = {"Wh.MAGE": "white mage", "Bl.MAGE": "black mage", "Bl.BELT": "black belt", "RedMAGE": "red mage", "FOR LEV UP": "for level up", "EXP.POINTS": "experience points"} for pos, string in text: if pos[0] == 24 and pos[1] == 4: output.append(string.strip().replace("LEV", "Level ")) elif pos[1]<12: output.append(lud2.get(string.strip(), string.strip())) elif pos[0] < 16: output.append(lud.get(string.strip(), string.strip())) for pos, string in text: if pos[1] >= 12 and pos[0] >= 16: if "HIT" in string: output.append("Hit percent") elif "EVADE" in string: output.append("Evade percent") else: output.append(string.strip()) elif menu_type == "formation_menu": names = ["" for x in range(4)] curr = -1 for pos, string in text: this_curr = -1 if pos[1] == 7: this_curr = 0 if pos[1] == 11: this_curr = 1 if pos[1] == 15: this_curr = 2 if pos[1] == 19: this_curr = 3 if this_curr >= 0: names[this_curr] = string.replace(">","").strip() if ">" in string: curr = this_curr output.append("formation menu") if curr > -1: output.append("position "+str(curr+1)+" "+names[curr]) return output @classmethod def is_shop(cls, image): dd = ImageChops.difference(image, cls.shop_image).convert("RGB") p = dd.resize((1,1), resample=Image.BILINEAR).getpixel((0,0)) if p[0] == 0 and p[1] == 0 and p[2] == 0: return True return False @classmethod def shop_parse(cls, image, text): title = text[0][1].strip().title() textbox = list() for box, l in text: if box[0] < 7 and box[1] < 18: textbox.append(l.strip()) textbox = " ".join(textbox).replace(" ", " ") if text[0][1].strip() in ["INN", "CLINIC"]: if len(text) > 2 and text[2][1].strip() == "Gold": textbox+=" Current "+text[-1][1].strip() elif text[0][1].strip() in ['WEAPON', "ARMOR", "WMAGIC", "BMAGIC", "ITEM"]: if textbox.endswith("Gold OK?"): textbox+=" Current "+text[-1][1].strip() select_menu = "" sx = 0 sy = 0 print(text) for box, l in text: if 20 < box[0] < 30 and 2 < box[1] < 24: if ">" in l: select_menu = l.replace(">", "").strip() sx, sy = box[0], box[1] elif select_menu != "" and sx==0 and sy == 0: sx, sy = box select_menu = (select_menu+" "+l).strip() if (sx,sy) != (0,0): for box, l in text: if box[1] == sy+2 and sx< box[0] <= 29: select_menu = select_menu + " "+l.strip() menu = "" for box, l in text: if 4 < box[0] < 8 and 18 < box[1] < 26: if ">" in l: menu = l.replace(">", "").strip() result = {"title": title, "text": textbox, "menu": select_menu+" "+menu} print(result) return result bridge_scene = to_image_key('iVBORw0KGgoAAAANSUhEUgAAAFgAAAAgCAIAAAAZhijPAAADBUlEQVR4nM1ZO47CMBCdjVIgyoiU1BwoZ1hFkU+QE3CCCCHOkANRU7JyuaJCWzg4zviTGceEfaKA2LGfx+OZ8eOr+7kCGU27Px1v9P7J0bT7TD4AAPqCxXwWuZ6A0juTj87VP7tsFS3zudNkuoPZKurSMVnqpYaRg2nmWfQFnK9Nu88uWwB4fv9m8qEZ43F2B7QSZQX1bnccmkRdQl+MnSq5ZD3RyAFALUb91mtz9lYL0/uf1Q9z39SLwwgAUEmxw7uqmiYPjRGUazyLDXVj0iE3qZhbGnDL7ueq9lbAlK4ap+UxmFhhGIF0TtMig+CaQ29am+YYp5Jid4gitjYyYj9iNB3hOVw+jO7wIeTOp8/vX+Th2WWrwxsR3fku6tIZKRCadt8UAGhSwosJ4TYEdvt37hUjZ70TbkMATHw72gqzTiHqUvRbAIBKfjaJegyxynHVccEOEE27dgalBstodOc7gDt9dOe7z9yn4+1ZbNZMOssM0ReqptB0hwPvdCiPtyfPFyYfOvwxgoJKUnx4iBSu0oMIUZfd+W6GVTuvacTNEuMRJiH3XaOSoi7NbRkOCOD6YrhuVdK+d42nA11GXvP6PnH+FeMR6takMd41PM+Hny+/QBcN/VX0nvT0Whga34e4U/Y1jdWJb/sf1y8QAnwiYwRXv1Cg6w4RugaFEqqPTT4xhuDqF+OstJIpQtcgUZpaHPHJhTXN7Lng6hf2sGHdgatraKHIhE0ssExRl7meJlQCIDD1C9RhXndg6hpaKNKgrAXxyQBUOUC2woKrBxFcXcNtBSaGOiI6/frgC13sOpKpa3Ch+eTPYjNEnQVWIOoXcboDXdfgwuSTn443ruJig6Jf/BPdQQPxWXbXMBHULxbqDsmdwuaTyBDBY/+vdAcfn7frEZBIdwjoGhSYRaSTzxqGGKmQ80WEroGB6jcr+yA+6WJECijdwdfK0zUqKerXd8IGMP7XQBIDCyzdIULXMHnqC3SgBrH5kDyCVXe6sUB3IOkaL5yON9gddKvYFe6eFp8/JVyxsafgBGkAAAAASUVORK5CYII=') bridge_credits = [ (to_image_key("iVBORw0KGgoAAAANSUhEUgAAAIAAAABQCAIAAABeYuqzAAABjklEQVR4nO3Y25KDIAyAYXD6/q/MXnSboUmAoGjt9P+utAshKCc3JQAAAAAAAAAAAAAAAADAUlmuSin/P+XcKOx41pqqcqWbp5dS2j6dwDKlFBlD9wk19Khvcs6q4fpWjaPZFFV5ibZv5rWCx4d8p137i4RdPqU2lU3ynuyzPVsmnkfd2ycbx777+DuWgHXwTihp1445t7xk2Kqy29sSdN68q5/4ZbNbtR550Nfb0vtwaOV6nB34w/LLc7BNuDMmUnFVDjs3YfWehg+0vNTVVRy7x0z1c2roSOE7TALcxvcOh+/NXB9DP5XH9YYn7Guexrhh97xsj4/qWoWKfE9E4rfMxk+vPSa408S/h2Zf22AT7pzTXf3zcud7QhWuN8kU7lU8fv1Xq7WgteJLEyrtyPUt/hXhdlidlNbGnx1YLce/bx5S/4wlb2rkKgsX4lNX8/otytR3m3avN7l3O9xahfctEZ3s1QjaF7afp7vEHUneRv6pUwwAAAAAAAAAAAAAAAAAAAAAAAAAAADwu/4AM1mC7+a34rIAAAAASUVORK5CYII="), "And so, their journey begins..."), (to_image_key('iVBORw0KGgoAAAANSUhEUgAAAIAAAABQCAIAAABeYuqzAAABz0lEQVR4nO3Z0XaDIAyAYejp+78yu2iHEQIGjMp2/u9ix1UlCAKhDQEAAAAAcLuUUkpJ/bc4hcL59nl5VSV7sM/U0F71uei53kWMGKO9Qp8DeYscOsUpezn5XnlQnFULrz/p1KdozX5VXZ5LZRoBaufHGD9Fy1M5WD57SC1n7vq6nq36yNaxVLX/XHXc3E/5NWrZOuBznXq1+sBPDW2XuHI8eZU2N/vtRsDo/GO/3qscr7hh/y5ftGhZhtcr/D5P/bdfdKhmRvXURDn5w+KgH9cYIt8oX09Lj849F2nk6pq96jLM3TlOQYsE2tLQ1Vr8tiZ41rv+qNgNdPJ9OS0WxyebzyvvbtXTUo6l/PN2aWgnn+3UTJLLZpECDy1HXnm3XAyDufVbG7qhddho6wDjlmQFQ3l3kUGtRpmCHCsqizrcE/qGyxZfSw6+imjNnqNDOwx+0RQGx3sr7x5t/dY+Y2gVASpsCFvmfw+gTV18F+E6dcs6+XWYmhZbKd1h3HqTMbquLEj5NrS1iKmNNZq5qh1mj/v/+P8k2UEWUbu1Ay56o//0ajS5DwizrWm8S43b+Z0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADgOj9pHOL9uqLofgAAAABJRU5ErkJggg=='), "What awaits the Four, they do not know."), (to_image_key('iVBORw0KGgoAAAANSUhEUgAAAIAAAABQCAIAAABeYuqzAAADsElEQVR4nO2Z0ZbrIAhFTVf//5czD5k6BAFBMUnvPfuptQqIimBLAQAAAAAAAABwKVspZd934YdtGxB3iPKPjfbvDhkQeC/v+umLjI4SWhW6HS/wybtt2vedKq4GMWu09iyi8sVzrEmwvbxtG3NC1E7/Kr7omIPWmkME/YnuqXaIKMeeA+tvyxclFDMuGWFWtN9l90eIJsdj/98CbB9aa+zNJe6gruKZ/uuILnyJ7zbGq21qj5JxiCbVfzvzd74QgqhP2V4Q21fcAVH5mp3fohfcxu8is6WL3irph2B1Oi/ON7E9bA3LcI6v0fYxxOEDMv1Dsuab4gehDrgSFj09O4jdQ8NyHkJ/AeiqemqNkAuOkkfrL/5Uw+BOaiVbTqt0zNoVCGkog06StRs1SAqi8KzEty7hvcelvwAlWJgsnU/Whr1941f6WRC78ethb/vXbtGJte5gurTQp43yqGOIm+yiLAiAp5B1wfgV3ZyGDqBlX5epzlX6bkWLob9VbOTj0dgtoumt8if/nxgI36H/Fbp++/3VlsUWRrNAuwnrkKh3uvI1pdF72PBOaLJawlLOfmv7n/4PMBS3kTEULqkFzlGa0kIm5tQetSeruPFM9vQcXZS90/5X49xotAOV0DXrgjw9ZM+MCnsWwpFheJ4iinL6up0Nuqn3zB3QNd6YxcCdZ/gN/FtE8+jL8u4UVljreguav4RvJMtO4yVmhlPiTz/YkTR0ATjlRPNoI/dln207Q5mrdit40mUx3Ro8ATRndaatBq2z6nzaHVc1elRodlYJ0bpB9MP+edZm3exNcPR3LUCUpXl0Vkgx6p7JziEe/RZk1KIpqyuqmGFA2quczxH94FGWe7+1wtl+Z0pZnBVDimjn6kIvdLuAO0lenFvWXHvM+QourQOWlg704cWj5SF1zLs46gDtMizBLW/I8QsJ0a0Pomlo21nL95111aV1gNaecp/TG7vrUNt+e5RYrxS3/cwJj64DokpDIeghLFmASR4SnRfBDtwj6oAUxBAUrQ+iiPm+7U+ne8HjyQ0Uk9K+N2o98Q74r/h7jGvz2WLmvyJa3t0dYrSL7/6GcC017Obvoj3aa35WHH/ZRlNlnjM+9s4udhNzSu393RZo5O9MCF0VWiJo7fPkh6Csp/Oxp46QXqPAZD9p7fPkL0DUCzNCuju9O7zdzuLGF9tTFuNVpZcM30UliC8zRntUYLcbcyJrYRtfuzYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgPIDXn3QrSWoYQgAAAAASUVORK5CYII='), "Each holding an Orb, that 2000 years ago shined with beauty from within. But now, only darkness."), (to_image_key('iVBORw0KGgoAAAANSUhEUgAAAIAAAABQCAIAAABeYuqzAAACx0lEQVR4nO2b3ZqEIAiGqWfu/5bbgxqX5EcsLWu+92RnzZARQbCGCAAAAAAAAADApUzrn2VZdq3T1GOwZVlUyVb7LzDTd/anLyTsAfrxKfZIxkiLVJqHr1/ZHzjMsin5ATHnIDtMTdOULnFnghtFUDyAT/oxMPVxyiHoAJbxatt/gZlYhFmhfXihGp+QojiWZ8BjwG1cWgcAnSxc+P+2GgWsFEK84xlqvp9EZTJrPUymv1KUOq71+Xxq14nyBPmqy6vZ91dLighcJSlEtYpjMKnPIGxpaDaDEUV7x5ORl21DtrOg2tkMTs35aq7t7A9oy1CMVufCuqW4o0RmIbItOfrEQygAjKdkio9Q8s28yQC7wzg/1p/Ju60AXSv/fSjPAzjO8wAVnm7LRwJSjvX8gB/q0Xtnn4oGuAZ178lOZN/KFoI6lYhBmbU565tMsnmAVXZaUbhViLCeH0TOPwBogL67Ps7HG+7VTUTFhfynoTxljB/GXW+qG/Oi4pHMgVOWI+8F8cbgsfCB+sBXpvZYKdjZx3mpIJjFSP1nfk1uqn6eni4FVY/XB74ca1yZzlr6H8M6qrEky/5S/1m9Fhx4NCxD9tPfL1QjC2sXgtZlIr2pecC9OIKPnFPklXBmNCtPlz1lf+rzzePxilz9mytTVXU+IqKAL0/ZA95Jmv2H2mDw1VN4z4cqA5yT1/vyz7cX9cluqa0PnHooXvdIZktQNmrVIoqf+6dGq39cjqMJH8WXb1Hb3697OIVKOGJDX13ZHmnkCtTe8ixu/n1A5qoS1ZYj5/UqjsJd9oDislVjcXapuAec1KrJHuDo068SAmPjp32DJ4XXM8RD+V/mQ1rSuojXyskIcPFIh4WvcvC9oHieK+UADkLQzbQxwLGljQ2Zst8JZx9oH3zOBJAsiGHeAQAAAAAAAAAAAAAAAAAAAAAAAAAAAC/mD4+4CUHYQSVTAAAAAElFTkSuQmCC'), "Come!! Start your journey! Return the light of peace to our world."), (to_image_key("iVBORw0KGgoAAAANSUhEUgAAAIAAAABQCAIAAABeYuqzAAABoUlEQVR4nO3c25KDIAyAYd3Z939l9qKzGYaQGJGDTP/vqiKmgohVpMcBAAAAAAAAAACAoc6OsVJKZfTzdNL1Kj/diZOvzYPkGSTFSdeFqqYXm79FSqnY18/iw3RZtPIXq6qJThwnvl+uLn57BRon2Nxe2iqvzDsAeasJVlZ1E52o+yvpZORz0clY6dVosfI16n8ArIqWyooXya/0eByrx7A6/WDYLvofAL8A1Wtg27cUcaxatr6x1548tOAaICX/fNCt20q34ug8wW6kmh75Ybb8sAEAAAAAmu10R+ePNxS3rLvcrG7wOLpQPHLYpaItP6t34Nvt1Hwuhzblyf7up8VL+UOD6d/0/XqELmix/S7CPJcHAAAAAAAAAADAHf3nCd99bUTP741kbtvEz7/NfGCLHha/HCKvzu+NZNaL8Q3j2SYM8a8fE25uZZs1T8OQWZLBF9ac+b1O5NGD8pMH/Ye8lmL970KXyOIY00VI8Dln2KguKH4M4pU48623abOIB76YFf+Ph7xRXwbML/W3Orq7p8u48xgAAAAAAAAAAHyXP9LOhecc41GgAAAAAElFTkSuQmCC"), "Programmed by Nasir"), (to_image_key("iVBORw0KGgoAAAANSUhEUgAAAIAAAABQCAIAAABeYuqzAAAB+ElEQVR4nO3b23KDIBCAYez0/V+ZXjBlKHvgHBP7f1dRN4sBQxsXQwAAAAAAAAAAAMBR1950McY/2a8r70yvc1jezG+Re6o8Vrzfbs/+dMhv9wPEGKvPkDat/dUhdedivHVUHQM/zyFfpxtoGr3KPuyqbPk+mt2ZJeSeNAmoE5E6dVTxVrsWddZS2z3q7ACUHeQPhpQ7faIXet5lBay0O+HsAPTwB0Ne5i+Yl9V2D9k5AOmkR7/Czc6t+kLGz7VrTUFWuwAAAACAZ3jFz7zR+/LykPVr2Soh9NQh/pH+OoEa37yhb23GX1W7b+X+m3FNzy4Y3D8AcvaYu7kWjNnpze+p3T8AzYpKGoyhG6v9pZvb3V+SlKy/DSvUmvs74L8gAAAAAAAAAAAAPJtXHqoqSuVmzxNuoVXJsiplVbx6AtZmGK/glxmq96oPDVonUMY3H7/JZoryVsOyR6pHi6oAq3AYxGA3+3RXvNrjfn512EJ3KfTgqojF6qv/dvkhTy8fOlRM9lZFlFeoep1a8XJJ2hB1UUl51Jp81Pih/Pm19VWQ+RfXWzSWpTizhBWfBXHqW+T855aZjGZeOZmdU1D/OPVnc1z2k/Ur+a1VXH7+6TGYGQBr6aC/pDDvH13mFvo6d2N8z2I9NSBfgnNLKwEAAAAAAAAAwDP9AKeVNvQLISpVAAAAAElFTkSuQmCC"), "Character Design by Yositaka Amano"), (to_image_key("iVBORw0KGgoAAAANSUhEUgAAAIAAAABQCAIAAABeYuqzAAABrElEQVR4nO3c23KDIBCAYe30/V+ZXjhh6LK7gAiK+b+rFpFDUEgE3DYAAAAAAAAAAAAMtc/JJoTwL9d9d8JFYDx0hMdzj5h5Ulbi+bmV5VleCCGtWPxXhG+f+ufh6YkiqTwLNVAc8gtmxR/hd3QGuUGX1aJX64wGOHoP9ZbPY8a/rd7gSM2PqXZNTr43mnQHiM9LfILpofSDdlKzUrCyro8/2YwGyAfPfnFMFrn48R/YBm/4FtQanmf98m9BAAAAAIDESr/0rOf74hfviCcf49zwOLqT9WhhUT93F+DbrXT5OFOMsdtZq/9ZjD9lmE9YLoEu6GbrDcIPn2IEAAAAAAAAAADAw5yZUbLW4Zzb3+snGxMplkdkqoZb5VS3/LXuNz43PXf9lKRVjtY1PPVLHNTlWcXyqBdEmogocGv8Sr2T8u9bBtJal866n78DrFuvdX/v6Mar2R+odlnFjZWt8VXnGyCtiXWr5qfMX0zod0G3L268YAxo3Tb9qLVTxX33RZ3VuX4QLm61TUdX5xUG6Ts3ei7SyvKoO/TVF4OIOD2NBwAAAAAAAAAAvsIfw9p6L1hAGSoAAAAASUVORK5CYII="), "Scenario by Kenji Terada"), (to_image_key("iVBORw0KGgoAAAANSUhEUgAAAIAAAABQCAIAAABeYuqzAAABoklEQVR4nO3c0Y6DIBBAUdj0/3+ZPpgSAgyMwGDp3vOwsaiDihJbmHUOAAAAAAAAAAAApvzCWCGEPLr3jfJyVXv7qzzddyxOuYsmTrZv+vFbhBCyE7g+GpXHZWl7aa20ql1vtep5f6sCYcxrW03VR96IRXzvvUXPs74BpAsd+9MNvadRLRZtsL4B2sdndB9tcx3/yoALY5VvC1J5bIO7by/S41WNozmqRnx33FsQAAAAAEDhsK9zym/Ozv73vv9IP35wEMYDHrZvPMDazvGGhX6nAQ666Cm6oIcddtcof68HAAAAAAAAAAAAPjqjSFLmiWZkKksjibtIQZzNPJ+y3u6Wt46nel5ZXYMZNVIa7d083mxVN7934Tyfar36XaSSdvxu+nHqxqyIyUHXp8ZsvzwlttUAV0bg/Hybsr8Kwn8ZUObdzdc7ELwaTYofl+NfKWznCciuiEV2oJQ/bHrnDgSfvwOqWg2gme6hnxLSPhq7/GHraaNSfOUZjXRBaXlc9t5n2zfuaOm9Quqaymh63XqVpONZ220CAAAAAAAAAIAf9AaQOdOneYrlMwAAAABJRU5ErkJggg=="), "Production of Square A-Team") ] @classmethod def text_box(cls, image, text): #print([x[1] for x in text]) #res = raw_text = " ".join([x[1] for x in text]) output = list() bridge_test = image_to_string_format(image.crop((40,128,128,160)), "BMP") if bridge_test == cls.bridge_scene: cropped = image_to_string_format(image.crop((40,32,168, 112)),"BMP") #import pdb #pdb.set_trace() for cred, t in cls.bridge_credits: if cred == cropped: output = [((1,1), t)] break else: for pos, entry in text: for r1,r2 in [("ORBS", "Orbs"), ("ORB", "Orb"), ("G0", "Go"), ("g0", "go")]: entry = entry.replace(r1, r2) output.append((pos, entry)) return [x[1] for x in output] def main3(): import os screen_test_list = list() ScreenSelector._load_content(None, None, None, None) for filename in os.listdir("./"): if filename.startswith("test_"): if "battle" in filename: screen_test_list.append(filename) for i, name in enumerate(sorted(screen_test_list, key=lambda x: int(x.partition("battle")[2].partition(".")[0]))): if i < 50: continue image = Image.open(name) print(name) ScreenSelector.parse_whole_screen(image) import pdb pdb.set_trace() def main2(): image_list = [Image.open("text"+str(i)+".png") for i in range(7)] f = ParseScreenText.get_font(image_list) start_image_id = ObjectId("5df9d8208ac3d956387c0941") doc = db.ocr_images.find_one({"_id": start_image_id}) game_id = doc['game_id'] user_id = doc['user_id'] for image in db.ocr_images.find({"user_id": user_id, "game_id": game_id}, sort=[("_id", pymongo.ASCENDING)]): im = load_image(image['image_data']) t = time.time() tex = ParseScreenText.parse_screen(im, f) print((time.time()-t)) for coord, line in tex: print((coord, line)) if tex: import pdb pdb.set_trace() def main4(): image_list = [Image.open("text"+str(i)+".png") for i in range(7)] f = ParseScreenText.get_font(image_list) start_image_id = ObjectId("5df9d8208ac3d956387c0941") doc = db.ocr_images.find_one({"_id": start_image_id}) game_id = doc['game_id'] user_id = doc['user_id'] c =0 enemy_data = { "iguana": {"w": 48}, "garland": {"x": 64, "y": 72, "ratio": 0.5}, "asp": {"ratio": 0.5}, "agama": {"w": 48}, "badman": {"x": 64}, "evilman": {"x": 64}, "bull": {"x": 16, "y": 40, "w": 48, "h": 48}, "hyena": {"x": 80}, "seasnake": {"w": 32, "ratio": 0.5}, "naga": {"w": 48, "ratio": 0.5}, "grnaga": {"w": 48, "ratio": 0.5}, "wzvamp": {"w": 48, "w": 32, "ratio": 0.25}, "kary": {"ratio": 0.05, "ratio2": 0.95,"w": 96}, "kraken": {"ratio": 0.05, "ratio2": 0.95, "w": 96}, "tiamat": {"ratio": 0.05, "ratio2": 0.95, "w": 96}, "medusa": {"x": 64}, "warmech": {"w": 48}, "vampire": {"x": 64, "w": 32}, "wzvamp": {"x": 64, "w": 32}, "zombull": {"x": 16, "y": 40, "w":48, "h":48}, "r.ankylo": {"w": 48}, "r.giant": {"w": 48}, "r.hydra": {"w": 48}, "wrwolf": {"x": 96, "ratio": 0.5}, } for filename in os.listdir("./"): if "enemy" in filename: if filename.split(".")[0].split("_")[-1].isdigit(): os.remove(filename) found = dict() saved = dict() for image in db.ocr_images.find({"user_id": user_id, "game_id": game_id}, sort=[("_id", pymongo.ASCENDING)]): im = load_image(image['image_data']) if ScreenSelector.is_battle(im): text = ParseScreenText.parse_screen(im, f) res = ScreenSelector.battle_parse(im, text) if not res.get("status") and res.get("menu").lower() in ['fight', 'magic', 'item', 'drink', 'run'] and len(res.get("enemy_names",[])) == 1: name = res['enemy_names'][0].strip().lower() found[name] = 1 boxes_to_check = list() #check 3x3 for i in range(3): for j in range(3): x = 16+32*i y = 40+32*j w = 32 h = 32 boxes_to_check.append((x,y,w,h)) #check for big enemy plus 3 small for i in range(1): for j in range(3): x = 16+48 y = 40+32*j w = 32 h = 32 boxes_to_check.append((x,y,w,h)) for i in range(3): for j in range(3): x = 32+32*i y = 40+32*j w = 32 h = 32 boxes_to_check.append((x,y,w,h)) #check for big enemies for i in range(2): for j in range(2): x = 16+48*i y = 40+48*j w = 48 h = 48 boxes_to_check.append((x,y,w,h)) for i in range(1): for j in range(2): x = 80 y = 40+48*j w = 48 h = 48 boxes_to_check.append((x,y,w,h)) #boss box check boxes_to_check.append((16+24, 40+24, 48, 48)) #chaos box check boxes_to_check.append((16, 40, 96, 96)) for i in range(2): if i == 1: ratio = 0.25 else: ratio = 0.75 for x,y,w,h in boxes_to_check: flag = False for ch in "xywh": var = locals()[ch] if enemy_data.get(name, {}).get(ch, var) != var: break else: flag = True if flag is False: continue subi = im.crop((x,y,x+w,y+h)) lines = [subi.crop((0,0, 1, h)), subi.crop((0,0, w, 1)), subi.crop((w-1, 0, w,h)), subi.crop((0, h-1, w,h))] flag = False for line in lines: for cc in line.convert("RGBA").getcolors(): amt = h*enemy_data.get(name, {}).get("ratio", ratio) if cc[1] == (0,0,0,255) and cc[0] > amt: break else: #this line did not have enough black pixels print("not enough black pixels") break else: #all the lines had enough black pixels. flag = True if flag is False: continue p = subi.convert("RGB").resize((1,1), resample=Image.BILINEAR).getpixel((0,0)) if not p[0] and not p[1] and not p[2]: continue ratio2 = 85/100.0 if enemy_data.get(name, {}).get("ratio2"): ratio2 = enemy_data[name]['ratio2'] for cc in subi.convert("RGB").getcolors(): if cc[1] == (0,0,0): if cc[0] < ratio2*w*h: #succ break else: #fail continue else: #fail continue i = 0 saved[name] = 1 while True: filename = "enemy_"+name+"_"+str(i)+".png" try: old_im = Image.open(filename) if image_to_string_format(old_im, "BMP") == image_to_string_format(subi, "BMP"): break else: i+=1 except: subi.save(filename) break break if name in saved: break im.save("test_battle"+str(c)+".png") c+=1 for key in found: if key not in saved: print(['not found', key]) def test_person(): im = Image.open("person_test.png") po = PackageOutput("ff1_data.lud", "enemy_lookup.dat") import pdb pdb.set_trace() print(("--", po.memory)) print((po.run(im, {"paused": 1}))) if __name__=='__main__': #main4() #main3() #main2() main() #main_c() #test_person()