Add: shop module support voucher shop (os supply / exchange)

This commit is contained in:
nEEtdo0d 2022-11-13 21:41:59 -05:00
parent 26aa797a72
commit 3b37e4afa0
29 changed files with 291 additions and 4 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

View File

@ -1,6 +1,6 @@
import re
FILTER_REGEX = re.compile(
FILTER_REGEX_SERIES = re.compile(
'(pr|dr)'
'([1-4]'
@ -28,7 +28,7 @@ def bp_redirect(value):
PRBP = PR; PR1BP = PRS1; PROdinBP = PROdin/PROdinS3
likewise for DR variants
"""
matches = re.findall(FILTER_REGEX, value)
matches = re.findall(FILTER_REGEX_SERIES, value)
if not matches:
return value
@ -45,5 +45,41 @@ def bp_redirect(value):
return value
FILTER_REGEX_VOUCHER = re.compile(
'(logger)'
'(file)?'
'(t[1-6])?',
flags=re.IGNORECASE)
def voucher_redirect(value):
"""
Redirects voucher shop filter to prevents users
from using banned strings i.e. Logger, LoggerT[1-6],
or LoggerFile
Banned strings can be used in special circumstances
handled by ALAS
"""
matches = re.findall(FILTER_REGEX_VOUCHER, value)
if not matches:
return value
for match in matches:
flat = ''.join(match)
pattern = rf'\b{flat}\b'
if match[2]:
value = re.sub(pattern, f'LoggerAbyssal{match[2].upper()} > LoggerObscure{match[2].upper()}', value)
elif match[1]:
value = re.sub(pattern, '', value)
value = re.sub('\>\s*\>', '>', value)
value = re.sub('\>\s*$', '', value)
else:
value = re.sub(pattern, f'LoggerAbyssal > LoggerObscure', value)
return value
if __name__ == '__main__':
print(bp_redirect('PlateGeneralT1 > DRAgirBP > CatT3 > PROdinBP > Chip > PR1BP > PRBP > DRDrakeBP > DR2BP'))
print(voucher_redirect('Coin > HECombatPlan > LoggerFile > TuningCombatT2 > LoggerT6 > Logger'))

View File

@ -15,6 +15,7 @@ SHOP_BUY_CONFIRM = Button(area={'cn': (703, 483, 876, 540), 'en': (708, 487, 872
SHOP_BUY_CONFIRM_AMOUNT = Button(area={'cn': (678, 590, 851, 647), 'en': (689, 594, 839, 644), 'jp': (694, 596, 832, 640), 'tw': (677, 589, 852, 649)}, color={'cn': (81, 130, 190), 'en': (103, 146, 197), 'jp': (84, 132, 191), 'tw': (82, 131, 191)}, button={'cn': (678, 590, 851, 647), 'en': (689, 594, 839, 644), 'jp': (694, 596, 832, 640), 'tw': (677, 589, 852, 649)}, file={'cn': './assets/cn/shop/SHOP_BUY_CONFIRM_AMOUNT.png', 'en': './assets/en/shop/SHOP_BUY_CONFIRM_AMOUNT.png', 'jp': './assets/jp/shop/SHOP_BUY_CONFIRM_AMOUNT.png', 'tw': './assets/tw/shop/SHOP_BUY_CONFIRM_AMOUNT.png'})
SHOP_BUY_CONFIRM_MISTAKE = Button(area={'cn': (590, 300, 612, 318), 'en': (590, 300, 612, 318), 'jp': (590, 300, 612, 318), 'tw': (590, 300, 612, 318)}, color={'cn': (154, 79, 103), 'en': (154, 79, 103), 'jp': (154, 79, 103), 'tw': (154, 79, 103)}, button={'cn': (590, 300, 612, 318), 'en': (590, 300, 612, 318), 'jp': (590, 300, 612, 318), 'tw': (590, 300, 612, 318)}, file={'cn': './assets/cn/shop/SHOP_BUY_CONFIRM_MISTAKE.png', 'en': './assets/en/shop/SHOP_BUY_CONFIRM_MISTAKE.png', 'jp': './assets/jp/shop/SHOP_BUY_CONFIRM_MISTAKE.png', 'tw': './assets/tw/shop/SHOP_BUY_CONFIRM_MISTAKE.png'})
SHOP_BUY_CONFIRM_SELECT = Button(area={'cn': (604, 642, 676, 671), 'en': (567, 630, 712, 675), 'jp': (588, 638, 689, 669), 'tw': (558, 627, 725, 680)}, color={'cn': (236, 191, 130), 'en': (229, 171, 90), 'jp': (230, 170, 89), 'tw': (225, 155, 60)}, button={'cn': (604, 642, 676, 671), 'en': (567, 630, 712, 675), 'jp': (588, 638, 689, 669), 'tw': (558, 627, 725, 680)}, file={'cn': './assets/cn/shop/SHOP_BUY_CONFIRM_SELECT.png', 'en': './assets/en/shop/SHOP_BUY_CONFIRM_SELECT.png', 'jp': './assets/jp/shop/SHOP_BUY_CONFIRM_SELECT.png', 'tw': './assets/tw/shop/SHOP_BUY_CONFIRM_SELECT.png'})
SHOP_BUY_CONFIRM_VOUCHER = Button(area={'cn': (698, 456, 843, 496), 'en': (698, 456, 843, 496), 'jp': (698, 456, 843, 496), 'tw': (698, 456, 843, 496)}, color={'cn': (125, 163, 212), 'en': (125, 163, 212), 'jp': (125, 163, 212), 'tw': (125, 163, 212)}, button={'cn': (698, 456, 843, 496), 'en': (698, 456, 843, 496), 'jp': (698, 456, 843, 496), 'tw': (698, 456, 843, 496)}, file={'cn': './assets/cn/shop/SHOP_BUY_CONFIRM_VOUCHER.png', 'en': './assets/en/shop/SHOP_BUY_CONFIRM_VOUCHER.png', 'jp': './assets/cn/shop/SHOP_BUY_CONFIRM_VOUCHER.png', 'tw': './assets/cn/shop/SHOP_BUY_CONFIRM_VOUCHER.png'})
SHOP_CLICK_SAFE_AREA = Button(area={'cn': (108, 108, 143, 233), 'en': (108, 108, 143, 233), 'jp': (108, 108, 143, 233), 'tw': (108, 108, 143, 233)}, color={'cn': (50, 57, 76), 'en': (50, 57, 76), 'jp': (50, 57, 76), 'tw': (50, 57, 76)}, button={'cn': (108, 108, 143, 233), 'en': (108, 108, 143, 233), 'jp': (108, 108, 143, 233), 'tw': (108, 108, 143, 233)}, file={'cn': './assets/cn/shop/SHOP_CLICK_SAFE_AREA.png', 'en': './assets/en/shop/SHOP_CLICK_SAFE_AREA.png', 'jp': './assets/jp/shop/SHOP_CLICK_SAFE_AREA.png', 'tw': './assets/tw/shop/SHOP_CLICK_SAFE_AREA.png'})
SHOP_CORE = Button(area={'cn': (1161, 71, 1261, 101), 'en': (1161, 71, 1261, 101), 'jp': (1161, 71, 1261, 101), 'tw': (1161, 71, 1261, 101)}, color={'cn': (68, 71, 82), 'en': (68, 71, 82), 'jp': (68, 71, 82), 'tw': (68, 71, 82)}, button={'cn': (1161, 71, 1261, 101), 'en': (1161, 71, 1261, 101), 'jp': (1161, 71, 1261, 101), 'tw': (1161, 71, 1261, 101)}, file={'cn': './assets/cn/shop/SHOP_CORE.png', 'en': './assets/en/shop/SHOP_CORE.png', 'jp': './assets/jp/shop/SHOP_CORE.png', 'tw': './assets/tw/shop/SHOP_CORE.png'})
SHOP_GEMS = Button(area={'cn': (1035, 23, 1133, 51), 'en': (1035, 23, 1133, 51), 'jp': (1035, 23, 1133, 51), 'tw': (1035, 23, 1133, 51)}, color={'cn': (55, 56, 53), 'en': (55, 56, 53), 'jp': (55, 56, 53), 'tw': (55, 56, 53)}, button={'cn': (1035, 23, 1133, 51), 'en': (1035, 23, 1133, 51), 'jp': (1035, 23, 1133, 51), 'tw': (1035, 23, 1133, 51)}, file={'cn': './assets/cn/shop/SHOP_GEMS.png', 'en': './assets/en/shop/SHOP_GEMS.png', 'jp': './assets/jp/shop/SHOP_GEMS.png', 'tw': './assets/tw/shop/SHOP_GEMS.png'})
@ -29,3 +30,5 @@ SHOP_SELECT_PR1 = Button(area={'cn': (178, 210, 293, 325), 'en': (178, 210, 293,
SHOP_SELECT_PR2 = Button(area={'cn': (334, 208, 453, 326), 'en': (334, 208, 453, 326), 'jp': (334, 208, 453, 326), 'tw': (334, 208, 453, 326)}, color={'cn': (166, 166, 158), 'en': (166, 166, 158), 'jp': (166, 166, 158), 'tw': (166, 166, 158)}, button={'cn': (334, 208, 453, 326), 'en': (334, 208, 453, 326), 'jp': (334, 208, 453, 326), 'tw': (334, 208, 453, 326)}, file={'cn': './assets/cn/shop/SHOP_SELECT_PR2.png', 'en': './assets/en/shop/SHOP_SELECT_PR2.png', 'jp': './assets/jp/shop/SHOP_SELECT_PR2.png', 'tw': './assets/tw/shop/SHOP_SELECT_PR2.png'})
SHOP_SELECT_PR3 = Button(area={'cn': (334, 208, 453, 327), 'en': (334, 208, 453, 327), 'jp': (334, 208, 453, 327), 'tw': (334, 208, 453, 327)}, color={'cn': (161, 162, 153), 'en': (161, 162, 153), 'jp': (161, 162, 153), 'tw': (161, 162, 153)}, button={'cn': (334, 208, 453, 327), 'en': (334, 208, 453, 327), 'jp': (334, 208, 453, 327), 'tw': (334, 208, 453, 327)}, file={'cn': './assets/cn/shop/SHOP_SELECT_PR3.png', 'en': './assets/en/shop/SHOP_SELECT_PR3.png', 'jp': './assets/jp/shop/SHOP_SELECT_PR3.png', 'tw': './assets/tw/shop/SHOP_SELECT_PR3.png'})
SHOP_SELECT_STOCK = Button(area={'cn': (1070, 152, 1126, 178), 'en': (1070, 152, 1126, 178), 'jp': (1070, 152, 1126, 178), 'tw': (1070, 152, 1126, 178)}, color={'cn': (76, 88, 90), 'en': (76, 88, 90), 'jp': (76, 88, 90), 'tw': (76, 88, 90)}, button={'cn': (1070, 152, 1126, 178), 'en': (1070, 152, 1126, 178), 'jp': (1070, 152, 1126, 178), 'tw': (1070, 152, 1126, 178)}, file={'cn': './assets/cn/shop/SHOP_SELECT_STOCK.png', 'en': './assets/en/shop/SHOP_SELECT_STOCK.png', 'jp': './assets/jp/shop/SHOP_SELECT_STOCK.png', 'tw': './assets/tw/shop/SHOP_SELECT_STOCK.png'})
SHOP_VOUCHER = Button(area={'cn': (1115, 123, 1261, 158), 'en': (1115, 123, 1261, 158), 'jp': (1115, 123, 1261, 158), 'tw': (1115, 123, 1261, 158)}, color={'cn': (90, 96, 110), 'en': (90, 96, 110), 'jp': (90, 96, 110), 'tw': (90, 96, 110)}, button={'cn': (1115, 123, 1261, 158), 'en': (1115, 123, 1261, 158), 'jp': (1115, 123, 1261, 158), 'tw': (1115, 123, 1261, 158)}, file={'cn': './assets/cn/shop/SHOP_VOUCHER.png', 'en': './assets/en/shop/SHOP_VOUCHER.png', 'jp': './assets/jp/shop/SHOP_VOUCHER.png', 'tw': './assets/tw/shop/SHOP_VOUCHER.png'})
VOUCHER_SHOP_SCROLL_AREA = Button(area={'cn': (1257, 184, 1263, 647), 'en': (1257, 184, 1263, 647), 'jp': (1257, 184, 1263, 647), 'tw': (1257, 184, 1263, 647)}, color={'cn': (255, 255, 255), 'en': (255, 255, 255), 'jp': (255, 255, 255), 'tw': (255, 255, 255)}, button={'cn': (1257, 184, 1263, 647), 'en': (1257, 184, 1263, 647), 'jp': (1257, 184, 1263, 647), 'tw': (1257, 184, 1263, 647)}, file={'cn': './assets/cn/shop/VOUCHER_SHOP_SCROLL_AREA.png', 'en': './assets/en/shop/VOUCHER_SHOP_SCROLL_AREA.png', 'jp': './assets/jp/shop/VOUCHER_SHOP_SCROLL_AREA.png', 'tw': './assets/tw/shop/VOUCHER_SHOP_SCROLL_AREA.png'})

View File

@ -14,7 +14,11 @@ from module.statistics.item import ItemGrid
from module.tactical.tactical_class import Book
FILTER_REGEX = re.compile(
'^(cube|drill|chip|array|pr|dr|box|bulin|book|food|plate|retrofit|cat)'
'^(array|book|box|bulin|cat'
'|chip|coin|cube|drill|food'
'|plate|retrofit|pr|dr'
'|logger|tuning'
'|hecombatplan)'
'(neptune|monarch|ibuki|izumo|roon|saintlouis'
'|seattle|georgia|kitakaze|azuma|friedrich'
@ -23,7 +27,9 @@ FILTER_REGEX = re.compile(
'|plymouth|rupprecht|harbin|chkalov|brest'
'|red|blue|yellow'
'|general|gun|torpedo|antiair|plane|wild'
'|dd|cl|bb|cv)?'
'|dd|cl|bb|cv'
'|abyssal|obscure|file'
'|combat|offense|survival)?'
'(s[1-5]|t[1-6])?$',
flags=re.IGNORECASE)

242
module/shop/shop_voucher.py Normal file
View File

@ -0,0 +1,242 @@
from module.base.button import ButtonGrid
from module.base.decorator import cached_property, del_cached_property
from module.base.timer import Timer
from module.config.redirect_utils.shop_filter import voucher_redirect
from module.logger import logger
from module.map_detection.utils import Points
from module.ocr.ocr import Digit, Ocr
from module.shop.assets import *
from module.shop.base import ShopItemGrid
from module.shop.clerk import ShopClerk
from module.ui.scroll import Scroll
OCR_SHOP_VOUCHER = Digit(SHOP_VOUCHER, letter=(255, 255, 255), name='OCR_SHOP_VOUCHER')
VOUCHER_SHOP_SCROLL = Scroll(VOUCHER_SHOP_SCROLL_AREA, color=(255, 255, 255))
class ShopPriceOcr(Digit):
def after_process(self, result):
result = Ocr.after_process(self, result)
# '100' detected as '00' on occasion
if result == '00':
result = '100'
return Digit.after_process(self, result)
PRICE_OCR = ShopPriceOcr([], letter=(255, 223, 57), threshold=32, name='Price_ocr')
TEMPLATE_VOUCHER_ICON = Template('./assets/shop/cost/Voucher.png')
class VoucherShop(ShopClerk):
@cached_property
def shop_filter(self):
"""
Returns:
str:
"""
return voucher_redirect(self.config.Voucher_Filter.strip())
def _get_vouchers(self):
"""
Returns:
np.array: [[x1, y1], [x2, y2]], location of the voucher icon upper-left corner.
"""
left_column = self.image_crop((476, 306, 1256, 646))
vouchers = TEMPLATE_VOUCHER_ICON.match_multi(left_column, similarity=0.75, threshold=5)
vouchers = Points([(0., v.area[1]) for v in vouchers]).group(threshold=5)
logger.attr('Vouchers_icon', len(vouchers))
logger.info(vouchers)
return vouchers
def wait_until_voucher_appear(self, skip_first_screenshot=True):
"""
After entering voucher shop page,
items are not loaded that fast,
wait until any voucher icon appears
"""
timeout = Timer(1, count=3).start()
while 1:
if skip_first_screenshot:
skip_first_screenshot = False
else:
self.device.screenshot()
vouchers = self._get_vouchers()
if timeout.reached():
break
if len(vouchers):
break
@cached_property
def shop_grid(self):
"""
Returns:
ButtonGrid:
"""
vouchers = self._get_vouchers()
count = len(vouchers)
if count == 0:
logger.warning('Unable to find voucher icon, assume item list is at top')
origin_y = 200
delta_y = 191
row = 2
elif count == 1:
y_list = vouchers[:, 1]
# +256, to location on screen
# -88, from the top of voucher icon to the top of shop item
origin_y = y_list[0] + 256 - 88
delta_y = 191
row = 1
elif count == 2:
y_list = vouchers[:, 1]
y1, y2 = y_list[0], y_list[1]
logger.info(y1)
logger.info(y2)
origin_y = min(y1, y2) + 256 - 88
delta_y = abs(y1 - y2)
row = 2
else:
logger.warning(f'Unexpected voucher icon match result: {[v.area for v in vouchers]}')
origin_y = 200
delta_y = 191
row = 2
# Make up a ButtonGrid
# Original grid is:
#shop_grid = ButtonGrid(
# origin=(463, 200), delta=(156, 191), button_shape=(99, 99), grid_shape=(5, 2), name='SHOP_GRID')
shop_grid = ButtonGrid(
origin=(463, origin_y), delta=(156, delta_y), button_shape=(99, 99), grid_shape=(5, row), name='SHOP_GRID')
return shop_grid
@cached_property
def shop_voucher_items(self):
"""
Returns:
ShopItemGrid:
"""
shop_grid = self.shop_grid
shop_voucher_items = ShopItemGrid(
shop_grid,
templates={}, amount_area=(60, 74, 96, 95),
price_area=(52, 132, 132, 162))
shop_voucher_items.load_template_folder('./assets/shop/voucher')
shop_voucher_items.load_cost_template_folder('./assets/shop/cost')
shop_voucher_items.similarity = 0.85
shop_voucher_items.cost_similarity = 0.5
shop_voucher_items.price_ocr = PRICE_OCR
return shop_voucher_items
def shop_items(self):
"""
Shared alias name for all shops,
so to use @Config must define
a unique alias as cover
Returns:
ShopItemGrid:
"""
return self.shop_voucher_items
def shop_currency(self):
"""
Ocr shop voucher currency
Then return voucher count
Returns:
int: voucher amount
"""
self._currency = OCR_SHOP_VOUCHER.ocr(self.device.image)
logger.info(f'Voucher: {self._currency}')
return self._currency
def shop_interval_clear(self):
"""
Clear interval on select assets for
shop_buy_handle
"""
super().shop_interval_clear()
self.interval_clear(SHOP_BUY_CONFIRM_SELECT)
self.interval_clear(SHOP_BUY_CONFIRM_AMOUNT)
self.interval_clear(SHOP_BUY_CONFIRM_VOUCHER)
def shop_buy_handle(self, item):
"""
Handle shop_voucher buy interface if detected
Args:
item: Item to handle
Returns:
bool: whether interface was detected and handled
"""
if self.appear(SHOP_BUY_CONFIRM_SELECT, offset=(20, 20), interval=3):
self.shop_buy_select_execute(item)
self.interval_reset(SHOP_BUY_CONFIRM_SELECT)
return True
if self.appear(SHOP_BUY_CONFIRM_AMOUNT, offset=(20, 20), interval=3):
self.shop_buy_amount_execute(item)
self.interval_reset(SHOP_BUY_CONFIRM_AMOUNT)
return True
if self.appear_then_click(SHOP_BUY_CONFIRM_VOUCHER, offset=(20, 20), interval=3):
return True
return False
def run(self):
"""
Run Voucher Shop
"""
# Base case; exit run if filter empty
if not self.shop_filter:
return
# When called, expected to be in
# correct Voucher Shop interface
logger.hr('Voucher Shop', level=1)
self.wait_until_voucher_appear()
# Execute buy operations
while 1:
self.shop_buy()
if VOUCHER_SHOP_SCROLL.at_bottom(main=self):
logger.info('Voucher Shop reach bottom, stop')
break
else:
VOUCHER_SHOP_SCROLL.next_page(main=self, page=0.66)
del_cached_property(self, 'shop_grid')
del_cached_property(self, 'shop_voucher_items')
continue
def run_once(self):
"""
Run Voucher Shop to purchase
a single logger file type item
Returns:
bool
"""
# Replace filter
self.shop_filter = 'LoggerFile'
# When called, expected to be in
# correct Voucher Shop interface
logger.hr('Voucher Shop Once', level=1)
self.wait_until_voucher_appear()
# Execute buy operations
items = self.shop_get_items()
self.shop_currency()
if self._currency <= 0:
logger.warning(f'Current funds: {self._currency}, stopped')
return False
item = self.shop_get_item_to_buy(items)
if item is None:
logger.info('No logger files available for purchase')
return False
self.shop_buy_execute(item)
logger.info('Purchased single logger file')
return True