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()