ff1ra/test.py

2365 lines
102 KiB
Python
Raw Normal View History

2024-08-05 13:41:50 -04:00
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<len(mapp) and mapp[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))
2024-08-05 13:41:50 -04:00
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))
2024-08-05 13:41:50 -04:00
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))
2024-08-05 13:41:50 -04:00
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]))
2024-08-05 13:41:50 -04:00
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()))
2024-08-05 13:41:50 -04:00
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))
2024-08-05 13:41:50 -04:00
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))
2024-08-05 13:41:50 -04:00
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']))
2024-08-05 13:41:50 -04:00
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))
2024-08-05 13:41:50 -04:00
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))
2024-08-05 13:41:50 -04:00
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))
2024-08-05 13:41:50 -04:00
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))
2024-08-05 13:41:50 -04:00
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..
2024-08-06 13:14:12 -04:00
if key.endswith(tile[int(-len(tile)*3/4):]):
2024-08-05 13:41:50 -04:00
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..
2024-08-06 14:03:13 -04:00
if key.endswith(tile[int(-len(tile)*3/4):]):
2024-08-05 13:41:50 -04:00
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:
2024-08-05 13:41:50 -04:00
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())
2024-08-05 13:41:50 -04:00
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())]
2024-08-05 13:41:50 -04:00
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):
2024-08-05 13:41:50 -04:00
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()):
2024-08-05 13:41:50 -04:00
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()):
2024-08-05 13:41:50 -04:00
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))
2024-08-05 13:41:50 -04:00
for coord, line in tex:
print((coord, line))
2024-08-05 13:41:50 -04:00
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})))
2024-08-05 13:41:50 -04:00
if __name__=='__main__':
#main4()
#main3()
#main2()
main()
#main_c()
#test_person()