mirror of
https://github.com/sui-feng-cb/AzurLaneAutoScript1.git
synced 2026-08-15 11:43:08 +08:00
191 lines
6.0 KiB
Python
191 lines
6.0 KiB
Python
|
|
"""Shared restaurant configuration and waitress helpers.
|
||
|
|
|
||
|
|
This module intentionally has no device or UI dependencies so it can be used by
|
||
|
|
the restaurant runner, IslandBusiness, the production planner, and config
|
||
|
|
migration code alike.
|
||
|
|
"""
|
||
|
|
|
||
|
|
from collections import OrderedDict
|
||
|
|
|
||
|
|
from module.exception import RequestHumanTakeover
|
||
|
|
|
||
|
|
|
||
|
|
WAITRESS_NONE = 'none'
|
||
|
|
WAITRESS_ANY = 'any'
|
||
|
|
|
||
|
|
|
||
|
|
# Keep the option/bonus data in one place. ``waitress_effects`` values are
|
||
|
|
# ``(capacity_delta, sales_bonus)`` and bonuses are only applied for explicitly
|
||
|
|
# selected named waitresses, matching the previous behaviour.
|
||
|
|
RESTAURANT_CONFIG = OrderedDict({
|
||
|
|
601: {
|
||
|
|
'name': 'Koi',
|
||
|
|
'grade_key': 'KoiGrade',
|
||
|
|
'waitress_keys': ('KoiWaitress1', 'KoiWaitress2'),
|
||
|
|
'legacy_waitress_key': 'KoiWaitress',
|
||
|
|
'menu_key': 'KoiMenu',
|
||
|
|
'waitress_options': ('Chao_Ho', 'Chang_Feng'),
|
||
|
|
'waitress_effects': {
|
||
|
|
'Chao_Ho': (1, 0.10),
|
||
|
|
'Chang_Feng': (1, 0),
|
||
|
|
},
|
||
|
|
},
|
||
|
|
602: {
|
||
|
|
'name': 'Bear',
|
||
|
|
'grade_key': 'BearGrade',
|
||
|
|
'waitress_keys': ('BearWaitress1', 'BearWaitress2'),
|
||
|
|
'legacy_waitress_key': 'BearWaitress',
|
||
|
|
'menu_key': 'BearMenu',
|
||
|
|
'waitress_options': ('Cheshire', 'Chang_Feng'),
|
||
|
|
'waitress_effects': {
|
||
|
|
'Cheshire': (1, 0.05),
|
||
|
|
'Chang_Feng': (1, 0),
|
||
|
|
},
|
||
|
|
},
|
||
|
|
603: {
|
||
|
|
'name': 'Eatery',
|
||
|
|
'grade_key': 'EateryGrade',
|
||
|
|
'waitress_keys': ('EateryWaitress1', 'EateryWaitress2'),
|
||
|
|
'legacy_waitress_key': 'EateryWaitress',
|
||
|
|
'menu_key': 'EateryMenu',
|
||
|
|
'waitress_options': ('Helena', 'Prinz_Eugen', 'Chang_Feng'),
|
||
|
|
'waitress_effects': {
|
||
|
|
'Helena': (1, 0.10),
|
||
|
|
'Prinz_Eugen': (0, 0.10),
|
||
|
|
'Chang_Feng': (1, 0),
|
||
|
|
},
|
||
|
|
},
|
||
|
|
604: {
|
||
|
|
'name': 'Grill',
|
||
|
|
'grade_key': 'GrillGrade',
|
||
|
|
'waitress_keys': ('GrillWaitress1', 'GrillWaitress2'),
|
||
|
|
'legacy_waitress_key': 'GrillWaitress',
|
||
|
|
'menu_key': 'GrillMenu',
|
||
|
|
'waitress_options': ('August_von_Parseval', 'Prinz_Eugen', 'Chang_Feng'),
|
||
|
|
'waitress_effects': {
|
||
|
|
'August_von_Parseval': (1, 0.10),
|
||
|
|
'Prinz_Eugen': (0, 0.10),
|
||
|
|
'Chang_Feng': (1, 0),
|
||
|
|
},
|
||
|
|
},
|
||
|
|
901: {
|
||
|
|
'name': 'Cafe',
|
||
|
|
'grade_key': 'CafeGrade',
|
||
|
|
'waitress_keys': ('CafeWaitress1', 'CafeWaitress2'),
|
||
|
|
'legacy_waitress_key': 'CafeWaitress',
|
||
|
|
'menu_key': 'CafeMenu',
|
||
|
|
'waitress_options': ('Cheshire', 'Belfast', 'Chang_Feng'),
|
||
|
|
'waitress_effects': {
|
||
|
|
'Cheshire': (1, 0.05),
|
||
|
|
'Belfast': (0, 0.10),
|
||
|
|
'Chang_Feng': (1, 0),
|
||
|
|
},
|
||
|
|
},
|
||
|
|
})
|
||
|
|
|
||
|
|
RESTAURANT_IDS = tuple(RESTAURANT_CONFIG.keys())
|
||
|
|
ISLAND_RESTAURANT_CONFIG_PREFIX = 'IslandBusiness.IslandRestaurant.'
|
||
|
|
|
||
|
|
|
||
|
|
def get_restaurant_config(restaurant_id):
|
||
|
|
return RESTAURANT_CONFIG[restaurant_id]
|
||
|
|
|
||
|
|
|
||
|
|
def get_config_key(restaurant_id, key):
|
||
|
|
return ISLAND_RESTAURANT_CONFIG_PREFIX + key
|
||
|
|
|
||
|
|
|
||
|
|
def get_waitress_options(restaurant_id):
|
||
|
|
return (WAITRESS_NONE, WAITRESS_ANY) + tuple(
|
||
|
|
get_restaurant_config(restaurant_id)['waitress_options']
|
||
|
|
)
|
||
|
|
|
||
|
|
|
||
|
|
def _waitress_sort_key(restaurant_id, value):
|
||
|
|
config = get_restaurant_config(restaurant_id)
|
||
|
|
if value == WAITRESS_NONE:
|
||
|
|
return (2, 0)
|
||
|
|
if value == WAITRESS_ANY:
|
||
|
|
return (1, 0)
|
||
|
|
try:
|
||
|
|
index = config['waitress_options'].index(value)
|
||
|
|
except ValueError:
|
||
|
|
index = len(config['waitress_options'])
|
||
|
|
return (0, index)
|
||
|
|
|
||
|
|
|
||
|
|
def normalize_waitress_slots(restaurant_id, values):
|
||
|
|
"""Validate and return a canonical, unordered pair of waitress values.
|
||
|
|
|
||
|
|
Slot order is canonicalized because the two slots are unordered. Invalid
|
||
|
|
combinations are not repaired: they require human intervention.
|
||
|
|
"""
|
||
|
|
allowed = set(get_waitress_options(restaurant_id))
|
||
|
|
values = list(values or [])
|
||
|
|
cleaned = []
|
||
|
|
seen_named = set()
|
||
|
|
for value in values:
|
||
|
|
if value is None:
|
||
|
|
value = WAITRESS_NONE
|
||
|
|
if value not in allowed:
|
||
|
|
raise RequestHumanTakeover(
|
||
|
|
f'Invalid waitress value for restaurant {restaurant_id}: {value}'
|
||
|
|
)
|
||
|
|
if value not in (WAITRESS_NONE, WAITRESS_ANY):
|
||
|
|
if value in seen_named:
|
||
|
|
raise RequestHumanTakeover(
|
||
|
|
f'Duplicate named waitress for restaurant {restaurant_id}: {value}'
|
||
|
|
)
|
||
|
|
seen_named.add(value)
|
||
|
|
cleaned.append(value)
|
||
|
|
|
||
|
|
if len(cleaned) > 2:
|
||
|
|
raise RequestHumanTakeover(
|
||
|
|
f'Restaurant {restaurant_id} has more than two waitress slots'
|
||
|
|
)
|
||
|
|
|
||
|
|
cleaned.sort(key=lambda value: _waitress_sort_key(restaurant_id, value))
|
||
|
|
cleaned.extend([WAITRESS_NONE] * (2 - len(cleaned)))
|
||
|
|
return tuple(cleaned)
|
||
|
|
|
||
|
|
|
||
|
|
def get_waitress_slots(config, restaurant_id):
|
||
|
|
config_data = get_restaurant_config(restaurant_id)
|
||
|
|
values = [
|
||
|
|
config.cross_get(get_config_key(restaurant_id, key), default=None)
|
||
|
|
for key in config_data['waitress_keys']
|
||
|
|
]
|
||
|
|
return normalize_waitress_slots(restaurant_id, values)
|
||
|
|
|
||
|
|
|
||
|
|
def is_restaurant_enabled(slots):
|
||
|
|
return any(value != WAITRESS_NONE for value in slots)
|
||
|
|
|
||
|
|
|
||
|
|
def get_selected_named_waitresses(slots):
|
||
|
|
return {
|
||
|
|
value for value in slots
|
||
|
|
if value not in (WAITRESS_NONE, WAITRESS_ANY)
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
def get_waitress_effect(restaurant_id, slots):
|
||
|
|
slots = normalize_waitress_slots(restaurant_id, slots)
|
||
|
|
capacity_delta = 0
|
||
|
|
sales_bonus = 0
|
||
|
|
effects = get_restaurant_config(restaurant_id)['waitress_effects']
|
||
|
|
for waitress in get_selected_named_waitresses(slots):
|
||
|
|
capacity, sales = effects.get(waitress, (0, 0))
|
||
|
|
capacity_delta += capacity
|
||
|
|
sales_bonus += sales
|
||
|
|
return capacity_delta, sales_bonus
|
||
|
|
|
||
|
|
|
||
|
|
def legacy_waitress_to_slots(value, restaurant_id):
|
||
|
|
"""Convert an old ``name+name`` waitress value into two new slots."""
|
||
|
|
if not isinstance(value, str):
|
||
|
|
values = []
|
||
|
|
else:
|
||
|
|
values = value.split('+')
|
||
|
|
return normalize_waitress_slots(restaurant_id, values)
|