def on_transition_in(self) -> None: from bastd.actor.controlsguide import ControlsGuide from ba import DualTeamSession super().on_transition_in() ControlsGuide(delay=1.0).autoretain() session = self.session assert isinstance(session, ba.MultiTeamSession) # Show info about the next up game. self._next_up_text = Text(ba.Lstr( value='${1} ${2}', subs=[('${1}', ba.Lstr(resource='upFirstText')), ('${2}', session.get_next_game_description())]), h_attach=Text.HAttach.CENTER, scale=0.7, v_attach=Text.VAttach.TOP, h_align=Text.HAlign.CENTER, position=(0, -70), flash=False, color=(0.5, 0.5, 0.5, 1.0), transition=Text.Transition.FADE_IN, transition_delay=5.0) # In teams mode, show our two team names. # FIXME: Lobby should handle this. if isinstance(ba.getsession(), DualTeamSession): team_names = [team.name for team in ba.getsession().sessionteams] team_colors = [ tuple(team.color) + (0.5, ) for team in ba.getsession().sessionteams ] if len(team_names) == 2: for i in range(2): Text(team_names[i], scale=0.7, h_attach=Text.HAttach.CENTER, v_attach=Text.VAttach.TOP, h_align=Text.HAlign.CENTER, position=(-200 + 350 * i, -100), color=team_colors[i], transition=Text.Transition.FADE_IN).autoretain() Text(ba.Lstr(resource='mustInviteFriendsText', subs=[('${GATHER}', ba.Lstr(resource='gatherWindow.titleText'))]), h_attach=Text.HAttach.CENTER, scale=0.8, host_only=True, v_attach=Text.VAttach.CENTER, h_align=Text.HAlign.CENTER, position=(0, 0), flash=False, color=(0, 1, 0, 1.0), transition=Text.Transition.FADE_IN, transition_delay=2.0, transition_out_delay=7.0).autoretain()
def _get_context(self, player: ba.Player) -> Tuple[bool, float, Dict]: """Return info on where we should be shown and stored.""" activity = ba.getactivity() if isinstance(ba.getsession(), ba.DualTeamSession): on_right = player.team.id % 2 == 1 # Store a list of icons in the team. icons = player.team.gamedata.get('_spaz_respawn_icons') if icons is None: player.team.gamedata['_spaz_respawn_icons'] = icons = {} assert isinstance(icons, dict) offs_extra = -20 else: on_right = False # Store a list of icons in the activity. icons = activity.gamedata.get('_spaz_respawn_icons') if icons is None: activity.gamedata['_spaz_respawn_icons'] = icons = {} assert isinstance(icons, dict) if isinstance(activity.session, ba.FreeForAllSession): offs_extra = -150 else: offs_extra = -20 return on_right, offs_extra, icons
def __init__(self, label: ba.Lstr = None, score_split: float = 0.7): """Instantiate a scoreboard. Label can be something like 'points' and will show up on boards if provided. """ self._flat_tex = ba.gettexture('null') self._entries: Dict[int, _Entry] = {} self._label = label self.score_split = score_split # For free-for-all we go simpler since we have one per player. self._pos: Sequence[float] if isinstance(ba.getsession(), ba.FreeForAllSession): self._do_cover = False self._spacing = 35.0 self._pos = (17.0, -65.0) self._scale = 0.8 self._flash_length = 0.5 else: self._do_cover = True self._spacing = 50.0 self._pos = (20.0, -70.0) self._scale = 1.0 self._flash_length = 1.0
def _get_context(self, player: ba.Player) -> Tuple[bool, float, Dict]: """Return info on where we should be shown and stored.""" activity = ba.getactivity() if isinstance(ba.getsession(), ba.DualTeamSession): on_right = player.team.get_id() % 2 == 1 # Store a list of icons in the team. try: respawn_icons = ( player.team.gamedata['_spaz_respawn_icons_right']) except Exception: respawn_icons = ( player.team.gamedata['_spaz_respawn_icons_right']) = {} offs_extra = -20 else: on_right = False # Store a list of icons in the activity. # FIXME: Need an elegant way to store our shared stuff with # the activity. try: respawn_icons = activity.spaz_respawn_icons_right except Exception: respawn_icons = activity.spaz_respawn_icons_right = {} if isinstance(activity.session, ba.FreeForAllSession): offs_extra = -150 else: offs_extra = -20 return on_right, offs_extra, respawn_icons
def __init__(self, settings: Dict[str, Any]): super().__init__(settings) session = ba.getsession() # Let's show a list of scores-to-beat for 1 player at least. assert session.campaign is not None level_name_full = (session.campaign.name + ':' + session.campaign_state['level']) config_str = ( '1p' + session.campaign.get_level(session.campaign_state['level']). get_score_version_string().replace(' ', '_')) _ba.get_scores_to_beat(level_name_full, config_str, ba.WeakCall(self._on_got_scores_to_beat))
def _check_fade_in(self) -> None: from ba.internal import get_device_value # If we have a touchscreen, we only fade in if we have a player with # an input device that is *not* the touchscreen. # (otherwise it is confusing to see the touchscreen buttons right # next to our display buttons) touchscreen: Optional[ba.InputDevice] = _ba.getinputdevice( 'TouchScreen', '#1', doraise=False) if touchscreen is not None: # We look at the session's players; not the activity's. # We want to get ones who are still in the process of # selecting a character, etc. input_devices = [ p.inputdevice for p in ba.getsession().sessionplayers ] input_devices = [ i for i in input_devices if i and i is not touchscreen ] fade_in = False if input_devices: # Only count this one if it has non-empty button names # (filters out wiimotes, the remote-app, etc). for device in input_devices: for name in ('buttonPunch', 'buttonJump', 'buttonBomb', 'buttonPickUp'): if self._meaningful_button_name( device, get_device_value(device, name)) != '': fade_in = True break if fade_in: break # No need to keep looking. else: # No touch-screen; fade in immediately. fade_in = True if fade_in: self._cancel_timer = None # Didn't need this. self._fade_in_timer = None # Done with this. self._fade_in()
def __init__(self, fade_time: float = 0.5, start_faded: bool = False, show_logo: bool = False): super().__init__() self._dying = False self.fade_time = fade_time # We're special in that we create our node in the session # scene instead of the activity scene. # This way we can overlap multiple activities for fades # and whatnot. session = ba.getsession() self._session = weakref.ref(session) with ba.Context(session): self.node = ba.newnode('image', delegate=self, attrs={ 'fill_screen': True, 'texture': ba.gettexture('bg'), 'tilt_translate': -0.3, 'has_alpha_channel': False, 'color': (1, 1, 1) }) if not start_faded: ba.animate(self.node, 'opacity', { 0.0: 0.0, self.fade_time: 1.0 }, loop=False) if show_logo: logo_texture = ba.gettexture('logo') logo_model = ba.getmodel('logo') logo_model_transparent = ba.getmodel('logoTransparent') self.logo = ba.newnode('image', owner=self.node, attrs={ 'texture': logo_texture, 'model_opaque': logo_model, 'model_transparent': logo_model_transparent, 'scale': (0.7, 0.7), 'vr_depth': -250, 'color': (0.15, 0.15, 0.15), 'position': (0, 0), 'tilt_translate': -0.05, 'absolute_scale': False }) self.node.connectattr('opacity', self.logo, 'opacity') # add jitter/pulse for a stop-motion-y look unless we're in VR # in which case stillness is better if not ba.app.vr_mode: self.cmb = ba.newnode('combine', owner=self.node, attrs={'size': 2}) for attr in ['input0', 'input1']: ba.animate(self.cmb, attr, { 0.0: 0.693, 0.05: 0.7, 0.5: 0.693 }, loop=True) self.cmb.connectattr('output', self.logo, 'scale') cmb = ba.newnode('combine', owner=self.node, attrs={'size': 2}) cmb.connectattr('output', self.logo, 'position') # Gen some random keys for that stop-motion-y look. keys = {} timeval = 0.0 for _i in range(10): keys[timeval] = (random.random() - 0.5) * 0.0015 timeval += random.random() * 0.1 ba.animate(cmb, 'input0', keys, loop=True) keys = {} timeval = 0.0 for _i in range(10): keys[timeval] = (random.random() - 0.5) * 0.0015 + 0.05 timeval += random.random() * 0.1 ba.animate(cmb, 'input1', keys, loop=True)
def _update(self) -> None: # pylint: disable=too-many-statements # pylint: disable=too-many-branches # pylint: disable=too-many-locals from ba.internal import get_device_value, get_remote_app_name if self._dead: return punch_button_names = set() jump_button_names = set() pickup_button_names = set() bomb_button_names = set() # We look at the session's players; not the activity's - we want to # get ones who are still in the process of selecting a character, etc. input_devices = [p.get_input_device() for p in ba.getsession().players] input_devices = [i for i in input_devices if i] # If there's no players with input devices yet, try to default to # showing keyboard controls. if not input_devices: kbd = _ba.get_input_device('Keyboard', '#1', doraise=False) if kbd is not None: input_devices.append(kbd) # We word things specially if we have nothing but keyboards. all_keyboards = (input_devices and all(i.name == 'Keyboard' for i in input_devices)) only_remote = (len(input_devices) == 1 and all(i.name == 'Amazon Fire TV Remote' for i in input_devices)) right_button_names = set() left_button_names = set() up_button_names = set() down_button_names = set() # For each player in the game with an input device, # get the name of the button for each of these 4 actions. # If any of them are uniform across all devices, display the name. for device in input_devices: # We only care about movement buttons in the case of keyboards. if all_keyboards: right_button_names.add( device.get_button_name( get_device_value(device, 'buttonRight'))) left_button_names.add( device.get_button_name( get_device_value(device, 'buttonLeft'))) down_button_names.add( device.get_button_name( get_device_value(device, 'buttonDown'))) up_button_names.add( device.get_button_name(get_device_value( device, 'buttonUp'))) # Ignore empty values; things like the remote app or # wiimotes can return these. bname = device.get_button_name( get_device_value(device, 'buttonPunch')) if bname != '': punch_button_names.add(bname) bname = device.get_button_name( get_device_value(device, 'buttonJump')) if bname != '': jump_button_names.add(bname) bname = device.get_button_name( get_device_value(device, 'buttonBomb')) if bname != '': bomb_button_names.add(bname) bname = device.get_button_name( get_device_value(device, 'buttonPickUp')) if bname != '': pickup_button_names.add(bname) # If we have no values yet, we may want to throw out some sane # defaults. if all(not lst for lst in (punch_button_names, jump_button_names, bomb_button_names, pickup_button_names)): # Otherwise on android show standard buttons. if ba.app.platform == 'android': punch_button_names.add('X') jump_button_names.add('A') bomb_button_names.add('B') pickup_button_names.add('Y') run_text = ba.Lstr( value='${R}: ${B}', subs=[('${R}', ba.Lstr(resource='runText')), ('${B}', ba.Lstr(resource='holdAnyKeyText' if all_keyboards else 'holdAnyButtonText'))]) # If we're all keyboards, lets show move keys too. if (all_keyboards and len(up_button_names) == 1 and len(down_button_names) == 1 and len(left_button_names) == 1 and len(right_button_names) == 1): up_text = list(up_button_names)[0] down_text = list(down_button_names)[0] left_text = list(left_button_names)[0] right_text = list(right_button_names)[0] run_text = ba.Lstr(value='${M}: ${U}, ${L}, ${D}, ${R}\n${RUN}', subs=[('${M}', ba.Lstr(resource='moveText')), ('${U}', up_text), ('${L}', left_text), ('${D}', down_text), ('${R}', right_text), ('${RUN}', run_text)]) self._run_text.text = run_text w_text: Union[ba.Lstr, str] if only_remote and self._lifespan is None: w_text = ba.Lstr(resource='fireTVRemoteWarningText', subs=[('${REMOTE_APP_NAME}', get_remote_app_name())]) else: w_text = '' self._extra_text.text = w_text if len(punch_button_names) == 1: self._punch_text.text = list(punch_button_names)[0] else: self._punch_text.text = '' if len(jump_button_names) == 1: tval = list(jump_button_names)[0] else: tval = '' self._jump_text.text = tval if tval == '': self._run_text.position = self._run_text_pos_top self._extra_text.position = (self._run_text_pos_top[0], self._run_text_pos_top[1] - 50) else: self._run_text.position = self._run_text_pos_bottom self._extra_text.position = (self._run_text_pos_bottom[0], self._run_text_pos_bottom[1] - 50) if len(bomb_button_names) == 1: self._bomb_text.text = list(bomb_button_names)[0] else: self._bomb_text.text = '' # Also move our title up/down depending on if this is shown. if len(pickup_button_names) == 1: self._pick_up_text.text = list(pickup_button_names)[0] if self._title_text is not None: self._title_text.position = self._title_text_pos_top else: self._pick_up_text.text = '' if self._title_text is not None: self._title_text.position = self._title_text_pos_bottom