StarRailCopilot/module/map/grid_info.py
LmeSzinc 83508b94d3 Fix: Enemy detection
- Log shows 'E' and wrong prediction is_siren, because attributes are kept to the next detection
- Fix missing predict also
- Fix log show DEFAULT_BUTTON for the entrance of campaign
2020-05-31 02:49:06 +08:00

227 lines
7.1 KiB
Python

from module.base.utils import location2node
from module.logger import logger
class GridInfo:
"""
Class that gather basic information of a grid in map_v1.
Visit 碧蓝航线WIKI(Chinese Simplified) http://wiki.biligame.com/blhx, to get basic info of a map_v1. For example,
visit http://wiki.biligame.com/blhx/7-2, to know more about campaign 7-2, which includes boss point, enemy spawn point.
A grid contains these unchangeable properties which can known from WIKI.
| print_name | property_name | description |
|------------|----------------|-------------------------|
| ++ | is_land | fleet can't go to land |
| -- | is_sea | sea |
| __ | | submarine spawn point |
| SP | is_spawn_point | fleet may spawns here |
| ME | may_enemy | enemy may spawns here |
| MB | may_boss | boss may spawns here |
| MM | may_mystery | mystery may spawns here |
| MA | may_ammo | fleet can get ammo here |
| MS | may_siren | Siren/Elite enemy spawn |
"""
# is_sea --
is_land = False # ++
is_spawn_point = False # SP
may_enemy = False # ME
may_boss = False # MB
may_mystery = False # MM
may_ammo = False # MA
may_siren = False # MS
is_enemy = False # example: 0L 1M 2C 3T 3E
is_boss = False # BO
is_mystery = False # MY
is_ammo = False # AM
is_fleet = False # FL
is_current_fleet = False
is_submarine = False # SS
is_siren = False # SI
enemy_scale = 0
enemy_genre = None # Light, Main, Carrier, Treasure, Enemy(unknown)
is_cleared = False
is_ambush_save = False
is_caught_by_siren = False
cost = 9999
connection = None
weight = 1
location = None
def decode(self, text):
dic = {
'++': 'is_land',
'SP': 'is_spawn_point',
'ME': 'may_enemy',
'MB': 'may_boss',
'MM': 'may_mystery',
'MA': 'may_ammo',
'MS': 'may_siren',
}
if text in dic:
self.__setattr__(dic[text], True)
if self.may_enemy or self.may_boss or self.may_mystery or self.may_mystery:
self.is_ambush_save = True
if self.may_siren:
self.may_enemy = True
if self.may_boss:
self.may_enemy = True
def encode(self):
dic = {
'++': 'is_land',
'BO': 'is_boss',
}
for key, value in dic.items():
if self.__getattribute__(value):
return key
if self.is_siren:
return ''.join([text[0] for text in self.enemy_genre.split('_')]).upper() if self.enemy_genre else 'SU'
if self.is_enemy:
return '%s%s' % (self.enemy_scale, self.enemy_genre[0].upper()) \
if self.enemy_genre and self.enemy_scale else '0E'
dic = {
'FL': 'is_current_fleet',
'Fl': 'is_fleet',
'Fc': 'is_caught_by_siren',
'MY': 'is_mystery',
'AM': 'is_ammo',
'==': 'is_cleared'
}
for key, value in dic.items():
if self.__getattribute__(value):
return key
return '--'
def __str__(self):
return location2node(self.location)
__repr__ = __str__
def __hash__(self):
return hash(self.location)
@property
def str(self):
return self.encode()
@property
def is_sea(self):
return False if self.is_land or self.is_enemy or self.is_boss else True
@property
def may_carrier(self):
return self.is_sea and not self.may_enemy
@property
def is_accessible(self):
return self.cost < 9999
@property
def is_nearby(self):
return self.cost < 20
def update(self, info, is_carrier_scan=False, ignore_may=False, ignore_cleared=False):
"""
Args:
info (GridInfo):
is_carrier_scan (bool): Is a scan for mystery: enemy_searching, which ignore may_enemy spawn point.
ignore_may (bool): Ignore map_data, force update.
ignore_cleared (bool): Ignore is_cleared property.
"""
for item in ['boss', 'siren']:
if info.enemy_scale or self.enemy_scale:
break
if info.__getattribute__('is_' + item):
flag = not info.is_fleet and not self.is_fleet
if not ignore_may:
flag &= self.__getattribute__('may_' + item)
if not ignore_cleared:
flag &= not self.is_cleared
if flag:
self.__setattr__('is_' + item, True)
# self.is_enemy = True
# self.enemy_scale = 0
self.enemy_genre = info.enemy_genre
return True
else:
logger.info(f'Wrong Prediction. Grid: {self}, Attr: is_{item}')
if info.is_enemy:
flag = not info.is_fleet and not self.is_fleet and not self.is_siren
if not is_carrier_scan:
if not ignore_may:
flag &= self.may_enemy
if not ignore_cleared:
flag &= not self.is_cleared
if flag:
self.is_enemy = True
self.enemy_scale = info.enemy_scale
self.enemy_genre = info.enemy_genre
if self.may_siren:
self.is_siren = True
return True
else:
logger.info(f'Wrong Prediction. Grid: {self}, Attr: is_enemy')
for item in ['mystery', 'ammo']:
if info.__getattribute__('is_' + item):
if self.__getattribute__('may_' + item) or ignore_may:
self.__setattr__('is_' + item, True)
return True
else:
logger.info(f'Wrong Prediction. Grid: {self}, Attr: {item}')
# failure += 1
self.is_fleet = info.is_fleet
if info.is_current_fleet:
self.is_current_fleet = True
if info.is_caught_by_siren:
self.is_caught_by_siren = True
return False
def wipe_out(self):
"""
Call this method when a fleet step on grid.
"""
self.is_enemy = False
self.enemy_scale = 0
self.enemy_genre = None
self.is_mystery = False
self.is_boss = False
self.is_ammo = False
self.is_siren = False
def reset(self):
"""
Call this method after entering a map.
"""
self.wipe_out()
self.is_fleet = False
self.is_current_fleet = False
self.is_submarine = False
self.is_cleared = False
def covered_grid(self):
"""Relative coordinate of the covered grid.
Returns:
list[tuple]:
"""
if self.is_current_fleet:
return [(0, -1), (0, -2)]
if self.is_fleet or self.is_siren or self.is_mystery:
return [(0, -1)]
return []