forked from tanjeffreyz/auto-maple
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathnotifier.py
128 lines (105 loc) · 4.36 KB
/
notifier.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
"""A module for detecting and notifying the user of dangerous in-game events."""
import config
import utils
import time
import cv2
import pygame
import threading
import numpy as np
import keyboard as kb
from components import Point
# A rune's symbol on the minimap
RUNE_RANGES = (
((141, 148, 245), (146, 158, 255)),
)
rune_filtered = utils.filter_color(cv2.imread('assets/rune_template.png'), RUNE_RANGES)
RUNE_TEMPLATE = cv2.cvtColor(rune_filtered, cv2.COLOR_BGR2GRAY)
# Other players' symbols on the minimap
OTHER_RANGES = (
((0, 245, 215), (10, 255, 255)),
)
other_filtered = utils.filter_color(cv2.imread('assets/other_template.png'), OTHER_RANGES)
OTHER_TEMPLATE = cv2.cvtColor(other_filtered, cv2.COLOR_BGR2GRAY)
# The Elite Boss's warning sign
ELITE_TEMPLATE = cv2.imread('assets/elite_template.jpg', 0)
class Notifier:
def __init__(self):
"""Initializes this Notifier object's main thread."""
pygame.mixer.init()
self.mixer = pygame.mixer.music
self.ready = False
self.thread = threading.Thread(target=self._main)
self.thread.daemon = True
def start(self):
"""Starts this Notifier's thread."""
print('\n[~] Started notifier.')
self.thread.start()
def _main(self):
self.ready = True
prev_others = 0
while True:
if config.enabled:
frame = config.capture.frame
height, width, _ = frame.shape
minimap = config.capture.minimap['minimap']
# Check for unexpected black screen
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
if np.count_nonzero(gray < 15) / height / width > 0.95:
self._alert()
# Check for elite warning
elite_frame = frame[height // 4:3 * height // 4, width // 4:3 * width // 4]
elite = utils.multi_match(elite_frame, ELITE_TEMPLATE, threshold=0.9)
if len(elite) > 0:
self._alert()
# Check for other players entering the map
filtered = utils.filter_color(minimap, OTHER_RANGES)
others = len(utils.multi_match(filtered, OTHER_TEMPLATE, threshold=0.5))
config.stage_fright = others > 0
if others != prev_others:
if others > prev_others:
self._ding()
prev_others = others
# Check for rune
if not config.bot.rune_active:
filtered = utils.filter_color(minimap, RUNE_RANGES)
matches = utils.multi_match(filtered, RUNE_TEMPLATE, threshold=0.9)
if matches and config.routine.sequence:
abs_rune_pos = (matches[0][0], matches[0][1])
config.bot.rune_pos = utils.convert_to_relative(abs_rune_pos, minimap)
distances = list(map(distance_to_rune, config.routine.sequence))
index = np.argmin(distances)
config.bot.rune_closest_pos = config.routine[index].location
config.bot.rune_active = True
time.sleep(0.05)
def _alert(self):
"""
Plays an alert to notify user of a dangerous event. Stops the alert
once the key bound to 'Start/stop' is pressed.
"""
config.enabled = False
config.listener.enabled = False
self.mixer.load('./assets/alert.mp3')
self.mixer.set_volume(0.75)
self.mixer.play(-1)
while not kb.is_pressed(config.listener.key_binds['Start/stop']):
time.sleep(0.1)
self.mixer.stop()
time.sleep(2)
config.listener.enabled = True
def _ding(self):
"""A quick notification for when another player enters the map."""
self.mixer.load('./assets/ding.mp3')
self.mixer.set_volume(0.50)
self.mixer.play()
#################################
# Helper Functions #
#################################
def distance_to_rune(point):
"""
Calculates the distance from POINT to the rune.
:param point: The position to check.
:return: The distance from POINT to the rune, infinity if it is not a Point object.
"""
if isinstance(point, Point):
return utils.distance(config.bot.rune_pos, point.location)
return float('inf')