bastd.ui.profile.upgrade
UI for player profile upgrades.
1# Released under the MIT License. See LICENSE for details. 2# 3"""UI for player profile upgrades.""" 4 5from __future__ import annotations 6 7import time 8import weakref 9from typing import TYPE_CHECKING 10 11import _ba 12import ba 13 14if TYPE_CHECKING: 15 from typing import Any 16 from bastd.ui.profile.edit import EditProfileWindow 17 18 19class ProfileUpgradeWindow(ba.Window): 20 """Window for player profile upgrades to global.""" 21 22 def __init__(self, 23 edit_profile_window: EditProfileWindow, 24 transition: str = 'in_right'): 25 from ba.internal import master_server_get 26 self._r = 'editProfileWindow' 27 28 self._width = 680 29 self._height = 350 30 uiscale = ba.app.ui.uiscale 31 self._base_scale = (2.05 if uiscale is ba.UIScale.SMALL else 32 1.5 if uiscale is ba.UIScale.MEDIUM else 1.2) 33 self._upgrade_start_time: float | None = None 34 self._name = edit_profile_window.getname() 35 self._edit_profile_window = weakref.ref(edit_profile_window) 36 37 top_extra = 15 if uiscale is ba.UIScale.SMALL else 15 38 super().__init__(root_widget=ba.containerwidget( 39 size=(self._width, self._height + top_extra), 40 toolbar_visibility='menu_currency', 41 transition=transition, 42 scale=self._base_scale, 43 stack_offset=(0, 15) if uiscale is ba.UIScale.SMALL else (0, 0))) 44 cancel_button = ba.buttonwidget(parent=self._root_widget, 45 position=(52, 30), 46 size=(155, 60), 47 scale=0.8, 48 autoselect=True, 49 label=ba.Lstr(resource='cancelText'), 50 on_activate_call=self._cancel) 51 self._upgrade_button = ba.buttonwidget( 52 parent=self._root_widget, 53 position=(self._width - 190, 30), 54 size=(155, 60), 55 scale=0.8, 56 autoselect=True, 57 label=ba.Lstr(resource='upgradeText'), 58 on_activate_call=self._on_upgrade_press) 59 ba.containerwidget(edit=self._root_widget, 60 cancel_button=cancel_button, 61 start_button=self._upgrade_button, 62 selected_child=self._upgrade_button) 63 64 ba.textwidget(parent=self._root_widget, 65 position=(self._width * 0.5, self._height - 38), 66 size=(0, 0), 67 text=ba.Lstr(resource=self._r + 68 '.upgradeToGlobalProfileText'), 69 color=ba.app.ui.title_color, 70 maxwidth=self._width * 0.45, 71 scale=1.0, 72 h_align='center', 73 v_align='center') 74 75 ba.textwidget(parent=self._root_widget, 76 position=(self._width * 0.5, self._height - 100), 77 size=(0, 0), 78 text=ba.Lstr(resource=self._r + 79 '.upgradeProfileInfoText'), 80 color=ba.app.ui.infotextcolor, 81 maxwidth=self._width * 0.8, 82 scale=0.7, 83 h_align='center', 84 v_align='center') 85 86 self._status_text = ba.textwidget( 87 parent=self._root_widget, 88 position=(self._width * 0.5, self._height - 160), 89 size=(0, 0), 90 text=ba.Lstr(resource=self._r + '.checkingAvailabilityText', 91 subs=[('${NAME}', self._name)]), 92 color=(0.8, 0.4, 0.0), 93 maxwidth=self._width * 0.8, 94 scale=0.65, 95 h_align='center', 96 v_align='center') 97 98 self._price_text = ba.textwidget(parent=self._root_widget, 99 position=(self._width * 0.5, 100 self._height - 230), 101 size=(0, 0), 102 text='', 103 color=(0.2, 1, 0.2), 104 maxwidth=self._width * 0.8, 105 scale=1.5, 106 h_align='center', 107 v_align='center') 108 109 self._tickets_text: ba.Widget | None 110 if not ba.app.ui.use_toolbars: 111 self._tickets_text = ba.textwidget( 112 parent=self._root_widget, 113 position=(self._width * 0.9 - 5, self._height - 30), 114 size=(0, 0), 115 text=ba.charstr(ba.SpecialChar.TICKET) + '123', 116 color=(0.2, 1, 0.2), 117 maxwidth=100, 118 scale=0.5, 119 h_align='right', 120 v_align='center') 121 else: 122 self._tickets_text = None 123 124 master_server_get('bsGlobalProfileCheck', { 125 'name': self._name, 126 'b': ba.app.build_number 127 }, 128 callback=ba.WeakCall(self._profile_check_result)) 129 self._cost = _ba.get_v1_account_misc_read_val('price.global_profile', 130 500) 131 self._status: str | None = 'waiting' 132 self._update_timer = ba.Timer(1.0, 133 ba.WeakCall(self._update), 134 timetype=ba.TimeType.REAL, 135 repeat=True) 136 self._update() 137 138 def _profile_check_result(self, result: dict[str, Any] | None) -> None: 139 if result is None: 140 ba.textwidget( 141 edit=self._status_text, 142 text=ba.Lstr(resource='internal.unavailableNoConnectionText'), 143 color=(1, 0, 0)) 144 self._status = 'error' 145 ba.buttonwidget(edit=self._upgrade_button, 146 color=(0.4, 0.4, 0.4), 147 textcolor=(0.5, 0.5, 0.5)) 148 else: 149 if result['available']: 150 ba.textwidget(edit=self._status_text, 151 text=ba.Lstr(resource=self._r + '.availableText', 152 subs=[('${NAME}', self._name)]), 153 color=(0, 1, 0)) 154 ba.textwidget(edit=self._price_text, 155 text=ba.charstr(ba.SpecialChar.TICKET) + 156 str(self._cost)) 157 self._status = None 158 else: 159 ba.textwidget(edit=self._status_text, 160 text=ba.Lstr(resource=self._r + 161 '.unavailableText', 162 subs=[('${NAME}', self._name)]), 163 color=(1, 0, 0)) 164 self._status = 'unavailable' 165 ba.buttonwidget(edit=self._upgrade_button, 166 color=(0.4, 0.4, 0.4), 167 textcolor=(0.5, 0.5, 0.5)) 168 169 def _on_upgrade_press(self) -> None: 170 from bastd.ui import getcurrency 171 if self._status is None: 172 # If it appears we don't have enough tickets, offer to buy more. 173 tickets = _ba.get_v1_account_ticket_count() 174 if tickets < self._cost: 175 ba.playsound(ba.getsound('error')) 176 getcurrency.show_get_tickets_prompt() 177 return 178 ba.screenmessage(ba.Lstr(resource='purchasingText'), 179 color=(0, 1, 0)) 180 self._status = 'pre_upgrading' 181 182 # Now we tell the original editor to save the profile, add an 183 # upgrade transaction, and then sit and wait for everything to 184 # go through. 185 edit_profile_window = self._edit_profile_window() 186 if edit_profile_window is None: 187 print('profile upgrade: original edit window gone') 188 return 189 success = edit_profile_window.save(transition_out=False) 190 if not success: 191 print('profile upgrade: error occurred saving profile') 192 ba.screenmessage(ba.Lstr(resource='errorText'), 193 color=(1, 0, 0)) 194 ba.playsound(ba.getsound('error')) 195 return 196 _ba.add_transaction({ 197 'type': 'UPGRADE_PROFILE', 198 'name': self._name 199 }) 200 _ba.run_transactions() 201 self._status = 'upgrading' 202 self._upgrade_start_time = time.time() 203 else: 204 ba.playsound(ba.getsound('error')) 205 206 def _update(self) -> None: 207 try: 208 t_str = str(_ba.get_v1_account_ticket_count()) 209 except Exception: 210 t_str = '?' 211 if self._tickets_text is not None: 212 ba.textwidget(edit=self._tickets_text, 213 text=ba.Lstr( 214 resource='getTicketsWindow.youHaveShortText', 215 subs=[('${COUNT}', 216 ba.charstr(ba.SpecialChar.TICKET) + t_str) 217 ])) 218 219 # Once we've kicked off an upgrade attempt and all transactions go 220 # through, we're done. 221 if (self._status == 'upgrading' 222 and not _ba.have_outstanding_transactions()): 223 self._status = 'exiting' 224 ba.containerwidget(edit=self._root_widget, transition='out_right') 225 edit_profile_window = self._edit_profile_window() 226 if edit_profile_window is None: 227 print('profile upgrade transition out:' 228 ' original edit window gone') 229 return 230 ba.playsound(ba.getsound('gunCocking')) 231 edit_profile_window.reload_window() 232 233 def _cancel(self) -> None: 234 # If we recently sent out an upgrade request, disallow canceling 235 # for a bit. 236 if (self._upgrade_start_time is not None 237 and time.time() - self._upgrade_start_time < 10.0): 238 ba.playsound(ba.getsound('error')) 239 return 240 ba.containerwidget(edit=self._root_widget, transition='out_right')
class
ProfileUpgradeWindow(ba.ui.Window):
20class ProfileUpgradeWindow(ba.Window): 21 """Window for player profile upgrades to global.""" 22 23 def __init__(self, 24 edit_profile_window: EditProfileWindow, 25 transition: str = 'in_right'): 26 from ba.internal import master_server_get 27 self._r = 'editProfileWindow' 28 29 self._width = 680 30 self._height = 350 31 uiscale = ba.app.ui.uiscale 32 self._base_scale = (2.05 if uiscale is ba.UIScale.SMALL else 33 1.5 if uiscale is ba.UIScale.MEDIUM else 1.2) 34 self._upgrade_start_time: float | None = None 35 self._name = edit_profile_window.getname() 36 self._edit_profile_window = weakref.ref(edit_profile_window) 37 38 top_extra = 15 if uiscale is ba.UIScale.SMALL else 15 39 super().__init__(root_widget=ba.containerwidget( 40 size=(self._width, self._height + top_extra), 41 toolbar_visibility='menu_currency', 42 transition=transition, 43 scale=self._base_scale, 44 stack_offset=(0, 15) if uiscale is ba.UIScale.SMALL else (0, 0))) 45 cancel_button = ba.buttonwidget(parent=self._root_widget, 46 position=(52, 30), 47 size=(155, 60), 48 scale=0.8, 49 autoselect=True, 50 label=ba.Lstr(resource='cancelText'), 51 on_activate_call=self._cancel) 52 self._upgrade_button = ba.buttonwidget( 53 parent=self._root_widget, 54 position=(self._width - 190, 30), 55 size=(155, 60), 56 scale=0.8, 57 autoselect=True, 58 label=ba.Lstr(resource='upgradeText'), 59 on_activate_call=self._on_upgrade_press) 60 ba.containerwidget(edit=self._root_widget, 61 cancel_button=cancel_button, 62 start_button=self._upgrade_button, 63 selected_child=self._upgrade_button) 64 65 ba.textwidget(parent=self._root_widget, 66 position=(self._width * 0.5, self._height - 38), 67 size=(0, 0), 68 text=ba.Lstr(resource=self._r + 69 '.upgradeToGlobalProfileText'), 70 color=ba.app.ui.title_color, 71 maxwidth=self._width * 0.45, 72 scale=1.0, 73 h_align='center', 74 v_align='center') 75 76 ba.textwidget(parent=self._root_widget, 77 position=(self._width * 0.5, self._height - 100), 78 size=(0, 0), 79 text=ba.Lstr(resource=self._r + 80 '.upgradeProfileInfoText'), 81 color=ba.app.ui.infotextcolor, 82 maxwidth=self._width * 0.8, 83 scale=0.7, 84 h_align='center', 85 v_align='center') 86 87 self._status_text = ba.textwidget( 88 parent=self._root_widget, 89 position=(self._width * 0.5, self._height - 160), 90 size=(0, 0), 91 text=ba.Lstr(resource=self._r + '.checkingAvailabilityText', 92 subs=[('${NAME}', self._name)]), 93 color=(0.8, 0.4, 0.0), 94 maxwidth=self._width * 0.8, 95 scale=0.65, 96 h_align='center', 97 v_align='center') 98 99 self._price_text = ba.textwidget(parent=self._root_widget, 100 position=(self._width * 0.5, 101 self._height - 230), 102 size=(0, 0), 103 text='', 104 color=(0.2, 1, 0.2), 105 maxwidth=self._width * 0.8, 106 scale=1.5, 107 h_align='center', 108 v_align='center') 109 110 self._tickets_text: ba.Widget | None 111 if not ba.app.ui.use_toolbars: 112 self._tickets_text = ba.textwidget( 113 parent=self._root_widget, 114 position=(self._width * 0.9 - 5, self._height - 30), 115 size=(0, 0), 116 text=ba.charstr(ba.SpecialChar.TICKET) + '123', 117 color=(0.2, 1, 0.2), 118 maxwidth=100, 119 scale=0.5, 120 h_align='right', 121 v_align='center') 122 else: 123 self._tickets_text = None 124 125 master_server_get('bsGlobalProfileCheck', { 126 'name': self._name, 127 'b': ba.app.build_number 128 }, 129 callback=ba.WeakCall(self._profile_check_result)) 130 self._cost = _ba.get_v1_account_misc_read_val('price.global_profile', 131 500) 132 self._status: str | None = 'waiting' 133 self._update_timer = ba.Timer(1.0, 134 ba.WeakCall(self._update), 135 timetype=ba.TimeType.REAL, 136 repeat=True) 137 self._update() 138 139 def _profile_check_result(self, result: dict[str, Any] | None) -> None: 140 if result is None: 141 ba.textwidget( 142 edit=self._status_text, 143 text=ba.Lstr(resource='internal.unavailableNoConnectionText'), 144 color=(1, 0, 0)) 145 self._status = 'error' 146 ba.buttonwidget(edit=self._upgrade_button, 147 color=(0.4, 0.4, 0.4), 148 textcolor=(0.5, 0.5, 0.5)) 149 else: 150 if result['available']: 151 ba.textwidget(edit=self._status_text, 152 text=ba.Lstr(resource=self._r + '.availableText', 153 subs=[('${NAME}', self._name)]), 154 color=(0, 1, 0)) 155 ba.textwidget(edit=self._price_text, 156 text=ba.charstr(ba.SpecialChar.TICKET) + 157 str(self._cost)) 158 self._status = None 159 else: 160 ba.textwidget(edit=self._status_text, 161 text=ba.Lstr(resource=self._r + 162 '.unavailableText', 163 subs=[('${NAME}', self._name)]), 164 color=(1, 0, 0)) 165 self._status = 'unavailable' 166 ba.buttonwidget(edit=self._upgrade_button, 167 color=(0.4, 0.4, 0.4), 168 textcolor=(0.5, 0.5, 0.5)) 169 170 def _on_upgrade_press(self) -> None: 171 from bastd.ui import getcurrency 172 if self._status is None: 173 # If it appears we don't have enough tickets, offer to buy more. 174 tickets = _ba.get_v1_account_ticket_count() 175 if tickets < self._cost: 176 ba.playsound(ba.getsound('error')) 177 getcurrency.show_get_tickets_prompt() 178 return 179 ba.screenmessage(ba.Lstr(resource='purchasingText'), 180 color=(0, 1, 0)) 181 self._status = 'pre_upgrading' 182 183 # Now we tell the original editor to save the profile, add an 184 # upgrade transaction, and then sit and wait for everything to 185 # go through. 186 edit_profile_window = self._edit_profile_window() 187 if edit_profile_window is None: 188 print('profile upgrade: original edit window gone') 189 return 190 success = edit_profile_window.save(transition_out=False) 191 if not success: 192 print('profile upgrade: error occurred saving profile') 193 ba.screenmessage(ba.Lstr(resource='errorText'), 194 color=(1, 0, 0)) 195 ba.playsound(ba.getsound('error')) 196 return 197 _ba.add_transaction({ 198 'type': 'UPGRADE_PROFILE', 199 'name': self._name 200 }) 201 _ba.run_transactions() 202 self._status = 'upgrading' 203 self._upgrade_start_time = time.time() 204 else: 205 ba.playsound(ba.getsound('error')) 206 207 def _update(self) -> None: 208 try: 209 t_str = str(_ba.get_v1_account_ticket_count()) 210 except Exception: 211 t_str = '?' 212 if self._tickets_text is not None: 213 ba.textwidget(edit=self._tickets_text, 214 text=ba.Lstr( 215 resource='getTicketsWindow.youHaveShortText', 216 subs=[('${COUNT}', 217 ba.charstr(ba.SpecialChar.TICKET) + t_str) 218 ])) 219 220 # Once we've kicked off an upgrade attempt and all transactions go 221 # through, we're done. 222 if (self._status == 'upgrading' 223 and not _ba.have_outstanding_transactions()): 224 self._status = 'exiting' 225 ba.containerwidget(edit=self._root_widget, transition='out_right') 226 edit_profile_window = self._edit_profile_window() 227 if edit_profile_window is None: 228 print('profile upgrade transition out:' 229 ' original edit window gone') 230 return 231 ba.playsound(ba.getsound('gunCocking')) 232 edit_profile_window.reload_window() 233 234 def _cancel(self) -> None: 235 # If we recently sent out an upgrade request, disallow canceling 236 # for a bit. 237 if (self._upgrade_start_time is not None 238 and time.time() - self._upgrade_start_time < 10.0): 239 ba.playsound(ba.getsound('error')) 240 return 241 ba.containerwidget(edit=self._root_widget, transition='out_right')
Window for player profile upgrades to global.
ProfileUpgradeWindow( edit_profile_window: bastd.ui.profile.edit.EditProfileWindow, transition: str = 'in_right')
23 def __init__(self, 24 edit_profile_window: EditProfileWindow, 25 transition: str = 'in_right'): 26 from ba.internal import master_server_get 27 self._r = 'editProfileWindow' 28 29 self._width = 680 30 self._height = 350 31 uiscale = ba.app.ui.uiscale 32 self._base_scale = (2.05 if uiscale is ba.UIScale.SMALL else 33 1.5 if uiscale is ba.UIScale.MEDIUM else 1.2) 34 self._upgrade_start_time: float | None = None 35 self._name = edit_profile_window.getname() 36 self._edit_profile_window = weakref.ref(edit_profile_window) 37 38 top_extra = 15 if uiscale is ba.UIScale.SMALL else 15 39 super().__init__(root_widget=ba.containerwidget( 40 size=(self._width, self._height + top_extra), 41 toolbar_visibility='menu_currency', 42 transition=transition, 43 scale=self._base_scale, 44 stack_offset=(0, 15) if uiscale is ba.UIScale.SMALL else (0, 0))) 45 cancel_button = ba.buttonwidget(parent=self._root_widget, 46 position=(52, 30), 47 size=(155, 60), 48 scale=0.8, 49 autoselect=True, 50 label=ba.Lstr(resource='cancelText'), 51 on_activate_call=self._cancel) 52 self._upgrade_button = ba.buttonwidget( 53 parent=self._root_widget, 54 position=(self._width - 190, 30), 55 size=(155, 60), 56 scale=0.8, 57 autoselect=True, 58 label=ba.Lstr(resource='upgradeText'), 59 on_activate_call=self._on_upgrade_press) 60 ba.containerwidget(edit=self._root_widget, 61 cancel_button=cancel_button, 62 start_button=self._upgrade_button, 63 selected_child=self._upgrade_button) 64 65 ba.textwidget(parent=self._root_widget, 66 position=(self._width * 0.5, self._height - 38), 67 size=(0, 0), 68 text=ba.Lstr(resource=self._r + 69 '.upgradeToGlobalProfileText'), 70 color=ba.app.ui.title_color, 71 maxwidth=self._width * 0.45, 72 scale=1.0, 73 h_align='center', 74 v_align='center') 75 76 ba.textwidget(parent=self._root_widget, 77 position=(self._width * 0.5, self._height - 100), 78 size=(0, 0), 79 text=ba.Lstr(resource=self._r + 80 '.upgradeProfileInfoText'), 81 color=ba.app.ui.infotextcolor, 82 maxwidth=self._width * 0.8, 83 scale=0.7, 84 h_align='center', 85 v_align='center') 86 87 self._status_text = ba.textwidget( 88 parent=self._root_widget, 89 position=(self._width * 0.5, self._height - 160), 90 size=(0, 0), 91 text=ba.Lstr(resource=self._r + '.checkingAvailabilityText', 92 subs=[('${NAME}', self._name)]), 93 color=(0.8, 0.4, 0.0), 94 maxwidth=self._width * 0.8, 95 scale=0.65, 96 h_align='center', 97 v_align='center') 98 99 self._price_text = ba.textwidget(parent=self._root_widget, 100 position=(self._width * 0.5, 101 self._height - 230), 102 size=(0, 0), 103 text='', 104 color=(0.2, 1, 0.2), 105 maxwidth=self._width * 0.8, 106 scale=1.5, 107 h_align='center', 108 v_align='center') 109 110 self._tickets_text: ba.Widget | None 111 if not ba.app.ui.use_toolbars: 112 self._tickets_text = ba.textwidget( 113 parent=self._root_widget, 114 position=(self._width * 0.9 - 5, self._height - 30), 115 size=(0, 0), 116 text=ba.charstr(ba.SpecialChar.TICKET) + '123', 117 color=(0.2, 1, 0.2), 118 maxwidth=100, 119 scale=0.5, 120 h_align='right', 121 v_align='center') 122 else: 123 self._tickets_text = None 124 125 master_server_get('bsGlobalProfileCheck', { 126 'name': self._name, 127 'b': ba.app.build_number 128 }, 129 callback=ba.WeakCall(self._profile_check_result)) 130 self._cost = _ba.get_v1_account_misc_read_val('price.global_profile', 131 500) 132 self._status: str | None = 'waiting' 133 self._update_timer = ba.Timer(1.0, 134 ba.WeakCall(self._update), 135 timetype=ba.TimeType.REAL, 136 repeat=True) 137 self._update()
Inherited Members
- ba.ui.Window
- get_root_widget