bauiv1lib.coop.gamebutton

Defines button for co-op games.

  1# Released under the MIT License. See LICENSE for details.
  2#
  3"""Defines button for co-op games."""
  4
  5from __future__ import annotations
  6
  7import random
  8from typing import TYPE_CHECKING
  9
 10import bauiv1 as bui
 11
 12if TYPE_CHECKING:
 13    from bauiv1lib.coop.browser import CoopBrowserWindow
 14
 15
 16class GameButton:
 17    """Button for entering co-op games."""
 18
 19    def __init__(
 20        self,
 21        window: CoopBrowserWindow,
 22        parent: bui.Widget,
 23        game: str,
 24        x: float,
 25        y: float,
 26        select: bool,
 27        row: str,
 28    ):
 29        # pylint: disable=too-many-statements
 30        # pylint: disable=too-many-locals
 31
 32        assert bui.app.classic is not None
 33        self._game = game
 34        sclx = 195.0
 35        scly = 195.0
 36
 37        campaignname, levelname = game.split(':')
 38
 39        # Hack: The Last Stand doesn't actually exist in the easy
 40        # tourney. We just want it for display purposes. Map it to
 41        # the hard-mode version.
 42        if game == 'Easy:The Last Stand':
 43            campaignname = 'Default'
 44
 45        rating: float | None
 46        campaign = bui.app.classic.getcampaign(campaignname)
 47        rating = campaign.getlevel(levelname).rating
 48
 49        if game == 'Easy:The Last Stand':
 50            rating = None
 51
 52        if rating is None or rating == 0.0:
 53            stars = 0
 54        elif rating >= 9.5:
 55            stars = 3
 56        elif rating >= 7.5:
 57            stars = 2
 58        else:
 59            stars = 1
 60
 61        self._button = btn = bui.buttonwidget(
 62            parent=parent,
 63            position=(x + 23, y + 4),
 64            size=(sclx, scly),
 65            label='',
 66            on_activate_call=bui.Call(window.run_game, game),
 67            button_type='square',
 68            autoselect=True,
 69            on_select_call=bui.Call(window.sel_change, row, game),
 70        )
 71        bui.widget(
 72            edit=btn,
 73            show_buffer_bottom=50,
 74            show_buffer_top=50,
 75            show_buffer_left=400,
 76            show_buffer_right=200,
 77        )
 78        if select:
 79            bui.containerwidget(
 80                edit=parent, selected_child=btn, visible_child=btn
 81            )
 82        image_width = sclx * 0.85 * 0.75
 83        self._preview_widget = bui.imagewidget(
 84            parent=parent,
 85            draw_controller=btn,
 86            position=(x + 21 + sclx * 0.5 - image_width * 0.5, y + scly - 104),
 87            size=(image_width, image_width * 0.5),
 88            mesh_transparent=window.lsbt,
 89            mesh_opaque=window.lsbo,
 90            texture=bui.gettexture(
 91                campaign.getlevel(levelname).preview_texture_name
 92            ),
 93            mask_texture=bui.gettexture('mapPreviewMask'),
 94        )
 95
 96        translated = campaign.getlevel(levelname).displayname
 97        self._achievements = bui.app.classic.ach.achievements_for_coop_level(
 98            game
 99        )
