Tidied up AccountSubsystem

This commit is contained in:
Eric Froemling 2020-10-16 14:26:30 -07:00
parent 8c6ec14208
commit 7535e0807b
26 changed files with 355 additions and 383 deletions

View File

@ -3932,24 +3932,24 @@
"assets/build/windows/Win32/ucrtbased.dll": "https://files.ballistica.net/cache/ba1/b5/85/f8b6d0558ddb87267f34254b1450",
"assets/build/windows/Win32/vc_redist.x86.exe": "https://files.ballistica.net/cache/ba1/1c/e1/4a1a2eddda2f4aebd5f8b64ab08e",
"assets/build/windows/Win32/vcruntime140d.dll": "https://files.ballistica.net/cache/ba1/50/8d/bc2600ac9491f1b14d659709451f",
"build/prefab/full/linux_x86_64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/4c/74/73bd143107ea1bc1cc150cf1d9a0",
"build/prefab/full/linux_x86_64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/d8/1f/b71688ce17abe2f1750d3b98c1a3",
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/7b/f5/0fb038ef5e8c9cb22f8487213622",
"build/prefab/full/linux_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/a7/22/7582b2dc2eb28e8c9b05c7860c83",
"build/prefab/full/mac_x86_64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/01/6a/6787038c5a2fe07be6dd08d6df5f",
"build/prefab/full/mac_x86_64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/eb/c3/12a2c00732a90af63ae853b76a3b",
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/63/e7/795fd31307cda51524ea0cfc4055",
"build/prefab/full/mac_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/92/48/1bfcef97e05d641771a934e312f3",
"build/prefab/full/windows_x86/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/cf/25/4ef41f30fb1380505759a16a7302",
"build/prefab/full/windows_x86/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/78/eb/9ee7487ac9d633020c02bcdd475b",
"build/prefab/full/windows_x86_server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/4e/59/bd1e3f68c9ccf0180187dbf60ce1",
"build/prefab/full/windows_x86_server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/3c/f2/e0eb7217dba038dd146421b0bf5e",
"build/prefab/lib/linux_x86_64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/66/0f/34874cece602328e1a2b27efbe09",
"build/prefab/lib/linux_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/ee/58/ccc75a3b2679f01a9e9b9f693ab0",
"build/prefab/lib/linux_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/2a/82/a34db5a370d695fb52891b0a7c54",
"build/prefab/lib/linux_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/1b/c4/0b7f73a301f24177650efb8cfa69",
"build/prefab/lib/mac_x86_64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/e6/55/d4819d9a2e5dcd48c2b2641c57df",
"build/prefab/lib/mac_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/21/3f/8c9d1590314cd5172e944f64e41c",
"build/prefab/lib/mac_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/91/72/b037555786dfb8a5ebc36467e60f",
"build/prefab/lib/mac_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/e3/e1/c9e61438f6458b9ce4ac4cfe66ed"
"build/prefab/full/linux_x86_64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/7e/ef/160b7c29aecf8594ce1aa3bb4d9f",
"build/prefab/full/linux_x86_64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/88/29/515b5c5def018fac0176b966bd93",
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/e2/4e/146ae464fad04c9a41ae0d7e01f3",
"build/prefab/full/linux_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/7a/14/febc99c12dabf2c09cf7969bd82f",
"build/prefab/full/mac_x86_64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/ed/78/7f2d157baabca2fb67b29d95c730",
"build/prefab/full/mac_x86_64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/e4/0e/05afd617a3333be2cebc6e7937f9",
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/47/49/9aef6c1fc8986c36740ae8ae5c83",
"build/prefab/full/mac_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/de/0c/e9bedd01292d103d92b8be7e9076",
"build/prefab/full/windows_x86/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/29/02/166905a0cfcb78acccd082a5d77e",
"build/prefab/full/windows_x86/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/7a/76/df87e67aef1847f9cc4f6d8bc43b",
"build/prefab/full/windows_x86_server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/d1/3d/431f9304a0c9eeb87d93af764bb6",
"build/prefab/full/windows_x86_server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/da/02/41c7bbfefbae5518f2faa2631a01",
"build/prefab/lib/linux_x86_64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/88/8a/aaeb70e76d31ce2686bee5cc4c14",
"build/prefab/lib/linux_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/fd/cd/3397d744c7405740df4d4ae567f0",
"build/prefab/lib/linux_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/c2/5b/ad020af2e062e5caff25e7d0aec4",
"build/prefab/lib/linux_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/54/40/8e0cc564f49f8963803834ec7995",
"build/prefab/lib/mac_x86_64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/bd/15/6ddf0c20288b9f72e5dd2c16a62a",
"build/prefab/lib/mac_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/b1/d0/fe3646d8225126baafec16641a93",
"build/prefab/lib/mac_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/23/b6/ada9721f37bc2a090fde0d0a1d83",
"build/prefab/lib/mac_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/99/4c/d5dd9bc0b501dcb0d817f8166243"
}

View File

