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

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

Return the underlying button bui.Widget.