Compare commits

...

150 Commits

Author SHA1 Message Date
7eed550797 Merge remote-tracking branch 'origin/master' 2023-08-24 09:43:27 +02:00
cc9789c65c ring fix 2023-08-24 09:43:13 +02:00
d64b704274 update menti 2023-08-06 16:36:52 +02:00
ed23f196a6 update menti 2023-08-06 16:32:45 +02:00
b8abdb690b update menti 2023-08-06 16:30:20 +02:00
8d2aad34b2 update menti 2023-08-06 16:25:52 +02:00
e70c7d2be9 update menti 2023-08-06 16:23:55 +02:00
5005670bd3 update menti 2023-08-06 16:21:48 +02:00
b1fc655c0b update menti 2023-08-06 16:12:13 +02:00
9cc4018747 update flappy 2023-07-30 18:46:40 +02:00
849aaf8e27 update flappy 2023-07-30 18:42:53 +02:00
804f178fbf update flappy 2023-07-30 15:08:29 +02:00
c1eecfd567 update flappy 2023-07-30 15:05:47 +02:00
99a2976b61 update flappy 2023-07-30 15:01:20 +02:00
cadcfe8103 update litris with board detection 2023-07-30 14:28:15 +02:00
ab0def9115 update litris with board detection 2023-07-30 10:57:43 +02:00
b24a835f18 update litris with board detection 2023-07-30 10:08:33 +02:00
0a15b57fe5 Merge remote-tracking branch 'origin/master' 2023-07-30 10:00:17 +02:00
a7d2a73b00 update litris with board detection 2023-07-30 10:00:07 +02:00
Thaloria@web.de
3d209ca811 litris update 2023-07-30 00:49:42 +02:00
Thaloria@web.de
01768dc115 litris update 2023-07-30 00:29:36 +02:00
f32cbb8f2d update litris with board detection 2023-07-30 00:08:39 +02:00
7a539e301b update litris with board detection 2023-07-29 21:43:48 +02:00
00461177de update litris with board detection 2023-07-29 21:36:31 +02:00
7c6af4411b update litris with board detection 2023-07-29 21:32:53 +02:00
c3e677ca0a update litris with board detection 2023-07-29 21:30:00 +02:00
332190394d update litris with board detection 2023-07-29 21:20:50 +02:00
d3ace50341 update litris with board detection 2023-07-29 21:14:13 +02:00
8918683e5a update litris with board detection 2023-07-29 21:07:22 +02:00
b08356b036 update litris with board detection 2023-07-29 21:01:51 +02:00
ffca884a25 update litris with board detection 2023-07-29 20:54:00 +02:00
d3d2e1e65e update litris with board detection 2023-07-29 20:46:25 +02:00
6ec1b71d28 update litris with board detection 2023-07-29 20:20:18 +02:00
07d00404d8 update litris with board detection 2023-07-29 20:20:11 +02:00
c9081bd371 update litris with board detection 2023-07-29 20:12:51 +02:00
a9b76cde97 flappy init 2023-07-29 19:42:17 +02:00
2fa0255761 flappy init 2023-07-29 19:34:12 +02:00
c7dd04590a flappy init 2023-07-28 15:31:16 +02:00
189b81b3a0 flappy init 2023-07-28 15:28:25 +02:00
545127dcbc flappy init 2023-07-28 13:26:54 +02:00
bfd8690535 flappy init 2023-07-28 13:13:20 +02:00
c43399ac2a flappy init 2023-07-27 21:16:19 +02:00
33c7400fa4 flappy init 2023-07-27 20:55:54 +02:00
862fbf8bc6 flappy init 2023-07-27 17:58:57 +02:00
8ded30d75a menti words init 2023-07-27 13:02:42 +02:00
eff65b3ca4 menti words init 2023-07-26 22:28:30 +02:00
ef7669f015 menti words init 2023-07-26 22:00:57 +02:00
2d23f8e311 menti words init 2023-07-26 17:11:30 +02:00
38ac30cc64 menti words init 2023-07-26 17:04:53 +02:00
fc965a5133 menti words init 2023-07-26 17:02:57 +02:00
e11b2b8e94 menti words init 2023-07-26 16:58:43 +02:00
a82c069048 menti words init 2023-07-26 16:55:41 +02:00
5c24629b85 menti words init 2023-07-26 16:52:43 +02:00
f1bb158b21 menti words init 2023-07-26 16:49:09 +02:00
95f87d1c2e menti words init 2023-07-26 16:46:15 +02:00
cde729f820 menti words init 2023-07-26 16:43:36 +02:00
9841d6fae4 menti words init 2023-07-26 16:41:08 +02:00
f4d7523c3d menti words init 2023-07-26 16:37:04 +02:00
fec2651930 menti words init 2023-07-26 16:30:14 +02:00
555d66c680 menti words init 2023-07-26 16:29:45 +02:00
2c4e51b44f menti words init 2023-07-26 16:29:15 +02:00
0fcf3d88a2 menti words init 2023-07-26 16:27:23 +02:00
12f86cc7fd menti words init 2023-07-26 16:19:41 +02:00
bdb448932d menti words init 2023-07-26 16:16:13 +02:00
1893d513f2 menti words init 2023-07-26 16:10:47 +02:00
5713422f49 threading update 2023-07-26 11:33:46 +02:00
1b9711a851 added async stone detection thread 2023-07-26 09:54:49 +02:00
7b63568fa5 added async stone detection thread 2023-07-26 09:46:33 +02:00
3c02d413a2 added async stone detection thread 2023-07-26 09:31:48 +02:00
84830e94a8 added async stone detection thread 2023-07-26 09:05:27 +02:00
d2c89cdc93 added async stone detection thread 2023-07-26 08:49:50 +02:00
3d2ce694e1 added async stone detection thread 2023-07-26 08:43:30 +02:00
e0a9cbc394 added async stone detection thread 2023-07-26 08:37:04 +02:00
fd6f17c3f8 added async stone detection thread 2023-07-26 08:25:39 +02:00
Thaloria@web.de
54cb23a923 litris update 2023-07-25 12:11:56 +02:00
Thaloria@web.de
de56e687f8 litris update 2023-07-25 11:54:05 +02:00
3fa581a935 added async stone detection thread 2023-07-25 10:02:32 +02:00
e7932f5762 added async stone detection thread 2023-07-25 09:59:20 +02:00
b570813c5a added async stone detection thread 2023-07-25 09:47:52 +02:00
8049e58e71 added async stone detection thread 2023-07-25 09:41:04 +02:00
5e201ea341 added async stone detection thread 2023-07-25 09:37:41 +02:00
37cf7f2f2f added async stone detection thread 2023-07-25 09:04:26 +02:00
e5cd8d6399 added async stone detection thread 2023-07-25 08:54:13 +02:00
Thaloria@web.de
3c723fb602 litris update 2023-07-25 08:43:04 +02:00
d3fa6fe807 added async stone detection thread 2023-07-24 13:54:42 +02:00
a2575370f9 added async stone detection thread 2023-07-24 13:51:16 +02:00
22edbe9a2f added async stone detection thread 2023-07-24 13:42:41 +02:00
e832ffe9ec added async stone detection thread 2023-07-24 13:34:49 +02:00
773aa5c765 added async stone detection thread 2023-07-24 13:33:41 +02:00
687218e29d added async stone detection thread 2023-07-24 13:22:44 +02:00
f35fe32264 litris fixes 2023-07-24 11:15:11 +02:00
a21f43fcfc added async stone detection thread 2023-07-24 10:14:41 +02:00
50ab6e17ef added async stone detection thread 2023-07-24 09:59:13 +02:00
761fa778c7 added async stone detection thread 2023-07-24 09:18:30 +02:00
62ff7cb40d added first draft litris 2023-07-23 18:38:50 +02:00
e614ba8dd0 added first draft litris 2023-07-23 18:13:21 +02:00
6d6081ec57 added first draft litris 2023-07-23 17:45:37 +02:00
c4f71f469b added first draft litris 2023-07-23 17:45:22 +02:00
17ff660069 added first draft litris 2023-07-23 17:25:03 +02:00
27f7638557 added first draft litris 2023-07-23 14:28:12 +02:00
Thaloria@web.de
6012a51538 litris update 2023-07-23 14:24:09 +02:00
ba2fd6c945 added first draft litris 2023-07-23 14:03:44 +02:00
f4b949c070 added first draft litris 2023-07-23 12:01:24 +02:00
0e265b0bb6 added first draft litris 2023-07-23 11:52:55 +02:00
b9d0e829bc added first draft litris 2023-07-23 11:32:23 +02:00
76d22227bf added first draft litris 2023-07-23 11:24:54 +02:00
ae752bdb7c added first draft litris 2023-07-22 21:22:44 +02:00
aa2662003d added first draft litris 2023-07-22 20:59:06 +02:00
47a7a50335 added first draft litris 2023-07-22 20:54:29 +02:00
2d35e032b5 added first draft litris 2023-07-22 20:52:36 +02:00
21237c3729 added first draft litris 2023-07-22 20:47:42 +02:00
1d4980eb95 added first draft litris 2023-07-22 20:45:30 +02:00
d78319a9f4 added first draft litris 2023-07-22 20:39:20 +02:00
fba0c2c506 litris fixes 2023-07-22 10:54:32 +02:00
704b1f462d added first draft litris 2023-07-22 09:49:15 +02:00
3176bf5269 added first draft litris 2023-07-22 09:44:48 +02:00
c2b5416542 added first draft litris 2023-07-21 15:28:22 +02:00
2906cb10e4 added first draft litris 2023-07-21 15:18:57 +02:00
93832d8bfc added first draft litris 2023-07-21 15:09:02 +02:00
ff173fea80 added first draft litris 2023-07-21 14:36:21 +02:00
d0f4937507 added first draft litris 2023-07-21 14:31:07 +02:00
403db80292 added first draft litris 2023-07-20 20:09:23 +02:00
b76ccf448e added first draft litris 2023-07-20 19:31:27 +02:00
b08b5fcb89 added first draft litris 2023-07-20 19:19:36 +02:00
0b97e346d8 added first draft litris 2023-07-20 19:17:38 +02:00
378259ab1c added first draft litris 2023-07-20 18:55:47 +02:00
597f7f426e added first draft litris 2023-07-20 18:51:12 +02:00
5eaa9ff5d4 added first draft litris 2023-07-19 21:30:52 +02:00
4d9ccbfd90 added first draft new pickaxe try 2023-07-17 20:44:03 +02:00
95abea3920 added first draft new pickaxe try 2023-07-17 20:33:14 +02:00
0df3f2d8a9 added first draft new pickaxe try 2023-07-17 20:31:24 +02:00
40fb6b7918 added first draft new pickaxe try 2023-07-17 14:18:45 +02:00
5cd1d63fc8 added first draft new pickaxe try 2023-07-17 14:14:46 +02:00
2d46fd65b9 added smaler mining area 2023-05-06 19:26:02 +02:00
Thaloria@web.de
a9e25527f5 update farm for 4.0 2023-05-05 19:17:40 +02:00
c7deaaf6c7 added sodoku to ui 2023-05-05 19:09:44 +02:00
f49087776e Merge remote-tracking branch 'origin/master' 2023-04-30 21:04:57 +02:00
b64dad8e5b added sodoku to ui 2023-04-30 21:04:40 +02:00
Thaloria@web.de
56cf726d4f timing changes 2023-04-30 20:31:41 +02:00
7af6f0c7ed fix equipment.py 2023-04-28 18:20:54 +02:00
71871d83f0 Merge branch 'master' of http://git.face-down.de/Thaloria/Litcraft_Python_B 2023-04-28 18:08:01 +02:00
bebcac9cf3 fix equipment.py 2023-04-28 17:59:55 +02:00
059712770a fix equipment.py 2023-04-28 17:58:51 +02:00
Thaloria@web.de
2264e0fb19 added fruit game support 2023-04-28 16:09:40 +02:00
86d2542edc added sodoku game first draft 2023-04-28 15:46:36 +02:00
088a4d9030 added sodoku game first draft 2023-04-28 15:42:03 +02:00
81d0c09003 added sodoku game first draft 2023-04-28 15:32:17 +02:00
07d3f5388e added sodoku game first draft 2023-04-28 15:25:03 +02:00
Thaloria@web.de
3772fbb843 Merge remote-tracking branch 'origin/master' 2023-04-28 15:12:10 +02:00
Thaloria@web.de
187cb80cf2 added fruit game support 2023-04-28 15:12:00 +02:00
155 changed files with 2125 additions and 64 deletions