100
101        self._name_widget = bui.textwidget(
102            parent=parent,
103            draw_controller=btn,
104            position=(x + 20 + sclx * 0.5, y + scly - 27),
105            size=(0, 0),
106            h_align='center',
107            text=translated,
108            v_align='center',
109            maxwidth=sclx * 0.76,
110            scale=0.85,
111        )
112        xscl = x + (67 if self._achievements else 50)
113        yscl = y + scly - (137 if self._achievements else 157)
114
115        starscale = 35.0 if self._achievements else 45.0
116
117        self._star_widgets: list[bui.Widget] = []
118        for _i in range(stars):
119            imw = bui.imagewidget(
120                parent=parent,
121                draw_controller=btn,
122                position=(xscl, yscl),
123                size=(starscale, starscale),
124                texture=window.star_tex,
125            )
126            self._star_widgets.append(imw)
127            xscl += starscale
128        for _i in range(3 - stars):
129            bui.imagewidget(
130                parent=parent,
131                draw_controller=btn,
132                position=(xscl, yscl),
133                size=(starscale, starscale),
134                color=(0, 0, 0),
135                texture=window.star_tex,
136                opacity=0.3,
137            )
138            xscl += starscale
139
140        xach = x + 69
141        yach = y + scly - 168
142        a_scale = 30.0
143        self._achievement_widgets: list[tuple[bui.Widget, bui.Widget]] = []
144        for ach in self._achievements:
145            a_complete = ach.complete
146            imw = bui.imagewidget(
147                parent=parent,
148                draw_controller=btn,
149                position=(xach, yach),
150                size=(a_scale, a_scale),
151                color=(
152                    tuple(ach.get_icon_color(a_complete)[:3])
153                    if a_complete
154                    else (1.2, 1.2, 1.2)
155                ),
156                texture=ach.get_icon_ui_texture(a_complete),
157            )
158            imw2 = bui.imagewidget(
159                parent=parent,
160                draw_controller=btn,
161                position=(xach, yach),
162                size=(a_scale, a_scale),
163                color=(2, 1.4, 0.4),
164                texture=window.a_outline_tex,
165                mesh_transparent=window.a_outline_mesh,
166            )
167            self._achievement_widgets.append((imw, imw2))
168            # if a_complete:
169            xach += a_scale * 1.2
170
171        # if not unlocked:
172        self._lock_widget = bui.imagewidget(
173            parent=parent,
174            draw_controller=btn,
175            position=(x - 8 + sclx * 0.5, y + scly * 0.5 - 20),
176            size=(60, 60),
177            opacity=0.0,
178            texture=bui.gettexture('lock'),
179        )
180
181        # give a quasi-random update increment to spread the load..
182        self._update_timer = bui.AppTimer(
183            0.001 * (900 + random.randrange(200)),
184            bui.WeakCall(self._update),
185            repeat=True,
186        )
187        self._update()
188
189    def get_button(self) -> bui.Widget:
190        """Return the underlying button bui.Widget."""
191        return self._button
192
193    def _update(self) -> None:
194        # pylint: disable=too-many-boolean-expressions
195
196        plus = bui.app.plus
197        assert plus is not None
198
199        classic = bui.app.classic
200        assert classic is not None
201
202        # In case we stick around after our UI...
203        if not self._button:
204            return
205
206        game = self._game
207        campaignname, levelname = game.split(':')
208
209        # Hack - The Last Stand doesn't actually exist in the
210        # easy tourney; we just want it for display purposes. Map it to
211        # the hard-mode version.
212        if game == 'Easy:The Last Stand':
213            campaignname = 'Default'
214
215        campaign = classic.getcampaign(campaignname)
216
217        # If this campaign is sequential, make sure we've unlocked
218        # everything up to here.
219        unlocked = True
220        if campaign.sequential:
221            for level in campaign.levels:
222                if level.name == levelname:
223                    break
224                if not level.complete:
225                    unlocked = False
226                    break
227
228        # We never actually allow playing last-stand on easy mode.
229        if game == 'Easy:The Last Stand':
230            unlocked = False
231
232        # Hard-code games we haven't unlocked.
233        assert bui.app.classic is not None
234        if (
235            (
236                game
237                in (
238                    'Challenges:Infinite Runaround',
239                    'Challenges:Infinite Onslaught',
240                )
241                and not bui.app.classic.accounts.have_pro()
242            )
243            or (
244                game in ('Challenges:Meteor Shower',)
245                and not plus.get_purchased('games.meteor_shower')
246            )
247            or (
248                game
249                in (
250                    'Challenges:Target Practice',
251                    'Challenges:Target Practice B',
252                )
253                and not plus.get_purchased('games.target_practice')
254            )
255            or (
256                game in ('Challenges:Ninja Fight',)
257                and not plus.get_purchased('games.ninja_fight')
258            )
259            or (
260                game in ('Challenges:Pro Ninja Fight',)
261                and not plus.get_purchased('games.ninja_fight')
262            )
263            or (
264                game
265                in (
266                    'Challenges:Easter Egg Hunt',
267                    'Challenges:Pro Easter Egg Hunt',
268                )
269                and not plus.get_purchased('games.easter_egg_hunt')
270            )
271        ):
272            unlocked = False
273
274        # Let's tint levels a slightly different color when easy mode
275        # is selected.
276        unlocked_color = (
277            (0.85, 0.95, 0.5) if game.startswith('Easy:') else (0.5, 0.7, 0.2)
278        )
279
280        bui.buttonwidget(
281            edit=self._button,
282            color=unlocked_color if unlocked else (0.5, 0.5, 0.5),
283        )
284
285        bui.imagewidget(
286            edit=self._lock_widget, opacity=0.0 if unlocked else 1.0
287        )
288        bui.imagewidget(
289            edit=self._preview_widget, opacity=1.0 if unlocked else 0.3
290        )
291        bui.textwidget(
292            edit=self._name_widget,
293            color=(0.8, 1.0, 0.8, 1.0) if unlocked else (0.7, 0.7, 0.7, 0.7),
294        )
295        for widget in self._star_widgets:
296            bui.imagewidget(
297                edit=widget,
298                opacity=1.0 if unlocked else 0.3,
299                color=(2.2, 1.2, 0.3) if unlocked else (1, 1, 1),
300            )
301        for i, ach in enumerate(self._achievements):
302            a_complete = ach.complete
303            bui.imagewidget(
304                edit=self._achievement_widgets[i][0],
305                opacity=1.0 if (a_complete and unlocked) else 0.3,
306            )
307            bui.imagewidget(
308                edit=self._achievement_widgets[i][1],
309                opacity=(
310                    1.0
311                    if (a_complete and unlocked)
312                    else 0.2 if a_complete else 0.0
313                ),
314            )
class GameButton:
 17class GameButton:
 18    """Button for entering co-op games."""
 19
 20    def __init__(
 21        self,
 22        window: CoopBrowserWindow,
 23        parent: bui.Widget,
 24        game: str,
 25        x: float,
 26        y: float,
 27        select: bool,
 28        row: str,
 29    ):
 30        # pylint: disable=too-many-statements
 31        # pylint: disable=too-many-locals
 32
 33        assert bui.app.classic is not None
 34        self._game = game
 35        sclx = 195.0
 36        scly = 195.0
 37
 38        campaignname, levelname = game.split(':')
 39
 40        # Hack: The Last Stand doesn't actually exist in the easy
 41        # tourney. We just want it for display purposes. Map it to
 42        # the hard-mode version.
 43        if game == 'Easy:The Last Stand':
 44            campaignname = 'Default'
 45
 46        rating: float | None
 47        campaign = bui.app.classic.getcampaign(campaignname)
 48        rating = campaign.getlevel(levelname).rating
 49
 50        if game == 'Easy:The Last Stand':
 51            rating = None
 52
 53        if rating is None or rating == 0.0:
 54            stars = 0
 55        elif rating >= 9.5:
 56            stars = 3
 57        elif rating >= 7.5:
 58            stars = 2
 59        else:
 60            stars = 1
 61
 62        self._button = btn = bui.buttonwidget(
 63            parent=parent,
 64            position=(x + 23, y + 4),
 65            size=(sclx, scly),
 66            label='',
 67            on_activate_call=bui.Call(window.run_game, game),
 68            button_type='square',
 69            autoselect=True,
 70            on_select_call=bui.Call(window.sel_change, row, game),
 71        )
 72        bui.widget(
 73            edit=btn,
 74            show_buffer_bottom=50,
 75            show_buffer_top=50,
 76            show_buffer_left=400,
 77            show_buffer_right=200,
 78        )
 79        if select:
 80            bui.containerwidget(
 81                edit=parent, selected_child=btn, visible_child=btn
 82            )
 83        image_width = sclx * 0.85 * 0.75
 84        self._preview_widget = bui.imagewidget(
 85            parent=parent,
 86            draw_controller=btn,
 87            position=(x + 21 + sclx * 0.5 - image_width * 0.5, y + scly - 104),
 88            size=(image_width, image_width * 0.5),
 89            mesh_transparent=window.lsbt,
 90            mesh_opaque=window.lsbo,
 91            texture=bui.gettexture(
 92                campaign.getlevel(levelname).preview_texture_name
 93            ),
 94            mask_texture=bui.gettexture('mapPreviewMask'),
 95        )
 96
 97        translated = campaign.getlevel(levelname).displayname
 98        self._achievements = bui.app.classic.ach.achievements_for_coop_level(
 99            game
100        )
101
102        self._name_widget = bui.textwidget(
103            parent=parent,
104            draw_controller=btn,
105            position=(x + 20 + sclx * 0.5, y + scly - 27),
106            size=(0, 0),
107            h_align='center',
108            text=translated,
109            v_align='center',
110            maxwidth=sclx * 0.76,
111            scale=0.85,
112        )
113        xscl = x + (67 if self._achievements else 50)
114        yscl = y + scly - (137 if self._achievements else 157)
115
116        starscale = 35.0 if self._achievements else 45.0
117
118        self._star_widgets: list[bui.Widget] = []
119        for _i in range(stars):
120            imw = bui.imagewidget(
121                parent=parent,
122                draw_controller=btn,
123                position=(xscl, yscl),
124                size=(starscale, starscale),
125                texture=window.star_tex,
126            )
127            self._star_widgets.append(imw)
128            xscl += starscale
129        for _i in range(3 - stars):
130            bui.imagewidget(
131                parent=parent,
132                draw_controller=btn,
133                position=(xscl, yscl),
134                size=(starscale, starscale),
135                color=(0, 0, 0),
136                texture=window.star_tex,
137                opacity=0.3,
138            )
139            xscl += starscale
140
141        xach = x + 69
142        yach = y + scly - 168
143        a_scale = 30.0
144        self._achievement_widgets: list[tuple[bui.Widget, bui.Widget]] = []
145        for ach in self._achievements:
146            a_complete = ach.complete
147            imw = bui.imagewidget(
148                parent=parent,
149                draw_controller=btn,
150                position=(xach, yach),
151                size=(a_scale, a_scale),
152                color=(
153                    tuple(ach.get_icon_color(a_complete)[:3])
154                    if a_complete
155                    else (1.2, 1.2, 1.2)
156                ),
157                texture=ach.get_icon_ui_texture(a_complete),
158            )
159            imw2 = bui.imagewidget(
160                parent=parent,
161                draw_controller=btn,
162                position=(xach, yach),
163                size=(a_scale, a_scale),
164                color=(2, 1.4, 0.4),
165                texture=window.a_outline_tex,
166                mesh_transparent=window.a_outline_mesh,
167            )
168            self._achievement_widgets.append((imw, imw2))
169            # if a_complete:
170            xach += a_scale * 1.2
171
172        # if not unlocked:
173        self._lock_widget = bui.imagewidget(
174            parent=parent,
175            draw_controller=btn,
176            position=(x - 8 + sclx * 0.5, y + scly * 0.5 - 20),
177            size=(60, 60),
178            opacity=0.0,
179            texture=bui.gettexture('lock'),
180        )
181
182        # give a quasi-random update increment to spread the load..
183        self._update_timer = bui.AppTimer(
184            0.001 * (900 + random.randrange(200)),
185            bui.WeakCall(self._update),
186            repeat=True,
187        )
188        self._update()
189
190    def get_button(self) -> bui.Widget:
191        """Return the underlying button bui.Widget."""
192        return self._button
193
194    def _update(self) -> None:
195        # pylint: disable=too-many-boolean-expressions
196
197        plus = bui.app.plus
198        assert plus is not None
199
200        classic = bui.app.classic
201        assert classic is not None
202
203        # In case we stick around after our UI...
204        if not self._button:
205            return
206
207        game = self._game
208        campaignname, levelname = game.split(':')
209
210        # Hack - The Last Stand doesn't actually exist in the
211        # easy tourney; we just want it for display purposes. Map it to
212        # the hard-mode version.
213        if game == 'Easy:The Last Stand':
214            campaignname = 'Default'
215
216        campaign = classic.getcampaign(campaignname)
217
218        # If this campaign is sequential, make sure we've unlocked
219        # everything up to here.
220        unlocked = True
221        if campaign.sequential:
222            for level in campaign.levels:
223                if level.name == levelname:
224                    break
225                if not level.complete:
226                    unlocked = False
227                    break
228
229        # We never actually allow playing last-stand on easy mode.
230        if game == 'Easy:The Last Stand':
231            unlocked = False
232
233        # Hard-code games we haven't unlocked.
234        assert bui.app.classic is not None
235        if (
236            (
237                game
238                in (
239                    'Challenges:Infinite Runaround',
240                    'Challenges:Infinite Onslaught',
241                )
242                and not bui.app.classic.accounts.have_pro()
243            )
244            or (
245                game in ('Challenges:Meteor Shower',)
246                and not plus.get_purchased('games.meteor_shower')
247            )
248            or (
249                game
250                in (
251                    'Challenges:Target Practice',
252                    'Challenges:Target Practice B',
253                )
254                and not plus.get_purchased('games.target_practice')
255            )
256            or (
257                game in ('Challenges:Ninja Fight',)
258                and not plus.get_purchased('games.ninja_fight')
259            )
260            or (
261                game in ('Challenges:Pro Ninja Fight',)
262                and not plus.get_purchased('games.ninja_fight')
263            )
264            or (
265                game
266                in (
267                    'Challenges:Easter Egg Hunt',
268                    'Challenges:Pro Easter Egg Hunt',
269                )
270                and not plus.get_purchased('games.easter_egg_hunt')
271            )
272        ):
273            unlocked = False
274
275        # Let's tint levels a slightly different color when easy mode
276        # is selected.
277        unlocked_color = (
278            (0.85, 0.95, 0.5) if game.startswith('Easy:') else (0.5, 0.7, 0.2)
279        )
280
281        bui.buttonwidget(
282            edit=self._button,
283            color=unlocked_color if unlocked else (0.5, 0.5, 0.5),
284        )
285
286        bui.imagewidget(
287            edit=self._lock_widget, opacity=0.0 if unlocked else 1.0
288        )
289        bui.imagewidget(
290            edit=self._preview_widget, opacity=1.0 if unlocked else 0.3
291        )
292        bui.textwidget(
293            edit=self._name_widget,
294            color=(0.8, 1.0, 0.8, 1.0) if unlocked else (0.7, 0.7, 0.7, 0.7),
295        )
296        for widget in self._star_widgets:
297            bui.imagewidget(
298                edit=widget,
299                opacity=1.0 if unlocked else 0.3,
300                color=(2.2, 1.2, 0.3) if unlocked else (1, 1, 1),
301            )
302        for i, ach in enumerate(self._achievements):
303            a_complete = ach.complete
304            bui.imagewidget(
305                edit=self._achievement_widgets[i][0],
306                opacity=1.0 if (a_complete and unlocked) else 0.3,
307            )
308            bui.imagewidget(
309                edit=self._achievement_widgets[i][1],
310                opacity=(
311                    1.0
312                    if (a_complete and unlocked)
313                    else 0.2 if a_complete else 0.0
314                ),
315            )