@ -5,6 +5,7 @@
from __future__ import annotations
import copy
import time
from typing import TYPE_CHECKING
import _ba
@ -25,6 +26,15 @@ class AccountSubsystem:
def __init__(self) -> None:
self.account_tournament_list: Optional[Tuple[int, List[str]]] = None
# FIXME: should abstract/structure these.
self.tournament_info: Dict = {}
self.league_rank_cache: Dict = {}
self.last_post_purchase_message_time: Optional[float] = None
# If we try to run promo-codes due to launch-args/etc we might
# not be signed in yet; go ahead and queue them up in that case.
self.pending_promo_codes: List[str] = []
def on_app_launch(self) -> None:
"""Called when the app is done bootstrapping."""
@ -36,190 +46,222 @@ class AccountSubsystem:
_ba.pushcall(do_auto_sign_in)
def on_app_resume(self) -> None:
"""Should be called when the app is resumed."""
def handle_account_gained_tickets(count: int) -> None:
"""Called when the current account has been awarded tickets.
# Mark our cached tourneys as invalid so anyone using them knows
# they might be out of date.
for entry in list(self.tournament_info.values()):
entry['valid'] = False
(internal)
"""
from ba._language import Lstr
_ba.screenmessage(Lstr(resource='getTicketsWindow.receivedTicketsText',
subs=[('${COUNT}', str(count))]),
color=(0, 1, 0))
_ba.playsound(_ba.getsound('cashRegister'))
def handle_account_gained_tickets(self, count: int) -> None:
"""Called when the current account has been awarded tickets.
(internal)
"""
from ba._language import Lstr
_ba.screenmessage(Lstr(resource='getTicketsWindow.receivedTicketsText',
subs=[('${COUNT}', str(count))]),
color=(0, 1, 0))
_ba.playsound(_ba.getsound('cashRegister'))
def cache_league_rank_data(data: Any) -> None:
"""(internal)"""
_ba.app.league_rank_cache['info'] = copy.deepcopy(data)
def cache_league_rank_data(self, data: Any) -> None:
"""(internal)"""
self.league_rank_cache['info'] = copy.deepcopy(data)
def get_cached_league_rank_data(self) -> Any:
"""(internal)"""
return self.league_rank_cache.get('info', None)
def get_cached_league_rank_data() -> Any:
"""(internal)"""
return _ba.app.league_rank_cache.get('info', None)
def get_league_rank_points(self,
data: Optional[Dict[str, Any]],
subset: str = None) -> int:
"""(internal)"""
if data is None:
return 0
# If the data contains an achievement total, use that. otherwise calc
# locally.
if data['at'] is not None:
total_ach_value = data['at']
else:
total_ach_value = 0
for ach in _ba.app.ach.achievements:
if ach.complete:
total_ach_value += ach.power_ranking_value
def get_league_rank_points(data: Optional[Dict[str, Any]],
subset: str = None) -> int:
"""(internal)"""
if data is None:
return 0
trophies_total: int = (data['t0a'] * data['t0am'] +
data['t0b'] * data['t0bm'] +
data['t1'] * data['t1m'] +
data['t2'] * data['t2m'] +
data['t3'] * data['t3m'] +
data['t4'] * data['t4m'])
if subset == 'trophyCount':
val: int = (data['t0a'] + data['t0b'] + data['t1'] + data['t2'] +
data['t3'] + data['t4'])
assert isinstance(val, int)
return val
if subset == 'trophies':
assert isinstance(trophies_total, int)
return trophies_total
if subset is not None:
raise ValueError('invalid subset value: ' + str(subset))
# If the data contains an achievement total, use that. otherwise calc
# locally.
if data['at'] is not None:
total_ach_value = data['at']
else:
total_ach_value = 0
for ach in _ba.app.ach.achievements:
if ach.complete:
total_ach_value += ach.power_ranking_value
if data['p']:
pro_mult = 1.0 + float(
_ba.get_account_misc_read_val('proPowerRankingBoost',
0.0)) * 0.01
else:
pro_mult = 1.0
trophies_total: int = (data['t0a'] * data['t0am'] +
data['t0b'] * data['t0bm'] +
data['t1'] * data['t1m'] +
data['t2'] * data['t2m'] +
data['t3'] * data['t3m'] + data['t4'] * data['t4m'])
if subset == 'trophyCount':
val: int = (data['t0a'] + data['t0b'] + data['t1'] + data['t2'] +
data['t3'] + data['t4'])
assert isinstance(val, int)
return val
if subset == 'trophies':
assert isinstance(trophies_total, int)
return trophies_total
if subset is not None:
raise ValueError('invalid subset value: ' + str(subset))
# For final value, apply our pro mult and activeness-mult.
return int(
(total_ach_value + trophies_total) *
(data['act'] if data['act'] is not None else 1.0) * pro_mult)
if data['p']:
pro_mult = 1.0 + float(
_ba.get_account_misc_read_val('proPowerRankingBoost', 0.0)) * 0.01
else:
pro_mult = 1.0
def cache_tournament_info(self, info: Any) -> None:
"""(internal)"""
from ba._enums import TimeType, TimeFormat
for entry in info:
cache_entry = self.tournament_info[entry['tournamentID']] = (
copy.deepcopy(entry))
# For final value, apply our pro mult and activeness-mult.
return int((total_ach_value + trophies_total) *
(data['act'] if data['act'] is not None else 1.0) * pro_mult)
# Also store the time we received this, so we can adjust
# time-remaining values/etc.
cache_entry['timeReceived'] = _ba.time(TimeType.REAL,
TimeFormat.MILLISECONDS)
cache_entry['valid'] = True
def get_purchased_icons(self) -> List[str]:
"""(internal)"""
# pylint: disable=cyclic-import
from ba import _store
if _ba.get_account_state() != 'signed_in':
return []
icons = []
store_items = _store.get_store_items()
for item_name, item in list(store_items.items()):
if item_name.startswith('icons.') and _ba.get_purchased(item_name):
icons.append(item['icon'])
return icons
def cache_tournament_info(info: Any) -> None:
"""(internal)"""
from ba._enums import TimeType, TimeFormat
for entry in info:
cache_entry = _ba.app.tournament_info[entry['tournamentID']] = (
copy.deepcopy(entry))
def ensure_have_account_player_profile(self) -> None:
"""
Ensure the standard account-named player profile exists;
creating if needed.
# Also store the time we received this, so we can adjust
# time-remaining values/etc.
cache_entry['timeReceived'] = _ba.time(TimeType.REAL,
TimeFormat.MILLISECONDS)
cache_entry['valid'] = True
(internal)
"""
# This only applies when we're signed in.
if _ba.get_account_state() != 'signed_in':
return
# If the short version of our account name currently cant be
# displayed by the game, cancel.
if not _ba.have_chars(_ba.get_account_display_string(full=False)):
return
def get_purchased_icons() -> List[str]:
"""(internal)"""
# pylint: disable=cyclic-import
from ba import _store
if _ba.get_account_state() != 'signed_in':
return []
icons = []
store_items = _store.get_store_items()
for item_name, item in list(store_items.items()):
if item_name.startswith('icons.') and _ba.get_purchased(item_name):
icons.append(item['icon'])
return icons
config = _ba.app.config
if ('Player Profiles' not in config
or '__account__' not in config['Player Profiles']):
# Create a spaz with a nice default purply color.
_ba.add_transaction({
'type': 'ADD_PLAYER_PROFILE',
'name': '__account__',
'profile': {
'character': 'Spaz',
'color': [0.5, 0.25, 1.0],
'highlight': [0.5, 0.25, 1.0]
}
})
_ba.run_transactions()
def ensure_have_account_player_profile() -> None:
"""
Ensure the standard account-named player profile exists;
creating if needed.
"""
# This only applies when we're signed in.
if _ba.get_account_state() != 'signed_in':
return
def have_pro(self) -> bool:
"""Return whether pro is currently unlocked."""
# If the short version of our account name currently cant be
# displayed by the game, cancel.
if not _ba.have_chars(_ba.get_account_display_string(full=False)):
return
# Check our tickets-based pro upgrade and our two real-IAP based
# upgrades. Also unlock this stuff in ballistica-core builds.
return bool(
_ba.get_purchased('upgrades.pro')
or _ba.get_purchased('static.pro')
or _ba.get_purchased('static.pro_sale')
or 'ballistica' + 'core' == _ba.appname())
config = _ba.app.config
if ('Player Profiles' not in config
or '__account__' not in config['Player Profiles']):
def have_pro_options(self) -> bool:
"""Return whether pro-options are present.
# Create a spaz with a nice default purply color.
This is True for owners of Pro or old installs
before Pro was a requirement for these.
"""
# We expose pro options if the server tells us to
# (which is generally just when we own pro),
# or also if we've been grandfathered in or are using ballistica-core
# builds.
return self.have_pro() or bool(
_ba.get_account_misc_read_val_2('proOptionsUnlocked', False)
or _ba.app.config.get('lc14292', 0) > 1)
def show_post_purchase_message(self) -> None:
"""(internal)"""
from ba._language import Lstr
from ba._enums import TimeType
cur_time = _ba.time(TimeType.REAL)
if (self.last_post_purchase_message_time is None
or cur_time - self.last_post_purchase_message_time > 3.0):
self.last_post_purchase_message_time = cur_time
with _ba.Context('ui'):
_ba.screenmessage(Lstr(resource='updatingAccountText',
fallback_resource='purchasingText'),
color=(0, 1, 0))
_ba.playsound(_ba.getsound('click01'))
def on_account_state_changed(self) -> None:
"""(internal)"""
from ba._language import Lstr
# Run any pending promo codes we had queued up while not signed in.
if _ba.get_account_state() == 'signed_in' and self.pending_promo_codes:
for code in self.pending_promo_codes:
_ba.screenmessage(Lstr(resource='submittingPromoCodeText'),
color=(0, 1, 0))
_ba.add_transaction({
'type': 'PROMO_CODE',
'expire_time': time.time() + 5,
'code': code
})
_ba.run_transactions()
self.pending_promo_codes = []
def add_pending_promo_code(self, code: str) -> None:
"""(internal)"""
from ba._language import Lstr
from ba._enums import TimeType
# If we're not signed in, queue up the code to run the next time we
# are and issue a warning if we haven't signed in within the next
# few seconds.
if _ba.get_account_state() != 'signed_in':
def check_pending_codes() -> None:
"""(internal)"""
# If we're still not signed in and have pending codes,
# inform the user that they need to sign in to use them.
if self.pending_promo_codes:
_ba.screenmessage(Lstr(resource='signInForPromoCodeText'),
color=(1, 0, 0))
_ba.playsound(_ba.getsound('error'))
self.pending_promo_codes.append(code)
_ba.timer(6.0, check_pending_codes, timetype=TimeType.REAL)
return
_ba.screenmessage(Lstr(resource='submittingPromoCodeText'),
color=(0, 1, 0))
_ba.add_transaction({
'type': 'ADD_PLAYER_PROFILE',
'name': '__account__',
'profile': {
'character': 'Spaz',
'color': [0.5, 0.25, 1.0],
'highlight': [0.5, 0.25, 1.0]
}
'type': 'PROMO_CODE',
'expire_time': time.time() + 5,
'code': code
})
_ba.run_transactions()
def have_pro() -> bool:
"""Return whether pro is currently unlocked."""
# Check our tickets-based pro upgrade and our two real-IAP based upgrades.
# Also unlock this stuff in ballistica-core builds.
return bool(
_ba.get_purchased('upgrades.pro') or _ba.get_purchased('static.pro')
or _ba.get_purchased('static.pro_sale')
or 'ballistica' + 'core' == _ba.appname())
def have_pro_options() -> bool:
"""Return whether pro-options are present.
This is True for owners of Pro or old installs
before Pro was a requirement for these.
"""
# We expose pro options if the server tells us to
# (which is generally just when we own pro),
# or also if we've been grandfathered in or are using ballistica-core
# builds.
return have_pro() or bool(
_ba.get_account_misc_read_val_2('proOptionsUnlocked', False)
or _ba.app.config.get('lc14292', 0) > 1)
def show_post_purchase_message() -> None:
"""(internal)"""
from ba._language import Lstr
from ba._enums import TimeType
app = _ba.app
cur_time = _ba.time(TimeType.REAL)
if (app.last_post_purchase_message_time is None
or cur_time - app.last_post_purchase_message_time > 3.0):
app.last_post_purchase_message_time = cur_time
with _ba.Context('ui'):
_ba.screenmessage(Lstr(resource='updatingAccountText',
fallback_resource='purchasingText'),
color=(0, 1, 0))
_ba.playsound(_ba.getsound('click01'))
def on_account_state_changed() -> None:
"""(internal)"""
import time
from ba import _language
app = _ba.app
# Run any pending promo codes we had queued up while not signed in.
if _ba.get_account_state() == 'signed_in' and app.pending_promo_codes:
for code in app.pending_promo_codes:
_ba.screenmessage(
_language.Lstr(resource='submittingPromoCodeText'),
color=(0, 1, 0))
_ba.add_transaction({
'type': 'PROMO_CODE',
'expire_time': time.time() + 5,
'code': code
})
_ba.run_transactions()
app.pending_promo_codes = []