2
.idea/lc-py.iml generated
View File

@@ -4,7 +4,7 @@
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/venv" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="jdk" jdkName="Python 3.7 (lc-py-b)" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

2
.idea/misc.xml generated
View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.7 (lc_py_b)" project-jdk-type="Python SDK" />
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.7 (lc-py-b)" project-jdk-type="Python SDK" />
</project>

View File

@@ -9,6 +9,10 @@ from craft import Craft
from mine import Mine
from sodoku import Sodoku
from fruit import Fruit
from pickaxe import Pickaxe_Field
from litris import Litris
from menti_words import MentiWords
from flappy import Flappy
def run():
@@ -32,7 +36,6 @@ def run():
overlay.run_mode = 'init'
continue
elif overlay.run_mode == 'quit':
overlay.destroy()
return
else:
break
@@ -56,9 +59,25 @@ def run():
mine = Mine(overlay)
mine.execute_main_loop()
elif overlay.rb_int.get() == 7:
fruit = Sodoku(overlay)
fruit = Fruit(overlay)
fruit.execute_main_loop()
elif overlay.rb_int.get() == 8:
sodo = Sodoku(overlay)
sodo.execute_main_loop()
elif overlay.rb_int.get() == 9:
paxe = Pickaxe_Field(overlay)
paxe.execute_main_loop()
elif overlay.rb_int.get() == 10:
ltris = Litris(overlay)
ltris.execute_main_loop()
ltris.stone_id_thread.run_mode = 'stop'
elif overlay.rb_int.get() == 11:
menti = MentiWords(overlay)
menti.execute_main_loop()
elif overlay.rb_int.get() == 12:
flappy = Flappy(overlay)
flappy.execute_main_loop()
flappy.flappy_pos_disc.run_mode = 'stop'
if __name__ == "__main__":
run()

View File