Button for entering co-op games.

GameButton( window: bauiv1lib.coop.browser.CoopBrowserWindow, parent: _bauiv1.Widget, game: str, x: float, y: float, select: bool, row: str)
 20    def __init__(
 21        self,
 22        window: CoopBrowserWindow,
 23        parent: bui.Widget,
 24        game: str,
 25        x: float,
 26        y: float,
 27        select: bool,
 28        row: str,
 29    ):
 30        # pylint: disable=too-many-statements
 31        # pylint: disable=too-many-locals
 32
 33        assert bui.app.classic is not None
 34        self._game = game
 35        sclx = 195.0
 36        scly = 195.0
 37
 38        campaignname, levelname = game.split(':')
 39
 40        # Hack: The Last Stand doesn't actually exist in the easy
 41        # tourney. We just want it for display purposes. Map it to
 42        # the hard-mode version.
 43        if game == 'Easy:The Last Stand':
 44            campaignname = 'Default'
 45
 46        rating: float | None
 47        campaign = bui.app.classic.getcampaign(campaignname)
 48        rating = campaign.getlevel(levelname).rating
 49
 50        if game == 'Easy:The Last Stand':
 51            rating = None
 52
 53        if rating is None or rating == 0.0:
 54            stars = 0
 55        elif rating >= 9.5:
 56            stars = 3
 57        elif rating >= 7.5:
 58            stars = 2
 59        else:
 60            stars = 1
 61
 62        self._button = btn = bui.buttonwidget(
 63            parent=parent,
 64            position=(x + 23, y + 4),
 65            size=(sclx, scly),
 66            label='',
 67            on_activate_call=bui.Call(window.run_game, game),
 68            button_type='square',
 69            autoselect=True,
 70            on_select_call=bui.Call(window.sel_change, row, game),
 71        )
 72        bui.widget(
 73            edit=btn,
 74            show_buffer_bottom=50,
 75            show_buffer_top=50,
 76            show_buffer_left=400,
 77            show_buffer_right=200,
 78        )
 79        if select:
 80            bui.containerwidget(
 81                edit=parent, selected_child=btn, visible_child=btn
 82            )
 83        image_width = sclx * 0.85 * 0.75
 84        self._preview_widget = bui.imagewidget(
 85            parent=parent,
 86            draw_controller=btn,
 87            position=(x + 21 + sclx * 0.5 - image_width * 0.5, y + scly - 104),
 88            size=(image_width, image_width * 0.5),
 89            mesh_transparent=window.lsbt,
 90            mesh_opaque=window.lsbo,
 91            texture=bui.gettexture(
 92                campaign.getlevel(levelname).preview_texture_name
 93            ),
 94            mask_texture=bui.gettexture('mapPreviewMask'),
 95        )
 96
 97        translated = campaign.getlevel(levelname).displayname
 98        self._achievements = bui.app.classic.ach.achievements_for_coop_level(
 99            game
100        )
101
102        self._name_widget = bui.textwidget(
103            parent=parent,
104            draw_controller=btn,
105            position=(x + 20 + sclx * 0.5, y + scly - 27),
106            size=(0, 0),
107            h_align='center',
108            text=translated,
109            v_align='center',
110            maxwidth=sclx * 0.76,
111            scale=0.85,
112        )
113        xscl = x + (67 if self._achievements else 50)
114        yscl = y + scly - (137 if self._achievements else 157)
115
116        starscale = 35.0 if self._achievements else 45.0
117
118        self._star_widgets: list[bui.Widget] = []
119        for _i in range(stars):
120            imw = bui.imagewidget(
121                parent=parent,
122                draw_controller=btn,
123                position=(xscl, yscl),
124                size=(starscale, starscale),
125                texture=window.star_tex,
126            )
127            self._star_widgets.append(imw)
128            xscl += starscale
129        for _i in range(3 - stars):
130            bui.imagewidget(
131                parent=parent,
132                draw_controller=btn,
133                position=(xscl, yscl),
134                size=(starscale, starscale),
135                color=(0, 0, 0),
136                texture=window.star_tex,
137                opacity=0.3,
138            )
139            xscl += starscale
140
141        xach = x + 69
142        yach = y + scly - 168
143        a_scale = 30.0
144        self._achievement_widgets: list[tuple[bui.Widget, bui.Widget]] = []
145        for ach in self._achievements:
146            a_complete = ach.complete
147            imw = bui.imagewidget(
148                parent=parent,
149                draw_controller=btn,
150                position=(xach, yach),
151                size=(a_scale, a_scale),
152                color=(
153                    tuple(ach.get_icon_color(a_complete)[:3])
154                    if a_complete
155                    else (1.2, 1.2, 1.2)
156                ),
157                texture=ach.get_icon_ui_texture(a_complete),
158            )
159            imw2 = bui.imagewidget(
160                parent=parent,
161                draw_controller=btn,
162                position=(xach, yach),
163                size=(a_scale, a_scale),
164                color=(2, 1.4, 0.4),
165                texture=window.a_outline_tex,
166                mesh_transparent=window.a_outline_mesh,
167            )
168            self._achievement_widgets.append((imw, imw2))
169            # if a_complete:
170            xach += a_scale * 1.2
171
172        # if not unlocked:
173        self._lock_widget = bui.imagewidget(
174            parent=parent,
175            draw_controller=btn,
176            position=(x - 8 + sclx * 0.5, y + scly * 0.5 - 20),
177            size=(60, 60),
178            opacity=0.0,
179            texture=bui.gettexture('lock'),
180        )
181
182        # give a quasi-random update increment to spread the load..
183        self._update_timer = bui.AppTimer(
184            0.001 * (900 + random.randrange(200)),
185            bui.WeakCall(self._update),
186            repeat=True,
187        )
188        self._update()
def get_button(self) -> _bauiv1.Widget:
190    def get_button(self) -> bui.Widget:
191        """Return the underlying button bui.Widget."""
192        return self._button

Return the underlying button bui.Widget.