Add: 增加了挂委托的功能
BIN
assets/reward/COMMISSION_ADVICE.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
assets/reward/COMMISSION_DAILY.png
Normal file
After Width: | Height: | Size: 7.6 KiB |
BIN
assets/reward/COMMISSION_HAS_PENDING.png
Normal file
After Width: | Height: | Size: 5.4 KiB |
BIN
assets/reward/COMMISSION_NOTICE_AT_CAMPAIGN.png
Normal file
After Width: | Height: | Size: 5.4 KiB |
BIN
assets/reward/COMMISSION_OIL_CONFIRM.png
Normal file
After Width: | Height: | Size: 9.8 KiB |
BIN
assets/reward/COMMISSION_START.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
assets/reward/COMMISSION_STOP_SCROLLING.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
assets/reward/COMMISSION_URGENT.png
Normal file
After Width: | Height: | Size: 7.6 KiB |
BIN
assets/ui/COMMISSION_CHECK.png
Normal file
After Width: | Height: | Size: 7.2 KiB |
BIN
assets/ui/REWARD_GOTO_COMMISSION.png
Normal file
After Width: | Height: | Size: 8.3 KiB |
@ -46,6 +46,26 @@ reward_interval = 20
|
||||
enable_oil_reward = yes
|
||||
enable_coin_reward = yes
|
||||
enable_mission_reward = yes
|
||||
enable_commission_reward = yes
|
||||
commission_time_limit = 23:30
|
||||
duration_shorter_than_2 = 11
|
||||
duration_longer_than_6 = -11
|
||||
expire_shorter_than_2 = 11
|
||||
expire_longer_than_6 = -11
|
||||
daily_comm = 100
|
||||
major_comm = 0
|
||||
extra_drill = 20
|
||||
extra_part = 60
|
||||
extra_cube = 80
|
||||
extra_oil = 90
|
||||
extra_book = 70
|
||||
urgent_drill = 45
|
||||
urgent_part = 95
|
||||
urgent_cube = 165
|
||||
urgent_book = 145
|
||||
urgent_box = 195
|
||||
urgent_gem = 205
|
||||
urgent_ship = 155
|
||||
|
||||
[Emulator]
|
||||
command = emulator
|
||||
|
30
main.pyw
@ -154,6 +154,36 @@ def main():
|
||||
reward_mission = reward_parser.add_argument_group('任务奖励', '')
|
||||
reward_mission.add_argument('--启用任务收获', default=default('--启用任务收获'), choices=['是', '否'])
|
||||
|
||||
reward_commission = reward_parser.add_argument_group('委托设置', '')
|
||||
reward_commission.add_argument('--启用委托收获', default=default('--启用委托收获'), choices=['是', '否'])
|
||||
reward_commission.add_argument('--委托时间限制', default=default('--委托时间限制'), help='忽略完成时间超过限制的委托, 格式: 23:30')
|
||||
|
||||
priority1 = reward_commission.add_argument_group('委托耗时优先级', '')
|
||||
priority1.add_argument('--委托耗时小于2h', default=default('--委托耗时小于2h'), help='')
|
||||
priority1.add_argument('--委托耗时超过6h', default=default('--委托耗时超过6h'), help='')
|
||||
priority1.add_argument('--委托过期小于2h', default=default('--委托过期小于2h'), help='')
|
||||
priority1.add_argument('--委托过期大于6h', default=default('--委托过期大于6h'), help='')
|
||||
|
||||
priority2 = reward_commission.add_argument_group('日常委托优先级', '')
|
||||
priority2.add_argument('--日常委托', default=default('--日常委托'), help='日常资源开发, 高阶战术研发')
|
||||
priority2.add_argument('--主要委托', default=default('--主要委托'), help='1200油/1000油委托')
|
||||
|
||||
priority3 = reward_commission.add_argument_group('额外委托优先级', '')
|
||||
priority3.add_argument('--钻头类额外委托', default=default('--钻头类额外委托'), help='短距离航行训练, 近海防卫巡逻')
|
||||
priority3.add_argument('--部件类额外委托', default=default('--部件类额外委托'), help='矿脉护卫委托, 林木护卫委托')
|
||||
priority3.add_argument('--魔方类额外委托', default=default('--魔方类额外委托'), help='舰队高阶演习, 舰队护卫演习')
|
||||
priority3.add_argument('--石油类额外委托', default=default('--石油类额外委托'), help='小型油田开发, 大型油田开发')
|
||||
priority3.add_argument('--教材类额外委托', default=default('--教材类额外委托'), help='小型商船护卫, 大型商船护卫')
|
||||
|
||||
priority4 = reward_commission.add_argument_group('紧急委托优先级', '')
|
||||
priority4.add_argument('--钻头类紧急委托', default=default('--钻头类紧急委托'), help='保卫运输部队, 歼灭敌精锐部队')
|
||||
priority4.add_argument('--部件类紧急委托', default=default('--部件类紧急委托'), help='支援维拉维拉岛, 支援恐班纳')
|
||||
priority4.add_argument('--魔方类紧急委托', default=default('--魔方类紧急委托'), help='解救商船, 敌袭')
|
||||
priority4.add_argument('--教材类紧急委托', default=default('--教材类紧急委托'), help='支援土豪尔岛, 支援萌岛')
|
||||
priority4.add_argument('--装备类紧急委托', default=default('--装备类紧急委托'), help='BIW装备运输, NYB装备研发')
|
||||
priority4.add_argument('--钻石类紧急委托', default=default('--钻石类紧急委托'), help='BIW要员护卫, NYB巡视护卫')
|
||||
priority4.add_argument('--观舰类紧急委托', default=default('--观舰类紧急委托'), help='小型观舰仪式, 同盟观舰仪式')
|
||||
|
||||
# ==========设备设置==========
|
||||
emulator_parser = subs.add_parser('设备设置')
|
||||
emulator = emulator_parser.add_argument_group('模拟器', '')
|
||||
|
@ -16,6 +16,8 @@ OCR_MODELS = {
|
||||
# Font: Impact
|
||||
# Charset: 0123456789ABCDEFSP-:/
|
||||
'stage': CnOcr(root='./cnocr_models/stage', model_epoch=56),
|
||||
|
||||
'cnocr': CnOcr(root='./cnocr_models/cnocr', model_epoch=20)
|
||||
}
|
||||
image_shape = (280, 32)
|
||||
width_range = (0.6, 1.4)
|
||||
@ -26,7 +28,7 @@ y_range = (-2, 2)
|
||||
|
||||
class Ocr:
|
||||
def __init__(self, buttons, lang, letter=(255, 255, 255), back=(0, 0, 0), mid_process_height=70, threshold=127,
|
||||
additional_preprocess=None, length=None, white_list=None, name='OCR'):
|
||||
additional_preprocess=None, use_binary=True, length=None, white_list=None, name='OCR'):
|
||||
"""
|
||||
Args:
|
||||
lang (str): OCR model. in ['digit', 'cnocr'].
|
||||
@ -34,6 +36,7 @@ class Ocr:
|
||||
back (tuple(int)): Background RGB.
|
||||
mid_process_height (int): 70
|
||||
additional_preprocess (callable):
|
||||
use_binary (bool):
|
||||
length (int, tuple(int)): Expected length.
|
||||
white_list (str): Expected str.
|
||||
buttons (Button, List[Button]): Button or list of Button instance.
|
||||
@ -45,6 +48,7 @@ class Ocr:
|
||||
self.mid_process_height = mid_process_height
|
||||
self.threshold = threshold
|
||||
self.additional_preprocess = additional_preprocess
|
||||
self.use_binary=use_binary
|
||||
self.length = (length, length) if isinstance(length, int) else length
|
||||
self.white_list = white_list
|
||||
self.buttons = buttons if isinstance(buttons, list) else [buttons]
|
||||
@ -80,7 +84,8 @@ class Ocr:
|
||||
image = self.additional_preprocess(image)
|
||||
|
||||
# Binarization.
|
||||
_, image = cv2.threshold(image, self.threshold, 255, cv2.THRESH_BINARY)
|
||||
if self.use_binary:
|
||||
_, image = cv2.threshold(image, self.threshold, 255, cv2.THRESH_BINARY)
|
||||
|
||||
# Resize to input size.
|
||||
size = (int(image.shape[1] / image.shape[0] * image_shape[1]), image_shape[1])
|
||||
|
@ -1,4 +1,5 @@
|
||||
import time
|
||||
from datetime import datetime, timedelta
|
||||
from functools import wraps
|
||||
|
||||
from module.logger import logger
|
||||
@ -16,6 +17,20 @@ def timer(function):
|
||||
return function_timer
|
||||
|
||||
|
||||
def future_time(string):
|
||||
"""
|
||||
Args:
|
||||
string (str): Such as 14:59.
|
||||
|
||||
Returns:
|
||||
datetime: Time with given hour, minute, second in the future.
|
||||
"""
|
||||
hour, minute = [int(x) for x in string.split(':')]
|
||||
future = datetime.now().replace(hour=hour, minute=minute, second=0, microsecond=0)
|
||||
future = future + timedelta(days=1) if future < datetime.now() else future
|
||||
return future
|
||||
|
||||
|
||||
class Timer:
|
||||
def __init__(self, limit):
|
||||
self.limit = limit
|
||||
|
@ -2,12 +2,13 @@ import codecs
|
||||
import configparser
|
||||
import copy
|
||||
import os
|
||||
from datetime import datetime, timedelta
|
||||
import cv2
|
||||
from datetime import datetime
|
||||
|
||||
import cv2
|
||||
import numpy as np
|
||||
from PIL import Image
|
||||
|
||||
from module.base.timer import future_time
|
||||
from module.config.dictionary import *
|
||||
from module.logger import logger
|
||||
|
||||
@ -240,6 +241,28 @@ class AzurLaneConfig:
|
||||
ENABLE_OIL_REWARD = True
|
||||
ENABLE_COIN_REWARD = True
|
||||
ENABLE_MISSION_REWARD = True
|
||||
ENABLE_COMMISSION_REWARD = True
|
||||
COMMISSION_PRIORITY = {
|
||||
'major_comm': 0,
|
||||
'daily_comm': 100,
|
||||
'extra_drill': 20,
|
||||
'extra_part': 60,
|
||||
'extra_cube': 80,
|
||||
'extra_oil': 90,
|
||||
'extra_book': 70,
|
||||
'urgent_drill': 45,
|
||||
'urgent_part': 95,
|
||||
'urgent_book': 145,
|
||||
'urgent_box': 195,
|
||||
'urgent_cube': 165,
|
||||
'urgent_gem': 205,
|
||||
'urgent_ship': 155,
|
||||
'expire_shorter_than_2': 11,
|
||||
'expire_longer_than_6': -11,
|
||||
'duration_shorter_than_2': 11,
|
||||
'duration_longer_than_6': -11,
|
||||
}
|
||||
COMMISSION_TIME_LIMIT = 0
|
||||
|
||||
"""
|
||||
C_7_2_mystery_farming
|
||||
@ -302,10 +325,7 @@ class AzurLaneConfig:
|
||||
self.ENABLE_STOP_CONDITION = to_bool(option['enable_stop_condition'])
|
||||
self.STOP_IF_COUNT_GREATER_THAN = int(option['if_count_greater_than'])
|
||||
if not option['if_time_reach'].isdigit():
|
||||
hour, minute = [int(x) for x in option['if_time_reach'].split(':')]
|
||||
limit = datetime.now().replace(hour=hour, minute=minute, second=0, microsecond=0)
|
||||
limit = limit + timedelta(1) if limit < datetime.now() else limit
|
||||
self.STOP_IF_TIME_REACH = limit
|
||||
self.STOP_IF_TIME_REACH = future_time(option['if_time_reach'])
|
||||
else:
|
||||
self.STOP_IF_TIME_REACH = 0
|
||||
self.STOP_IF_OIL_LOWER_THAN = int(option['if_oil_lower_than'])
|
||||
@ -340,8 +360,11 @@ class AzurLaneConfig:
|
||||
# Reward
|
||||
option = config['Reward']
|
||||
self.REWARD_INTERVAL = int(option['reward_interval'])
|
||||
for attr in ['enable_reward', 'enable_oil_reward', 'enable_coin_reward', 'enable_mission_reward']:
|
||||
for attr in ['enable_reward', 'enable_oil_reward', 'enable_coin_reward', 'enable_mission_reward', 'enable_commission_reward']:
|
||||
self.__setattr__(attr.upper(), to_bool(option[attr]))
|
||||
self.COMMISSION_TIME_LIMIT = future_time(option['commission_time_limit'])
|
||||
for attr in self.COMMISSION_PRIORITY.keys():
|
||||
self.COMMISSION_PRIORITY[attr] = int(option[attr])
|
||||
|
||||
option = config['Main']
|
||||
self.CAMPAIGN_NAME = option['main_stage']
|
||||
|
@ -76,6 +76,26 @@ dic_chi_to_eng = {
|
||||
'启用石油收获': 'enable_oil_reward',
|
||||
'启用物资收获': 'enable_coin_reward',
|
||||
'启用任务收获': 'enable_mission_reward',
|
||||
'启用委托收获': 'enable_commission_reward',
|
||||
'委托时间限制': 'commission_time_limit',
|
||||
'委托耗时小于2h': 'duration_shorter_than_2',
|
||||
'委托耗时超过6h': 'duration_longer_than_6',
|
||||
'委托过期小于2h': 'expire_shorter_than_2',
|
||||
'委托过期大于6h': 'expire_longer_than_6',
|
||||
'日常委托': 'daily_comm',
|
||||
'主要委托': 'major_comm',
|
||||
'钻头类额外委托': 'extra_drill',
|
||||
'部件类额外委托': 'extra_part',
|
||||
'魔方类额外委托': 'extra_cube',
|
||||
'石油类额外委托': 'extra_oil',
|
||||
'教材类额外委托': 'extra_book',
|
||||
'钻头类紧急委托': 'urgent_drill',
|
||||
'部件类紧急委托': 'urgent_part',
|
||||
'魔方类紧急委托': 'urgent_cube',
|
||||
'教材类紧急委托': 'urgent_book',
|
||||
'装备类紧急委托': 'urgent_box',
|
||||
'钻石类紧急委托': 'urgent_gem',
|
||||
'观舰类紧急委托': 'urgent_ship',
|
||||
'设备': 'serial',
|
||||
'打每日': 'enable_daily_mission',
|
||||
'打困难': 'enable_hard_campaign',
|
||||
|
@ -5,6 +5,14 @@ from module.base.template import Template
|
||||
# Don't modified it manually.
|
||||
|
||||
COIN = Button(area=(403, 64, 436, 88), color=(226, 173, 72), button=(403, 64, 436, 88), file='./assets/reward/COIN.png')
|
||||
COMMISSION_ADVICE = Button(area=(871, 322, 999, 383), color=(230, 177, 116), button=(871, 322, 999, 383), file='./assets/reward/COMMISSION_ADVICE.png')
|
||||
COMMISSION_DAILY = Button(area=(35, 132, 67, 186), color=(208, 172, 118), button=(35, 132, 67, 186), file='./assets/reward/COMMISSION_DAILY.png')
|
||||
COMMISSION_HAS_PENDING = Button(area=(357, 300, 359, 330), color=(86, 201, 173), button=(357, 300, 359, 330), file='./assets/reward/COMMISSION_HAS_PENDING.png')
|
||||
COMMISSION_NOTICE_AT_CAMPAIGN = Button(area=(1054, 647, 1061, 654), color=(197, 89, 64), button=(1054, 647, 1061, 654), file='./assets/reward/COMMISSION_NOTICE_AT_CAMPAIGN.png')
|
||||
COMMISSION_OIL_CONFIRM = Button(area=(704, 493, 876, 550), color=(96, 145, 204), button=(704, 493, 876, 550), file='./assets/reward/COMMISSION_OIL_CONFIRM.png')
|
||||
COMMISSION_START = Button(area=(1028, 322, 1156, 383), color=(229, 175, 113), button=(1028, 322, 1156, 383), file='./assets/reward/COMMISSION_START.png')
|
||||
COMMISSION_STOP_SCROLLING = Button(area=(115, 236, 179, 487), color=(50, 55, 74), button=(115, 236, 179, 487), file='./assets/reward/COMMISSION_STOP_SCROLLING.png')
|
||||
COMMISSION_URGENT = Button(area=(35, 231, 68, 281), color=(215, 188, 124), button=(35, 231, 68, 281), file='./assets/reward/COMMISSION_URGENT.png')
|
||||
EXP_INFO_S_REWARD = Button(area=(498, 140, 557, 154), color=(233, 241, 127), button=(498, 140, 557, 154), file='./assets/reward/EXP_INFO_S_REWARD.png')
|
||||
MISSION_MULTI = Button(area=(1041, 8, 1101, 39), color=(226, 192, 142), button=(1041, 8, 1101, 39), file='./assets/reward/MISSION_MULTI.png')
|
||||
MISSION_NOTICE = Button(area=(940, 670, 945, 681), color=(183, 83, 66), button=(940, 670, 945, 681), file='./assets/reward/MISSION_NOTICE.png')
|
||||
|
465
module/reward/commission.py
Normal file
@ -0,0 +1,465 @@
|
||||
import re
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
import cv2
|
||||
import numpy as np
|
||||
from scipy import signal
|
||||
|
||||
from module.base.ocr import Ocr
|
||||
from module.base.timer import Timer
|
||||
from module.base.utils import area_offset, get_color
|
||||
from module.handler.info_bar import InfoBarHandler
|
||||
from module.logger import logger
|
||||
from module.reward.assets import *
|
||||
from module.ui.page import page_reward, page_commission
|
||||
from module.ui.ui import UI
|
||||
|
||||
dictionary = {
|
||||
'major_comm': ['自主训练', '对抗演习', '科研任务', '工具整备', '战术课程', '货物运输'],
|
||||
'daily_comm': ['日常资源开发', '高阶战术研发'],
|
||||
'extra_drill': ['航行训练', '防卫巡逻', '海域浮标检查作业'],
|
||||
'extra_part': ['委托'],
|
||||
'extra_cube': ['演习'],
|
||||
'extra_oil': ['油田'],
|
||||
'extra_book': ['商船护卫'],
|
||||
'urgent_drill': ['运输部队', '侦查部队', '主力部队', '精锐部队'],
|
||||
'urgent_part': ['维拉', '伊', '多伦瓦', '恐班纳'],
|
||||
'urgent_book': ['土豪尔', '姆波罗', '马拉基', '卡波罗', '马内', '玛丽', '萌', '特林'],
|
||||
'urgent_box': ['装备', '物资'],
|
||||
'urgent_cube': ['解救', '敌袭'],
|
||||
'urgent_gem': ['要员', '度假', '巡视'],
|
||||
'urgent_ship': ['观舰']
|
||||
}
|
||||
|
||||
|
||||
class Commission:
|
||||
def __init__(self, image, y):
|
||||
self.y = y
|
||||
self.stack_y = y
|
||||
self.area = (188, y - 119, 1199, y)
|
||||
self.image = image
|
||||
self.valid = True
|
||||
|
||||
# Name
|
||||
area = area_offset((211, 26, 415, 49), self.area[0:2])
|
||||
button = Button(area=area, color=(), button=area, name='COMMISSION')
|
||||
ocr = Ocr(button, lang='cnocr', back=(74, 97, 148), use_binary=False)
|
||||
self.button = button
|
||||
self.name = ocr.ocr(image)
|
||||
self.genre = self.parse_name(self.name)
|
||||
|
||||
# Duration time
|
||||
area = area_offset((290, 74, 390, 92), self.area[0:2])
|
||||
button = Button(area=area, color=(), button=area, name='DURATION')
|
||||
ocr = Ocr(button, lang='stage', back=(57, 85, 132))
|
||||
self.duration = self.parse_time(ocr.ocr(image))
|
||||
|
||||
# Expire time
|
||||
area = area_offset((-49, 68, -45, 84), self.area[0:2])
|
||||
button = Button(area=area, color=(189, 65, 66), button=area, name='IS_URGENT')
|
||||
if button.appear_on(image):
|
||||
area = area_offset((-49, 73, 45, 91), self.area[0:2])
|
||||
button = Button(area=area, color=(), button=area, name='EXPIRE')
|
||||
ocr = Ocr(button, lang='stage', back=(189, 65, 66))
|
||||
self.expire = self.parse_time(ocr.ocr(image))
|
||||
else:
|
||||
self.expire = None
|
||||
|
||||
# Status
|
||||
area = area_offset((179, 71, 187, 93), self.area[0:2])
|
||||
dic = {
|
||||
0: 'finished',
|
||||
1: 'running',
|
||||
2: 'pending'
|
||||
}
|
||||
self.status = dic[int(np.argmax(get_color(image, area)))]
|
||||
|
||||
def __str__(self):
|
||||
if self.valid:
|
||||
if self.expire:
|
||||
return f'{self.name} (Genre: {self.genre}, Status: {self.status}, Duration: {self.duration}, Expire: {self.expire})'
|
||||
else:
|
||||
return f'{self.name} (Genre: {self.genre}, Status: {self.status}, Duration: {self.duration})'
|
||||
else:
|
||||
return f'{self.name} (Invalid)'
|
||||
|
||||
def __eq__(self, other):
|
||||
"""
|
||||
Args:
|
||||
other (Commission):
|
||||
|
||||
Returns:
|
||||
bool:
|
||||
"""
|
||||
threshold = timedelta(seconds=30)
|
||||
if not self.valid or not other.valid:
|
||||
return False
|
||||
if self.genre != other.genre or self.status != other.status:
|
||||
return False
|
||||
if (other.duration < self.duration - threshold) or (other.duration > self.duration + threshold):
|
||||
return False
|
||||
if (not self.expire and other.expire) or (self.expire and not other.expire):
|
||||
return False
|
||||
if self.expire and other.expire:
|
||||
if (other.expire < self.expire - threshold) or (other.expire > self.expire + threshold):
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def parse_time(self, string):
|
||||
"""
|
||||
Args:
|
||||
string (str): Such as 01:00:00, 05:47:10, 17:50:51.
|
||||
|
||||
Returns:
|
||||
timedelta: datetime.timedelta instance.
|
||||
"""
|
||||
string = string.replace('D', '0') # Poor OCR
|
||||
result = re.search('(\d+):(\d+):(\d+)', string)
|
||||
if not result:
|
||||
logger.warning(f'Invalid time string: {string}')
|
||||
self.valid = False
|
||||
return None
|
||||
else:
|
||||
result = [int(s) for s in result.groups()]
|
||||
return timedelta(hours=result[0], minutes=result[1], seconds=result[2])
|
||||
|
||||
def parse_name(self, string):
|
||||
"""
|
||||
Args:
|
||||
string (str): Commission name, such as 'NYB要员护卫'.
|
||||
|
||||
Returns:
|
||||
str: Commission genre, such as 'urgent_gem'.
|
||||
"""
|
||||
for key, value in dictionary.items():
|
||||
for keyword in value:
|
||||
if keyword in string:
|
||||
return key
|
||||
|
||||
logger.warning(f'Name with unknown genre: {string}')
|
||||
self.valid = False
|
||||
return ''
|
||||
|
||||
|
||||
class CommissionGroup:
|
||||
show = (188, 67, 1199, 692)
|
||||
height = 210 # About 1.5 commission height
|
||||
lower = int((show[3] - show[1]) / 2 - height / 2)
|
||||
template_area = (620, lower, 1154, lower + height)
|
||||
|
||||
def __init__(self):
|
||||
self.template = None
|
||||
self.swipe = 0
|
||||
self.commission = []
|
||||
|
||||
def __contains__(self, item):
|
||||
for commission in self.commission:
|
||||
if commission == item:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def __iter__(self):
|
||||
return iter(self.commission)
|
||||
|
||||
def __bool__(self):
|
||||
return len(self.commission) > 0
|
||||
|
||||
@property
|
||||
def count(self):
|
||||
return len(self.commission)
|
||||
|
||||
def merge(self, image):
|
||||
"""Load commissions from image.
|
||||
If you want to load commissions from multiple image,
|
||||
make sure that the next one and previous one have something same.
|
||||
Which means, you merge a image, then swipe a little bit, then merge another image.
|
||||
|
||||
Args:
|
||||
image (PIl.Image.Image):
|
||||
"""
|
||||
# Find swipe distance
|
||||
if self.template is None:
|
||||
self.template = np.array(image.crop(self.template_area))
|
||||
self.swipe = 0
|
||||
res = cv2.matchTemplate(self.template, np.array(image), cv2.TM_CCOEFF_NORMED)
|
||||
_, similarity, _, position = cv2.minMaxLoc(res)
|
||||
if similarity < 0.85:
|
||||
logger.warning(f'Low similarity when finding swipe. Similarity: {similarity}, Position: {position}')
|
||||
self.swipe -= position[1] - self.template_area[1]
|
||||
self.template = np.array(image.crop(self.template_area))
|
||||
|
||||
# Find commission position
|
||||
color_height = np.mean(image.crop((597, 0, 619, 720)).convert('L'), axis=1)
|
||||
parameters = {'height': 200}
|
||||
peaks, _ = signal.find_peaks(color_height, **parameters)
|
||||
peaks = [y for y in peaks if y > 67 + 117]
|
||||
|
||||
# Add commission to list
|
||||
for y in peaks:
|
||||
stack_y = y + self.swipe
|
||||
diff = np.array([c.stack_y - stack_y for c in self.commission])
|
||||
if np.any(np.abs(diff) < 3):
|
||||
continue
|
||||
commission = Commission(image, y=y)
|
||||
commission.stack_y = stack_y
|
||||
logger.info(f'Add commission: {commission}')
|
||||
self.commission.append(commission)
|
||||
|
||||
|
||||
def commission_choose(daily, urgent, priority, time_limit=None):
|
||||
"""
|
||||
Args:
|
||||
daily (CommissionGroup):
|
||||
urgent (CommissionGroup):
|
||||
priority (dict):
|
||||
time_limit (datetime):
|
||||
|
||||
Returns:
|
||||
CommissionGroup, CommissionGroup: Chosen daily commission, Chosen urgent commission
|
||||
"""
|
||||
# Count Commission
|
||||
commission = daily.commission + urgent.commission
|
||||
running_count = np.sum([1 for c in commission if c.status == 'running'])
|
||||
logger.attr('Running', running_count)
|
||||
if running_count >= 4:
|
||||
return [], []
|
||||
|
||||
# Calculate priority
|
||||
commission = [c for c in commission if c.valid and c.status == 'pending']
|
||||
comm_priority = []
|
||||
for comm in commission:
|
||||
pri = priority[comm.genre]
|
||||
if comm.duration <= timedelta(hours=2):
|
||||
pri += priority['duration_shorter_than_2']
|
||||
if comm.duration >= timedelta(hours=6):
|
||||
pri += priority['duration_longer_than_6']
|
||||
if comm.expire:
|
||||
if comm.expire <= timedelta(hours=2):
|
||||
pri += priority['expire_shorter_than_2']
|
||||
if comm.expire >= timedelta(hours=6):
|
||||
pri += priority['expire_longer_than_6']
|
||||
comm_priority.append(pri)
|
||||
|
||||
# Sort
|
||||
commission = list(np.array(commission)[np.argsort(comm_priority)])[::-1]
|
||||
if time_limit:
|
||||
commission = [comm for comm in commission if datetime.now() + comm.duration <= time_limit]
|
||||
commission = commission[:4 - running_count]
|
||||
daily_choose, urgent_choose = CommissionGroup(), CommissionGroup()
|
||||
for comm in commission:
|
||||
if comm in daily:
|
||||
daily_choose.commission.append(comm)
|
||||
if comm in urgent:
|
||||
urgent_choose.commission.append(comm)
|
||||
|
||||
if daily_choose:
|
||||
logger.info('Choose daily commission')
|
||||
for comm in daily_choose:
|
||||
logger.info(comm)
|
||||
if urgent_choose:
|
||||
logger.info('Choose urgent commission')
|
||||
for comm in urgent_choose:
|
||||
logger.info(comm)
|
||||
|
||||
return daily_choose, urgent_choose
|
||||
|
||||
|
||||
class RewardCommission(UI, InfoBarHandler):
|
||||
daily: CommissionGroup
|
||||
urgent: CommissionGroup
|
||||
daily_choose: CommissionGroup
|
||||
urgent_choose: CommissionGroup
|
||||
|
||||
def _commission_ensure_mode(self, mode):
|
||||
if self.appear(COMMISSION_DAILY):
|
||||
current = 'daily'
|
||||
elif self.appear(COMMISSION_URGENT):
|
||||
current = 'urgent'
|
||||
else:
|
||||
logger.warning('Unknown Commission mode')
|
||||
return False
|
||||
if current == mode:
|
||||
return False
|
||||
|
||||
if mode == 'daily':
|
||||
self.device.click(COMMISSION_DAILY)
|
||||
if mode == 'urgent':
|
||||
self.device.click(COMMISSION_URGENT)
|
||||
|
||||
self.device.sleep(0.3)
|
||||
self.device.screenshot()
|
||||
return True
|
||||
|
||||
def _commission_mode_reset(self):
|
||||
if self.appear(COMMISSION_DAILY):
|
||||
current, another = COMMISSION_DAILY, COMMISSION_URGENT
|
||||
elif self.appear(COMMISSION_URGENT):
|
||||
current, another = COMMISSION_URGENT, COMMISSION_DAILY
|
||||
else:
|
||||
logger.warning('Unknown Commission mode')
|
||||
return False
|
||||
|
||||
self.device.click(another)
|
||||
self.device.screenshot()
|
||||
self.device.click(current)
|
||||
self.device.sleep(0.3)
|
||||
self.device.screenshot()
|
||||
|
||||
return True
|
||||
|
||||
def _commission_swipe(self, distance=180):
|
||||
# Distance of two commission is 146px
|
||||
self.device.swipe((0, -distance), box=(620, 67, 1154, 692), random_range=(-20, -5, 20, 5))
|
||||
self.device.click(COMMISSION_STOP_SCROLLING)
|
||||
self.device.sleep(0.3)
|
||||
self.device.screenshot()
|
||||
|
||||
def _commission_scan_list(self):
|
||||
commission = CommissionGroup()
|
||||
commission.merge(self.device.image)
|
||||
if commission.count <= 3:
|
||||
return commission
|
||||
|
||||
prev = commission.count
|
||||
for _ in range(15):
|
||||
self._commission_swipe()
|
||||
commission.merge(self.device.image)
|
||||
if commission.count - prev <= 0:
|
||||
break
|
||||
prev = commission.count
|
||||
|
||||
return commission
|
||||
|
||||
def _commission_scan_all(self):
|
||||
logger.hr('Scan daily')
|
||||
self._commission_ensure_mode('daily')
|
||||
daily = self._commission_scan_list()
|
||||
|
||||
logger.hr('Scan urgent')
|
||||
self._commission_ensure_mode('urgent')
|
||||
urgent = self._commission_scan_list()
|
||||
|
||||
logger.hr('Showing commission')
|
||||
logger.info('Daily commission')
|
||||
for comm in daily:
|
||||
logger.info(comm)
|
||||
if urgent.count:
|
||||
logger.info('Urgent commission')
|
||||
for comm in urgent:
|
||||
logger.info(comm)
|
||||
|
||||
self.daily = daily
|
||||
self.urgent = urgent
|
||||
self.daily_choose, self.urgent_choose = commission_choose(
|
||||
self.daily,
|
||||
self.urgent,
|
||||
priority=self.config.COMMISSION_PRIORITY,
|
||||
time_limit=self.config.COMMISSION_TIME_LIMIT)
|
||||
return daily, urgent
|
||||
|
||||
def _commission_start_click(self, comm):
|
||||
"""
|
||||
Args:
|
||||
comm (Commission):
|
||||
"""
|
||||
logger.info(f'Start commission {comm}')
|
||||
comm_timer = Timer(3)
|
||||
while 1:
|
||||
if comm_timer.reached():
|
||||
self.device.click(comm.button)
|
||||
comm_timer.reset()
|
||||
|
||||
if self.appear_then_click(COMMISSION_OIL_CONFIRM, offset=True, interval=3):
|
||||
pass
|
||||
if self.appear_then_click(COMMISSION_START, interval=3):
|
||||
pass
|
||||
if self.appear_then_click(COMMISSION_ADVICE, interval=3):
|
||||
pass
|
||||
|
||||
if self.handle_info_bar():
|
||||
break
|
||||
|
||||
self.device.screenshot()
|
||||
|
||||
return True
|
||||
|
||||
def _commission_find_and_start(self, comm):
|
||||
"""
|
||||
Args:
|
||||
comm (Commission):
|
||||
"""
|
||||
logger.hr(f'Finding commission')
|
||||
logger.info(f'Finding commission {comm}')
|
||||
|
||||
commission = CommissionGroup()
|
||||
prev = 0
|
||||
for _ in range(15):
|
||||
commission.merge(self.device.image)
|
||||
|
||||
if commission.count - prev <= 0:
|
||||
return True
|
||||
prev = commission.count
|
||||
|
||||
if comm in commission:
|
||||
# Update commission position.
|
||||
# Because once you start a commission, the commission list changes.
|
||||
for new_comm in commission:
|
||||
if comm == new_comm:
|
||||
comm = new_comm
|
||||
self._commission_start_click(comm)
|
||||
self._commission_mode_reset()
|
||||
return True
|
||||
|
||||
self._commission_swipe()
|
||||
|
||||
logger.warning(f'Commission not found: {comm}')
|
||||
return False
|
||||
|
||||
def commission_start(self):
|
||||
"""
|
||||
Method to scan and run commissions.
|
||||
Make sure current page is page_commission before calls.
|
||||
"""
|
||||
logger.hr('Commission scan', level=2)
|
||||
self._commission_scan_all()
|
||||
|
||||
logger.hr('Commission run', level=2)
|
||||
if self.daily_choose:
|
||||
for comm in self.daily_choose:
|
||||
self._commission_ensure_mode('daily')
|
||||
self._commission_find_and_start(comm)
|
||||
if self.urgent_choose:
|
||||
for comm in self.urgent_choose:
|
||||
self._commission_ensure_mode('urgent')
|
||||
self._commission_find_and_start(comm)
|
||||
if not self.daily_choose and not self.urgent_choose:
|
||||
logger.info('No commission chose')
|
||||
|
||||
def handle_commission_start(self):
|
||||
"""Make sure current page is page_reward before calls.
|
||||
|
||||
Returns:
|
||||
bool: If runs a commission.
|
||||
"""
|
||||
if not self.config.ENABLE_COMMISSION_REWARD:
|
||||
return False
|
||||
self.device.screenshot()
|
||||
if not self.appear(COMMISSION_HAS_PENDING):
|
||||
logger.info('No commission pending')
|
||||
return False
|
||||
|
||||
self.ui_goto(page_commission)
|
||||
|
||||
self.commission_start()
|
||||
|
||||
self.ui_goto(page_reward, skip_first_screenshot=True)
|
||||
|
||||
def commission_notice_show_at_campaign(self):
|
||||
"""Make sure current page is page_campaign before calls.
|
||||
|
||||
Returns:
|
||||
bool: If any commission finished.
|
||||
"""
|
||||
return self.appear(COMMISSION_NOTICE_AT_CAMPAIGN)
|
@ -5,10 +5,10 @@ from module.combat.assets import *
|
||||
from module.logger import logger
|
||||
from module.reward.assets import *
|
||||
from module.ui.page import *
|
||||
from module.ui.ui import UI
|
||||
from module.reward.commission import RewardCommission
|
||||
|
||||
|
||||
class Reward(UI):
|
||||
class Reward(RewardCommission):
|
||||
def reward(self):
|
||||
logger.hr('Reward start')
|
||||
self.ui_goto_main()
|
||||
@ -17,6 +17,8 @@ class Reward(UI):
|
||||
self.ui_goto(page_reward, skip_first_screenshot=True)
|
||||
|
||||
self._reward_receive()
|
||||
self.handle_info_bar()
|
||||
self.handle_commission_start()
|
||||
|
||||
self.ui_click(
|
||||
click_button=page_reward.links[page_main],
|
||||
@ -47,6 +49,16 @@ class Reward(UI):
|
||||
exit_timer = Timer(1)
|
||||
click_timer = Timer(1)
|
||||
exit_timer.start()
|
||||
btn = []
|
||||
if self.config.ENABLE_REWARD:
|
||||
btn.append(REWARD_3)
|
||||
if self.config.ENABLE_COMMISSION_REWARD:
|
||||
btn.append(REWARD_1)
|
||||
if self.config.ENABLE_OIL_REWARD:
|
||||
btn.append(OIL)
|
||||
if self.config.ENABLE_COIN_REWARD:
|
||||
btn.append(COIN)
|
||||
|
||||
while 1:
|
||||
self.device.screenshot()
|
||||
|
||||
@ -57,7 +69,7 @@ class Reward(UI):
|
||||
reward = True
|
||||
continue
|
||||
|
||||
for button in [REWARD_1, REWARD_3, OIL, COIN]:
|
||||
for button in btn:
|
||||
if not click_timer.reached():
|
||||
continue
|
||||
if self.appear_then_click(button, interval=1):
|
||||
|
@ -8,6 +8,7 @@ BACK_ARROW = Button(area=(36, 53, 82, 55), color=(251, 251, 255), button=(33, 31
|
||||
CAMPAIGN_GOTO_DAILY = Button(area=(804, 648, 892, 703), color=(189, 145, 78), button=(804, 648, 892, 703), file='./assets/ui/CAMPAIGN_GOTO_DAILY.png')
|
||||
CAMPAIGN_GOTO_EVENT = Button(area=(804, 648, 892, 703), color=(189, 145, 78), button=(1178, 171, 1230, 223), file='./assets/ui/CAMPAIGN_GOTO_EVENT.png')
|
||||
CAMPAIGN_GOTO_EXERCISE = Button(area=(1166, 648, 1248, 703), color=(177, 136, 69), button=(1166, 648, 1248, 703), file='./assets/ui/CAMPAIGN_GOTO_EXERCISE.png')
|
||||
COMMISSION_CHECK = Button(area=(122, 16, 175, 39), color=(157, 173, 210), button=(122, 16, 175, 39), file='./assets/ui/COMMISSION_CHECK.png')
|
||||
DAILY_CHECK = Button(area=(23, 656, 67, 698), color=(84, 139, 210), button=(23, 656, 67, 698), file='./assets/ui/DAILY_CHECK.png')
|
||||
EVENT_CHECK = Button(area=(123, 63, 206, 109), color=(88, 104, 138), button=(123, 63, 206, 109), file='./assets/ui/EVENT_CHECK.png')
|
||||
EXERCISE_CHECK = Button(area=(1065, 340, 1204, 382), color=(129, 166, 220), button=(1065, 340, 1204, 382), file='./assets/ui/EXERCISE_CHECK.png')
|
||||
@ -20,5 +21,6 @@ MAIN_GOTO_REWARD = Button(area=(11, 139, 30, 189), color=(69, 81, 115), button=(
|
||||
MISSION_CHECK = Button(area=(120, 15, 173, 40), color=(141, 156, 194), button=(120, 15, 173, 40), file='./assets/ui/MISSION_CHECK.png')
|
||||
OCR_OIL_CV = Button(area=(634, 27, 714, 48), color=(93, 95, 109), button=(634, 27, 714, 48), file='./assets/ui/OCR_OIL_CV.png')
|
||||
REWARD_CHECK = Button(area=(302, 119, 371, 195), color=(146, 118, 120), button=(302, 119, 371, 195), file='./assets/ui/REWARD_CHECK.png')
|
||||
REWARD_GOTO_COMMISSION = Button(area=(383, 262, 503, 302), color=(91, 136, 199), button=(383, 262, 503, 302), file='./assets/ui/REWARD_GOTO_COMMISSION.png')
|
||||
REWARD_GOTO_MAIN = Button(area=(1037, 611, 1107, 656), color=(134, 122, 127), button=(1037, 611, 1107, 656), file='./assets/ui/REWARD_GOTO_MAIN.png')
|
||||
SP_CHECK = Button(area=(123, 63, 206, 109), color=(95, 110, 145), button=(123, 63, 206, 109), file='./assets/ui/SP_CHECK.png')
|
||||
|
@ -70,3 +70,10 @@ page_main.link(button=MAIN_GOTO_REWARD, destination=page_reward)
|
||||
page_mission = Page(MISSION_CHECK)
|
||||
page_mission.link(button=GOTO_MAIN, destination=page_main)
|
||||
page_main.link(button=MAIN_GOTO_MISSION, destination=page_mission)
|
||||
|
||||
# Commission
|
||||
# Please don't goto commission from campaign.
|
||||
page_commission = Page(COMMISSION_CHECK)
|
||||
page_commission.link(button=GOTO_MAIN, destination=page_main)
|
||||
page_commission.link(button=BACK_ARROW, destination=page_reward)
|
||||
page_reward.link(button=REWARD_GOTO_COMMISSION, destination=page_commission)
|
||||
|