@@ -1,6 +1,7 @@
# Run tkinter code in another thread
import threading
import tkinter as tk
import game_base_class
from tkinter import ttk
from mine_overlay import DiggingOverlay
@@ -32,7 +33,7 @@ class PrimaryOverlay(threading.Thread):
self.Emitter_Box = ttk.Combobox
self.RadioButtons = dict
self.RadioButtonNames = ["Equip", "Crops", "Farm", "Magic", "Craft", "Mine", "Fruit"]
self.RadioButtonNames = ["Equip", "Crops", "Farm", "Magic", "Craft", "Mine", "Fruit", "Sodo", "PAxe", "Ltris", "Menti", "Flapp"]
self.RadioButton1 = tk.Radiobutton
self.RadioButton2 = tk.Radiobutton
self.RadioButton3 = tk.Radiobutton
@@ -40,12 +41,17 @@ class PrimaryOverlay(threading.Thread):
self.RadioButton5 = tk.Radiobutton
self.RadioButton6 = tk.Radiobutton
self.RadioButton7 = tk.Radiobutton
self.RadioButton8 = tk.Radiobutton
self.RadioButton9 = tk.Radiobutton
self.RadioButton10 = tk.Radiobutton
self.RadioButton11 = tk.Radiobutton
self.RadioButton12 = tk.Radiobutton
self.StartButton = tk.Button
self.StopButton = tk.Button
self.PauseButton = tk.Button
self.QuitButton = tk.Button
self.TkPosition = '133x329+60+600'
self.TkPosition = '133x454+60+600'
self.setDaemon(True)
self.StatusLabel = tk.Label
@@ -66,14 +72,14 @@ class PrimaryOverlay(threading.Thread):
self.start()
def run(self):
self.MiningOverlay = DiggingOverlay()
self.MiningOverlay = DiggingOverlay(game_base_class.MINING_LARGE)
self.root = tk.Tk()
self.rb_frame = tk.Frame(self.root)
self.rb_int = tk.IntVar(self.root, value=1)
self.RadioButtons = dict()
# var = tk.IntVar(value=1)
for i in range(1, 8):
for i in range(1, 13):
self.RadioButtons[i] = tk.Radiobutton(self.rb_frame, text=self.RadioButtonNames[i - 1],
variable=self.rb_int,
value=i, command=self.radio_button_callback)
@@ -174,6 +180,7 @@ class PrimaryOverlay(threading.Thread):
def destroy(self):
self.hide_mining_overlay()
del self.MiningOverlay
self.root.destroy()
def start_button_callback(self):
@@ -181,7 +188,7 @@ class PrimaryOverlay(threading.Thread):
self.StopButton.configure(state=tk.NORMAL)
self.PauseButton.configure(state=tk.NORMAL)
self.QuitButton.configure(state=tk.DISABLED)
for i in range(1, 7):
for i in range(1, 9):
tt = self.rb_int.get()
if self.rb_int.get() != i:
(self.RadioButtons[i]).configure(state=tk.DISABLED)
@@ -193,7 +200,7 @@ class PrimaryOverlay(threading.Thread):
self.StopButton.configure(state=tk.DISABLED)
self.PauseButton.configure(state=tk.DISABLED)
self.QuitButton.configure(state=tk.NORMAL)
for i in range(1, 7):
for i in range(1, 9):
self.RadioButtons[i].configure(state=tk.NORMAL)
self.run_mode = 'stopped'
@@ -288,7 +295,61 @@ class PrimaryOverlay(threading.Thread):
self.SpawnLabel.configure(text="")
self.EnergyLabel.configure(text="")
self.hide_mining_overlay()
elif self.rb_int.get() == 8:
self.EnergyEntry.configure(state=tk.DISABLED)
self.energy_use.set('')
self.SpawnEntry.configure(state=tk.DISABLED)
self.spawn_use.set('')
self.Emitter_Box.configure(state=tk.DISABLED)
self.emitter_use.set('')
self.EmitterLabel.configure(text="")
self.SpawnLabel.configure(text="")
self.EnergyLabel.configure(text="")
self.hide_mining_overlay()
elif self.rb_int.get() == 9:
self.EnergyEntry.configure(state=tk.DISABLED)
self.energy_use.set('')
self.SpawnEntry.configure(state=tk.DISABLED)
self.spawn_use.set('')
self.Emitter_Box.configure(state=tk.DISABLED)
self.emitter_use.set('')
self.EmitterLabel.configure(text="")
self.SpawnLabel.configure(text="")
self.EnergyLabel.configure(text="")
self.hide_mining_overlay()
elif self.rb_int.get() == 10:
self.EnergyEntry.configure(state=tk.DISABLED)
self.energy_use.set('')
self.SpawnEntry.configure(state=tk.DISABLED)
self.spawn_use.set('')
self.Emitter_Box.configure(state=tk.DISABLED)
self.emitter_use.set('')
self.EmitterLabel.configure(text="")
self.SpawnLabel.configure(text="")
self.EnergyLabel.configure(text="")
self.hide_mining_overlay()
elif self.rb_int.get() == 11:
self.EnergyEntry.configure(state=tk.DISABLED)
self.energy_use.set('')
self.SpawnEntry.configure(state=tk.DISABLED)
self.spawn_use.set('')
self.Emitter_Box.configure(state=tk.DISABLED)
self.emitter_use.set('')
self.EmitterLabel.configure(text="")
self.SpawnLabel.configure(text="")
self.EnergyLabel.configure(text="")
self.hide_mining_overlay()
elif self.rb_int.get() == 12:
self.EnergyEntry.configure(state=tk.DISABLED)
self.energy_use.set('')
self.SpawnEntry.configure(state=tk.DISABLED)
self.spawn_use.set('')
self.Emitter_Box.configure(state=tk.DISABLED)
self.emitter_use.set('')
self.EmitterLabel.configure(text="")
self.SpawnLabel.configure(text="")
self.EnergyLabel.configure(text="")
self.hide_mining_overlay()
def get_run_mode(self):
return self.run_mode

View File

@@ -59,9 +59,12 @@ class UserConfigs:
else:
pass
def returnDiggingWindowPos2(self):
def returnDiggingWindowPos2(self, large=True):
if self.user == self.THALOUSER:
return [1440, 1150, 570, 22]
if large:
return [1440, 1150, 570, 22]
else:
return [1440, 210, 560, 700]
elif self.user == self.ADWAUSER:
return [740, 450, 1625, 985]
elif self.user == self.EDDIEUSER:

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

BIN
control_elements/play.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

View File

@@ -10,7 +10,7 @@ from config_file import UserConfigs
# load the original input image and display it to our screen
#filename = "equip/chests/chest_23_32"
path = "equip/wands/"
path = "flappy/"
os.chdir(path)
for entry in os.listdir():

View File

@@ -142,7 +142,7 @@ class Crops(GameBase):
# get an updated image of the game
screenshot = self.capture_window.get_screenshot()
# screenshot = cv.imread("playfield.jpg")
screenshot = screenshot[58:1134, 230:2113] # 1883,1076
screenshot = screenshot[190:1230, 260:2090]
self.screenshot = screenshot
# gray = cv.cvtColor(screenshot, cv.COLOR_BGR2GRAY)
# thresh = cv.threshold(gray, 0, 255, cv.THRESH_BINARY_INV + cv.THRESH_OTSU)[1]
@@ -153,17 +153,17 @@ class Crops(GameBase):
self.current_strategy = RAINBOW_STRATEGY
cv.waitKey(500)
screenshot = self.capture_window.get_screenshot()
screenshot = screenshot[58:1134, 230:2113]
screenshot = screenshot[190:1230, 260:2090]
if self.check_for_button_and_execute(screenshot, self.next_level_x, offset_left, offset_down):
cv.waitKey(500)
screenshot = self.capture_window.get_screenshot()
screenshot = screenshot[58:1134, 230:2113]
screenshot = screenshot[190:1230, 260:2090]
# cv.imshow("screenshot", screenshot)
# cv.waitKey(150)
# continue
data_coords = np.zeros((8, 14), dtype=object)
# field = Field()
# field = Pickaxe_Field()
for needle_key in self.needles.keys():
# gray_needle = cv.cvtColor(self.needles[needle_key], cv.COLOR_BGR2GRAY)

View File

@@ -76,7 +76,7 @@ class Equipment(GameBase):
self.include_chests()
self.include_keys()
self.include_pots()
self.include_coins()
#self.include_coins()
self.include_runes()
elif emitter == EMITTER_SWORD:
self.include_swords()
@@ -112,6 +112,9 @@ class Equipment(GameBase):
spawn_1 = self.find_emitter(emitter, screenshot, 1)
if len(spawn_1) == 1:
#output_by_area = self.vision_stun.draw_rectangles(screenshot, spawn_1)
#cv.imshow("spawn_1", output_by_area)
#cv.waitKey(150)
points = self.vision_stun.get_click_points(spawn_1)
for i in range(0, self.SPAWN_COUNT, 1):
self.click_point(points[0][0], points[0][1])
@@ -124,12 +127,17 @@ class Equipment(GameBase):
points = self.vision_stun.get_click_points(spawn_0)
if len(points) >= 1:
self.click_point(points[0][0], points[0][1])
if self.overlay.run_mode == 'stopped' or self.overlay.run_mode == 'paused':
continue
continue
cv.waitKey(500)
if emitter == EMITTER_MAIN:
loop_time = time()
while True:
if (time() - loop_time) >= 10:
break
screenshot = self.capture_window.get_screenshot()
c_rectangles = self.vision_stun.find(screenshot, self.c_needle, 0.95, 1, True, self.c_mask)
k_rectangles = self.vision_stun.find(screenshot, self.k_needle, 0.95, 1, True, self.k_mask)
@@ -137,13 +145,17 @@ class Equipment(GameBase):
c_point = self.vision_stun.get_click_points(c_rectangles)[0]
k_point = self.vision_stun.get_click_points(k_rectangles)[0]
self.move_tile(k_point, c_point)
if self.overlay.run_mode == 'stopped' or self.overlay.run_mode == 'paused':
break
else:
break
if self.overlay.run_mode == 'stopped' or self.overlay.run_mode == 'paused':
continue
for rer in range(0, len(self.needles), 1):
loop_time = time()
while True:
if (time() - loop_time) >= 60:
if (time() - loop_time) >= 20:
break
screenshot = self.capture_window.get_screenshot_by_area(self.config.returnOKWindowPos())
rectangles = self.vision_stun.find(screenshot, self.dig_button, 0.5, 1)
@@ -307,7 +319,7 @@ class Equipment(GameBase):
else:
needle = cv.imread("equip/emitters/ring_e2_32.jpg", cv.IMREAD_UNCHANGED)
mask = cv.imread("equip/emitters/ring_e2_32-mask.png", cv.IMREAD_COLOR)
return self.vision_stun.find(screen, needle, 0.95, 1, True, mask)
return self.vision_stun.find(screen, needle, 0.95, 1, False, mask)
elif emitter_to_use == EMITTER_WAND:
if layer == 0:
needle = cv.imread("equip/emitters/wand_e1_32.jpg", cv.IMREAD_UNCHANGED)

19
farm.py
View File

