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