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=tuple(ach.get_icon_color(a_complete)[:3])
152                if a_complete
153                else (1.2, 1.2, 1.2),
154                texture=ach.get_icon_ui_texture(a_complete),
155            )
156            imw2 = bui.imagewidget(
157                parent=parent,
158                draw_controller=btn,
159                position=(xach, yach),
160                size=(a_scale, a_scale),
161                color=(2, 1.4, 0.4),
162                texture=window.a_outline_tex,
163                mesh_transparent=window.a_outline_mesh,
164            )
165            self._achievement_widgets.append((imw, imw2))
166            # if a_complete:
167            xach += a_scale * 1.2
168
169        # if not unlocked:
170        self._lock_widget = bui.imagewidget(
171            parent=parent,
172            draw_controller=btn,
173            position=(x - 8 + sclx * 0.5, y + scly * 0.5 - 20),
174            size=(60, 60),
175            opacity=0.0,
176            texture=bui.gettexture('lock'),
177        )
178
179        # give a quasi-random update increment to spread the load..
180        self._update_timer = bui.AppTimer(
181            0.001 * (900 + random.randrange(200)),
182            bui.WeakCall(self._update),
183            repeat=True,
184        )
185        self._update()
186
187    def get_button(self) -> bui.Widget:
188        """Return the underlying button bui.Widget."""
189        return self._button
190
191    def _update(self) -> None:
192        # pylint: disable=too-many-boolean-expressions
193
194        plus = bui.app.plus
195        assert plus is not None
196
197        classic = bui.app.classic
198        assert classic is not None
199
200        # In case we stick around after our UI...
201        if not self._button:
202            return
203
204        game = self._game
205        campaignname, levelname = game.split(':')
206
207        # Hack - The Last Stand doesn't actually exist in the
208        # easy tourney; we just want it for display purposes. Map it to
209        # the hard-mode version.
210        if game == 'Easy:The Last Stand':
211            campaignname = 'Default'
212
213        campaign = classic.getcampaign(campaignname)
214
215        # If this campaign is sequential, make sure we've unlocked
216        # everything up to here.
217        unlocked = True
218        if campaign.sequential:
219            for level in campaign.levels:
220                if level.name == levelname:
221                    break
222                if not level.complete:
223                    unlocked = False
224                    break
225
226        # We never actually allow playing last-stand on easy mode.
227        if game == 'Easy:The Last Stand':
228            unlocked = False
229
230        # Hard-code games we haven't unlocked.
231        assert bui.app.classic is not None
232        if (
233            (
234                game
235                in (
236                    'Challenges:Infinite Runaround',
237                    'Challenges:Infinite Onslaught',
238                )
239                and not bui.app.classic.accounts.have_pro()
240            )
241            or (
242                game in ('Challenges:Meteor Shower',)
243                and not plus.get_purchased('games.meteor_shower')
244            )
245            or (
246                game
247                in (
248                    'Challenges:Target Practice',
249                    'Challenges:Target Practice B',
250                )
251                and not plus.get_purchased('games.target_practice')
252            )
253            or (
254                game in ('Challenges:Ninja Fight',)
255                and not plus.get_purchased('games.ninja_fight')
256            )
257            or (
258                game in ('Challenges:Pro Ninja Fight',)
259                and not plus.get_purchased('games.ninja_fight')
260            )
261            or (
262                game
263                in (
264                    'Challenges:Easter Egg Hunt',
265                    'Challenges:Pro Easter Egg Hunt',
266                )
267                and not plus.get_purchased('games.easter_egg_hunt')
268            )
269        ):
270            unlocked = False
271
272        # Let's tint levels a slightly different color when easy mode
273        # is selected.
274        unlocked_color = (
275            (0.85, 0.95, 0.5) if game.startswith('Easy:') else (0.5, 0.7, 0.2)
276        )
277
278        bui.buttonwidget(
279            edit=self._button,
280            color=unlocked_color if unlocked else (0.5, 0.5, 0.5),
281        )
282
283        bui.imagewidget(
284            edit=self._lock_widget, opacity=0.0 if unlocked else 1.0
285        )
286        bui.imagewidget(
287            edit=self._preview_widget, opacity=1.0 if unlocked else 0.3
288        )
289        bui.textwidget(
290            edit=self._name_widget,
291            color=(0.8, 1.0, 0.8, 1.0) if unlocked else (0.7, 0.7, 0.7, 0.7),
292        )
293        for widget in self._star_widgets:
294            bui.imagewidget(
295                edit=widget,
296                opacity=1.0 if unlocked else 0.3,
297                color=(2.2, 1.2, 0.3) if unlocked else (1, 1, 1),
298            )
299        for i, ach in enumerate(self._achievements):
300            a_complete = ach.complete
301            bui.imagewidget(
302                edit=self._achievement_widgets[i][0],
303                opacity=1.0 if (a_complete and unlocked) else 0.3,
304            )
305            bui.imagewidget(
306                edit=self._achievement_widgets[i][1],
307                opacity=(
308                    1.0
309                    if (a_complete and unlocked)
310                    else 0.2
311                    if a_complete
312                    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=tuple(ach.get_icon_color(a_complete)[:3])
153                if a_complete
154                else (1.2, 1.2, 1.2),
155                texture=ach.get_icon_ui_texture(a_complete),
156            )
157            imw2 = bui.imagewidget(
158                parent=parent,
159                draw_controller=btn,
160                position=(xach, yach),
161                size=(a_scale, a_scale),
162                color=(2, 1.4, 0.4),
163                texture=window.a_outline_tex,
164                mesh_transparent=window.a_outline_mesh,
165            )
166            self._achievement_widgets.append((imw, imw2))
167            # if a_complete:
168            xach += a_scale * 1.2
169
170        # if not unlocked:
171        self._lock_widget = bui.imagewidget(
172            parent=parent,
173            draw_controller=btn,
174            position=(x - 8 + sclx * 0.5, y + scly * 0.5 - 20),
175            size=(60, 60),
176            opacity=0.0,
177            texture=bui.gettexture('lock'),
178        )
179
180        # give a quasi-random update increment to spread the load..
181        self._update_timer = bui.AppTimer(
182            0.001 * (900 + random.randrange(200)),
183            bui.WeakCall(self._update),
184            repeat=True,
185        )
186        self._update()
187
188    def get_button(self) -> bui.Widget:
189        """Return the underlying button bui.Widget."""
190        return self._button
191
192    def _update(self) -> None:
193        # pylint: disable=too-many-boolean-expressions
194
195        plus = bui.app.plus
196        assert plus is not None
197
198        classic = bui.app.classic
199        assert classic is not None
200
201        # In case we stick around after our UI...
202        if not self._button:
203            return
204
205        game = self._game
206        campaignname, levelname = game.split(':')
207
208        # Hack - The Last Stand doesn't actually exist in the
209        # easy tourney; we just want it for display purposes. Map it to
210        # the hard-mode version.
211        if game == 'Easy:The Last Stand':
212            campaignname = 'Default'
213
214        campaign = classic.getcampaign(campaignname)
215
216        # If this campaign is sequential, make sure we've unlocked
217        # everything up to here.
218        unlocked = True
219        if campaign.sequential:
220            for level in campaign.levels:
221                if level.name == levelname:
222                    break
223                if not level.complete:
224                    unlocked = False
225                    break
226
227        # We never actually allow playing last-stand on easy mode.
228        if game == 'Easy:The Last Stand':
229            unlocked = False
230
231        # Hard-code games we haven't unlocked.
232        assert bui.app.classic is not None
233        if (
234            (
235                game
236                in (
237                    'Challenges:Infinite Runaround',
238                    'Challenges:Infinite Onslaught',
239                )
240                and not bui.app.classic.accounts.have_pro()
241            )
242            or (
243                game in ('Challenges:Meteor Shower',)
244                and not plus.get_purchased('games.meteor_shower')
245            )
246            or (
247                game
248                in (
249                    'Challenges:Target Practice',
250                    'Challenges:Target Practice B',
251                )
252                and not plus.get_purchased('games.target_practice')
253            )
254            or (
255                game in ('Challenges:Ninja Fight',)
256                and not plus.get_purchased('games.ninja_fight')
257            )
258            or (
259                game in ('Challenges:Pro Ninja Fight',)
260                and not plus.get_purchased('games.ninja_fight')
261            )
262            or (
263                game
264                in (
265                    'Challenges:Easter Egg Hunt',
266                    'Challenges:Pro Easter Egg Hunt',
267                )
268                and not plus.get_purchased('games.easter_egg_hunt')
269            )
270        ):
271            unlocked = False
272
273        # Let's tint levels a slightly different color when easy mode
274        # is selected.
275        unlocked_color = (
276            (0.85, 0.95, 0.5) if game.startswith('Easy:') else (0.5, 0.7, 0.2)
277        )
278
279        bui.buttonwidget(
280            edit=self._button,
281            color=unlocked_color if unlocked else (0.5, 0.5, 0.5),
282        )
283
284        bui.imagewidget(
285            edit=self._lock_widget, opacity=0.0 if unlocked else 1.0
286        )
287        bui.imagewidget(
288            edit=self._preview_widget, opacity=1.0 if unlocked else 0.3
289        )
290        bui.textwidget(
291            edit=self._name_widget,
292            color=(0.8, 1.0, 0.8, 1.0) if unlocked else (0.7, 0.7, 0.7, 0.7),
293        )
294        for widget in self._star_widgets:
295            bui.imagewidget(
296                edit=widget,
297                opacity=1.0 if unlocked else 0.3,
298                color=(2.2, 1.2, 0.3) if unlocked else (1, 1, 1),
299            )
300        for i, ach in enumerate(self._achievements):
301            a_complete = ach.complete
302            bui.imagewidget(
303                edit=self._achievement_widgets[i][0],
304                opacity=1.0 if (a_complete and unlocked) else 0.3,
305            )
306            bui.imagewidget(
307                edit=self._achievement_widgets[i][1],
308                opacity=(
309                    1.0
310                    if (a_complete and unlocked)
311                    else 0.2
312                    if a_complete
313                    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=tuple(ach.get_icon_color(a_complete)[:3])
153                if a_complete
154                else (1.2, 1.2, 1.2),
155                texture=ach.get_icon_ui_texture(a_complete),
156            )
157            imw2 = bui.imagewidget(
158                parent=parent,
159                draw_controller=btn,
160                position=(xach, yach),
161                size=(a_scale, a_scale),
162                color=(2, 1.4, 0.4),
163                texture=window.a_outline_tex,
164                mesh_transparent=window.a_outline_mesh,
165            )
166            self._achievement_widgets.append((imw, imw2))
167            # if a_complete:
168            xach += a_scale * 1.2
169
170        # if not unlocked:
171        self._lock_widget = bui.imagewidget(
172            parent=parent,
173            draw_controller=btn,
174            position=(x - 8 + sclx * 0.5, y + scly * 0.5 - 20),
175            size=(60, 60),
176            opacity=0.0,
177            texture=bui.gettexture('lock'),
178        )
179
180        # give a quasi-random update increment to spread the load..
181        self._update_timer = bui.AppTimer(
182            0.001 * (900 + random.randrange(200)),
183            bui.WeakCall(self._update),
184            repeat=True,
185        )
186        self._update()
def get_button(self) -> _bauiv1.Widget:
188    def get_button(self) -> bui.Widget:
189        """Return the underlying button bui.Widget."""
190        return self._button

Return the underlying button bui.Widget.