@@ -31,6 +31,8 @@ class Farm(GameBase):
def __init__(self, overlay):
super().__init__(overlay)
self.farm_reset_board = cv.imread("control_elements/farm_reset_button.jpg", cv.IMREAD_COLOR)
self.colors.append(PINK)
self.fill_data_coordinates()
@@ -78,7 +80,7 @@ class Farm(GameBase):
return
elif self.reset_counter >= 3:
screenshot = self.capture_window.get_screenshot()
if self.check_for_button_and_execute(screenshot, self.reset_board):
if self.check_for_button_and_execute(screenshot, self.farm_reset_board):
cv.waitKey(500)
screenshot = self.capture_window.get_screenshot()
if self.check_for_button_and_execute(screenshot, self.reset_confirm):
@@ -97,23 +99,24 @@ class Farm(GameBase):
# get an updated image of the game
screenshot = self.capture_window.get_screenshot()
# screenshot = cv.imread("field_farm.jpg")
screenshot = screenshot[58:1134, 230:2113] # 1883,1076
screenshot = screenshot[190:1230, 260:2090] # 1883,1076
# gray = cv.cvtColor(screenshot, cv.COLOR_BGR2GRAY)
# thresh = cv.threshold(gray, 0, 255, cv.THRESH_BINARY_INV + cv.THRESH_OTSU)[1]
if self.check_for_next_level(screenshot, self.next_level):
cv.waitKey(500)
screenshot = self.capture_window.get_screenshot()
screenshot = screenshot[58:1134, 230:2113]
screenshot = screenshot[190:1230, 260:2090]
if self.check_for_next_level(screenshot, self.next_level_x):
cv.waitKey(500)
screenshot = self.capture_window.get_screenshot()
screenshot = screenshot[58:1134, 230:2113]
screenshot = screenshot[190:1230, 260:2090]
# cv.imshow("screenshot", screenshot)
# cv.waitKey(150)
# continue
#cv.imshow("screenshot", screenshot)
#cv.waitKey(150)
#return
#continue
data_coords = np.zeros((8, 14), dtype=object)
# field = Field()
# field = Pickaxe_Field()
for needle_key in self.needles.keys():
# gray_needle = cv.cvtColor(self.needles[needle_key], cv.COLOR_BGR2GRAY)
# thresh_needle = cv.threshold(gray_needle, 0, 255, cv.THRESH_BINARY_INV + cv.THRESH_OTSU)[1]

213
field.py Normal file
View File

@@ -0,0 +1,213 @@
#!/usr/bin/python
from copy import copy
from tetromino import Tetromino
class Field():
WIDTH = 20
HEIGHT = 20
def __init__(self, state=None):
if state:
self.state = state
else:
self.state = [[' ' for cols in range(Field.WIDTH)]
for rows in range(Field.HEIGHT)]
self.cleared_rows = 1
def __str__(self):
BAR = ' ' + '-' * (Field.WIDTH * 2 + 1) + '\n ' + \
' '.join(map(str, range(Field.WIDTH))) + '\n'
return BAR + '\n'.join([
'{:2d} |'.format(i) + ' '.join(row) + '|'
for i, row in enumerate(self.state)]) + '\n' + BAR
@staticmethod
def matrixflip(m, d):
tempm = m.copy()
if d == 'h':
for i in range(0, len(tempm), 1):
tempm[i].reverse()
elif d == 'v':
tempm.reverse()
return (tempm)
@staticmethod
def rotate_90_degree_anticlckwise(matrix):
new_matrix = []
for i in range(len(matrix[0]), 0, -1):
new_matrix.append(list(map(lambda x: x[i - 1], matrix)))
return new_matrix
@staticmethod
def rotate_90_degree_clckwise(matrix):
new_matrix = []
for i in range(len(matrix[0])):
li = list(map(lambda x: x[i], matrix))
li.reverse()
new_matrix.append(li)
return new_matrix
def reset_field(self):
self.state = [[' ' for cols in range(Field.WIDTH)]
for rows in range(Field.HEIGHT)]
def reset_half_field(self):
for row in range(int(self.HEIGHT/2)):
self.state[row] = [' ' for cols in range(Field.WIDTH)]
def rotate_state(self):
self.state = Field.rotate_90_degree_anticlckwise(self.state)
def get_line_count(self):
return self.cleared_rows
def _test_tetromino(self, tetromino, row, column):
"""
Tests to see if a tetromino can be placed at the specified row and
column. It performs the test with the bottom left corner of the
tetromino at the specified row and column.
"""
assert column >= 0
assert column + tetromino.width() <= Field.WIDTH
assert row - tetromino.height() + 1 >= 0
assert row < Field.HEIGHT
for ti, si in list(enumerate(range(row - tetromino.height() + 1,
row + 1)))[::-1]:
for tj, sj in enumerate(range(column, column + tetromino.width())):
if tetromino[ti][tj] != ' ' and self.state[si][sj] != ' ':
return False
return True
def _place_tetromino(self, tetromino, row, column):
"""
Place a tetromino at the specified row and column.
The bottom left corner of the tetromino will be placed at the specified
row and column. This function does not perform checks and will overwrite
filled spaces in the field.
"""
assert column >= 0
assert column + tetromino.width() <= Field.WIDTH
assert row - tetromino.height() + 1 >= 0
assert row < Field.HEIGHT
for ti, si in list(enumerate(range(row - tetromino.height() + 1,
row + 1)))[::-1]:
for tj, sj in enumerate(range(column, column + tetromino.width())):
if tetromino[ti][tj] != ' ':
self.state[si][sj] = tetromino[ti][tj]
def _get_tetromino_drop_row(self, tetromino, column):
"""
Given a tetromino and a column, return the row that the tetromino
would end up in if it were dropped in that column.
Assumes the leftmost column of the tetromino will be aligned with the
specified column.
"""
assert isinstance(tetromino, Tetromino)
assert column >= 0
assert column + tetromino.width() <= Field.WIDTH
last_fit = -1
for row in range(tetromino.height(), Field.HEIGHT):
if self._test_tetromino(tetromino, row, column):
last_fit = row
else:
return last_fit
return last_fit
def _line_clear(self):
"""
Checks and removes all filled lines.
"""
self.state = list(filter(lambda row: row.count(' ') != 0, self.state))
while len(self.state) < Field.HEIGHT:
self.state.insert(0, [' ' for col in range(Field.WIDTH)])
self.cleared_rows = self.cleared_rows + 1
print("cleared rows: ", self.cleared_rows)
def copy(self):
"""
Returns a shallow copy of the field.
"""
return Field([row[:] for row in self.state])
def drop(self, tetromino, column):
"""
Drops a tetromino in the specified column.
The leftmost column of the tetromino will be aligned with the specified
column.
Returns the row it was dropped in for computations.
"""
assert isinstance(tetromino, Tetromino)
assert column >= 0
assert column + tetromino.width() <= Field.WIDTH
row = self._get_tetromino_drop_row(tetromino, column)
assert row != -1
self._place_tetromino(tetromino, row, column)
self._line_clear()
return row
def check_crucial_pos_to_be_free(self):
if self.state[19][9] == ' ' and self.state[19][10] == ' ' and self.state[18][9] == ' ' and self.state[18][10] == ' ':
return True
return False
def predict_gaps_in_next_rotation(self):
tmp_state = copy(self.state)
tmp_state = Field.rotate_90_degree_anticlckwise(tmp_state)
for row in range(int(self.HEIGHT/2)):
tmp_state[row] = [' ' for cols in range(Field.WIDTH)]
return sum(
["".join([row[col] for row in tmp_state]).lstrip().count(' ')
for col in range(Field.WIDTH)])
def count_gaps(self):
"""
Check each column one by one to make sure there are no gaps in the
column.
"""
return sum(
["".join([row[col] for row in self.state]).lstrip().count(' ')
for col in range(Field.WIDTH)])
def height(self):
"""
Returns the height on the field of the highest placed tetromino on the
field.
"""
for i, row in enumerate(self.state):
if ''.join(row).strip():
return Field.HEIGHT - i
if __name__ == '__main__':
import sys
f = Field()
if len(sys.argv) > 1 and sys.argv[1] == 'sim':
from optimizer import Optimizer
i = input()
while i != 'q':
t = Tetromino.create(i)
opt = Optimizer.get_optimal_drop(f, t)
t.rotate(opt['orientation'])
f.drop(t, opt['column'])
print(f)
i = input()
t = Tetromino.JTetromino().rotate_right()
print(t)
f.drop(t, 0)
print(f)
# f.drop(Tetromino.LTetromino(), 2)
# print(f)
# f.drop(Tetromino.JTetromino().rotate_left(), 5)
# print(f)
# t = Tetromino.LTetromino().flip()
# f.drop(t, 0)
# f.drop(Tetromino.TTetromino().flip(), 0)
# f.drop(Tetromino.JTetromino(), 4)
# print(f)

