bastd.ui.continues

Provides a popup window to continue a game.

  1# Released under the MIT License. See LICENSE for details.
  2#
  3"""Provides a popup window to continue a game."""
  4
  5from __future__ import annotations
  6
  7import weakref
  8from typing import TYPE_CHECKING
  9
 10import ba
 11import ba.internal
 12
 13if TYPE_CHECKING:
 14    from typing import Any, Callable
 15
 16
 17class ContinuesWindow(ba.Window):
 18    """A window to continue a game."""
 19
 20    def __init__(
 21        self,
 22        activity: ba.Activity,
 23        cost: int,
 24        continue_call: Callable[[], Any],
 25        cancel_call: Callable[[], Any],
 26    ):
 27        self._activity = weakref.ref(activity)
 28        self._cost = cost
 29        self._continue_call = continue_call
 30        self._cancel_call = cancel_call
 31        self._start_count = self._count = 20
 32        self._width = 300
 33        self._height = 200
 34        self._transitioning_out = False
 35        super().__init__(
 36            ba.containerwidget(
 37                size=(self._width, self._height),
 38                background=False,
 39                toolbar_visibility='menu_currency',
 40                transition='in_scale',
 41                scale=1.5,
 42            )
 43        )
 44        txt = (
 45            ba.Lstr(resource='continuePurchaseText')
 46            .evaluate()
 47            .split('${PRICE}')
 48        )
 49        t_left = txt[0]
 50        t_left_width = ba.internal.get_string_width(
 51            t_left, suppress_warning=True
 52        )
 53        t_price = ba.charstr(ba.SpecialChar.TICKET) + str(self._cost)
 54        t_price_width = ba.internal.get_string_width(
 55            t_price, suppress_warning=True
 56        )
 57        t_right = txt[-1]
 58        t_right_width = ba.internal.get_string_width(
 59            t_right, suppress_warning=True
 60        )
 61        width_total_half = (t_left_width + t_price_width + t_right_width) * 0.5
 62
 63        ba.textwidget(
 64            parent=self._root_widget,
 65            text=t_left,
 66            flatness=1.0,
 67            shadow=1.0,
 68            size=(0, 0),
 69            h_align='left',
 70            v_align='center',
 71            position=(self._width * 0.5 - width_total_half, self._height - 30),
 72        )
 73        ba.textwidget(
 74            parent=self._root_widget,
 75            text=t_price,
 76            flatness=1.0,
 77            shadow=1.0,
 78            color=(0.2, 1.0, 0.2),
 79            size=(0, 0),
 80            position=(
 81                self._width * 0.5 - width_total_half + t_left_width,
 82                self._height - 30,
 83            ),
 84            h_align='left',
 85            v_align='center',
 86        )
 87        ba.textwidget(
 88            parent=self._root_widget,
 89            text=t_right,
 90            flatness=1.0,
 91            shadow=1.0,
 92            size=(0, 0),
 93            h_align='left',
 94            v_align='center',
 95            position=(
 96                self._width * 0.5
 97                - width_total_half
 98                + t_left_width
 99                + t_price_width
100                + 5,
101                self._height - 30,
102            ),
103        )
104
105        self._tickets_text_base: str | None
106        self._tickets_text: ba.Widget | None
107        if not ba.app.ui.use_toolbars:
108            self._tickets_text_base = ba.Lstr(
109                resource='getTicketsWindow.youHaveShortText',
110                fallback_resource='getTicketsWindow.youHaveText',
111            ).evaluate()
112            self._tickets_text = ba.textwidget(
113                parent=self._root_widget,
114                text='',
115                flatness=1.0,
116                color=(0.2, 1.0, 0.2),
117                shadow=1.0,
118                position=(
119                    self._width * 0.5 + width_total_half,
120                    self._height - 50,
121                ),
122                size=(0, 0),
123                scale=0.35,
124                h_align='right',
125                v_align='center',
126            )
127        else:
128            self._tickets_text_base = None
129            self._tickets_text = None
130
131        self._counter_text = ba.textwidget(
132            parent=self._root_widget,
133            text=str(self._count),
134            color=(0.7, 0.7, 0.7),
135            scale=1.2,
136            size=(0, 0),
137            big=True,
138            position=(self._width * 0.5, self._height - 80),
139            flatness=1.0,
140            shadow=1.0,
141            h_align='center',
142            v_align='center',
143        )
144        self._cancel_button = ba.buttonwidget(
145            parent=self._root_widget,
146            position=(30, 30),
147            size=(120, 50),
148            label=ba.Lstr(resource='endText', fallback_resource='cancelText'),
149            autoselect=True,
150            enable_sound=False,
151            on_activate_call=self._on_cancel_press,
152        )
153        self._continue_button = ba.buttonwidget(
154            parent=self._root_widget,
155            label=ba.Lstr(resource='continueText'),
156            autoselect=True,
157            position=(self._width - 130, 30),
158            size=(120, 50),
159            on_activate_call=self._on_continue_press,
160        )
161        ba.containerwidget(
162            edit=self._root_widget,
163            cancel_button=self._cancel_button,
164            start_button=self._continue_button,
165            selected_child=self._cancel_button,
166        )
167
168        self._counting_down = True
169        self._countdown_timer = ba.Timer(
170            1.0, ba.WeakCall(self._tick), repeat=True, timetype=ba.TimeType.REAL
171        )
172
173        # If there is foreground activity, suspend it.
174        ba.app.pause()
175        self._tick()
176
177    def __del__(self) -> None:
178        # If there is suspended foreground activity, resume it.
179        ba.app.resume()
180
181    def _tick(self) -> None:
182        # if our target activity is gone or has ended, go away
183        activity = self._activity()
184        if activity is None or activity.has_ended():
185            self._on_cancel()
186            return
187
188        if ba.internal.get_v1_account_state() == 'signed_in':
189            sval = ba.charstr(ba.SpecialChar.TICKET) + str(
190                ba.internal.get_v1_account_ticket_count()
191            )
192        else:
193            sval = '?'
194        if self._tickets_text is not None:
195            assert self._tickets_text_base is not None
196            ba.textwidget(
197                edit=self._tickets_text,
198                text=self._tickets_text_base.replace('${COUNT}', sval),
199            )
200
201        if self._counting_down:
202            self._count -= 1
203            ba.playsound(ba.getsound('tick'))
204            if self._count <= 0:
205                self._on_cancel()
206            else:
207                ba.textwidget(edit=self._counter_text, text=str(self._count))
208
209    def _on_cancel_press(self) -> None:
210        # disallow for first second
211        if self._start_count - self._count < 2:
212            ba.playsound(ba.getsound('error'))
213        else:
214            self._on_cancel()
215
216    def _on_continue_press(self) -> None:
217        from bastd.ui import getcurrency
218
219        # Disallow for first second.
220        if self._start_count - self._count < 2:
221            ba.playsound(ba.getsound('error'))
222        else:
223            # If somehow we got signed out...
224            if ba.internal.get_v1_account_state() != 'signed_in':
225                ba.screenmessage(
226                    ba.Lstr(resource='notSignedInText'), color=(1, 0, 0)
227                )
228                ba.playsound(ba.getsound('error'))
229                return
230
231            # If it appears we don't have enough tickets, offer to buy more.
232            tickets = ba.internal.get_v1_account_ticket_count()
233            if tickets < self._cost:
234                # FIXME: Should we start the timer back up again after?
235                self._counting_down = False
236                ba.textwidget(edit=self._counter_text, text='')
237                ba.playsound(ba.getsound('error'))
238                getcurrency.show_get_tickets_prompt()
239                return
240            if not self._transitioning_out:
241                ba.playsound(ba.getsound('swish'))
242                self._transitioning_out = True
243                ba.containerwidget(
244                    edit=self._root_widget, transition='out_scale'
245                )
246                self._continue_call()
247
248    def _on_cancel(self) -> None:
249        if not self._transitioning_out:
250            ba.playsound(ba.getsound('swish'))
251            self._transitioning_out = True
252            ba.containerwidget(edit=self._root_widget, transition='out_scale')
253            self._cancel_call()
class ContinuesWindow(ba.ui.Window):
 18class ContinuesWindow(ba.Window):
 19    """A window to continue a game."""
 20
 21    def __init__(
 22        self,
 23        activity: ba.Activity,
 24        cost: int,
 25        continue_call: Callable[[], Any],
 26        cancel_call: Callable[[], Any],
 27    ):
 28        self._activity = weakref.ref(activity)
 29        self._cost = cost
 30        self._continue_call = continue_call
 31        self._cancel_call = cancel_call
 32        self._start_count = self._count = 20
 33        self._width = 300
 34        self._height = 200
 35        self._transitioning_out = False
 36        super().__init__(
 37            ba.containerwidget(
 38                size=(self._width, self._height),
 39                background=False,
 40                toolbar_visibility='menu_currency',
 41                transition='in_scale',
 42                scale=1.5,
 43            )
 44        )
 45        txt = (
 46            ba.Lstr(resource='continuePurchaseText')
 47            .evaluate()
 48            .split('${PRICE}')
 49        )
 50        t_left = txt[0]
 51        t_left_width = ba.internal.get_string_width(
 52            t_left, suppress_warning=True
 53        )
 54        t_price = ba.charstr(ba.SpecialChar.TICKET) + str(self._cost)
 55        t_price_width = ba.internal.get_string_width(
 56            t_price, suppress_warning=True
 57        )
 58        t_right = txt[-1]
 59        t_right_width = ba.internal.get_string_width(
 60            t_right, suppress_warning=True
 61        )
 62        width_total_half = (t_left_width + t_price_width + t_right_width) * 0.5
 63
 64        ba.textwidget(
 65            parent=self._root_widget,
 66            text=t_left,
 67            flatness=1.0,
 68            shadow=1.0,
 69            size=(0, 0),
 70            h_align='left',
 71            v_align='center',
 72            position=(self._width * 0.5 - width_total_half, self._height - 30),
 73        )
 74        ba.textwidget(
 75            parent=self._root_widget,
 76            text=t_price,
 77            flatness=1.0,
 78            shadow=1.0,
 79            color=(0.2, 1.0, 0.2),
 80            size=(0, 0),
 81            position=(
 82                self._width * 0.5 - width_total_half + t_left_width,
 83                self._height - 30,
 84            ),
 85            h_align='left',
 86            v_align='center',
 87        )
 88        ba.textwidget(
 89            parent=self._root_widget,
 90            text=t_right,
 91            flatness=1.0,
 92            shadow=1.0,
 93            size=(0, 0),
 94            h_align='left',
 95            v_align='center',
 96            position=(
 97                self._width * 0.5
 98                - width_total_half
 99                + t_left_width
100                + t_price_width
101                + 5,
102                self._height - 30,
103            ),
104        )
105
106        self._tickets_text_base: str | None
107        self._tickets_text: ba.Widget | None
108        if not ba.app.ui.use_toolbars:
109            self._tickets_text_base = ba.Lstr(
110                resource='getTicketsWindow.youHaveShortText',
111                fallback_resource='getTicketsWindow.youHaveText',
112            ).evaluate()
113            self._tickets_text = ba.textwidget(
114                parent=self._root_widget,
115                text='',
116                flatness=1.0,
117                color=(0.2, 1.0, 0.2),
118                shadow=1.0,
119                position=(
120                    self._width * 0.5 + width_total_half,
121                    self._height - 50,
122                ),
123                size=(0, 0),
124                scale=0.35,
125                h_align='right',
126                v_align='center',
127            )
128        else:
129            self._tickets_text_base = None
130            self._tickets_text = None
131
132        self._counter_text = ba.textwidget(
133            parent=self._root_widget,
134            text=str(self._count),
135            color=(0.7, 0.7, 0.7),
136            scale=1.2,
137            size=(0, 0),
138            big=True,
139            position=(self._width * 0.5, self._height - 80),
140            flatness=1.0,
141            shadow=1.0,
142            h_align='center',
143            v_align='center',
144        )
145        self._cancel_button = ba.buttonwidget(
146            parent=self._root_widget,
147            position=(30, 30),
148            size=(120, 50),
149            label=ba.Lstr(resource='endText', fallback_resource='cancelText'),
150            autoselect=True,
151            enable_sound=False,
152            on_activate_call=self._on_cancel_press,
153        )
154        self._continue_button = ba.buttonwidget(
155            parent=self._root_widget,
156            label=ba.Lstr(resource='continueText'),
157            autoselect=True,
158            position=(self._width - 130, 30),
159            size=(120, 50),
160            on_activate_call=self._on_continue_press,
161        )
162        ba.containerwidget(
163            edit=self._root_widget,
164            cancel_button=self._cancel_button,
165            start_button=self._continue_button,
166            selected_child=self._cancel_button,
167        )
168
169        self._counting_down = True
170        self._countdown_timer = ba.Timer(
171            1.0, ba.WeakCall(self._tick), repeat=True, timetype=ba.TimeType.REAL
172        )
173
174        # If there is foreground activity, suspend it.
175        ba.app.pause()
176        self._tick()
177
178    def __del__(self) -> None:
179        # If there is suspended foreground activity, resume it.
180        ba.app.resume()
181
182    def _tick(self) -> None:
183        # if our target activity is gone or has ended, go away
184        activity = self._activity()
185        if activity is None or activity.has_ended():
186            self._on_cancel()
187            return
188
189        if ba.internal.get_v1_account_state() == 'signed_in':
190            sval = ba.charstr(ba.SpecialChar.TICKET) + str(
191                ba.internal.get_v1_account_ticket_count()
192            )
193        else:
194            sval = '?'
195        if self._tickets_text is not None:
196            assert self._tickets_text_base is not None
197            ba.textwidget(
198                edit=self._tickets_text,
199                text=self._tickets_text_base.replace('${COUNT}', sval),
200            )
201
202        if self._counting_down:
203            self._count -= 1
204            ba.playsound(ba.getsound('tick'))
205            if self._count <= 0:
206                self._on_cancel()
207            else:
208                ba.textwidget(edit=self._counter_text, text=str(self._count))
209
210    def _on_cancel_press(self) -> None:
211        # disallow for first second
212        if self._start_count - self._count < 2:
213            ba.playsound(ba.getsound('error'))
214        else:
215            self._on_cancel()
216
217    def _on_continue_press(self) -> None:
218        from bastd.ui import getcurrency
219
220        # Disallow for first second.
221        if self._start_count - self._count < 2:
222            ba.playsound(ba.getsound('error'))
223        else:
224            # If somehow we got signed out...
225            if ba.internal.get_v1_account_state() != 'signed_in':
226                ba.screenmessage(
227                    ba.Lstr(resource='notSignedInText'), color=(1, 0, 0)
228                )
229                ba.playsound(ba.getsound('error'))
230                return
231
232            # If it appears we don't have enough tickets, offer to buy more.
233            tickets = ba.internal.get_v1_account_ticket_count()
234            if tickets < self._cost:
235                # FIXME: Should we start the timer back up again after?
236                self._counting_down = False
237                ba.textwidget(edit=self._counter_text, text='')
238                ba.playsound(ba.getsound('error'))
239                getcurrency.show_get_tickets_prompt()
240                return
241            if not self._transitioning_out:
242                ba.playsound(ba.getsound('swish'))
243                self._transitioning_out = True
244                ba.containerwidget(
245                    edit=self._root_widget, transition='out_scale'
246                )
247                self._continue_call()
248
249    def _on_cancel(self) -> None:
250        if not self._transitioning_out:
251            ba.playsound(ba.getsound('swish'))
252            self._transitioning_out = True
253            ba.containerwidget(edit=self._root_widget, transition='out_scale')
254            self._cancel_call()

