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