49
flappy.py Normal file
View File

@@ -0,0 +1,49 @@
import cv2 as cv
import pydirectinput
from game_base_class import GameBase
from flappy_pos_discovery_thread import FlappyPosDiscovery
from keyboard_thread import KeyboardEvent
class Flappy(GameBase):
def __init__(self, overlay):
super().__init__(overlay)
self.litris_reset_board = cv.imread("control_elements/sodoku_reset_button.jpg", cv.IMREAD_COLOR)
self.flappy_pos_disc = FlappyPosDiscovery()
self.keyboard_listener = KeyboardEvent()
def assess_playfield_and_make_move(self):
#last_letter_received = time()
while True:
if self.overlay.run_mode == 'stopped' or self.overlay.run_mode == 'paused':
return
wait_timer = 380 + self.keyboard_listener.offset_value
self.click()
cv.waitKey(wait_timer)
'''
if self.flappy_pos_disc.next_gate_height[0] is not 0:
offset = (self.flappy_pos_disc.next_gate_height[0] + 120) - self.flappy_pos_disc.get_actual_pet_height()
if offset > 50:
self.click()
cv.waitKey(int(wait_timer -100))
print("pet_pos: ", self.flappy_pos_disc.get_actual_pet_height())
if self.flappy_pos_disc.next_gate_height[0] is not 0:
offset = (self.flappy_pos_disc.next_gate_height[0] + 120) - self.flappy_pos_disc.current_pet_height
if offset > 50:
offset = 50
elif offset < -50:
offset = -50
print(offset)
wait_timer = 380 + offset
print(wait_timer)
print("pet_pos: ", self.flappy_pos_disc.current_pet_height)
print("next gate: ", self.flappy_pos_disc.next_gate_height[0] + 120) '''
def click(self):
pydirectinput.mouseDown()
cv.waitKey(50)
pydirectinput.mouseUp()

BIN
flappy/flappy-mask.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 716 B

BIN
flappy/flappy.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

BIN
flappy/flappy.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

BIN
flappy/gate-mask.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

BIN
flappy/gate.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

BIN
flappy/gate.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 436 KiB

BIN
flappy/screen.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 530 KiB

View File

