mirror of
https://github.com/RYDE-WORK/ballistica.git
synced 2026-02-05 23:13:46 +08:00
Tidied up AccountSubsystem
This commit is contained in:
parent
8c6ec14208
commit
7535e0807b
@ -3932,24 +3932,24 @@
|
|||||||
"assets/build/windows/Win32/ucrtbased.dll": "https://files.ballistica.net/cache/ba1/b5/85/f8b6d0558ddb87267f34254b1450",
|
"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/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",
|
"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/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/d8/1f/b71688ce17abe2f1750d3b98c1a3",
|
"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/7b/f5/0fb038ef5e8c9cb22f8487213622",
|
"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/a7/22/7582b2dc2eb28e8c9b05c7860c83",
|
"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/01/6a/6787038c5a2fe07be6dd08d6df5f",
|
"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/eb/c3/12a2c00732a90af63ae853b76a3b",
|
"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/63/e7/795fd31307cda51524ea0cfc4055",
|
"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/92/48/1bfcef97e05d641771a934e312f3",
|
"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/cf/25/4ef41f30fb1380505759a16a7302",
|
"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/78/eb/9ee7487ac9d633020c02bcdd475b",
|
"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/4e/59/bd1e3f68c9ccf0180187dbf60ce1",
|
"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/3c/f2/e0eb7217dba038dd146421b0bf5e",
|
"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/66/0f/34874cece602328e1a2b27efbe09",
|
"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/ee/58/ccc75a3b2679f01a9e9b9f693ab0",
|
"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/2a/82/a34db5a370d695fb52891b0a7c54",
|
"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/1b/c4/0b7f73a301f24177650efb8cfa69",
|
"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/e6/55/d4819d9a2e5dcd48c2b2641c57df",
|
"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/21/3f/8c9d1590314cd5172e944f64e41c",
|
"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/91/72/b037555786dfb8a5ebc36467e60f",
|
"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/e3/e1/c9e61438f6458b9ce4ac4cfe66ed"
|
"build/prefab/lib/mac_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/99/4c/d5dd9bc0b501dcb0d817f8166243"
|
||||||
}
|
}
|
||||||
@ -5,6 +5,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import copy
|
import copy
|
||||||
|
import time
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
import _ba
|
import _ba
|
||||||
@ -25,6 +26,15 @@ class AccountSubsystem:
|
|||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
self.account_tournament_list: Optional[Tuple[int, List[str]]] = 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:
|
def on_app_launch(self) -> None:
|
||||||
"""Called when the app is done bootstrapping."""
|
"""Called when the app is done bootstrapping."""
|
||||||
|
|
||||||
@ -36,190 +46,222 @@ class AccountSubsystem:
|
|||||||
|
|
||||||
_ba.pushcall(do_auto_sign_in)
|
_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:
|
# Mark our cached tourneys as invalid so anyone using them knows
|
||||||
"""Called when the current account has been awarded tickets.
|
# they might be out of date.
|
||||||
|
for entry in list(self.tournament_info.values()):
|
||||||
|
entry['valid'] = False
|
||||||
|
|
||||||
(internal)
|
def handle_account_gained_tickets(self, count: int) -> None:
|
||||||
"""
|
"""Called when the current account has been awarded tickets.
|
||||||
from ba._language import Lstr
|
|
||||||
_ba.screenmessage(Lstr(resource='getTicketsWindow.receivedTicketsText',
|
|
||||||
subs=[('${COUNT}', str(count))]),
|
|
||||||
color=(0, 1, 0))
|
|
||||||
_ba.playsound(_ba.getsound('cashRegister'))
|
|
||||||
|
|
||||||
|
(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:
|
def cache_league_rank_data(self, data: Any) -> None:
|
||||||
"""(internal)"""
|
"""(internal)"""
|
||||||
_ba.app.league_rank_cache['info'] = copy.deepcopy(data)
|
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:
|
def get_league_rank_points(self,
|
||||||
"""(internal)"""
|
data: Optional[Dict[str, Any]],
|
||||||
return _ba.app.league_rank_cache.get('info', None)
|
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]],
|
trophies_total: int = (data['t0a'] * data['t0am'] +
|
||||||
subset: str = None) -> int:
|
data['t0b'] * data['t0bm'] +
|
||||||
"""(internal)"""
|
data['t1'] * data['t1m'] +
|
||||||
if data is None:
|
data['t2'] * data['t2m'] +
|
||||||
return 0
|
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
|
if data['p']:
|
||||||
# locally.
|
pro_mult = 1.0 + float(
|
||||||
if data['at'] is not None:
|
_ba.get_account_misc_read_val('proPowerRankingBoost',
|
||||||
total_ach_value = data['at']
|
0.0)) * 0.01
|
||||||
else:
|
else:
|
||||||
total_ach_value = 0
|
pro_mult = 1.0
|
||||||
for ach in _ba.app.ach.achievements:
|
|
||||||
if ach.complete:
|
|
||||||
total_ach_value += ach.power_ranking_value
|
|
||||||
|
|
||||||
trophies_total: int = (data['t0a'] * data['t0am'] +
|
# For final value, apply our pro mult and activeness-mult.
|
||||||
data['t0b'] * data['t0bm'] +
|
return int(
|
||||||
data['t1'] * data['t1m'] +
|
(total_ach_value + trophies_total) *
|
||||||
data['t2'] * data['t2m'] +
|
(data['act'] if data['act'] is not None else 1.0) * pro_mult)
|
||||||
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 data['p']:
|
def cache_tournament_info(self, info: Any) -> None:
|
||||||
pro_mult = 1.0 + float(
|
"""(internal)"""
|
||||||
_ba.get_account_misc_read_val('proPowerRankingBoost', 0.0)) * 0.01
|
from ba._enums import TimeType, TimeFormat
|
||||||
else:
|
for entry in info:
|
||||||
pro_mult = 1.0
|
cache_entry = self.tournament_info[entry['tournamentID']] = (
|
||||||
|
copy.deepcopy(entry))
|
||||||
|
|
||||||
# For final value, apply our pro mult and activeness-mult.
|
# Also store the time we received this, so we can adjust
|
||||||
return int((total_ach_value + trophies_total) *
|
# time-remaining values/etc.
|
||||||
(data['act'] if data['act'] is not None else 1.0) * pro_mult)
|
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:
|
def ensure_have_account_player_profile(self) -> None:
|
||||||
"""(internal)"""
|
"""
|
||||||
from ba._enums import TimeType, TimeFormat
|
Ensure the standard account-named player profile exists;
|
||||||
for entry in info:
|
creating if needed.
|
||||||
cache_entry = _ba.app.tournament_info[entry['tournamentID']] = (
|
|
||||||
copy.deepcopy(entry))
|
|
||||||
|
|
||||||
# Also store the time we received this, so we can adjust
|
(internal)
|
||||||
# time-remaining values/etc.
|
"""
|
||||||
cache_entry['timeReceived'] = _ba.time(TimeType.REAL,
|
# This only applies when we're signed in.
|
||||||
TimeFormat.MILLISECONDS)
|
if _ba.get_account_state() != 'signed_in':
|
||||||
cache_entry['valid'] = True
|
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]:
|
config = _ba.app.config
|
||||||
"""(internal)"""
|
if ('Player Profiles' not in config
|
||||||
# pylint: disable=cyclic-import
|
or '__account__' not in config['Player Profiles']):
|
||||||
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
|
|
||||||
|
|
||||||
|
# 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:
|
def have_pro(self) -> bool:
|
||||||
"""
|
"""Return whether pro is currently unlocked."""
|
||||||
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
|
|
||||||
|
|
||||||
# If the short version of our account name currently cant be
|
# Check our tickets-based pro upgrade and our two real-IAP based
|
||||||
# displayed by the game, cancel.
|
# upgrades. Also unlock this stuff in ballistica-core builds.
|
||||||
if not _ba.have_chars(_ba.get_account_display_string(full=False)):
|
return bool(
|
||||||
return
|
_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
|
def have_pro_options(self) -> bool:
|
||||||
if ('Player Profiles' not in config
|
"""Return whether pro-options are present.
|
||||||
or '__account__' not in config['Player Profiles']):
|
|
||||||
|
|
||||||
# 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({
|
_ba.add_transaction({
|
||||||
'type': 'ADD_PLAYER_PROFILE',
|
'type': 'PROMO_CODE',
|
||||||
'name': '__account__',
|
'expire_time': time.time() + 5,
|
||||||
'profile': {
|
'code': code
|
||||||
'character': 'Spaz',
|
|
||||||
'color': [0.5, 0.25, 1.0],
|
|
||||||
'highlight': [0.5, 0.25, 1.0]
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
_ba.run_transactions()
|
_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 = []
|
|
||||||
|
|||||||
@ -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)
|
(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)
|
val: int = _ba.get_account_misc_read_val('achAwardMult', 5)
|
||||||
assert isinstance(val, int)
|
assert isinstance(val, int)
|
||||||
if include_pro_bonus and _account.have_pro():
|
if include_pro_bonus and _ba.app.accounts.have_pro():
|
||||||
val *= 2
|
val *= 2
|
||||||
return val
|
return val
|
||||||
|
|
||||||
@ -1178,7 +1177,7 @@ class Achievement:
|
|||||||
objt.node.host_only = True
|
objt.node.host_only = True
|
||||||
|
|
||||||
# Add the 'x 2' if we've got pro.
|
# Add the 'x 2' if we've got pro.
|
||||||
if _account.have_pro():
|
if app.accounts.have_pro():
|
||||||
objt = Text('x 2',
|
objt = Text('x 2',
|
||||||
position=(-120 - 180 + 45, 80 + y_offs - 50),
|
position=(-120 - 180 + 45, 80 + y_offs - 50),
|
||||||
v_attach=Text.VAttach.BOTTOM,
|
v_attach=Text.VAttach.BOTTOM,
|
||||||
|
|||||||
@ -209,15 +209,11 @@ class App:
|
|||||||
self.did_weak_call_warning = False
|
self.did_weak_call_warning = False
|
||||||
self.ran_on_app_launch = 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.last_in_game_ad_remove_message_show_time: Optional[float] = None
|
||||||
self.log_have_new = False
|
self.log_have_new = False
|
||||||
self.log_upload_timer_started = False
|
self.log_upload_timer_started = False
|
||||||
self._config: Optional[ba.AppConfig] = None
|
self._config: Optional[ba.AppConfig] = None
|
||||||
self.printed_live_object_warning = False
|
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
|
# We include this extra hash with shared input-mapping names so
|
||||||
# that we don't share mappings between differently-configured
|
# 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_window_refresh_check_count = 0 # FIXME: Mv to mainmenu.
|
||||||
self.main_menu_resume_callbacks: list = [] # Can probably go away.
|
self.main_menu_resume_callbacks: list = [] # Can probably go away.
|
||||||
self.special_offer: Optional[Dict] = None
|
self.special_offer: Optional[Dict] = None
|
||||||
self.league_rank_cache: Dict = {}
|
|
||||||
self.tournament_info: Dict = {}
|
|
||||||
self.ping_thread_count = 0
|
self.ping_thread_count = 0
|
||||||
self.invite_confirm_windows: List[Any] = [] # FIXME: Don't use Any.
|
self.invite_confirm_windows: List[Any] = [] # FIXME: Don't use Any.
|
||||||
self.store_layout: Optional[Dict[str, List[Dict[str, Any]]]] = None
|
self.store_layout: Optional[Dict[str, List[Dict[str, Any]]]] = None
|
||||||
@ -512,13 +506,9 @@ class App:
|
|||||||
def on_app_resume(self) -> None:
|
def on_app_resume(self) -> None:
|
||||||
"""Run when the app resumes from a suspended state."""
|
"""Run when the app resumes from a suspended state."""
|
||||||
|
|
||||||
self.music.on_app_resume()
|
|
||||||
self.fg_state += 1
|
self.fg_state += 1
|
||||||
|
self.accounts.on_app_resume()
|
||||||
# Mark our cached tourneys as invalid so anyone using them knows
|
self.music.on_app_resume()
|
||||||
# they might be out of date.
|
|
||||||
for entry in list(self.tournament_info.values()):
|
|
||||||
entry['valid'] = False
|
|
||||||
|
|
||||||
def launch_coop_game(self,
|
def launch_coop_game(self,
|
||||||
game: str,
|
game: str,
|
||||||
@ -596,38 +586,10 @@ class App:
|
|||||||
def handle_deep_link(self, url: str) -> None:
|
def handle_deep_link(self, url: str) -> None:
|
||||||
"""Handle a deep link URL."""
|
"""Handle a deep link URL."""
|
||||||
from ba._language import Lstr
|
from ba._language import Lstr
|
||||||
from ba._enums import TimeType
|
|
||||||
appname = _ba.appname()
|
appname = _ba.appname()
|
||||||
if url.startswith(f'{appname}://code/'):
|
if url.startswith(f'{appname}://code/'):
|
||||||
code = url.replace(f'{appname}://code/', '')
|
code = url.replace(f'{appname}://code/', '')
|
||||||
|
self.accounts.add_pending_promo_code(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()
|
|
||||||
else:
|
else:
|
||||||
_ba.screenmessage(Lstr(resource='errorText'), color=(1, 0, 0))
|
_ba.screenmessage(Lstr(resource='errorText'), color=(1, 0, 0))
|
||||||
_ba.playsound(_ba.getsound('error'))
|
_ba.playsound(_ba.getsound('error'))
|
||||||
|
|||||||
@ -246,7 +246,6 @@ def call_after_ad(call: Callable[[], Any]) -> None:
|
|||||||
# pylint: disable=too-many-statements
|
# pylint: disable=too-many-statements
|
||||||
# pylint: disable=too-many-branches
|
# pylint: disable=too-many-branches
|
||||||
# pylint: disable=too-many-locals
|
# pylint: disable=too-many-locals
|
||||||
from ba._account import have_pro
|
|
||||||
from ba._enums import TimeType
|
from ba._enums import TimeType
|
||||||
import time
|
import time
|
||||||
app = _ba.app
|
app = _ba.app
|
||||||
@ -255,7 +254,7 @@ def call_after_ad(call: Callable[[], Any]) -> None:
|
|||||||
# No ads without net-connections, etc.
|
# No ads without net-connections, etc.
|
||||||
if not _ba.can_show_ad():
|
if not _ba.can_show_ad():
|
||||||
show = False
|
show = False
|
||||||
if have_pro():
|
if app.accounts.have_pro():
|
||||||
show = False # Pro disables interstitials.
|
show = False # Pro disables interstitials.
|
||||||
try:
|
try:
|
||||||
session = _ba.get_foreground_host_session()
|
session = _ba.get_foreground_host_session()
|
||||||
|
|||||||
@ -8,6 +8,7 @@ from __future__ import annotations
|
|||||||
import random
|
import random
|
||||||
from typing import TYPE_CHECKING, TypeVar
|
from typing import TYPE_CHECKING, TypeVar
|
||||||
|
|
||||||
|
import _ba
|
||||||
from ba._activity import Activity
|
from ba._activity import Activity
|
||||||
from ba._score import ScoreConfig
|
from ba._score import ScoreConfig
|
||||||
from ba._language import Lstr
|
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._general import Call, WeakCall
|
||||||
from ba._player import PlayerInfo
|
from ba._player import PlayerInfo
|
||||||
from ba import _map
|
from ba import _map
|
||||||
import _ba
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from typing import (List, Optional, Dict, Type, Any, Callable, Sequence,
|
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,
|
def _on_tournament_query_response(self, data: Optional[Dict[str,
|
||||||
Any]]) -> None:
|
Any]]) -> None:
|
||||||
from ba._account import cache_tournament_info
|
|
||||||
if data is not None:
|
if data is not None:
|
||||||
data_t = data['t'] # This used to be the whole payload.
|
data_t = data['t'] # This used to be the whole payload.
|
||||||
|
|
||||||
# Keep our cached tourney info up to date
|
# 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(
|
self._setup_tournament_time_limit(
|
||||||
max(5, data_t[0]['timeRemaining']))
|
max(5, data_t[0]['timeRemaining']))
|
||||||
|
|
||||||
|
|||||||
@ -881,7 +881,6 @@ class Lobby:
|
|||||||
def reload_profiles(self) -> None:
|
def reload_profiles(self) -> None:
|
||||||
"""Reload available player profiles."""
|
"""Reload available player profiles."""
|
||||||
# pylint: disable=cyclic-import
|
# pylint: disable=cyclic-import
|
||||||
from ba._account import ensure_have_account_player_profile
|
|
||||||
from bastd.actor.spazappearance import get_appearances
|
from bastd.actor.spazappearance import get_appearances
|
||||||
|
|
||||||
# We may have gained or lost character names if the user
|
# 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())
|
self.character_names_local_unlocked.sort(key=lambda x: x.lower())
|
||||||
|
|
||||||
# Do any overall prep we need to such as creating account profile.
|
# 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:
|
for chooser in self.choosers:
|
||||||
try:
|
try:
|
||||||
chooser.reload_profiles()
|
chooser.reload_profiles()
|
||||||
|
|||||||
@ -440,7 +440,6 @@ def get_available_sale_time(tab: str) -> Optional[int]:
|
|||||||
# pylint: disable=too-many-locals
|
# pylint: disable=too-many-locals
|
||||||
try:
|
try:
|
||||||
import datetime
|
import datetime
|
||||||
from ba._account import have_pro
|
|
||||||
from ba._enums import TimeType, TimeFormat
|
from ba._enums import TimeType, TimeFormat
|
||||||
app = _ba.app
|
app = _ba.app
|
||||||
sale_times: List[Optional[int]] = []
|
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).
|
# Calc time for our pro sale (old special case).
|
||||||
if tab == 'extras':
|
if tab == 'extras':
|
||||||
config = app.config
|
config = app.config
|
||||||
if have_pro():
|
if app.accounts.have_pro():
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# If we haven't calced/loaded start times yet.
|
# If we haven't calced/loaded start times yet.
|
||||||
|
|||||||
@ -16,12 +16,6 @@ from ba._appconfig import commit_app_config
|
|||||||
from ba._input import (get_device_value, get_input_map_hash,
|
from ba._input import (get_device_value, get_input_map_hash,
|
||||||
get_input_device_config)
|
get_input_device_config)
|
||||||
from ba._general import getclass, json_prep, get_type_name
|
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._activitytypes import JoinActivity, ScoreScreenActivity
|
||||||
from ba._apputils import (is_browser_likely_available, get_remote_app_name,
|
from ba._apputils import (is_browser_likely_available, get_remote_app_name,
|
||||||
should_submit_debug_info, show_ad, show_ad_2)
|
should_submit_debug_info, show_ad, show_ad_2)
|
||||||
|
|||||||
@ -1197,8 +1197,9 @@ class CoopScoreScreen(ba.Activity[ba.Player, ba.Team]):
|
|||||||
try:
|
try:
|
||||||
tournament_id = self.session.tournament_id
|
tournament_id = self.session.tournament_id
|
||||||
if tournament_id is not None:
|
if tournament_id is not None:
|
||||||
if tournament_id in ba.app.tournament_info:
|
if tournament_id in ba.app.accounts.tournament_info:
|
||||||
tourney_info = ba.app.tournament_info[tournament_id]
|
tourney_info = ba.app.accounts.tournament_info[
|
||||||
|
tournament_id]
|
||||||
# pylint: disable=unbalanced-tuple-unpacking
|
# pylint: disable=unbalanced-tuple-unpacking
|
||||||
pr1, pv1, pr2, pv2, pr3, pv3 = (
|
pr1, pv1, pr2, pv2, pr3, pv3 = (
|
||||||
get_tournament_prize_strings(tourney_info))
|
get_tournament_prize_strings(tourney_info))
|
||||||
|
|||||||
@ -28,7 +28,7 @@ class ColorPicker(PopupWindow):
|
|||||||
offset: Tuple[float, float] = (0.0, 0.0),
|
offset: Tuple[float, float] = (0.0, 0.0),
|
||||||
tag: Any = ''):
|
tag: Any = ''):
|
||||||
# pylint: disable=too-many-locals
|
# 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()
|
c_raw = get_player_colors()
|
||||||
assert len(c_raw) == 16
|
assert len(c_raw) == 16
|
||||||
@ -94,7 +94,7 @@ class ColorPicker(PopupWindow):
|
|||||||
on_activate_call=ba.WeakCall(self._select_other))
|
on_activate_call=ba.WeakCall(self._select_other))
|
||||||
|
|
||||||
# Custom colors are limited to pro currently.
|
# Custom colors are limited to pro currently.
|
||||||
if not have_pro():
|
if not ba.app.accounts.have_pro():
|
||||||
ba.imagewidget(parent=self.root_widget,
|
ba.imagewidget(parent=self.root_widget,
|
||||||
position=(50, 12),
|
position=(50, 12),
|
||||||
size=(30, 30),
|
size=(30, 30),
|
||||||
@ -116,10 +116,9 @@ class ColorPicker(PopupWindow):
|
|||||||
|
|
||||||
def _select_other(self) -> None:
|
def _select_other(self) -> None:
|
||||||
from bastd.ui import purchase
|
from bastd.ui import purchase
|
||||||
from ba.internal import have_pro
|
|
||||||
|
|
||||||
# Requires pro.
|
# Requires pro.
|
||||||
if not have_pro():
|
if not ba.app.accounts.have_pro():
|
||||||
purchase.PurchaseWindow(items=['pro'])
|
purchase.PurchaseWindow(items=['pro'])
|
||||||
self._transition_out()
|
self._transition_out()
|
||||||
return
|
return
|
||||||
|
|||||||
@ -253,11 +253,11 @@ class CoopBrowserWindow(ba.Window):
|
|||||||
if (app.accounts.account_tournament_list is not None
|
if (app.accounts.account_tournament_list is not None
|
||||||
and app.accounts.account_tournament_list[0]
|
and app.accounts.account_tournament_list[0]
|
||||||
== _ba.get_account_state_num() and all([
|
== _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]
|
for t_id in app.accounts.account_tournament_list[1]
|
||||||
])):
|
])):
|
||||||
tourney_data = [
|
tourney_data = [
|
||||||
app.tournament_info[t_id]
|
app.accounts.tournament_info[t_id]
|
||||||
for t_id in app.accounts.account_tournament_list[1]
|
for t_id in app.accounts.account_tournament_list[1]
|
||||||
]
|
]
|
||||||
self._update_for_data(tourney_data)
|
self._update_for_data(tourney_data)
|
||||||
@ -350,10 +350,10 @@ class CoopBrowserWindow(ba.Window):
|
|||||||
self._update_hard_mode_lock_image()
|
self._update_hard_mode_lock_image()
|
||||||
|
|
||||||
def _update_hard_mode_lock_image(self) -> None:
|
def _update_hard_mode_lock_image(self) -> None:
|
||||||
from ba.internal import have_pro_options
|
|
||||||
try:
|
try:
|
||||||
ba.imagewidget(edit=self._hard_button_lock_image,
|
ba.imagewidget(
|
||||||
opacity=0.0 if have_pro_options() else 1.0)
|
edit=self._hard_button_lock_image,
|
||||||
|
opacity=0.0 if ba.app.accounts.have_pro_options() else 1.0)
|
||||||
except Exception:
|
except Exception:
|
||||||
ba.print_exception('Error updating campaign lock.')
|
ba.print_exception('Error updating campaign lock.')
|
||||||
|
|
||||||
@ -475,7 +475,8 @@ class CoopBrowserWindow(ba.Window):
|
|||||||
tbtn['required_league'] = (None if 'requiredLeague' not in entry
|
tbtn['required_league'] = (None if 'requiredLeague' not in entry
|
||||||
else entry['requiredLeague'])
|
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:
|
if game is None:
|
||||||
ba.textwidget(edit=tbtn['button_text'], text='-')
|
ba.textwidget(edit=tbtn['button_text'], text='-')
|
||||||
@ -485,7 +486,7 @@ class CoopBrowserWindow(ba.Window):
|
|||||||
else:
|
else:
|
||||||
campaignname, levelname = game.split(':')
|
campaignname, levelname = game.split(':')
|
||||||
campaign = getcampaign(campaignname)
|
campaign = getcampaign(campaignname)
|
||||||
max_players = ba.app.tournament_info[
|
max_players = ba.app.accounts.tournament_info[
|
||||||
tbtn['tournament_id']]['maxPlayers']
|
tbtn['tournament_id']]['maxPlayers']
|
||||||
txt = ba.Lstr(
|
txt = ba.Lstr(
|
||||||
value='${A} ${B}',
|
value='${A} ${B}',
|
||||||
@ -534,9 +535,9 @@ class CoopBrowserWindow(ba.Window):
|
|||||||
ba.charstr(ba.SpecialChar.TICKET_BACKING) +
|
ba.charstr(ba.SpecialChar.TICKET_BACKING) +
|
||||||
str(final_fee))
|
str(final_fee))
|
||||||
|
|
||||||
ad_tries_remaining = ba.app.tournament_info[
|
ad_tries_remaining = ba.app.accounts.tournament_info[
|
||||||
tbtn['tournament_id']]['adTriesRemaining']
|
tbtn['tournament_id']]['adTriesRemaining']
|
||||||
free_tries_remaining = ba.app.tournament_info[
|
free_tries_remaining = ba.app.accounts.tournament_info[
|
||||||
tbtn['tournament_id']]['freeTriesRemaining']
|
tbtn['tournament_id']]['freeTriesRemaining']
|
||||||
|
|
||||||
# Now, if this fee allows ads and we support video ads, show
|
# 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,
|
def _on_tournament_query_response(self, data: Optional[Dict[str,
|
||||||
Any]]) -> None:
|
Any]]) -> None:
|
||||||
from ba.internal import cache_tournament_info
|
accounts = ba.app.accounts
|
||||||
app = ba.app
|
|
||||||
if data is not None:
|
if data is not None:
|
||||||
tournament_data = data['t'] # This used to be the whole payload.
|
tournament_data = data['t'] # This used to be the whole payload.
|
||||||
self._last_tournament_query_response_time = ba.time(
|
self._last_tournament_query_response_time = ba.time(
|
||||||
@ -598,22 +598,21 @@ class CoopBrowserWindow(ba.Window):
|
|||||||
# Keep our cached tourney info up to date.
|
# Keep our cached tourney info up to date.
|
||||||
if data is not None:
|
if data is not None:
|
||||||
self._tourney_data_up_to_date = True
|
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.
|
# Also cache the current tourney list/order for this account.
|
||||||
app.accounts.account_tournament_list = (
|
accounts.account_tournament_list = (_ba.get_account_state_num(), [
|
||||||
_ba.get_account_state_num(),
|
e['tournamentID'] for e in tournament_data
|
||||||
[e['tournamentID'] for e in tournament_data])
|
])
|
||||||
|
|
||||||
self._doing_tournament_query = False
|
self._doing_tournament_query = False
|
||||||
self._update_for_data(tournament_data)
|
self._update_for_data(tournament_data)
|
||||||
|
|
||||||
def _set_campaign_difficulty(self, difficulty: str) -> None:
|
def _set_campaign_difficulty(self, difficulty: str) -> None:
|
||||||
# pylint: disable=cyclic-import
|
# pylint: disable=cyclic-import
|
||||||
from ba.internal import have_pro_options
|
|
||||||
from bastd.ui.purchase import PurchaseWindow
|
from bastd.ui.purchase import PurchaseWindow
|
||||||
if difficulty != self._campaign_difficulty:
|
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'])
|
PurchaseWindow(items=['pro'])
|
||||||
return
|
return
|
||||||
ba.playsound(ba.getsound('gunCocking'))
|
ba.playsound(ba.getsound('gunCocking'))
|
||||||
@ -1412,7 +1411,6 @@ class CoopBrowserWindow(ba.Window):
|
|||||||
# pylint: disable=too-many-statements
|
# pylint: disable=too-many-statements
|
||||||
# pylint: disable=too-many-return-statements
|
# pylint: disable=too-many-return-statements
|
||||||
# pylint: disable=cyclic-import
|
# pylint: disable=cyclic-import
|
||||||
from ba.internal import have_pro
|
|
||||||
from bastd.ui.confirm import ConfirmWindow
|
from bastd.ui.confirm import ConfirmWindow
|
||||||
from bastd.ui.tournamententry import TournamentEntryWindow
|
from bastd.ui.tournamententry import TournamentEntryWindow
|
||||||
from bastd.ui.purchase import PurchaseWindow
|
from bastd.ui.purchase import PurchaseWindow
|
||||||
@ -1460,7 +1458,7 @@ class CoopBrowserWindow(ba.Window):
|
|||||||
return
|
return
|
||||||
|
|
||||||
# Game is whatever the tournament tells us it is.
|
# 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']
|
tournament_button['tournament_id']]['game']
|
||||||
|
|
||||||
if tournament_button is None and game == 'Easy:The Last Stand':
|
if tournament_button is None and game == 'Easy:The Last Stand':
|
||||||
@ -1475,7 +1473,8 @@ class CoopBrowserWindow(ba.Window):
|
|||||||
# need be.
|
# need be.
|
||||||
if tournament_button is None and game in (
|
if tournament_button is None and game in (
|
||||||
'Challenges:Infinite Runaround',
|
'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':
|
if _ba.get_account_state() != 'signed_in':
|
||||||
show_sign_in_prompt()
|
show_sign_in_prompt()
|
||||||
else:
|
else:
|
||||||
|
|||||||
@ -164,7 +164,7 @@ class GameButton:
|
|||||||
|
|
||||||
def _update(self) -> None:
|
def _update(self) -> None:
|
||||||
# pylint: disable=too-many-boolean-expressions
|
# pylint: disable=too-many-boolean-expressions
|
||||||
from ba.internal import have_pro, getcampaign
|
from ba.internal import getcampaign
|
||||||
game = self._game
|
game = self._game
|
||||||
campaignname, levelname = game.split(':')
|
campaignname, levelname = game.split(':')
|
||||||
|
|
||||||
@ -193,7 +193,8 @@ class GameButton:
|
|||||||
|
|
||||||
# Hard-code games we haven't unlocked.
|
# Hard-code games we haven't unlocked.
|
||||||
if ((game in ('Challenges:Infinite Runaround',
|
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', )
|
or (game in ('Challenges:Meteor Shower', )
|
||||||
and not _ba.get_purchased('games.meteor_shower'))
|
and not _ba.get_purchased('games.meteor_shower'))
|
||||||
or (game in ('Challenges:Target Practice',
|
or (game in ('Challenges:Target Practice',
|
||||||
|
|||||||
@ -1256,9 +1256,8 @@ class GatherWindow(ba.Window):
|
|||||||
texture=ba.gettexture('lock'))
|
texture=ba.gettexture('lock'))
|
||||||
|
|
||||||
def _is_internet_locked(self) -> bool:
|
def _is_internet_locked(self) -> bool:
|
||||||
from ba.internal import have_pro
|
|
||||||
if _ba.get_account_misc_read_val('ilck', False):
|
if _ba.get_account_misc_read_val('ilck', False):
|
||||||
return not have_pro()
|
return not ba.app.accounts.have_pro()
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def _on_max_public_party_size_minus_press(self) -> None:
|
def _on_max_public_party_size_minus_press(self) -> None:
|
||||||
|
|||||||
@ -28,7 +28,6 @@ class IconPicker(popup.PopupWindow):
|
|||||||
tint2_color: Sequence[float] = (1.0, 1.0, 1.0),
|
tint2_color: Sequence[float] = (1.0, 1.0, 1.0),
|
||||||
selected_icon: str = None):
|
selected_icon: str = None):
|
||||||
# pylint: disable=too-many-locals
|
# pylint: disable=too-many-locals
|
||||||
from ba.internal import get_purchased_icons
|
|
||||||
del parent # unused here
|
del parent # unused here
|
||||||
del tint_color # unused_here
|
del tint_color # unused_here
|
||||||
del tint2_color # unused here
|
del tint2_color # unused here
|
||||||
@ -40,7 +39,8 @@ class IconPicker(popup.PopupWindow):
|
|||||||
self._delegate = delegate
|
self._delegate = delegate
|
||||||
self._transitioning_out = False
|
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)
|
count = len(self._icons)
|
||||||
columns = 4
|
columns = 4
|
||||||
rows = int(math.ceil(float(count) / columns))
|
rows = int(math.ceil(float(count) / columns))
|
||||||
|
|||||||
@ -26,7 +26,6 @@ class LeagueRankButton:
|
|||||||
color: Tuple[float, float, float] = None,
|
color: Tuple[float, float, float] = None,
|
||||||
textcolor: Tuple[float, float, float] = None,
|
textcolor: Tuple[float, float, float] = None,
|
||||||
smooth_update_delay: float = None):
|
smooth_update_delay: float = None):
|
||||||
from ba.internal import get_cached_league_rank_data
|
|
||||||
if on_activate_call is None:
|
if on_activate_call is None:
|
||||||
on_activate_call = ba.WeakCall(self._default_on_activate_call)
|
on_activate_call = ba.WeakCall(self._default_on_activate_call)
|
||||||
self._on_activate_call = on_activate_call
|
self._on_activate_call = on_activate_call
|
||||||
@ -107,7 +106,7 @@ class LeagueRankButton:
|
|||||||
self._update()
|
self._update()
|
||||||
|
|
||||||
# If we've got cached power-ranking data already, apply it.
|
# 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:
|
if data is not None:
|
||||||
self._update_for_league_rank_data(data)
|
self._update_for_league_rank_data(data)
|
||||||
|
|
||||||
@ -216,7 +215,6 @@ class LeagueRankButton:
|
|||||||
Any]]) -> None:
|
Any]]) -> None:
|
||||||
# pylint: disable=too-many-branches
|
# pylint: disable=too-many-branches
|
||||||
# pylint: disable=too-many-statements
|
# pylint: disable=too-many-statements
|
||||||
from ba.internal import get_league_rank_points
|
|
||||||
|
|
||||||
# If our button has died, ignore.
|
# If our button has died, ignore.
|
||||||
if not self._button:
|
if not self._button:
|
||||||
@ -250,7 +248,7 @@ class LeagueRankButton:
|
|||||||
self._percent = self._rank = None
|
self._percent = self._rank = None
|
||||||
status_text = '-'
|
status_text = '-'
|
||||||
else:
|
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]
|
progress = float(our_points) / data['scores'][-1][1]
|
||||||
self._percent = int(progress * 100.0)
|
self._percent = int(progress * 100.0)
|
||||||
self._rank = None
|
self._rank = None
|
||||||
@ -328,9 +326,8 @@ class LeagueRankButton:
|
|||||||
|
|
||||||
def _on_power_ranking_query_response(
|
def _on_power_ranking_query_response(
|
||||||
self, data: Optional[Dict[str, Any]]) -> None:
|
self, data: Optional[Dict[str, Any]]) -> None:
|
||||||
from ba.internal import cache_league_rank_data
|
|
||||||
self._doing_power_ranking_query = False
|
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)
|
self._update_for_league_rank_data(data)
|
||||||
|
|
||||||
def _update(self) -> None:
|
def _update(self) -> None:
|
||||||
|
|||||||
@ -22,7 +22,6 @@ class LeagueRankWindow(ba.Window):
|
|||||||
transition: str = 'in_right',
|
transition: str = 'in_right',
|
||||||
modal: bool = False,
|
modal: bool = False,
|
||||||
origin_widget: ba.Widget = None):
|
origin_widget: ba.Widget = None):
|
||||||
from ba.internal import get_cached_league_rank_data
|
|
||||||
ba.set_analytics_screen('League Rank Window')
|
ba.set_analytics_screen('League Rank Window')
|
||||||
|
|
||||||
self._league_rank_data: Optional[Dict[str, Any]] = None
|
self._league_rank_data: Optional[Dict[str, Any]] = None
|
||||||
@ -125,7 +124,7 @@ class LeagueRankWindow(ba.Window):
|
|||||||
self._restore_state()
|
self._restore_state()
|
||||||
|
|
||||||
# if we've got cached power-ranking data already, display it
|
# 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:
|
if info is not None:
|
||||||
self._update_for_league_rank_data(info)
|
self._update_for_league_rank_data(info)
|
||||||
|
|
||||||
@ -194,11 +193,10 @@ class LeagueRankWindow(ba.Window):
|
|||||||
|
|
||||||
def _on_power_ranking_query_response(
|
def _on_power_ranking_query_response(
|
||||||
self, data: Optional[Dict[str, Any]]) -> None:
|
self, data: Optional[Dict[str, Any]]) -> None:
|
||||||
from ba.internal import cache_league_rank_data
|
|
||||||
self._doing_power_ranking_query = False
|
self._doing_power_ranking_query = False
|
||||||
# important: *only* cache this if we requested the current season..
|
# important: *only* cache this if we requested the current season..
|
||||||
if data is not None and data.get('s', None) is None:
|
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)
|
# always store a copy locally though (even for other seasons)
|
||||||
self._league_rank_data = copy.deepcopy(data)
|
self._league_rank_data = copy.deepcopy(data)
|
||||||
self._update_for_league_rank_data(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-statements
|
||||||
# pylint: disable=too-many-branches
|
# pylint: disable=too-many-branches
|
||||||
# pylint: disable=too-many-locals
|
# pylint: disable=too-many-locals
|
||||||
from ba.internal import get_league_rank_points
|
|
||||||
if not self._root_widget:
|
if not self._root_widget:
|
||||||
return
|
return
|
||||||
|
accounts = ba.app.accounts
|
||||||
in_top = (data is not None and data['rank'] is not None)
|
in_top = (data is not None and data['rank'] is not None)
|
||||||
eq_text = self._rdict.powerRankingPointsEqualsText
|
eq_text = self._rdict.powerRankingPointsEqualsText
|
||||||
pts_txt = self._rdict.powerRankingPointsText
|
pts_txt = self._rdict.powerRankingPointsText
|
||||||
@ -622,7 +620,7 @@ class LeagueRankWindow(ba.Window):
|
|||||||
finished_season_unranked = True
|
finished_season_unranked = True
|
||||||
self._can_do_more_button = False
|
self._can_do_more_button = False
|
||||||
else:
|
else:
|
||||||
our_points = get_league_rank_points(data)
|
our_points = accounts.get_league_rank_points(data)
|
||||||
progress = float(our_points) / max(1,
|
progress = float(our_points) / max(1,
|
||||||
data['scores'][-1][1])
|
data['scores'][-1][1])
|
||||||
status_text = str(int(progress * 100.0)) + '%'
|
status_text = str(int(progress * 100.0)) + '%'
|
||||||
@ -820,8 +818,10 @@ class LeagueRankWindow(ba.Window):
|
|||||||
('+ ' +
|
('+ ' +
|
||||||
pts_txt.replace('${NUMBER}', str(total_ach_value))))
|
pts_txt.replace('${NUMBER}', str(total_ach_value))))
|
||||||
|
|
||||||
total_trophies_count = (get_league_rank_points(data, 'trophyCount'))
|
total_trophies_count = (accounts.get_league_rank_points(
|
||||||
total_trophies_value = (get_league_rank_points(data, 'trophies'))
|
data, 'trophyCount'))
|
||||||
|
total_trophies_value = (accounts.get_league_rank_points(
|
||||||
|
data, 'trophies'))
|
||||||
ba.buttonwidget(edit=self._power_ranking_trophies_button,
|
ba.buttonwidget(edit=self._power_ranking_trophies_button,
|
||||||
label=('' if data is None else
|
label=('' if data is None else
|
||||||
(str(total_trophies_count) + ' ')) +
|
(str(total_trophies_count) + ' ')) +
|
||||||
@ -831,9 +831,10 @@ class LeagueRankWindow(ba.Window):
|
|||||||
text='-' if data is None else
|
text='-' if data is None else
|
||||||
('+ ' + pts_txt.replace('${NUMBER}', str(total_trophies_value))))
|
('+ ' + pts_txt.replace('${NUMBER}', str(total_trophies_value))))
|
||||||
|
|
||||||
ba.textwidget(edit=self._power_ranking_total_text,
|
ba.textwidget(
|
||||||
text='-' if data is None else eq_text.replace(
|
edit=self._power_ranking_total_text,
|
||||||
'${NUMBER}', str(get_league_rank_points(data))))
|
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:
|
for widget in self._power_ranking_score_widgets:
|
||||||
widget.delete()
|
widget.delete()
|
||||||
self._power_ranking_score_widgets = []
|
self._power_ranking_score_widgets = []
|
||||||
|
|||||||
@ -253,8 +253,7 @@ class PlaylistCustomizeBrowserWindow(ba.Window):
|
|||||||
self._update()
|
self._update()
|
||||||
|
|
||||||
def _update(self) -> None:
|
def _update(self) -> None:
|
||||||
from ba.internal import have_pro_options
|
have = ba.app.accounts.have_pro_options()
|
||||||
have = have_pro_options()
|
|
||||||
for lock in self._lock_images:
|
for lock in self._lock_images:
|
||||||
ba.imagewidget(edit=lock, opacity=0.0 if have else 1.0)
|
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:
|
def _new_playlist(self) -> None:
|
||||||
# pylint: disable=cyclic-import
|
# pylint: disable=cyclic-import
|
||||||
from ba.internal import have_pro_options
|
from bastd.ui.playlist.editcontroller import PlaylistEditController
|
||||||
from bastd.ui.playlist import editcontroller
|
from bastd.ui.purchase import PurchaseWindow
|
||||||
from bastd.ui import purchase
|
if not ba.app.accounts.have_pro_options():
|
||||||
if not have_pro_options():
|
PurchaseWindow(items=['pro'])
|
||||||
purchase.PurchaseWindow(items=['pro'])
|
|
||||||
return
|
return
|
||||||
|
|
||||||
# Clamp at our max playlist number.
|
# Clamp at our max playlist number.
|
||||||
@ -402,16 +400,15 @@ class PlaylistCustomizeBrowserWindow(ba.Window):
|
|||||||
self._save_playlist_selection()
|
self._save_playlist_selection()
|
||||||
|
|
||||||
# Kick off the edit UI.
|
# Kick off the edit UI.
|
||||||
editcontroller.PlaylistEditController(sessiontype=self._sessiontype)
|
PlaylistEditController(sessiontype=self._sessiontype)
|
||||||
ba.containerwidget(edit=self._root_widget, transition='out_left')
|
ba.containerwidget(edit=self._root_widget, transition='out_left')
|
||||||
|
|
||||||
def _edit_playlist(self) -> None:
|
def _edit_playlist(self) -> None:
|
||||||
# pylint: disable=cyclic-import
|
# pylint: disable=cyclic-import
|
||||||
from ba.internal import have_pro_options
|
from bastd.ui.playlist.editcontroller import PlaylistEditController
|
||||||
from bastd.ui.playlist import editcontroller
|
from bastd.ui.purchase import PurchaseWindow
|
||||||
from bastd.ui import purchase
|
if not ba.app.accounts.have_pro_options():
|
||||||
if not have_pro_options():
|
PurchaseWindow(items=['pro'])
|
||||||
purchase.PurchaseWindow(items=['pro'])
|
|
||||||
return
|
return
|
||||||
if self._selected_playlist_name is None:
|
if self._selected_playlist_name is None:
|
||||||
return
|
return
|
||||||
@ -421,7 +418,7 @@ class PlaylistCustomizeBrowserWindow(ba.Window):
|
|||||||
'.cantEditDefaultText'))
|
'.cantEditDefaultText'))
|
||||||
return
|
return
|
||||||
self._save_playlist_selection()
|
self._save_playlist_selection()
|
||||||
editcontroller.PlaylistEditController(
|
PlaylistEditController(
|
||||||
existing_playlist_name=self._selected_playlist_name,
|
existing_playlist_name=self._selected_playlist_name,
|
||||||
sessiontype=self._sessiontype)
|
sessiontype=self._sessiontype)
|
||||||
ba.containerwidget(edit=self._root_widget, transition='out_left')
|
ba.containerwidget(edit=self._root_widget, transition='out_left')
|
||||||
@ -474,10 +471,9 @@ class PlaylistCustomizeBrowserWindow(ba.Window):
|
|||||||
|
|
||||||
def _share_playlist(self) -> None:
|
def _share_playlist(self) -> None:
|
||||||
# pylint: disable=cyclic-import
|
# pylint: disable=cyclic-import
|
||||||
from ba.internal import have_pro_options
|
from bastd.ui.purchase import PurchaseWindow
|
||||||
from bastd.ui import purchase
|
if not ba.app.accounts.have_pro_options():
|
||||||
if not have_pro_options():
|
PurchaseWindow(items=['pro'])
|
||||||
purchase.PurchaseWindow(items=['pro'])
|
|
||||||
return
|
return
|
||||||
|
|
||||||
# Gotta be signed in for this to work.
|
# Gotta be signed in for this to work.
|
||||||
@ -510,11 +506,10 @@ class PlaylistCustomizeBrowserWindow(ba.Window):
|
|||||||
|
|
||||||
def _delete_playlist(self) -> None:
|
def _delete_playlist(self) -> None:
|
||||||
# pylint: disable=cyclic-import
|
# pylint: disable=cyclic-import
|
||||||
from ba.internal import have_pro_options
|
from bastd.ui.purchase import PurchaseWindow
|
||||||
from bastd.ui import purchase
|
from bastd.ui.confirm import ConfirmWindow
|
||||||
from bastd.ui import confirm
|
if not ba.app.accounts.have_pro_options():
|
||||||
if not have_pro_options():
|
PurchaseWindow(items=['pro'])
|
||||||
purchase.PurchaseWindow(items=['pro'])
|
|
||||||
return
|
return
|
||||||
|
|
||||||
if self._selected_playlist_name is None:
|
if self._selected_playlist_name is None:
|
||||||
@ -524,7 +519,7 @@ class PlaylistCustomizeBrowserWindow(ba.Window):
|
|||||||
ba.screenmessage(
|
ba.screenmessage(
|
||||||
ba.Lstr(resource=self._r + '.cantDeleteDefaultText'))
|
ba.Lstr(resource=self._r + '.cantDeleteDefaultText'))
|
||||||
else:
|
else:
|
||||||
confirm.ConfirmWindow(
|
ConfirmWindow(
|
||||||
ba.Lstr(resource=self._r + '.deleteConfirmText',
|
ba.Lstr(resource=self._r + '.deleteConfirmText',
|
||||||
subs=[('${LIST}', self._selected_playlist_name)]),
|
subs=[('${LIST}', self._selected_playlist_name)]),
|
||||||
self._do_delete_playlist, 450, 150)
|
self._do_delete_playlist, 450, 150)
|
||||||
@ -538,10 +533,9 @@ class PlaylistCustomizeBrowserWindow(ba.Window):
|
|||||||
def _duplicate_playlist(self) -> None:
|
def _duplicate_playlist(self) -> None:
|
||||||
# pylint: disable=too-many-branches
|
# pylint: disable=too-many-branches
|
||||||
# pylint: disable=cyclic-import
|
# pylint: disable=cyclic-import
|
||||||
from ba.internal import have_pro_options
|
from bastd.ui.purchase import PurchaseWindow
|
||||||
from bastd.ui import purchase
|
if not ba.app.accounts.have_pro_options():
|
||||||
if not have_pro_options():
|
PurchaseWindow(items=['pro'])
|
||||||
purchase.PurchaseWindow(items=['pro'])
|
|
||||||
return
|
return
|
||||||
if self._selected_playlist_name is None:
|
if self._selected_playlist_name is None:
|
||||||
return
|
return
|
||||||
|
|||||||
@ -26,8 +26,7 @@ class PlayOptionsWindow(popup.PopupWindow):
|
|||||||
# pylint: disable=too-many-branches
|
# pylint: disable=too-many-branches
|
||||||
# pylint: disable=too-many-statements
|
# pylint: disable=too-many-statements
|
||||||
# pylint: disable=too-many-locals
|
# pylint: disable=too-many-locals
|
||||||
from ba.internal import (getclass, have_pro,
|
from ba.internal import (getclass, get_default_teams_playlist,
|
||||||
get_default_teams_playlist,
|
|
||||||
get_default_free_for_all_playlist,
|
get_default_free_for_all_playlist,
|
||||||
filter_playlist)
|
filter_playlist)
|
||||||
from ba.internal import get_map_class
|
from ba.internal import get_map_class
|
||||||
@ -256,7 +255,7 @@ class PlayOptionsWindow(popup.PopupWindow):
|
|||||||
autoselect=True,
|
autoselect=True,
|
||||||
textcolor=(0.8, 0.8, 0.8),
|
textcolor=(0.8, 0.8, 0.8),
|
||||||
label=ba.Lstr(resource='teamNamesColorText'))
|
label=ba.Lstr(resource='teamNamesColorText'))
|
||||||
if not have_pro():
|
if not ba.app.accounts.have_pro():
|
||||||
ba.imagewidget(
|
ba.imagewidget(
|
||||||
parent=self.root_widget,
|
parent=self.root_widget,
|
||||||
size=(30, 30),
|
size=(30, 30),
|
||||||
@ -350,21 +349,19 @@ class PlayOptionsWindow(popup.PopupWindow):
|
|||||||
self._update()
|
self._update()
|
||||||
|
|
||||||
def _custom_colors_names_press(self) -> None:
|
def _custom_colors_names_press(self) -> None:
|
||||||
from ba.internal import have_pro
|
from bastd.ui.account import show_sign_in_prompt
|
||||||
from bastd.ui import account as accountui
|
from bastd.ui.teamnamescolors import TeamNamesColorsWindow
|
||||||
from bastd.ui import teamnamescolors
|
from bastd.ui.purchase import PurchaseWindow
|
||||||
from bastd.ui import purchase
|
if not ba.app.accounts.have_pro():
|
||||||
if not have_pro():
|
|
||||||
if _ba.get_account_state() != 'signed_in':
|
if _ba.get_account_state() != 'signed_in':
|
||||||
accountui.show_sign_in_prompt()
|
show_sign_in_prompt()
|
||||||
else:
|
else:
|
||||||
purchase.PurchaseWindow(items=['pro'])
|
PurchaseWindow(items=['pro'])
|
||||||
self._transition_out()
|
self._transition_out()
|
||||||
return
|
return
|
||||||
assert self._custom_colors_names_button
|
assert self._custom_colors_names_button
|
||||||
teamnamescolors.TeamNamesColorsWindow(
|
TeamNamesColorsWindow(scale_origin=self._custom_colors_names_button.
|
||||||
scale_origin=self._custom_colors_names_button.
|
get_screen_space_center())
|
||||||
get_screen_space_center())
|
|
||||||
|
|
||||||
def _does_target_playlist_exist(self) -> bool:
|
def _does_target_playlist_exist(self) -> bool:
|
||||||
if self._playlist == '__default__':
|
if self._playlist == '__default__':
|
||||||
|
|||||||
@ -23,7 +23,6 @@ class ProfileBrowserWindow(ba.Window):
|
|||||||
origin_widget: ba.Widget = None):
|
origin_widget: ba.Widget = None):
|
||||||
# pylint: disable=too-many-statements
|
# pylint: disable=too-many-statements
|
||||||
# pylint: disable=too-many-locals
|
# pylint: disable=too-many-locals
|
||||||
from ba.internal import ensure_have_account_player_profile
|
|
||||||
self._in_main_menu = in_main_menu
|
self._in_main_menu = in_main_menu
|
||||||
if self._in_main_menu:
|
if self._in_main_menu:
|
||||||
back_label = ba.Lstr(resource='backText')
|
back_label = ba.Lstr(resource='backText')
|
||||||
@ -52,7 +51,7 @@ class ProfileBrowserWindow(ba.Window):
|
|||||||
self._r = 'playerProfilesWindow'
|
self._r = 'playerProfilesWindow'
|
||||||
|
|
||||||
# Ensure we've got an account-profile in cases where we're signed in.
|
# 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
|
top_extra = 20 if uiscale is ba.UIScale.SMALL else 0
|
||||||
|
|
||||||
@ -171,14 +170,13 @@ class ProfileBrowserWindow(ba.Window):
|
|||||||
|
|
||||||
def _new_profile(self) -> None:
|
def _new_profile(self) -> None:
|
||||||
# pylint: disable=cyclic-import
|
# pylint: disable=cyclic-import
|
||||||
from ba.internal import have_pro_options
|
|
||||||
from bastd.ui.profile.edit import EditProfileWindow
|
from bastd.ui.profile.edit import EditProfileWindow
|
||||||
from bastd.ui.purchase import PurchaseWindow
|
from bastd.ui.purchase import PurchaseWindow
|
||||||
|
|
||||||
# Limit to a handful profiles if they don't have pro-options.
|
# Limit to a handful profiles if they don't have pro-options.
|
||||||
max_non_pro_profiles = _ba.get_account_misc_read_val('mnpp', 5)
|
max_non_pro_profiles = _ba.get_account_misc_read_val('mnpp', 5)
|
||||||
assert self._profiles is not None
|
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):
|
and len(self._profiles) >= max_non_pro_profiles):
|
||||||
PurchaseWindow(items=['pro'],
|
PurchaseWindow(items=['pro'],
|
||||||
header_text=ba.Lstr(
|
header_text=ba.Lstr(
|
||||||
|
|||||||
@ -114,12 +114,11 @@ class PurchaseWindow(ba.Window):
|
|||||||
selected_child=self._purchase_button)
|
selected_child=self._purchase_button)
|
||||||
|
|
||||||
def _update(self) -> None:
|
def _update(self) -> None:
|
||||||
from ba.internal import have_pro
|
|
||||||
can_die = False
|
can_die = False
|
||||||
|
|
||||||
# We go away if we see that our target item is owned.
|
# We go away if we see that our target item is owned.
|
||||||
if self._items == ['pro']:
|
if self._items == ['pro']:
|
||||||
if have_pro():
|
if ba.app.accounts.have_pro():
|
||||||
can_die = True
|
can_die = True
|
||||||
else:
|
else:
|
||||||
if _ba.get_purchased(self._items[0]):
|
if _ba.get_purchased(self._items[0]):
|
||||||
|
|||||||
@ -211,8 +211,7 @@ class SoundtrackBrowserWindow(ba.Window):
|
|||||||
on_cancel_call=self._back)
|
on_cancel_call=self._back)
|
||||||
|
|
||||||
def _update(self) -> None:
|
def _update(self) -> None:
|
||||||
from ba.internal import have_pro_options
|
have = ba.app.accounts.have_pro_options()
|
||||||
have = have_pro_options()
|
|
||||||
for lock in self._lock_images:
|
for lock in self._lock_images:
|
||||||
ba.imagewidget(edit=lock, opacity=0.0 if have else 1.0)
|
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:
|
def _delete_soundtrack(self) -> None:
|
||||||
# pylint: disable=cyclic-import
|
# pylint: disable=cyclic-import
|
||||||
from ba.internal import have_pro_options
|
from bastd.ui.purchase import PurchaseWindow
|
||||||
from bastd.ui import purchase
|
from bastd.ui.confirm import ConfirmWindow
|
||||||
from bastd.ui import confirm
|
if not ba.app.accounts.have_pro_options():
|
||||||
if not have_pro_options():
|
PurchaseWindow(items=['pro'])
|
||||||
purchase.PurchaseWindow(items=['pro'])
|
|
||||||
return
|
return
|
||||||
if self._selected_soundtrack is None:
|
if self._selected_soundtrack is None:
|
||||||
return
|
return
|
||||||
@ -245,17 +243,16 @@ class SoundtrackBrowserWindow(ba.Window):
|
|||||||
'.cantDeleteDefaultText'),
|
'.cantDeleteDefaultText'),
|
||||||
color=(1, 0, 0))
|
color=(1, 0, 0))
|
||||||
else:
|
else:
|
||||||
confirm.ConfirmWindow(
|
ConfirmWindow(
|
||||||
ba.Lstr(resource=self._r + '.deleteConfirmText',
|
ba.Lstr(resource=self._r + '.deleteConfirmText',
|
||||||
subs=[('${NAME}', self._selected_soundtrack)]),
|
subs=[('${NAME}', self._selected_soundtrack)]),
|
||||||
self._do_delete_soundtrack, 450, 150)
|
self._do_delete_soundtrack, 450, 150)
|
||||||
|
|
||||||
def _duplicate_soundtrack(self) -> None:
|
def _duplicate_soundtrack(self) -> None:
|
||||||
# pylint: disable=cyclic-import
|
# pylint: disable=cyclic-import
|
||||||
from ba.internal import have_pro_options
|
from bastd.ui.purchase import PurchaseWindow
|
||||||
from bastd.ui import purchase
|
if not ba.app.accounts.have_pro_options():
|
||||||
if not have_pro_options():
|
PurchaseWindow(items=['pro'])
|
||||||
purchase.PurchaseWindow(items=['pro'])
|
|
||||||
return
|
return
|
||||||
cfg = ba.app.config
|
cfg = ba.app.config
|
||||||
cfg.setdefault('Soundtracks', {})
|
cfg.setdefault('Soundtracks', {})
|
||||||
@ -324,21 +321,19 @@ class SoundtrackBrowserWindow(ba.Window):
|
|||||||
|
|
||||||
def _edit_soundtrack_with_sound(self) -> None:
|
def _edit_soundtrack_with_sound(self) -> None:
|
||||||
# pylint: disable=cyclic-import
|
# pylint: disable=cyclic-import
|
||||||
from ba.internal import have_pro_options
|
from bastd.ui.purchase import PurchaseWindow
|
||||||
from bastd.ui import purchase
|
if not ba.app.accounts.have_pro_options():
|
||||||
if not have_pro_options():
|
PurchaseWindow(items=['pro'])
|
||||||
purchase.PurchaseWindow(items=['pro'])
|
|
||||||
return
|
return
|
||||||
ba.playsound(ba.getsound('swish'))
|
ba.playsound(ba.getsound('swish'))
|
||||||
self._edit_soundtrack()
|
self._edit_soundtrack()
|
||||||
|
|
||||||
def _edit_soundtrack(self) -> None:
|
def _edit_soundtrack(self) -> None:
|
||||||
# pylint: disable=cyclic-import
|
# pylint: disable=cyclic-import
|
||||||
from ba.internal import have_pro_options
|
from bastd.ui.purchase import PurchaseWindow
|
||||||
from bastd.ui import purchase
|
from bastd.ui.soundtrack.edit import SoundtrackEditWindow
|
||||||
from bastd.ui.soundtrack import edit as stedit
|
if not ba.app.accounts.have_pro_options():
|
||||||
if not have_pro_options():
|
PurchaseWindow(items=['pro'])
|
||||||
purchase.PurchaseWindow(items=['pro'])
|
|
||||||
return
|
return
|
||||||
if self._selected_soundtrack is None:
|
if self._selected_soundtrack is None:
|
||||||
return
|
return
|
||||||
@ -352,9 +347,8 @@ class SoundtrackBrowserWindow(ba.Window):
|
|||||||
self._save_state()
|
self._save_state()
|
||||||
ba.containerwidget(edit=self._root_widget, transition='out_left')
|
ba.containerwidget(edit=self._root_widget, transition='out_left')
|
||||||
ba.app.ui.set_main_menu_window(
|
ba.app.ui.set_main_menu_window(
|
||||||
stedit.SoundtrackEditWindow(
|
SoundtrackEditWindow(existing_soundtrack=self._selected_soundtrack
|
||||||
existing_soundtrack=self._selected_soundtrack).get_root_widget(
|
).get_root_widget())
|
||||||
))
|
|
||||||
|
|
||||||
def _get_soundtrack_display_name(self, soundtrack: str) -> ba.Lstr:
|
def _get_soundtrack_display_name(self, soundtrack: str) -> ba.Lstr:
|
||||||
if soundtrack == '__default__':
|
if soundtrack == '__default__':
|
||||||
@ -438,15 +432,14 @@ class SoundtrackBrowserWindow(ba.Window):
|
|||||||
|
|
||||||
def _new_soundtrack(self) -> None:
|
def _new_soundtrack(self) -> None:
|
||||||
# pylint: disable=cyclic-import
|
# pylint: disable=cyclic-import
|
||||||
from ba.internal import have_pro_options
|
from bastd.ui.purchase import PurchaseWindow
|
||||||
from bastd.ui import purchase
|
from bastd.ui.soundtrack.edit import SoundtrackEditWindow
|
||||||
from bastd.ui.soundtrack import edit as stedit
|
if not ba.app.accounts.have_pro_options():
|
||||||
if not have_pro_options():
|
PurchaseWindow(items=['pro'])
|
||||||
purchase.PurchaseWindow(items=['pro'])
|
|
||||||
return
|
return
|
||||||
self._save_state()
|
self._save_state()
|
||||||
ba.containerwidget(edit=self._root_widget, transition='out_left')
|
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:
|
def _create_done(self, new_soundtrack: str) -> None:
|
||||||
if new_soundtrack is not None:
|
if new_soundtrack is not None:
|
||||||
|
|||||||
@ -331,7 +331,6 @@ class SpecialOfferWindow(ba.Window):
|
|||||||
text=str(self._cancel_delay) if self._cancel_delay > 0 else '')
|
text=str(self._cancel_delay) if self._cancel_delay > 0 else '')
|
||||||
|
|
||||||
def _update(self) -> None:
|
def _update(self) -> None:
|
||||||
from ba.internal import have_pro
|
|
||||||
|
|
||||||
# If we've got seconds left on our countdown, update it.
|
# If we've got seconds left on our countdown, update it.
|
||||||
if self._cancel_delay > 0:
|
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.
|
# We go away if we see that our target item is owned.
|
||||||
if self._offer_item == 'pro':
|
if self._offer_item == 'pro':
|
||||||
if have_pro():
|
if _ba.app.accounts.have_pro():
|
||||||
can_die = True
|
can_die = True
|
||||||
else:
|
else:
|
||||||
if _ba.get_purchased(self._offer_item):
|
if _ba.get_purchased(self._offer_item):
|
||||||
|
|||||||
@ -515,7 +515,7 @@ class StoreBrowserWindow(ba.Window):
|
|||||||
# pylint: disable=too-many-statements
|
# pylint: disable=too-many-statements
|
||||||
# pylint: disable=too-many-branches
|
# pylint: disable=too-many-branches
|
||||||
# pylint: disable=too-many-locals
|
# 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
|
from ba import SpecialChar
|
||||||
if not self._root_widget:
|
if not self._root_widget:
|
||||||
return
|
return
|
||||||
@ -539,7 +539,7 @@ class StoreBrowserWindow(ba.Window):
|
|||||||
for b_type, b_info in self.button_infos.items():
|
for b_type, b_info in self.button_infos.items():
|
||||||
|
|
||||||
if b_type in ['upgrades.pro', 'pro']:
|
if b_type in ['upgrades.pro', 'pro']:
|
||||||
purchased = have_pro()
|
purchased = _ba.app.accounts.have_pro()
|
||||||
else:
|
else:
|
||||||
purchased = _ba.get_purchased(b_type)
|
purchased = _ba.get_purchased(b_type)
|
||||||
|
|
||||||
|
|||||||
@ -33,7 +33,8 @@ class TournamentEntryWindow(popup.PopupWindow):
|
|||||||
ba.set_analytics_screen('Tournament Entry Window')
|
ba.set_analytics_screen('Tournament Entry Window')
|
||||||
|
|
||||||
self._tournament_id = tournament_id
|
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.
|
# Set a few vars depending on the tourney fee.
|
||||||
self._fee = self._tournament_info['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
|
# If there seems to be a relatively-recent valid cached info for this
|
||||||
# tournament, use it. Otherwise we'll kick off a query ourselves.
|
# tournament, use it. Otherwise we'll kick off a query ourselves.
|
||||||
if (self._tournament_id in ba.app.tournament_info
|
if (self._tournament_id in ba.app.accounts.tournament_info and
|
||||||
and ba.app.tournament_info[self._tournament_id]['valid'] and
|
ba.app.accounts.tournament_info[self._tournament_id]['valid']
|
||||||
(ba.time(ba.TimeType.REAL, ba.TimeFormat.MILLISECONDS) -
|
and (ba.time(ba.TimeType.REAL, ba.TimeFormat.MILLISECONDS) -
|
||||||
ba.app.tournament_info[self._tournament_id]['timeReceived'] <
|
ba.app.accounts.tournament_info[self._tournament_id]
|
||||||
1000 * 60 * 5)):
|
['timeReceived'] < 1000 * 60 * 5)):
|
||||||
try:
|
try:
|
||||||
info = ba.app.tournament_info[self._tournament_id]
|
info = ba.app.accounts.tournament_info[self._tournament_id]
|
||||||
self._seconds_remaining = max(
|
self._seconds_remaining = max(
|
||||||
0, info['timeRemaining'] - int(
|
0, info['timeRemaining'] - int(
|
||||||
(ba.time(ba.TimeType.REAL, ba.TimeFormat.MILLISECONDS)
|
(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,
|
def _on_tournament_query_response(self, data: Optional[Dict[str,
|
||||||
Any]]) -> None:
|
Any]]) -> None:
|
||||||
from ba.internal import cache_tournament_info
|
accounts = ba.app.accounts
|
||||||
self._running_query = False
|
self._running_query = False
|
||||||
if data is not None:
|
if data is not None:
|
||||||
data = data['t'] # This used to be the whole payload.
|
data = data['t'] # This used to be the whole payload.
|
||||||
cache_tournament_info(data)
|
accounts.cache_tournament_info(data)
|
||||||
self._seconds_remaining = ba.app.tournament_info[
|
self._seconds_remaining = accounts.tournament_info[
|
||||||
self._tournament_id]['timeRemaining']
|
self._tournament_id]['timeRemaining']
|
||||||
self._have_valid_data = True
|
self._have_valid_data = True
|
||||||
|
|
||||||
@ -348,7 +349,8 @@ class TournamentEntryWindow(popup.PopupWindow):
|
|||||||
self._running_query = True
|
self._running_query = True
|
||||||
|
|
||||||
# Grab the latest info on our tourney.
|
# 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 we don't have valid data always show a '-' for time.
|
||||||
if not self._have_valid_data:
|
if not self._have_valid_data:
|
||||||
|
|||||||
@ -73,7 +73,7 @@ def get_binding_values() -> object:
|
|||||||
_hooks.do_quit, # kQuitCall
|
_hooks.do_quit, # kQuitCall
|
||||||
_hooks.shutdown, # kShutdownCall
|
_hooks.shutdown, # kShutdownCall
|
||||||
_hooks.gc_disable, # kGCDisableCall
|
_hooks.gc_disable, # kGCDisableCall
|
||||||
_account.show_post_purchase_message, # kShowPostPurchaseMessageCall
|
ba.app.accounts.show_post_purchase_message, # kShowPostPurchaseMessageCall
|
||||||
_hooks.device_menu_press, # kDeviceMenuPressCall
|
_hooks.device_menu_press, # kDeviceMenuPressCall
|
||||||
_hooks.show_url_window, # kShowURLWindowCall
|
_hooks.show_url_window, # kShowURLWindowCall
|
||||||
_hooks.party_invite_revoke, # kHandlePartyInviteRevokeCall
|
_hooks.party_invite_revoke, # kHandlePartyInviteRevokeCall
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user