A window to continue a game.

ContinuesWindow( activity: ba._activity.Activity, cost: int, continue_call: Callable[[], Any], cancel_call: Callable[[], Any])
 21    def __init__(
 22        self,
 23        activity: ba.Activity,
 24        cost: int,
 25        continue_call: Callable[[], Any],
 26        cancel_call: Callable[[], Any],
 27    ):
 28        self._activity = weakref.ref(activity)
 29        self._cost = cost
 30        self._continue_call = continue_call
 31        self._cancel_call = cancel_call
 32        self._start_count = self._count = 20
 33        self._width = 300
 34        self._height = 200
 35        self._transitioning_out = False
 36        super().__init__(
 37            ba.containerwidget(
 38                size=(self._width, self._height),
 39                background=False,
 40                toolbar_visibility='menu_currency',
 41                transition='in_scale',
 42                scale=1.5,
 43            )
 44        )
 45        txt = (
 46            ba.Lstr(resource='continuePurchaseText')
 47            .evaluate()
 48            .split('${PRICE}')
 49        )
 50        t_left = txt[0]
 51        t_left_width = ba.internal.get_string_width(
 52            t_left, suppress_warning=True
 53        )
 54        t_price = ba.charstr(ba.SpecialChar.TICKET) + str(self._cost)
 55        t_price_width = ba.internal.get_string_width(
 56            t_price, suppress_warning=True
 57        )
 58        t_right = txt[-1]
 59        t_right_width = ba.internal.get_string_width(
 60            t_right, suppress_warning=True
 61        )
 62        width_total_half = (t_left_width + t_price_width + t_right_width) * 0.5
 63
 64        ba.textwidget(
 65            parent=self._root_widget,
 66            text=t_left,
 67            flatness=1.0,
 68            shadow=1.0,
 69            size=(0, 0),
 70            h_align='left',
 71            v_align='center',
 72            position=(self._width * 0.5 - width_total_half, self._height - 30),
 73        )
 74        ba.textwidget(
 75            parent=self._root_widget,
 76            text=t_price,
 77            flatness=1.0,
 78            shadow=1.0,
 79            color=(0.2, 1.0, 0.2),
 80            size=(0, 0),
 81            position=(
 82                self._width * 0.5 - width_total_half + t_left_width,
 83                self._height - 30,
 84            ),
 85            h_align='left',
 86            v_align='center',
 87        )
 88        ba.textwidget(
 89            parent=self._root_widget,
 90            text=t_right,
 91            flatness=1.0,
 92            shadow=1.0,
 93            size=(0, 0),
 94            h_align='left',
 95            v_align='center',
 96            position=(
 97                self._width * 0.5
 98                - width_total_half
 99                + t_left_width
100                + t_price_width
101                + 5,
102                self._height - 30,
103            ),
104        )
105
106        self._tickets_text_base: str | None
107        self._tickets_text: ba.Widget | None
108        if not ba.app.ui.use_toolbars:
109            self._tickets_text_base = ba.Lstr(
110                resource='getTicketsWindow.youHaveShortText',
111                fallback_resource='getTicketsWindow.youHaveText',
112            ).evaluate()
113            self._tickets_text = ba.textwidget(
114                parent=self._root_widget,
115                text='',
116                flatness=1.0,
117                color=(0.2, 1.0, 0.2),
118                shadow=1.0,
119                position=(
120                    self._width * 0.5 + width_total_half,
121                    self._height - 50,
122                ),
123                size=(0, 0),
124                scale=0.35,
125                h_align='right',
126                v_align='center',
127            )
128        else:
129            self._tickets_text_base = None
130            self._tickets_text = None
131
132        self._counter_text = ba.textwidget(
133            parent=self._root_widget,
134            text=str(self._count),
135            color=(0.7, 0.7, 0.7),
136            scale=1.2,
137            size=(0, 0),
138            big=True,
139            position=(self._width * 0.5, self._height - 80),
140            flatness=1.0,
141            shadow=1.0,
142            h_align='center',
143            v_align='center',
144        )
145        self._cancel_button = ba.buttonwidget(
146            parent=self._root_widget,
147            position=(30, 30),
148            size=(120, 50),
149            label=ba.Lstr(resource='endText', fallback_resource='cancelText'),
150            autoselect=True,
151            enable_sound=False,
152            on_activate_call=self._on_cancel_press,
153        )
154        self._continue_button = ba.buttonwidget(
155            parent=self._root_widget,
156            label=ba.Lstr(resource='continueText'),
157            autoselect=True,
158            position=(self._width - 130, 30),
159            size=(120, 50),
160            on_activate_call=self._on_continue_press,
161        )
162        ba.containerwidget(
163            edit=self._root_widget,
164            cancel_button=self._cancel_button,
165            start_button=self._continue_button,
166            selected_child=self._cancel_button,
167        )
168
169        self._counting_down = True
170        self._countdown_timer = ba.Timer(
171            1.0, ba.WeakCall(self._tick), repeat=True, timetype=ba.TimeType.REAL
172        )
173
174        # If there is foreground activity, suspend it.
175        ba.app.pause()
176        self._tick()
Inherited Members
ba.ui.Window
get_root_widget