@@ -0,0 +1,83 @@
import threading
import cv2 as cv
from window_capture import WindowCapture
from vision import Vision
from config_file import UserConfigs
class FlappyPosDiscovery(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self.config = UserConfigs()
self.capture_window = WindowCapture(None, None, self.config)
self.vision_stun = Vision()
self.needle_f = self.scale_picture(cv.imread("flappy/flappy.jpg"), 50)
self.mask_f = self.scale_picture(cv.imread("flappy/flappy-mask.png"), 50)
self.needle_g = self.scale_picture(cv.imread("flappy/gate.jpg"), 50)
self.mask_g = self.scale_picture(cv.imread("flappy/gate-mask.png"), 50)
self.run_mode = 'run'
self.current_pet_height = []
self.next_gate_height = [0,0,0]
self.offset_down = 90
self.start()
def run(self):
while self.run_mode == 'run':
screenshot_g = self.scale_picture(self.capture_window.get_screenshot_by_area([700, 1200, 1860, 90]), 50)
screenshot_f = self.scale_picture(self.capture_window.get_screenshot_by_area([200, 1250, 610, 90]), 50)
#cv.imshow("screenshot_g", screenshot_f)
#cv.waitKey(150)
rectangles_g = self.vision_stun.find(screenshot_g, self.needle_g, 0.8, 1)
rectangles_f = self.vision_stun.find(screenshot_f, self.needle_f, 0.7, 1) #, True, self.mask_f)
if len(rectangles_g) is not 0:
height = rectangles_g[0][1] + rectangles_g[0][3] + (self.offset_down /2)
if self.next_gate_height[2] is not height:
self.next_gate_height.append(height)
if len(self.next_gate_height) > 3:
self.next_gate_height.pop(0)
#pro_screen = self.vision_stun.draw_rectangles(screenshot_g, rectangles_g)
#cv.imshow("screenshot_g", pro_screen)
#cv.waitKey(150)
else:
pass
if len(rectangles_f) is not 0:
self.current_pet_height.append(rectangles_f[0][1] + rectangles_f[0][3] + self.offset_down)
if len(self.current_pet_height) > 5:
self.current_pet_height.pop(0)
#print("pet_pos: ", self.current_pet_height)
#print("next gate: ", self.next_gate_height)
def scale_picture(self, img, scale_percent):
width = int(img.shape[1] * scale_percent / 100)
height = int(img.shape[0] * scale_percent / 100)
resized_img = cv.resize(img, (width, height), interpolation=4)
gray = cv.cvtColor(resized_img, cv.COLOR_BGR2GRAY)
thresh = cv.threshold(gray, 0, 255, cv.THRESH_BINARY_INV + cv.THRESH_OTSU)[1]
return thresh
def get_actual_pet_height(self):
return sum(self.current_pet_height) / len(self.current_pet_height)
def get_next_gate_height(self):
return self.next_gate_height

View File

@@ -20,7 +20,7 @@ class Fruit(GameBase):
self.colors = [GREEN, YELLOW, RED, BLUE, ORANGE]
self.offset_left = 553
self.offset_left = 390
self.offset_down = 188
self.fill_data_coordinates()
@@ -35,7 +35,10 @@ class Fruit(GameBase):
def fill_data_coordinates(self):
# 553 to 1861 = 1330 / 11 = 119
# 188 to 1022 = 1076 / 7 = 119
dim = 119
# 390 to 2000 = 1610 / 11 = 143
# 188 to 1210 = 1076 / 7 = 119
dim = 143
for e in range(0, 7, 1):
for i in range(0, 11, 1):
self.data_coordinates[e][i] = [i * dim, e * dim, dim, dim]
@@ -90,11 +93,16 @@ class Fruit(GameBase):
#cv.waitKey(150)
# continue
data_coords = np.zeros((7, 11), dtype=object)
# field = Field()
# field = Pickaxe_Field()
for needle_key in self.needles.keys():
# gray_needle = cv.cvtColor(self.needles[needle_key], cv.COLOR_BGR2GRAY)
# thresh_needle = cv.threshold(gray_needle, 0, 255, cv.THRESH_BINARY_INV + cv.THRESH_OTSU)[1]
rectangles = self.vision_stun.find(screenshot, self.needles[needle_key], 0.74, 56)
rectangles = self.vision_stun.find(screenshot, self.needles[needle_key], 0.78, 56)
#output_image = self.vision_stun.draw_rectangles(screenshot, rectangles)
#cv.imshow("output_image", output_image)
#cv.waitKey(150)
if len(rectangles) == 0:
continue
points = self.vision_stun.get_click_points(rectangles)

View File

@@ -29,6 +29,7 @@ TENESENT = 23
CIBUTRANT = 24
ARTISENT = 25
MINING_LARGE = True
class GameBase:
@@ -104,10 +105,12 @@ class GameBase:
def assess_playfield_and_make_move(self):
pass
#screenshot = screenshot[190:1230, 260:2090]
#[58: 1134, 230: 2113]
def fill_data_coordinates(self):
# 230 to 2110 = 1883 / 14 = 134.5
# 60 to 1130 = 1076 / 8 = 134.5
dim = 134.5
# 260 to 2090 = 1883 / 14 = 130
# 190 to 1230 = 1076 / 8 = 130
dim = 130
for e in range(0, 8, 1):
for i in range(0, 14, 1):
self.data_coordinates[e][i] = [i * dim, e * dim, dim, dim]
@@ -121,8 +124,8 @@ class GameBase:
return True
def check_for_next_level(self, screen, needle):
offset_left = 230
offset_down = 58
offset_left = 260
offset_down = 190
rectangles = self.vision_stun.find(screen, needle, 0.70, 1)
if len(rectangles) == 0:
return False
@@ -218,8 +221,8 @@ class GameBase:
return int(center_x), int(center_y)
def move_tile(self, point_source, point_dest):
offset_left = 230
offset_down = 58
offset_left = 260
offset_down = 190
pydirectinput.moveTo(point_source[0] + offset_left, point_source[1] + offset_down)
# pydirectinput.moveTo(0,0)
pydirectinput.mouseDown()

32
keyboard_thread.py Normal file
View File

@@ -0,0 +1,32 @@
import threading
import cv2 as cv
import keyboard
class KeyboardEvent(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self.run_mode = 'run'
self.offset_value = 0
self.start()
def run(self):
while self.run_mode == 'run':
if keyboard.is_pressed('up'): # if key 'q' is pressed
self.offset_value = -75
elif keyboard.is_pressed('down'):
self.offset_value = 75
elif keyboard.is_pressed('left') or keyboard.is_pressed('right'):
self.offset_value = 0
cv.waitKey(10)
def callback(self):
pass
def destroy(self):
self.destroy()
def get_run_mode(self):
return self.run_mode

235
litris.py Normal file
View File

@@ -0,0 +1,235 @@
from copy import copy
import cv2 as cv
import numpy as np
from time import time
from game_base_class import GameBase
from pynput.keyboard import Key, Controller
from field import Field
from tetromino import Tetromino
from optimizer import Optimizer
from litris_stone_id_thread import NewStoneID
class Litris(GameBase):
def __init__(self, overlay):
super().__init__(overlay)
self.keyboard = Controller()
self.offset_left = 610
self.offset_down = 40
self.field = Field()
self.litris_reset_board = cv.imread("control_elements/sodoku_reset_button.jpg", cv.IMREAD_COLOR)
self.stone_id_thread = NewStoneID()
self.move_mode = 1
self.moved_around_full = False
self.field_state_storage = {
1: self.field,
2: self.field,
3: self.field,
4: self.field
}
def reset(self):
self.field.reset_field()
self.field.cleared_rows = 1
self.move_mode = 1
self.moved_around_full = False
def assess_playfield_and_make_move(self):
last_letter_received = time()
while True:
if self.stone_id_thread.get_pick_up_status() == False:
if (time() - last_letter_received) >= 5:
self.reset()
last_letter_received = time()
self.dig_point(1500, 980, 100)
if self.overlay.run_mode == 'stopped' or self.overlay.run_mode == 'paused':
return
continue
if self.overlay.run_mode == 'stopped' or self.overlay.run_mode == 'paused':
return
cv.waitKey(25)
continue
current_letter = self.stone_id_thread.get_actual_letter()
print("current_letter: ", current_letter)
last_letter_received = time()
current_tetromino = Tetromino.create(current_letter)
if self.move_mode == 2:
current_tetromino.rotate(3)
elif self.move_mode == 3:
current_tetromino.rotate(2)
elif self.move_mode == 4:
current_tetromino.rotate(1)
opt = Optimizer.get_optimal_drop(self.field, current_tetromino)
rotation = opt['tetromino_rotation']
column = opt['tetromino_column']
print("Rota:", rotation)
print("column:", column)
current_tetromino.rotate(rotation)
offset_col = current_tetromino.get_offset_column(rotation, self.move_mode)
print("offset column:", offset_col)
self.field.drop(current_tetromino, column)
self.move_stone(column - offset_col, rotation)
self.drop_down()
print(self.field)
if self.field.get_line_count() >= 6 and self.field.height() <= 2 and self.field.check_crucial_pos_to_be_free():
if self.field.predict_gaps_in_next_rotation() <= 3:
self.field_state_storage[self.move_mode] = copy(self.field)
self.update_move_mode()
#self.field.state = self.stone_id_thread.get_current_board_state()
self.field.rotate_state()
#self.update_move_mode()
self.field.reset_half_field()
self.update_field_with_stored_edges()
#field_mem = copy(self.field)
#self.field = copy(self.field_mem)
#self.field_mem = copy(field_mem)
self.field.cleared_rows = 1
cv.waitKey(100)
self.stone_id_thread.set_pick_up_status(False)
def update_field_with_stored_edges(self):
if self.move_mode == 1 and self.moved_around_full:
state_copy = Field.rotate_90_degree_clckwise(copy(self.field_state_storage[2].state))
for i in range(11,20,1):
for e in range(0,2,1):
self.field.state[i][e] = state_copy[i][e]
elif self.move_mode == 2 and self.moved_around_full:
state_copy = Field.rotate_90_degree_clckwise(copy(self.field_state_storage[3].state))
for i in range(11,20,1):
for e in range(0,2,1):
self.field.state[i][e] = state_copy[i][e]
elif self.move_mode == 3 and self.moved_around_full:
state_copy = Field.rotate_90_degree_clckwise(copy(self.field_state_storage[4].state))
for i in range(11, 20, 1):
for e in range(0, 2, 1):
self.field.state[i][e] = state_copy[i][e]
elif self.move_mode == 4:
state_copy = Field.rotate_90_degree_clckwise(copy(self.field_state_storage[1].state))
for i in range(11,20,1):
for e in range(0,2,1):
self.field.state[i][e] = state_copy[i][e]
self.moved_around_full = True
def drop_down(self):
if self.move_mode == 1:
down = Key.down
left = Key.left
right = Key.right
elif self.move_mode == 2:
down = Key.left
left = Key.up
right = Key.down
elif self.move_mode == 3:
down = Key.up
left = Key.right
right = Key.left
elif self.move_mode == 4:
down = Key.right
left = Key.down
right = Key.up
for i in range(1, 10, 1):
self.keyboard.press(down)
self.keyboard.release(down)
print("drop down pressed:", down)
cv.waitKey(40)
def update_move_mode(self):
if self.move_mode <=3:
self.move_mode = self.move_mode + 1
elif self.move_mode == 4:
self.move_mode = 1
def move_stone(self, col_movement, rotation):
if col_movement is None:
return
if self.move_mode == 1:
down = Key.down
left = Key.left
right = Key.right
elif self.move_mode == 2:
down = Key.left
left = Key.up
right = Key.down
elif self.move_mode == 3:
down = Key.up
left = Key.right
right = Key.left
elif self.move_mode == 4:
down = Key.right
left = Key.down
right = Key.up
# Press and release space
self.keyboard.press(down)
self.keyboard.release(down)
print("direction pressed: ", down)
cv.waitKey(60)
if rotation == 3:
self.keyboard.press('e')
self.keyboard.release('e')
print("rotation 1 pressed: e")
cv.waitKey(30)
elif rotation == 2:
self.keyboard.press('e')
self.keyboard.release('e')
print("rotation 2 pressed: e 1")
cv.waitKey(30)
self.keyboard.press('e')
self.keyboard.release('e')
print("rotation 2 pressed: e 2")
cv.waitKey(30)
elif rotation == 1:
self.keyboard.press('e')
self.keyboard.release('e')
print("rotation 3 pressed: e 1")
cv.waitKey(30)
self.keyboard.press('e')
self.keyboard.release('e')
print("rotation 3 pressed: e 2")
cv.waitKey(30)
self.keyboard.press('e')
self.keyboard.release('e')
print("rotation 3 pressed: e 3")
cv.waitKey(30)
if col_movement < 0:
for i in range(0, col_movement, - 1):
self.keyboard.press(left)
self.keyboard.release(left)
print("move left 3 pressed:", left)
cv.waitKey(30)
else:
for i in range(0, col_movement, 1):
self.keyboard.press(right)
self.keyboard.release(right)
print("move right 3 pressed:", right)
cv.waitKey(30)
def point_in_rect(self, point):
for e in range(0, 20, 1):
for i in range(0, 20, 1):
x1, y1, w, h = self.data_coordinates[e][i]
x2, y2 = x1 + w, y1 + h
x, y = point
if x1 < x and x < x2:
if y1 < y and y < y2:
return e, i
return None, None

BIN
litris/A-mask.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 251 B

BIN
litris/A.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

BIN
litris/A.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

BIN
litris/B-mask.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 233 B

BIN
litris/B.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

BIN
litris/B.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
litris/C-mask.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 195 B

BIN
litris/C.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

BIN
litris/C.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

BIN
litris/D-mask.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 427 B

BIN
litris/D.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

BIN
litris/D.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

BIN
litris/I-mask.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 274 B

BIN
litris/I.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

BIN
litris/I.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

BIN
litris/J-mask.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 476 B

BIN
litris/J.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

BIN
litris/J.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

BIN
litris/L-mask.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 473 B

BIN
litris/L.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

BIN
litris/L.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

BIN
litris/O-mask.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 370 B

BIN
litris/O.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

BIN
litris/O.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

BIN
litris/S-mask.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 553 B

BIN
litris/S.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

BIN
litris/S.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

BIN
litris/T-mask.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 528 B

BIN
litris/T.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

BIN
litris/T.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

BIN
litris/Z-mask.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 553 B

BIN
litris/Z.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

BIN
litris/Z.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

BIN
litris/blue_needle.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
litris/main_playfield.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 578 KiB

193
litris_stone_id_thread.py Normal file
View File

@@ -0,0 +1,193 @@
import threading
import cv2 as cv
import numpy as np
from window_capture import WindowCapture
from vision import Vision
from config_file import UserConfigs
O_FULL = [[0, 0, 0, 0], [0, 1, 1, 0], [0, 1, 1, 0], [0, 0, 0, 0]]
D_FULL = [[0, 0, 0, 0], [0, 1, 1, 0], [0, 0, 1, 0], [0, 0, 0, 0]]
L_FULL = [[0, 0, 0, 0], [0, 0, 1, 0], [1, 1, 1, 0], [0, 0, 0, 0]]
J_FULL = [[0, 0, 0, 0], [1, 1, 1, 0], [0, 0, 1, 0], [0, 0, 0, 0]]
I_FULL = [[0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0]]
C_FULL = [[0, 0, 0, 0], [0, 0, 1, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
B_FULL = [[0, 0, 0, 0], [0, 1, 1, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
A_FULL = [[0, 0, 0, 0], [0, 1, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0]]
S_FULL = [[0, 0, 0, 0], [0, 0, 1, 1], [0, 1, 1, 0], [0, 0, 0, 0]]
Z_FULL = [[0, 0, 0, 0], [0, 1, 1, 0], [0, 0, 1, 1], [0, 0, 0, 0]]
T_FULL = [[0, 0, 0, 0], [0, 1, 1, 1], [0, 0, 1, 0], [0, 0, 0, 0]]
class NewStoneID(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self.config = UserConfigs()
self.capture_window = WindowCapture(None, None, self.config)
self.vision_stun = Vision()
self.stone_coordinates = np.zeros((4, 4), dtype=object)
self.data_coordinates = np.zeros((20, 20), dtype=object)
self.fill_data_coordinates()
self.needles = {'Q': cv.imread("litris/blue_needle.jpg", cv.IMREAD_UNCHANGED)}
self.run_mode = 'run'
self.actual_letter = ""
self.to_pick_up = False
self.start()
def run(self):
while self.run_mode == 'run':
current_stone = self.new_stone_detection()
if current_stone is None:
cv.waitKey(50)
continue
else:
current_letter = self.get_letter_for_stone(current_stone)
if current_letter is None:
continue
else:
self.actual_letter = current_letter
self.to_pick_up = True
while self.to_pick_up:
cv.waitKey(10)
self.actual_letter = ""
def get_actual_letter(self):
return self.actual_letter
def set_pick_up_status(self, status):
self.to_pick_up = status
def get_pick_up_status(self):
return self.to_pick_up
def callback(self):
pass
def destroy(self):
self.destroy()
def get_run_mode(self):
return self.run_mode
def new_stone_detection(self):
screenshot = self.capture_window.get_screenshot()
screenshot = screenshot[580:845, 1148:1412]
rectangles = self.vision_stun.find(screenshot, self.needles['Q'], 0.85, 16)
if len(rectangles) == 0:
return None
points = self.vision_stun.get_click_points(rectangles)
stone_coords = np.zeros((4, 4), dtype=object)
for point in points:
x, y = self.point_in_small_rect(point)
if x is not None and y is not None:
stone_coords[x][y] = 1
# self.change_value(x, y, int(needle_key))
# print(field.data_value_grid)
#cv.circle(screenshot, points[0], 7, (0, 255, 0), -1)
#output_image = self.vision_stun.draw_rectangles(screenshot, rectangles)
#cv.imshow("output_image", output_image)
#cv.waitKey(150)
return stone_coords
def get_letter_for_stone(self, stone):
if np.array_equal(stone, O_FULL):
return "O"
elif np.array_equal(stone, D_FULL):
return "D"
elif np.array_equal(stone, L_FULL):
return "L"
elif np.array_equal(stone, J_FULL):
return "J"
elif np.array_equal(stone, I_FULL):
return "I"
elif np.array_equal(stone, C_FULL):
return "C"
elif np.array_equal(stone, B_FULL):
return "B"
elif np.array_equal(stone, A_FULL):
return "A"
elif np.array_equal(stone, S_FULL):
return "S"
elif np.array_equal(stone, Z_FULL):
return "Z"
elif np.array_equal(stone, T_FULL):
return "T"
else:
return None
def point_in_small_rect(self, point):
for e in range(0, 4, 1):
for i in range(0, 4, 1):
x1, y1, w, h = self.stone_coordinates[e][i]
x2, y2 = x1 + w, y1 + h
x, y = point
if x1 < x and x < x2:
if y1 < y and y < y2:
return e, i
return None, None
def get_current_board_state(self):
# get an updated image of the game
screenshot = self.capture_window.get_screenshot()
#screenshot = cv.imread("litris/main_playfield.jpg")
screenshot = screenshot[40:1380, 610:1950] # 1000,1000
# cv.imshow("screenshot", screenshot)
# cv.waitKey(150)
# continue
#data_coords = np.zeros((20, 20), dtype=object)
data_coords = np.full((20, 20), ' ', dtype=object)
#field = Pickaxe_Field()
for needle_key in self.needles.keys():
#gray_needle = cv.cvtColor(self.needles[needle_key], cv.COLOR_BGR2GRAY)
#thresh_needle = cv.threshold(gray_needle, 0, 255, cv.THRESH_BINARY_INV + cv.THRESH_OTSU)[1]
rectangles = self.vision_stun.find(screenshot, self.needles[needle_key], 0.8, 200)
if len(rectangles) == 0:
continue
points = self.vision_stun.get_click_points(rectangles)
for point in points:
x, y = self.point_in_rect(point)
if x is not None and y is not None:
data_coords[x][y] = needle_key
#self.change_value(x, y, int(needle_key))
# print(field.data_value_grid)
# cv.circle(screenshot, points[0], 7, (0, 255, 0), -1)
#output_image = self.vision_stun.draw_rectangles(screenshot, rectangles)
#cv.imshow("output_image", output_image)
#cv.waitKey(150)
return data_coords.tolist()
def point_in_rect(self, point):
for e in range(0, 20, 1):
for i in range(0, 20, 1):
x1, y1, w, h = self.data_coordinates[e][i]
x2, y2 = x1 + w, y1 + h
x, y = point
if x1 < x and x < x2:
if y1 < y and y < y2:
return e, i
return None, None
def fill_data_coordinates(self):
# 610 to 1950 = 1340 - 76 / 20 = 63
# 40 to 1380 = 1340 - 76 / 20 = 63
# spacing 19 * 4
dim = 63
e_spacing = 4
i_spacing = 4
for e in range(0, 4, 1):
for i in range(0, 4, 1):
self.stone_coordinates[e][i] = [(i * dim) + (i * i_spacing), (e * dim) + (e * e_spacing), dim, dim]
for e in range(0, 20, 1):
for i in range(0, 20, 1):
self.data_coordinates[e][i] = [(i * dim) + (i * i_spacing), (e * dim) + (e * e_spacing), dim, dim]

144
menti_dic Normal file
View File

@@ -0,0 +1,144 @@
HIT
IT
HI
POT
TOP
TO
HAS
ASH
HA
AS
AH
NOW
NO
ON
OWN
WON
WHEN
NEW
HE
WE
FORM
OR
OF
FROM
FOR
HIST
HIS
HITS
THIS
SIT
ITS
FIND
IF
FIN
IN
BEST
BET
SET
BE
HAT
NAT
TAN
ANT
AN
THAN
RACE
ACE
ACER
CARE
ERA
ARC
CAR
EAR
TEA
LATE
LET
ATE
EAT
TALE
HIRE
TIRE
THEIR
TIE
TIER
TAB
BOAT
BUT
OUT
ABOUT
AUTO
HER
HERO
OTHER
TOE
HOT
RICE
PRICE
RIP
PIE
RIPE
ICE
FIRST
FIST
SIR
FIT
FITS
SAT
TASTE
STATE
SEA
EAST
TEST
MAIL
EMAIL
MALE
LIE
AIM
MILE
FEAR
ART
RATE
AFTER
FAR
ARE
DEAF
FACE
CAFE
FED
FACED
INK
LINK
LINKS
SIN
SKIN
SKI
HERO

185
menti_words.py Normal file
View File

@@ -0,0 +1,185 @@
import cv2 as cv
import numpy as np
import pydirectinput
from nltk.corpus import words
from pytesseract import pytesseract
import utils
from utils import mse
from game_base_class import GameBase
import random
GREEN = 1
YELLOW = 2
RED = 3
BLUE = 4
ORANGE = 5
class MentiWords(GameBase):
def __init__(self, overlay):
super().__init__(overlay)
pytesseract.tesseract_cmd = r'C:\Program Files\Tesseract-OCR\tesseract.exe'
self.observation = np.zeros((9, 9), dtype=int)
self.colors = [1, 2, 3, 4, 5, 6, 7, 8, 9]
self.offset_left = 1080
self.offset_down = 870
self.menti_play_button = cv.imread("control_elements/play.jpg", cv.IMREAD_COLOR)
self.needles = {
'A': cv.imread("menti_words/a.jpg", cv.IMREAD_COLOR),
'B': cv.imread("menti_words/b.jpg", cv.IMREAD_COLOR),
'C': cv.imread("menti_words/c.jpg", cv.IMREAD_COLOR),
'D': cv.imread("menti_words/d.jpg", cv.IMREAD_COLOR),
'E': cv.imread("menti_words/e.jpg", cv.IMREAD_COLOR),
'F': cv.imread("menti_words/f.jpg", cv.IMREAD_COLOR),
'H': cv.imread("menti_words/h.jpg", cv.IMREAD_COLOR),
'I': cv.imread("menti_words/i.jpg", cv.IMREAD_COLOR),
'L': cv.imread("menti_words/l.jpg", cv.IMREAD_COLOR),
'M': cv.imread("menti_words/m.jpg", cv.IMREAD_COLOR),
'N': cv.imread("menti_words/n.jpg", cv.IMREAD_COLOR),
'O': cv.imread("menti_words/o.jpg", cv.IMREAD_COLOR),
'P': cv.imread("menti_words/p.jpg", cv.IMREAD_COLOR),
'R': cv.imread("menti_words/r.jpg", cv.IMREAD_COLOR),
'S': cv.imread("menti_words/s.jpg", cv.IMREAD_COLOR),
'T': cv.imread("menti_words/t.jpg", cv.IMREAD_COLOR),
'U': cv.imread("menti_words/u.jpg", cv.IMREAD_COLOR),
'W': cv.imread("menti_words/w.jpg", cv.IMREAD_COLOR)
}
self.masks = {
'A': cv.imread("menti_words/a-mask.png", cv.IMREAD_COLOR),
'B': cv.imread("menti_words/b-mask.png", cv.IMREAD_COLOR),
'C': cv.imread("menti_words/c-mask.png", cv.IMREAD_COLOR),
'D': cv.imread("menti_words/d-mask.png", cv.IMREAD_COLOR),
'E': cv.imread("menti_words/e-mask.png", cv.IMREAD_COLOR),
'F': cv.imread("menti_words/f-mask.png", cv.IMREAD_COLOR),
'H': cv.imread("menti_words/h-mask.png", cv.IMREAD_COLOR),
'I': cv.imread("menti_words/i-mask.png", cv.IMREAD_COLOR),
'L': cv.imread("menti_words/l-mask.png", cv.IMREAD_COLOR),
'M': cv.imread("menti_words/m-mask.png", cv.IMREAD_COLOR),
'N': cv.imread("menti_words/n-mask.png", cv.IMREAD_COLOR),
'O': cv.imread("menti_words/o-mask.png", cv.IMREAD_COLOR),
'P': cv.imread("menti_words/p-mask.png", cv.IMREAD_COLOR),
'R': cv.imread("menti_words/r-mask.png", cv.IMREAD_COLOR),
'S': cv.imread("menti_words/s-mask.png", cv.IMREAD_COLOR),
'T': cv.imread("menti_words/t-mask.png", cv.IMREAD_COLOR),
'U': cv.imread("menti_words/u-mask.png", cv.IMREAD_COLOR),
'W': cv.imread("menti_words/w-mask.png", cv.IMREAD_COLOR)
}
self.current_letters = []
self.letter_coords = {}
with open("menti_dic") as file:
self.word_list = [line.rstrip() for line in file]
#self.word_list2 = words.words()
def reset_lists(self):
self.current_letters = []
self.letter_coords = {}
def assess_playfield_and_make_move(self):
if self.check_for_button_and_execute(self.capture_window.get_screenshot(), self.menti_play_button):
cv.waitKey(2000)
self.reset_lists()
self.get_current_board_state()
if self.overlay.run_mode == 'stopped' or self.overlay.run_mode == 'paused':
return
matches = self.possible_words(self.word_list, self.current_letters)
matches.sort()
new_matches = list(map(list,matches))
for letter_list in new_matches:
self.type_word_into_ui(letter_list)
if self.overlay.run_mode == 'stopped' or self.overlay.run_mode == 'paused':
return
def type_word_into_ui(self, letters):
for letter in letters:
pydirectinput.moveTo(self.letter_coords[letter][0] + self.offset_left, self.letter_coords[letter][1] + self.offset_down)
pydirectinput.mouseDown()
w = random.randint(25, 50)
cv.waitKey(100 + w)
if self.overlay.run_mode == 'stopped' or self.overlay.run_mode == 'paused':
return
pydirectinput.mouseUp()
cv.waitKey(400)
def get_current_board_state(self):
#screenshot = cv.imread("menti_words/screenshot.jpg")
screenshot = self.capture_window.get_screenshot()
screenshot = utils.scale_screenshot(screenshot[870:1270, 1080:1480], 200, False)
#cv.imshow("screenshot", screenshot)
#cv.waitKey(150)
#continue
for needle_key in self.needles.keys():
# gray_needle = cv.cvtColor(self.needles[needle_key], cv.COLOR_BGR2GRAY)
# thresh_needle = cv.threshold(gray_needle, 0, 255, cv.THRESH_BINARY_INV + cv.THRESH_OTSU)[1]
thresh_needle = utils.scale_screenshot(self.needles[needle_key], 200, False)
rectangles = self.vision_stun.find(screenshot, thresh_needle , 0.85, 2)
#rectangles = self.vision_stun.find(screenshot, self.needles[needle_key], 0.95, 1 ,True, self.masks[needle_key])
if len(rectangles) == 0:
continue
points = self.vision_stun.get_click_points(rectangles)
for point in points:
self.current_letters.append(needle_key)
self.letter_coords[needle_key] = (int(point[0]/2), int(point[1]/2))
'''
cropped1 = self.vision_stun.draw_display_picture(screenshot, rectangles, 10)
#cropped1 = utils.scale_screenshot(cropped1)
cv.imshow("cropped1", cropped1)
cv.waitKey(150)
text_1 = pytesseract.image_to_string(cropped1, lang='eng', config='--psm 6').strip()
if str.isalpha(text_1):
#cv.imshow("cropped1", cropped1)
#cv.waitKey(150)
points = self.vision_stun.get_click_points(rectangles)
self.current_letters.append(text_1)
self.letter_coords[text_1] = points[0]'''
if self.overlay.run_mode == 'stopped' or self.overlay.run_mode == 'paused':
return
def possible_words(self, lwords, charSet):
lst = []
for word in lwords:
if len(word) <= 1:
continue
flag = 1
chars = self.charCount(word)
for key in chars:
if key not in charSet:
flag = 0
else:
if charSet.count(key) != chars[key]:
flag = 0
if flag == 1:
lst.append(word)
#print(word)
return list(set(lst))
def charCount(self, word):
dict = {}
for i in word:
dict[i] = dict.get(i, 0) + 1
return dict

BIN
menti_words/a-mask.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 405 B

BIN
menti_words/a.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

BIN
menti_words/a.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

BIN
menti_words/b-mask.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 341 B

BIN
menti_words/b.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

BIN
menti_words/b.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

BIN
menti_words/c-mask.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 B

BIN
menti_words/c.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
menti_words/c.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

BIN
menti_words/d-mask.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 344 B

BIN
menti_words/d.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

BIN
menti_words/d.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

BIN
menti_words/e-mask.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 209 B

BIN
menti_words/e.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
menti_words/e.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
menti_words/f-mask.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 238 B

BIN
menti_words/f.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
menti_words/f.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
menti_words/h-mask.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 262 B

BIN
menti_words/h.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
menti_words/h.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
menti_words/i-mask.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 231 B

BIN
menti_words/i.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
menti_words/i.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 782 B

BIN
menti_words/l-mask.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 274 B

BIN
menti_words/l.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
menti_words/l.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
menti_words/m-mask.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 499 B

BIN
menti_words/m.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

BIN
menti_words/m.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

BIN
menti_words/n-mask.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 388 B

BIN
menti_words/n.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

BIN
menti_words/n.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

BIN
menti_words/o-mask.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 397 B

BIN
menti_words/o.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

BIN
menti_words/o.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Some files were not shown because too many files have changed in this diff Show More