View File

@ -409,10 +409,9 @@ def _get_ach_mult(include_pro_bonus: bool = False) -> int:
(just for display; changing this here won't affect actual rewards)
"""
from ba import _account
val: int = _ba.get_account_misc_read_val('achAwardMult', 5)
assert isinstance(val, int)
if include_pro_bonus and _account.have_pro():
if include_pro_bonus and _ba.app.accounts.have_pro():
val *= 2
return val
@ -1178,7 +1177,7 @@ class Achievement:
objt.node.host_only = True
# Add the 'x 2' if we've got pro.
if _account.have_pro():
if app.accounts.have_pro():
objt = Text('x 2',
position=(-120 - 180 + 45, 80 + y_offs - 50),
v_attach=Text.VAttach.BOTTOM,

View File

@ -209,15 +209,11 @@ class App:
self.did_weak_call_warning = False
self.ran_on_app_launch = False
# If we try to run promo-codes due to launch-args/etc we might
# not be signed in yet; go ahead and queue them up in that case.
self.pending_promo_codes: List[str] = []
self.last_in_game_ad_remove_message_show_time: Optional[float] = None
self.log_have_new = False
self.log_upload_timer_started = False
self._config: Optional[ba.AppConfig] = None
self.printed_live_object_warning = False
self.last_post_purchase_message_time: Optional[float] = None
# We include this extra hash with shared input-mapping names so
# that we don't share mappings between differently-configured
@ -273,8 +269,6 @@ class App:
self.main_menu_window_refresh_check_count = 0 # FIXME: Mv to mainmenu.
self.main_menu_resume_callbacks: list = [] # Can probably go away.
self.special_offer: Optional[Dict] = None
self.league_rank_cache: Dict = {}
self.tournament_info: Dict = {}
self.ping_thread_count = 0
self.invite_confirm_windows: List[Any] = [] # FIXME: Don't use Any.
self.store_layout: Optional[Dict[str, List[Dict[str, Any]]]] = None
@ -512,13 +506,9 @@ class App:
def on_app_resume(self) -> None:
"""Run when the app resumes from a suspended state."""
self.music.on_app_resume()
self.fg_state += 1
# Mark our cached tourneys as invalid so anyone using them knows
# they might be out of date.
for entry in list(self.tournament_info.values()):
entry['valid'] = False
self.accounts.on_app_resume()
self.music.on_app_resume()
def launch_coop_game(self,
game: str,
@ -596,38 +586,10 @@ class App:
def handle_deep_link(self, url: str) -> None:
"""Handle a deep link URL."""
from ba._language import Lstr
from ba._enums import TimeType
appname = _ba.appname()
if url.startswith(f'{appname}://code/'):
code = url.replace(f'{appname}://code/', '')
# If we're not signed in, queue up the code to run the next time we
# are and issue a warning if we haven't signed in within the next
# few seconds.
if _ba.get_account_state() != 'signed_in':
def check_pending_codes() -> None:
"""(internal)"""
# If we're still not signed in and have pending codes,
# inform the user that they need to sign in to use them.
if self.pending_promo_codes:
_ba.screenmessage(
Lstr(resource='signInForPromoCodeText'),
color=(1, 0, 0))
_ba.playsound(_ba.getsound('error'))
self.pending_promo_codes.append(code)
_ba.timer(6.0, check_pending_codes, timetype=TimeType.REAL)
return
_ba.screenmessage(Lstr(resource='submittingPromoCodeText'),
color=(0, 1, 0))
_ba.add_transaction({
'type': 'PROMO_CODE',
'expire_time': time.time() + 5,
'code': code
})
_ba.run_transactions()
self.accounts.add_pending_promo_code(code)
else:
_ba.screenmessage(Lstr(resource='errorText'), color=(1, 0, 0))
_ba.playsound(_ba.getsound('error'))

View File

@ -246,7 +246,6 @@ def call_after_ad(call: Callable[[], Any]) -> None:
# pylint: disable=too-many-statements
# pylint: disable=too-many-branches
# pylint: disable=too-many-locals
from ba._account import have_pro
from ba._enums import TimeType
import time
app = _ba.app
@ -255,7 +254,7 @@ def call_after_ad(call: Callable[[], Any]) -> None:
# No ads without net-connections, etc.
if not _ba.can_show_ad():
show = False
if have_pro():
if app.accounts.have_pro():
show = False # Pro disables interstitials.
try:
session = _ba.get_foreground_host_session()

View File

@ -8,6 +8,7 @@ from __future__ import annotations
import random
from typing import TYPE_CHECKING, TypeVar
import _ba
from ba._activity import Activity
from ba._score import ScoreConfig
from ba._language import Lstr
@ -16,7 +17,6 @@ from ba._error import NotFoundError, print_error, print_exception
from ba._general import Call, WeakCall
from ba._player import PlayerInfo
from ba import _map
import _ba
if TYPE_CHECKING:
from typing import (List, Optional, Dict, Type, Any, Callable, Sequence,
@ -461,12 +461,11 @@ class GameActivity(Activity[PlayerType, TeamType]):
def _on_tournament_query_response(self, data: Optional[Dict[str,
Any]]) -> None:
from ba._account import cache_tournament_info
if data is not None:
data_t = data['t'] # This used to be the whole payload.
# Keep our cached tourney info up to date
cache_tournament_info(data_t)
_ba.app.accounts.cache_tournament_info(data_t)
self._setup_tournament_time_limit(
max(5, data_t[0]['timeRemaining']))

View File

@ -881,7 +881,6 @@ class Lobby:
def reload_profiles(self) -> None:
"""Reload available player profiles."""
# pylint: disable=cyclic-import
from ba._account import ensure_have_account_player_profile
from bastd.actor.spazappearance import get_appearances
# We may have gained or lost character names if the user
@ -890,7 +889,7 @@ class Lobby:
self.character_names_local_unlocked.sort(key=lambda x: x.lower())
# Do any overall prep we need to such as creating account profile.
ensure_have_account_player_profile()
_ba.app.accounts.ensure_have_account_player_profile()
for chooser in self.choosers:
try:
chooser.reload_profiles()

View File

@ -440,7 +440,6 @@ def get_available_sale_time(tab: str) -> Optional[int]:
# pylint: disable=too-many-locals
try:
import datetime
from ba._account import have_pro
from ba._enums import TimeType, TimeFormat
app = _ba.app
sale_times: List[Optional[int]] = []
@ -448,7 +447,7 @@ def get_available_sale_time(tab: str) -> Optional[int]:
# Calc time for our pro sale (old special case).
if tab == 'extras':
config = app.config
if have_pro():
if app.accounts.have_pro():
return None
# If we haven't calced/loaded start times yet.

View File

@ -16,12 +16,6 @@ from ba._appconfig import commit_app_config
from ba._input import (get_device_value, get_input_map_hash,
get_input_device_config)
from ba._general import getclass, json_prep, get_type_name
from ba._account import (on_account_state_changed,
handle_account_gained_tickets, have_pro_options,
have_pro, cache_tournament_info,
ensure_have_account_player_profile,
get_purchased_icons, get_cached_league_rank_data,
get_league_rank_points, cache_league_rank_data)
from ba._activitytypes import JoinActivity, ScoreScreenActivity
from ba._apputils import (is_browser_likely_available, get_remote_app_name,
should_submit_debug_info, show_ad, show_ad_2)

View File

@ -1197,8 +1197,9 @@ class CoopScoreScreen(ba.Activity[ba.Player, ba.Team]):
try:
tournament_id = self.session.tournament_id
if tournament_id is not None:
if tournament_id in ba.app.tournament_info:
tourney_info = ba.app.tournament_info[tournament_id]
if tournament_id in ba.app.accounts.tournament_info:
tourney_info = ba.app.accounts.tournament_info[
tournament_id]
# pylint: disable=unbalanced-tuple-unpacking
pr1, pv1, pr2, pv2, pr3, pv3 = (
get_tournament_prize_strings(tourney_info))

View File

@ -28,7 +28,7 @@ class ColorPicker(PopupWindow):
offset: Tuple[float, float] = (0.0, 0.0),
tag: Any = ''):
# pylint: disable=too-many-locals
from ba.internal import have_pro, get_player_colors
from ba.internal import get_player_colors
c_raw = get_player_colors()
assert len(c_raw) == 16
@ -94,7 +94,7 @@ class ColorPicker(PopupWindow):
on_activate_call=ba.WeakCall(self._select_other))
# Custom colors are limited to pro currently.
if not have_pro():
if not ba.app.accounts.have_pro():
ba.imagewidget(parent=self.root_widget,
position=(50, 12),
size=(30, 30),
@ -116,10 +116,9 @@ class ColorPicker(PopupWindow):
def _select_other(self) -> None:
from bastd.ui import purchase
from ba.internal import have_pro
# Requires pro.
if not have_pro():
if not ba.app.accounts.have_pro():
purchase.PurchaseWindow(items=['pro'])
self._transition_out()
return

View File

@ -253,11 +253,11 @@ class CoopBrowserWindow(ba.Window):
if (app.accounts.account_tournament_list is not None
and app.accounts.account_tournament_list[0]
== _ba.get_account_state_num() and all([
t_id in app.tournament_info
t_id in app.accounts.tournament_info
for t_id in app.accounts.account_tournament_list[1]
])):
tourney_data = [
app.tournament_info[t_id]
app.accounts.tournament_info[t_id]
for t_id in app.accounts.account_tournament_list[1]
]
self._update_for_data(tourney_data)
@ -350,10 +350,10 @@ class CoopBrowserWindow(ba.Window):
self._update_hard_mode_lock_image()
def _update_hard_mode_lock_image(self) -> None:
from ba.internal import have_pro_options
try:
ba.imagewidget(edit=self._hard_button_lock_image,
opacity=0.0 if have_pro_options() else 1.0)
ba.imagewidget(
edit=self._hard_button_lock_image,
opacity=0.0 if ba.app.accounts.have_pro_options() else 1.0)
except Exception:
ba.print_exception('Error updating campaign lock.')
@ -475,7 +475,8 @@ class CoopBrowserWindow(ba.Window):
tbtn['required_league'] = (None if 'requiredLeague' not in entry
else entry['requiredLeague'])
game = ba.app.tournament_info[tbtn['tournament_id']]['game']
game = ba.app.accounts.tournament_info[
tbtn['tournament_id']]['game']
if game is None:
ba.textwidget(edit=tbtn['button_text'], text='-')
@ -485,7 +486,7 @@ class CoopBrowserWindow(ba.Window):
else:
campaignname, levelname = game.split(':')
campaign = getcampaign(campaignname)
max_players = ba.app.tournament_info[
max_players = ba.app.accounts.tournament_info[
tbtn['tournament_id']]['maxPlayers']
txt = ba.Lstr(
value='${A} ${B}',
@ -534,9 +535,9 @@ class CoopBrowserWindow(ba.Window):
ba.charstr(ba.SpecialChar.TICKET_BACKING) +
str(final_fee))
ad_tries_remaining = ba.app.tournament_info[
ad_tries_remaining = ba.app.accounts.tournament_info[
tbtn['tournament_id']]['adTriesRemaining']
free_tries_remaining = ba.app.tournament_info[
free_tries_remaining = ba.app.accounts.tournament_info[
tbtn['tournament_id']]['freeTriesRemaining']
# Now, if this fee allows ads and we support video ads, show
@ -586,8 +587,7 @@ class CoopBrowserWindow(ba.Window):
def _on_tournament_query_response(self, data: Optional[Dict[str,
Any]]) -> None:
from ba.internal import cache_tournament_info
app = ba.app
accounts = ba.app.accounts
if data is not None:
tournament_data = data['t'] # This used to be the whole payload.
self._last_tournament_query_response_time = ba.time(
@ -598,22 +598,21 @@ class CoopBrowserWindow(ba.Window):
# Keep our cached tourney info up to date.
if data is not None:
self._tourney_data_up_to_date = True
cache_tournament_info(tournament_data)
accounts.cache_tournament_info(tournament_data)
# Also cache the current tourney list/order for this account.
app.accounts.account_tournament_list = (
_ba.get_account_state_num(),
[e['tournamentID'] for e in tournament_data])
accounts.account_tournament_list = (_ba.get_account_state_num(), [
e['tournamentID'] for e in tournament_data
])
self._doing_tournament_query = False
self._update_for_data(tournament_data)
def _set_campaign_difficulty(self, difficulty: str) -> None:
# pylint: disable=cyclic-import
from ba.internal import have_pro_options
from bastd.ui.purchase import PurchaseWindow
if difficulty != self._campaign_difficulty:
if difficulty == 'hard' and not have_pro_options():
if difficulty == 'hard' and not ba.app.accounts.have_pro_options():
PurchaseWindow(items=['pro'])
return
ba.playsound(ba.getsound('gunCocking'))
@ -1412,7 +1411,6 @@ class CoopBrowserWindow(ba.Window):
# pylint: disable=too-many-statements
# pylint: disable=too-many-return-statements
# pylint: disable=cyclic-import
from ba.internal import have_pro
from bastd.ui.confirm import ConfirmWindow
from bastd.ui.tournamententry import TournamentEntryWindow
from bastd.ui.purchase import PurchaseWindow
@ -1460,7 +1458,7 @@ class CoopBrowserWindow(ba.Window):
return
# Game is whatever the tournament tells us it is.
game = ba.app.tournament_info[
game = ba.app.accounts.tournament_info[
tournament_button['tournament_id']]['game']
if tournament_button is None and game == 'Easy:The Last Stand':
@ -1475,7 +1473,8 @@ class CoopBrowserWindow(ba.Window):
# need be.
if tournament_button is None and game in (
'Challenges:Infinite Runaround',
'Challenges:Infinite Onslaught') and not have_pro():
'Challenges:Infinite Onslaught'
) and not ba.app.accounts.have_pro():
if _ba.get_account_state() != 'signed_in':
show_sign_in_prompt()
else:

View File

@ -164,7 +164,7 @@ class GameButton:
def _update(self) -> None:
# pylint: disable=too-many-boolean-expressions
from ba.internal import have_pro, getcampaign
from ba.internal import getcampaign
game = self._game
campaignname, levelname = game.split(':')
@ -193,7 +193,8 @@ class GameButton:
# Hard-code games we haven't unlocked.
if ((game in ('Challenges:Infinite Runaround',
'Challenges:Infinite Onslaught') and not have_pro())
'Challenges:Infinite Onslaught')
and not ba.app.accounts.have_pro())
or (game in ('Challenges:Meteor Shower', )
and not _ba.get_purchased('games.meteor_shower'))
or (game in ('Challenges:Target Practice',

View File

@ -1256,9 +1256,8 @@ class GatherWindow(ba.Window):
texture=ba.gettexture('lock'))
def _is_internet_locked(self) -> bool:
from ba.internal import have_pro
if _ba.get_account_misc_read_val('ilck', False):
return not have_pro()
return not ba.app.accounts.have_pro()
return False
def _on_max_public_party_size_minus_press(self) -> None:

View File

@ -28,7 +28,6 @@ class IconPicker(popup.PopupWindow):
tint2_color: Sequence[float] = (1.0, 1.0, 1.0),
selected_icon: str = None):
# pylint: disable=too-many-locals
from ba.internal import get_purchased_icons
del parent # unused here
del tint_color # unused_here
del tint2_color # unused here
@ -40,7 +39,8 @@ class IconPicker(popup.PopupWindow):
self._delegate = delegate
self._transitioning_out = False
self._icons = [ba.charstr(ba.SpecialChar.LOGO)] + get_purchased_icons()
self._icons = [ba.charstr(ba.SpecialChar.LOGO)
] + ba.app.accounts.get_purchased_icons()
count = len(self._icons)
columns = 4
rows = int(math.ceil(float(count) / columns))

View File

@ -26,7 +26,6 @@ class LeagueRankButton:
color: Tuple[float, float, float] = None,
textcolor: Tuple[float, float, float] = None,
smooth_update_delay: float = None):
from ba.internal import get_cached_league_rank_data
if on_activate_call is None:
on_activate_call = ba.WeakCall(self._default_on_activate_call)
self._on_activate_call = on_activate_call
@ -107,7 +106,7 @@ class LeagueRankButton:
self._update()
# If we've got cached power-ranking data already, apply it.
data = get_cached_league_rank_data()
data = ba.app.accounts.get_cached_league_rank_data()
if data is not None:
self._update_for_league_rank_data(data)
@ -216,7 +215,6 @@ class LeagueRankButton:
Any]]) -> None:
# pylint: disable=too-many-branches
# pylint: disable=too-many-statements
from ba.internal import get_league_rank_points
# If our button has died, ignore.
if not self._button:
@ -250,7 +248,7 @@ class LeagueRankButton:
self._percent = self._rank = None
status_text = '-'
else:
our_points = get_league_rank_points(data)
our_points = ba.app.accounts.get_league_rank_points(data)
progress = float(our_points) / data['scores'][-1][1]
self._percent = int(progress * 100.0)
self._rank = None
@ -328,9 +326,8 @@ class LeagueRankButton:
def _on_power_ranking_query_response(
self, data: Optional[Dict[str, Any]]) -> None:
from ba.internal import cache_league_rank_data
self._doing_power_ranking_query = False
cache_league_rank_data(data)
ba.app.accounts.cache_league_rank_data(data)
self._update_for_league_rank_data(data)
def _update(self) -> None:

View File

@ -22,7 +22,6 @@ class LeagueRankWindow(ba.Window):
transition: str = 'in_right',
modal: bool = False,
origin_widget: ba.Widget = None):
from ba.internal import get_cached_league_rank_data
ba.set_analytics_screen('League Rank Window')
self._league_rank_data: Optional[Dict[str, Any]] = None
@ -125,7 +124,7 @@ class LeagueRankWindow(ba.Window):
self._restore_state()
# if we've got cached power-ranking data already, display it
info = get_cached_league_rank_data()
info = ba.app.accounts.get_cached_league_rank_data()
if info is not None:
self._update_for_league_rank_data(info)
@ -194,11 +193,10 @@ class LeagueRankWindow(ba.Window):
def _on_power_ranking_query_response(
self, data: Optional[Dict[str, Any]]) -> None:
from ba.internal import cache_league_rank_data
self._doing_power_ranking_query = False
# important: *only* cache this if we requested the current season..
if data is not None and data.get('s', None) is None:
cache_league_rank_data(data)
ba.app.accounts.cache_league_rank_data(data)
# always store a copy locally though (even for other seasons)
self._league_rank_data = copy.deepcopy(data)
self._update_for_league_rank_data(data)
@ -594,9 +592,9 @@ class LeagueRankWindow(ba.Window):
# pylint: disable=too-many-statements
# pylint: disable=too-many-branches
# pylint: disable=too-many-locals
from ba.internal import get_league_rank_points
if not self._root_widget:
return
accounts = ba.app.accounts
in_top = (data is not None and data['rank'] is not None)
eq_text = self._rdict.powerRankingPointsEqualsText
pts_txt = self._rdict.powerRankingPointsText
@ -622,7 +620,7 @@ class LeagueRankWindow(ba.Window):
finished_season_unranked = True
self._can_do_more_button = False
else:
our_points = get_league_rank_points(data)
our_points = accounts.get_league_rank_points(data)
progress = float(our_points) / max(1,
data['scores'][-1][1])
status_text = str(int(progress * 100.0)) + '%'
@ -820,8 +818,10 @@ class LeagueRankWindow(ba.Window):
('+ ' +
pts_txt.replace('${NUMBER}', str(total_ach_value))))
total_trophies_count = (get_league_rank_points(data, 'trophyCount'))
total_trophies_value = (get_league_rank_points(data, 'trophies'))
total_trophies_count = (accounts.get_league_rank_points(
data, 'trophyCount'))
total_trophies_value = (accounts.get_league_rank_points(
data, 'trophies'))
ba.buttonwidget(edit=self._power_ranking_trophies_button,
label=('' if data is None else
(str(total_trophies_count) + ' ')) +
@ -831,9 +831,10 @@ class LeagueRankWindow(ba.Window):
text='-' if data is None else
('+ ' + pts_txt.replace('${NUMBER}', str(total_trophies_value))))
ba.textwidget(edit=self._power_ranking_total_text,
text='-' if data is None else eq_text.replace(
'${NUMBER}', str(get_league_rank_points(data))))
ba.textwidget(
edit=self._power_ranking_total_text,
text='-' if data is None else eq_text.replace(
'${NUMBER}', str(accounts.get_league_rank_points(data))))
for widget in self._power_ranking_score_widgets:
widget.delete()
self._power_ranking_score_widgets = []

View File

@ -253,8 +253,7 @@ class PlaylistCustomizeBrowserWindow(ba.Window):
self._update()
def _update(self) -> None:
from ba.internal import have_pro_options
have = have_pro_options()
have = ba.app.accounts.have_pro_options()
for lock in self._lock_images:
ba.imagewidget(edit=lock, opacity=0.0 if have else 1.0)
@ -382,11 +381,10 @@ class PlaylistCustomizeBrowserWindow(ba.Window):
def _new_playlist(self) -> None:
# pylint: disable=cyclic-import
from ba.internal import have_pro_options
from bastd.ui.playlist import editcontroller
from bastd.ui import purchase
if not have_pro_options():
purchase.PurchaseWindow(items=['pro'])
from bastd.ui.playlist.editcontroller import PlaylistEditController
from bastd.ui.purchase import PurchaseWindow
if not ba.app.accounts.have_pro_options():
PurchaseWindow(items=['pro'])
return
# Clamp at our max playlist number.
@ -402,16 +400,15 @@ class PlaylistCustomizeBrowserWindow(ba.Window):
self._save_playlist_selection()
# Kick off the edit UI.
editcontroller.PlaylistEditController(sessiontype=self._sessiontype)
PlaylistEditController(sessiontype=self._sessiontype)
ba.containerwidget(edit=self._root_widget, transition='out_left')
def _edit_playlist(self) -> None:
# pylint: disable=cyclic-import
from ba.internal import have_pro_options
from bastd.ui.playlist import editcontroller
from bastd.ui import purchase
if not have_pro_options():
purchase.PurchaseWindow(items=['pro'])
from bastd.ui.playlist.editcontroller import PlaylistEditController
from bastd.ui.purchase import PurchaseWindow
if not ba.app.accounts.have_pro_options():
PurchaseWindow(items=['pro'])
return
if self._selected_playlist_name is None:
return
@ -421,7 +418,7 @@ class PlaylistCustomizeBrowserWindow(ba.Window):
'.cantEditDefaultText'))
return
self._save_playlist_selection()
editcontroller.PlaylistEditController(
PlaylistEditController(
existing_playlist_name=self._selected_playlist_name,
sessiontype=self._sessiontype)
ba.containerwidget(edit=self._root_widget, transition='out_left')
@ -474,10 +471,9 @@ class PlaylistCustomizeBrowserWindow(ba.Window):
def _share_playlist(self) -> None:
# pylint: disable=cyclic-import
from ba.internal import have_pro_options
from bastd.ui import purchase
if not have_pro_options():
purchase.PurchaseWindow(items=['pro'])
from bastd.ui.purchase import PurchaseWindow
if not ba.app.accounts.have_pro_options():
PurchaseWindow(items=['pro'])
return
# Gotta be signed in for this to work.
@ -510,11 +506,10 @@ class PlaylistCustomizeBrowserWindow(ba.Window):
def _delete_playlist(self) -> None:
# pylint: disable=cyclic-import
from ba.internal import have_pro_options
from bastd.ui import purchase
from bastd.ui import confirm
if not have_pro_options():
purchase.PurchaseWindow(items=['pro'])
from bastd.ui.purchase import PurchaseWindow
from bastd.ui.confirm import ConfirmWindow
if not ba.app.accounts.have_pro_options():
PurchaseWindow(items=['pro'])
return
if self._selected_playlist_name is None:
@ -524,7 +519,7 @@ class PlaylistCustomizeBrowserWindow(ba.Window):
ba.screenmessage(
ba.Lstr(resource=self._r + '.cantDeleteDefaultText'))
else:
confirm.ConfirmWindow(
ConfirmWindow(
ba.Lstr(resource=self._r + '.deleteConfirmText',
subs=[('${LIST}', self._selected_playlist_name)]),
self._do_delete_playlist, 450, 150)
@ -538,10 +533,9 @@ class PlaylistCustomizeBrowserWindow(ba.Window):
def _duplicate_playlist(self) -> None:
# pylint: disable=too-many-branches
# pylint: disable=cyclic-import
from ba.internal import have_pro_options
from bastd.ui import purchase
if not have_pro_options():
purchase.PurchaseWindow(items=['pro'])
from bastd.ui.purchase import PurchaseWindow
if not ba.app.accounts.have_pro_options():
PurchaseWindow(items=['pro'])
return
if self._selected_playlist_name is None:
return

View File

@ -26,8 +26,7 @@ class PlayOptionsWindow(popup.PopupWindow):
# pylint: disable=too-many-branches
# pylint: disable=too-many-statements
# pylint: disable=too-many-locals
from ba.internal import (getclass, have_pro,
get_default_teams_playlist,
from ba.internal import (getclass, get_default_teams_playlist,
get_default_free_for_all_playlist,
filter_playlist)
from ba.internal import get_map_class
@ -256,7 +255,7 @@ class PlayOptionsWindow(popup.PopupWindow):
autoselect=True,
textcolor=(0.8, 0.8, 0.8),
label=ba.Lstr(resource='teamNamesColorText'))
if not have_pro():
if not ba.app.accounts.have_pro():
ba.imagewidget(
parent=self.root_widget,
size=(30, 30),
@ -350,21 +349,19 @@ class PlayOptionsWindow(popup.PopupWindow):
self._update()
def _custom_colors_names_press(self) -> None:
from ba.internal import have_pro
from bastd.ui import account as accountui
from bastd.ui import teamnamescolors
from bastd.ui import purchase
if not have_pro():
from bastd.ui.account import show_sign_in_prompt
from bastd.ui.teamnamescolors import TeamNamesColorsWindow
from bastd.ui.purchase import PurchaseWindow
if not ba.app.accounts.have_pro():
if _ba.get_account_state() != 'signed_in':
accountui.show_sign_in_prompt()
show_sign_in_prompt()
else:
purchase.PurchaseWindow(items=['pro'])
PurchaseWindow(items=['pro'])
self._transition_out()
return
assert self._custom_colors_names_button
teamnamescolors.TeamNamesColorsWindow(
scale_origin=self._custom_colors_names_button.
get_screen_space_center())
TeamNamesColorsWindow(scale_origin=self._custom_colors_names_button.
get_screen_space_center())
def _does_target_playlist_exist(self) -> bool:
if self._playlist == '__default__':

View File

@ -23,7 +23,6 @@ class ProfileBrowserWindow(ba.Window):
origin_widget: ba.Widget = None):
# pylint: disable=too-many-statements
# pylint: disable=too-many-locals
from ba.internal import ensure_have_account_player_profile
self._in_main_menu = in_main_menu
if self._in_main_menu:
back_label = ba.Lstr(resource='backText')
@ -52,7 +51,7 @@ class ProfileBrowserWindow(ba.Window):
self._r = 'playerProfilesWindow'
# Ensure we've got an account-profile in cases where we're signed in.
ensure_have_account_player_profile()
ba.app.accounts.ensure_have_account_player_profile()
top_extra = 20 if uiscale is ba.UIScale.SMALL else 0
@ -171,14 +170,13 @@ class ProfileBrowserWindow(ba.Window):
def _new_profile(self) -> None:
# pylint: disable=cyclic-import
from ba.internal import have_pro_options
from bastd.ui.profile.edit import EditProfileWindow
from bastd.ui.purchase import PurchaseWindow
# Limit to a handful profiles if they don't have pro-options.
max_non_pro_profiles = _ba.get_account_misc_read_val('mnpp', 5)
assert self._profiles is not None
if (not have_pro_options()
if (not ba.app.accounts.have_pro_options()
and len(self._profiles) >= max_non_pro_profiles):
PurchaseWindow(items=['pro'],
header_text=ba.Lstr(

View File

@ -114,12 +114,11 @@ class PurchaseWindow(ba.Window):
selected_child=self._purchase_button)
def _update(self) -> None:
from ba.internal import have_pro
can_die = False
# We go away if we see that our target item is owned.
if self._items == ['pro']:
if have_pro():
if ba.app.accounts.have_pro():
can_die = True
else:
if _ba.get_purchased(self._items[0]):

View File

@ -211,8 +211,7 @@ class SoundtrackBrowserWindow(ba.Window):
on_cancel_call=self._back)
def _update(self) -> None:
from ba.internal import have_pro_options
have = have_pro_options()
have = ba.app.accounts.have_pro_options()
for lock in self._lock_images:
ba.imagewidget(edit=lock, opacity=0.0 if have else 1.0)
@ -231,11 +230,10 @@ class SoundtrackBrowserWindow(ba.Window):
def _delete_soundtrack(self) -> None:
# pylint: disable=cyclic-import
from ba.internal import have_pro_options
from bastd.ui import purchase
from bastd.ui import confirm
if not have_pro_options():
purchase.PurchaseWindow(items=['pro'])
from bastd.ui.purchase import PurchaseWindow
from bastd.ui.confirm import ConfirmWindow
if not ba.app.accounts.have_pro_options():
PurchaseWindow(items=['pro'])
return
if self._selected_soundtrack is None:
return
@ -245,17 +243,16 @@ class SoundtrackBrowserWindow(ba.Window):
'.cantDeleteDefaultText'),
color=(1, 0, 0))
else:
confirm.ConfirmWindow(
ConfirmWindow(
ba.Lstr(resource=self._r + '.deleteConfirmText',
subs=[('${NAME}', self._selected_soundtrack)]),
self._do_delete_soundtrack, 450, 150)
def _duplicate_soundtrack(self) -> None:
# pylint: disable=cyclic-import
from ba.internal import have_pro_options
from bastd.ui import purchase
if not have_pro_options():
purchase.PurchaseWindow(items=['pro'])
from bastd.ui.purchase import PurchaseWindow
if not ba.app.accounts.have_pro_options():
PurchaseWindow(items=['pro'])
return
cfg = ba.app.config
cfg.setdefault('Soundtracks', {})
@ -324,21 +321,19 @@ class SoundtrackBrowserWindow(ba.Window):
def _edit_soundtrack_with_sound(self) -> None:
# pylint: disable=cyclic-import
from ba.internal import have_pro_options
from bastd.ui import purchase
if not have_pro_options():
purchase.PurchaseWindow(items=['pro'])
from bastd.ui.purchase import PurchaseWindow
if not ba.app.accounts.have_pro_options():
PurchaseWindow(items=['pro'])
return
ba.playsound(ba.getsound('swish'))
self._edit_soundtrack()
def _edit_soundtrack(self) -> None:
# pylint: disable=cyclic-import
from ba.internal import have_pro_options
from bastd.ui import purchase
from bastd.ui.soundtrack import edit as stedit
if not have_pro_options():
purchase.PurchaseWindow(items=['pro'])
from bastd.ui.purchase import PurchaseWindow
from bastd.ui.soundtrack.edit import SoundtrackEditWindow
if not ba.app.accounts.have_pro_options():
PurchaseWindow(items=['pro'])
return
if self._selected_soundtrack is None:
return
@ -352,9 +347,8 @@ class SoundtrackBrowserWindow(ba.Window):
self._save_state()
ba.containerwidget(edit=self._root_widget, transition='out_left')
ba.app.ui.set_main_menu_window(
stedit.SoundtrackEditWindow(
existing_soundtrack=self._selected_soundtrack).get_root_widget(
))
SoundtrackEditWindow(existing_soundtrack=self._selected_soundtrack
).get_root_widget())
def _get_soundtrack_display_name(self, soundtrack: str) -> ba.Lstr:
if soundtrack == '__default__':
@ -438,15 +432,14 @@ class SoundtrackBrowserWindow(ba.Window):
def _new_soundtrack(self) -> None:
# pylint: disable=cyclic-import
from ba.internal import have_pro_options
from bastd.ui import purchase
from bastd.ui.soundtrack import edit as stedit
if not have_pro_options():
purchase.PurchaseWindow(items=['pro'])
from bastd.ui.purchase import PurchaseWindow
from bastd.ui.soundtrack.edit import SoundtrackEditWindow
if not ba.app.accounts.have_pro_options():
PurchaseWindow(items=['pro'])
return
self._save_state()
ba.containerwidget(edit=self._root_widget, transition='out_left')
stedit.SoundtrackEditWindow(existing_soundtrack=None)
SoundtrackEditWindow(existing_soundtrack=None)
def _create_done(self, new_soundtrack: str) -> None:
if new_soundtrack is not None:

View File

@ -331,7 +331,6 @@ class SpecialOfferWindow(ba.Window):
text=str(self._cancel_delay) if self._cancel_delay > 0 else '')
def _update(self) -> None:
from ba.internal import have_pro
# If we've got seconds left on our countdown, update it.
if self._cancel_delay > 0:
@ -342,7 +341,7 @@ class SpecialOfferWindow(ba.Window):
# We go away if we see that our target item is owned.
if self._offer_item == 'pro':
if have_pro():
if _ba.app.accounts.have_pro():
can_die = True
else:
if _ba.get_purchased(self._offer_item):

View File

@ -515,7 +515,7 @@ class StoreBrowserWindow(ba.Window):
# pylint: disable=too-many-statements
# pylint: disable=too-many-branches
# pylint: disable=too-many-locals
from ba.internal import have_pro, get_available_sale_time
from ba.internal import get_available_sale_time
from ba import SpecialChar
if not self._root_widget:
return
@ -539,7 +539,7 @@ class StoreBrowserWindow(ba.Window):
for b_type, b_info in self.button_infos.items():
if b_type in ['upgrades.pro', 'pro']:
purchased = have_pro()
purchased = _ba.app.accounts.have_pro()
else:
purchased = _ba.get_purchased(b_type)

View File

@ -33,7 +33,8 @@ class TournamentEntryWindow(popup.PopupWindow):
ba.set_analytics_screen('Tournament Entry Window')
self._tournament_id = tournament_id
self._tournament_info = (ba.app.tournament_info[self._tournament_id])
self._tournament_info = (
ba.app.accounts.tournament_info[self._tournament_id])
# Set a few vars depending on the tourney fee.
self._fee = self._tournament_info['fee']
@ -264,13 +265,13 @@ class TournamentEntryWindow(popup.PopupWindow):
# If there seems to be a relatively-recent valid cached info for this
# tournament, use it. Otherwise we'll kick off a query ourselves.
if (self._tournament_id in ba.app.tournament_info
and ba.app.tournament_info[self._tournament_id]['valid'] and
(ba.time(ba.TimeType.REAL, ba.TimeFormat.MILLISECONDS) -
ba.app.tournament_info[self._tournament_id]['timeReceived'] <
1000 * 60 * 5)):
if (self._tournament_id in ba.app.accounts.tournament_info and
ba.app.accounts.tournament_info[self._tournament_id]['valid']
and (ba.time(ba.TimeType.REAL, ba.TimeFormat.MILLISECONDS) -
ba.app.accounts.tournament_info[self._tournament_id]
['timeReceived'] < 1000 * 60 * 5)):
try:
info = ba.app.tournament_info[self._tournament_id]
info = ba.app.accounts.tournament_info[self._tournament_id]
self._seconds_remaining = max(
0, info['timeRemaining'] - int(
(ba.time(ba.TimeType.REAL, ba.TimeFormat.MILLISECONDS)
@ -294,12 +295,12 @@ class TournamentEntryWindow(popup.PopupWindow):
def _on_tournament_query_response(self, data: Optional[Dict[str,
Any]]) -> None:
from ba.internal import cache_tournament_info
accounts = ba.app.accounts
self._running_query = False
if data is not None:
data = data['t'] # This used to be the whole payload.
cache_tournament_info(data)
self._seconds_remaining = ba.app.tournament_info[
accounts.cache_tournament_info(data)
self._seconds_remaining = accounts.tournament_info[
self._tournament_id]['timeRemaining']
self._have_valid_data = True
@ -348,7 +349,8 @@ class TournamentEntryWindow(popup.PopupWindow):
self._running_query = True
# Grab the latest info on our tourney.
self._tournament_info = ba.app.tournament_info[self._tournament_id]
self._tournament_info = ba.app.accounts.tournament_info[
self._tournament_id]
# If we don't have valid data always show a '-' for time.
if not self._have_valid_data:

View File

@ -73,7 +73,7 @@ def get_binding_values() -> object:
_hooks.do_quit, # kQuitCall
_hooks.shutdown, # kShutdownCall
_hooks.gc_disable, # kGCDisableCall
_account.show_post_purchase_message, # kShowPostPurchaseMessageCall
ba.app.accounts.show_post_purchase_message, # kShowPostPurchaseMessageCall
_hooks.device_menu_press, # kDeviceMenuPressCall
_hooks.show_url_window, # kShowURLWindowCall
_hooks.party_invite_revoke, # kHandlePartyInviteRevokeCall