def _update_linked_accounts_text(self) -> None: if self._linked_accounts_text is None: return # if this is not present, we haven't had contact from the server so # let's not proceed.. if _ba.get_public_login_id() is None: num = int(time.time()) % 4 accounts_str = num * '.' + (4 - num) * ' ' else: accounts = _ba.get_v1_account_misc_read_val_2('linkedAccounts', []) # our_account = _bs.get_v1_account_display_string() # accounts = [a for a in accounts if a != our_account] # accounts_str = u', '.join(accounts) if accounts else # ba.Lstr(translate=('settingNames', 'None')) # UPDATE - we now just print the number here; not the actual # accounts # (they can see that in the unlink section if they're curious) accounts_str = str(max(0, len(accounts) - 1)) ba.textwidget(edit=self._linked_accounts_text, text=ba.Lstr(value='${L} ${A}', subs=[('${L}', ba.Lstr(resource=self._r + '.linkedAccountsText')), ('${A}', accounts_str)]))
def _have_unlinkable_accounts(self) -> bool: # if this is not present, we haven't had contact from the server so # let's not proceed.. if _ba.get_public_login_id() is None: return False accounts = _ba.get_v1_account_misc_read_val_2('linkedAccounts', []) return len(accounts) > 1
def _update_field(self, response: dict[str, Any]) -> None: if self._angry_computer_image is None: self._angry_computer_image = ba.imagewidget( parent=self._root_widget, position=(self._width - 180, self._height * 0.5 - 65), size=(150, 150), texture=self.lineup_tex, model_transparent=self._angry_computer_transparent_model) if self._line_image is None: self._line_image = ba.imagewidget( parent=self._root_widget, color=(0.0, 0.0, 0.0), opacity=0.2, position=(self._line_left, self._line_bottom - 2.0), size=(self._line_width, 4.0), texture=self._white_tex) # now go through the data they sent, creating dudes for us and our # enemies as needed and updating target positions on all of them.. # mark all as unclaimed so we know which ones to kill off.. for dude in self._dudes: dude.claimed = False # always have a dude for ourself.. if -1 not in self._dudes_by_id: dude = self.Dude( self, response['d'], self._initial_offset, True, _ba.get_v1_account_misc_read_val_2('resolvedAccountID', None), _ba.get_v1_account_display_string()) self._dudes_by_id[-1] = dude self._dudes.append(dude) else: self._dudes_by_id[-1].set_target_distance(response['d']) self._dudes_by_id[-1].claimed = True # now create/destroy enemies for (enemy_id, enemy_distance, enemy_account_id, enemy_name) in response['e']: if enemy_id not in self._dudes_by_id: dude = self.Dude(self, enemy_distance, self._initial_offset, False, enemy_account_id, enemy_name) self._dudes_by_id[enemy_id] = dude self._dudes.append(dude) else: self._dudes_by_id[enemy_id].set_target_distance(enemy_distance) self._dudes_by_id[enemy_id].claimed = True # remove unclaimed dudes from both of our lists # noinspection PyUnresolvedReferences self._dudes_by_id = dict([ item for item in list(self._dudes_by_id.items()) if item[1].claimed ]) self._dudes = [dude for dude in self._dudes if dude.claimed]
def have_pro_options(self) -> bool: """Return whether pro-options are present. This is True for owners of Pro or for old installs before Pro was a requirement for these options. """ # 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_v1_account_misc_read_val_2('proOptionsUnlocked', False) or _ba.app.config.get('lc14292', 0) > 1)
def _do_purchase(self, item: str) -> None: if item == 'ad': import datetime # if ads are disabled until some time, error.. next_reward_ad_time = _ba.get_v1_account_misc_read_val_2( 'nextRewardAdTime', None) if next_reward_ad_time is not None: next_reward_ad_time = datetime.datetime.utcfromtimestamp( next_reward_ad_time) now = datetime.datetime.utcnow() if ((next_reward_ad_time is not None and next_reward_ad_time > now) or self._ad_button_greyed): ba.playsound(ba.getsound('error')) ba.screenmessage(ba.Lstr( resource='getTicketsWindow.unavailableTemporarilyText'), color=(1, 0, 0)) elif self._enable_ad_button: _ba.app.ads.show_ad('tickets') else: _ba.purchase(item)
def _update(self) -> None: import datetime # if we somehow get signed out, just die.. if _ba.get_v1_account_state() != 'signed_in': self._back() return self._ticket_count = _ba.get_v1_account_ticket_count() # update our incentivized ad button depending on whether ads are # available if self._ad_button is not None: next_reward_ad_time = _ba.get_v1_account_misc_read_val_2( 'nextRewardAdTime', None) if next_reward_ad_time is not None: next_reward_ad_time = datetime.datetime.utcfromtimestamp( next_reward_ad_time) now = datetime.datetime.utcnow() if (_ba.have_incentivized_ad() and (next_reward_ad_time is None or next_reward_ad_time <= now)): self._ad_button_greyed = False ba.buttonwidget(edit=self._ad_button, color=(0.65, 0.5, 0.7)) ba.textwidget(edit=self._ad_label, color=(0.7, 0.9, 0.7, 1.0)) ba.textwidget(edit=self._ad_free_text, color=(1, 1, 0, 1)) ba.imagewidget(edit=self._ad_image, opacity=0.6) ba.textwidget(edit=self._ad_time_text, text='') else: self._ad_button_greyed = True ba.buttonwidget(edit=self._ad_button, color=(0.5, 0.5, 0.5)) ba.textwidget(edit=self._ad_label, color=(0.7, 0.9, 0.7, 0.2)) ba.textwidget(edit=self._ad_free_text, color=(1, 1, 0, 0.2)) ba.imagewidget(edit=self._ad_image, opacity=0.6 * 0.25) sval: Union[str, ba.Lstr] if (next_reward_ad_time is not None and next_reward_ad_time > now): sval = ba.timestring( (next_reward_ad_time - now).total_seconds() * 1000.0, centi=False, timeformat=ba.TimeFormat.MILLISECONDS) else: sval = '' ba.textwidget(edit=self._ad_time_text, text=sval) # if this is our first update, assign immediately; otherwise kick # off a smooth transition if the value has changed if self._smooth_ticket_count is None: self._smooth_ticket_count = float(self._ticket_count) self._smooth_update() # will set the text widget elif (self._ticket_count != int(self._smooth_ticket_count) and self._smooth_update_timer is None): self._smooth_update_timer = ba.Timer(0.05, ba.WeakCall( self._smooth_update), repeat=True, timetype=ba.TimeType.REAL) diff = abs(float(self._ticket_count) - self._smooth_ticket_count) self._smooth_increase_speed = (diff / 100.0 if diff >= 5000 else diff / 50.0 if diff >= 1500 else diff / 30.0 if diff >= 500 else diff / 15.0)
def update(self, index: int, party: PartyEntry, sub_scroll_width: float, sub_scroll_height: float, lineheight: float, columnwidget: ba.Widget, join_text: ba.Widget, filter_text: ba.Widget, existing_selection: Optional[Selection], tab: PublicGatherTab) -> None: """Update for the given data.""" # pylint: disable=too-many-locals # Quick-out: if we've been marked clean for a certain index and # we're still at that index, we're done. if party.clean_display_index == index: return ping_good = _ba.get_v1_account_misc_read_val('pingGood', 100) ping_med = _ba.get_v1_account_misc_read_val('pingMed', 500) self._clear() hpos = 20 vpos = sub_scroll_height - lineheight * index - 50 self._name_widget = ba.textwidget( text=ba.Lstr(value=party.name), parent=columnwidget, size=(sub_scroll_width * 0.63, 20), position=(0 + hpos, 4 + vpos), selectable=True, on_select_call=ba.WeakCall( tab.set_public_party_selection, Selection(party.get_key(), SelectionComponent.NAME)), on_activate_call=ba.WeakCall(tab.on_public_party_activate, party), click_activate=True, maxwidth=sub_scroll_width * 0.45, corner_scale=1.4, autoselect=True, color=(1, 1, 1, 0.3 if party.ping is None else 1.0), h_align='left', v_align='center') ba.widget(edit=self._name_widget, left_widget=join_text, show_buffer_top=64.0, show_buffer_bottom=64.0) if existing_selection == Selection(party.get_key(), SelectionComponent.NAME): ba.containerwidget(edit=columnwidget, selected_child=self._name_widget) if party.stats_addr: url = party.stats_addr.replace( '${ACCOUNT}', _ba.get_v1_account_misc_read_val_2('resolvedAccountID', 'UNKNOWN')) self._stats_button = ba.buttonwidget( color=(0.3, 0.6, 0.94), textcolor=(1.0, 1.0, 1.0), label=ba.Lstr(resource='statsText'), parent=columnwidget, autoselect=True, on_activate_call=ba.Call(ba.open_url, url), on_select_call=ba.WeakCall( tab.set_public_party_selection, Selection(party.get_key(), SelectionComponent.STATS_BUTTON)), size=(120, 40), position=(sub_scroll_width * 0.66 + hpos, 1 + vpos), scale=0.9) if existing_selection == Selection( party.get_key(), SelectionComponent.STATS_BUTTON): ba.containerwidget(edit=columnwidget, selected_child=self._stats_button) self._size_widget = ba.textwidget( text=str(party.size) + '/' + str(party.size_max), parent=columnwidget, size=(0, 0), position=(sub_scroll_width * 0.86 + hpos, 20 + vpos), scale=0.7, color=(0.8, 0.8, 0.8), h_align='right', v_align='center') if index == 0: ba.widget(edit=self._name_widget, up_widget=filter_text) if self._stats_button: ba.widget(edit=self._stats_button, up_widget=filter_text) self._ping_widget = ba.textwidget(parent=columnwidget, size=(0, 0), position=(sub_scroll_width * 0.94 + hpos, 20 + vpos), scale=0.7, h_align='right', v_align='center') if party.ping is None: ba.textwidget(edit=self._ping_widget, text='-', color=(0.5, 0.5, 0.5)) else: ba.textwidget(edit=self._ping_widget, text=str(int(party.ping)), color=(0, 1, 0) if party.ping <= ping_good else (1, 1, 0) if party.ping <= ping_med else (1, 0, 0)) party.clean_display_index = index
def __init__(self, origin_widget: ba.Widget = None): scale_origin: Optional[tuple[float, float]] if origin_widget is not None: self._transition_out = 'out_scale' scale_origin = origin_widget.get_screen_space_center() transition = 'in_scale' else: self._transition_out = 'out_right' scale_origin = None transition = 'in_right' bg_color = (0.4, 0.4, 0.5) self._width = 540 self._height = 350 self._scroll_width = 400 self._scroll_height = 200 uiscale = ba.app.ui.uiscale base_scale = (2.0 if uiscale is ba.UIScale.SMALL else 1.6 if uiscale is ba.UIScale.MEDIUM else 1.1) super().__init__(root_widget=ba.containerwidget( size=(self._width, self._height), transition=transition, scale=base_scale, scale_origin_stack_offset=scale_origin, stack_offset=(0, -10) if uiscale is ba.UIScale.SMALL else (0, 0))) self._cancel_button = ba.buttonwidget(parent=self._root_widget, position=(30, self._height - 50), size=(50, 50), scale=0.7, label='', color=bg_color, on_activate_call=self._cancel, autoselect=True, icon=ba.gettexture('crossOut'), iconscale=1.2) ba.textwidget( parent=self._root_widget, position=(self._width * 0.5, self._height * 0.88), size=(0, 0), text=ba.Lstr( resource='accountSettingsWindow.unlinkAccountsInstructionsText' ), maxwidth=self._width * 0.7, color=ba.app.ui.infotextcolor, h_align='center', v_align='center') ba.containerwidget(edit=self._root_widget, cancel_button=self._cancel_button) self._scrollwidget = ba.scrollwidget( parent=self._root_widget, highlight=False, position=((self._width - self._scroll_width) * 0.5, self._height - 85 - self._scroll_height), size=(self._scroll_width, self._scroll_height)) ba.containerwidget(edit=self._scrollwidget, claims_left_right=True) self._columnwidget = ba.columnwidget(parent=self._scrollwidget, border=2, margin=0, left_border=10) our_login_id = _ba.get_public_login_id() if our_login_id is None: entries = [] else: account_infos = _ba.get_v1_account_misc_read_val_2( 'linkedAccounts2', []) entries = [{ 'name': ai['d'], 'id': ai['id'] } for ai in account_infos if ai['id'] != our_login_id] # (avoid getting our selection stuck on an empty column widget) if not entries: ba.containerwidget(edit=self._scrollwidget, selectable=False) for i, entry in enumerate(entries): txt = ba.textwidget(parent=self._columnwidget, selectable=True, text=entry['name'], size=(self._scroll_width - 30, 30), autoselect=True, click_activate=True, on_activate_call=ba.Call( self._on_entry_selected, entry)) ba.widget(edit=txt, left_widget=self._cancel_button) if i == 0: ba.widget(edit=txt, up_widget=self._cancel_button)