Exemple #1
0
    def _edit_game_done(self, config: Optional[dict[str, Any]]) -> None:
        from bastd.ui.playlist.edit import PlaylistEditWindow
        from bastd.ui.playlist.addgame import PlaylistAddGameWindow
        from ba.internal import get_type_name
        if config is None:
            # If we were editing, go back to our list.
            if self._editing_game:
                ba.playsound(ba.getsound('powerdown01'))
                ba.app.ui.clear_main_menu_window(transition='out_right')
                ba.app.ui.set_main_menu_window(
                    PlaylistEditWindow(editcontroller=self,
                                       transition='in_left').get_root_widget())

            # Otherwise we were adding; go back to the add type choice list.
            else:
                ba.app.ui.clear_main_menu_window(transition='out_right')
                ba.app.ui.set_main_menu_window(
                    PlaylistAddGameWindow(
                        editcontroller=self,
                        transition='in_left').get_root_widget())
        else:
            # Make sure type is in there.
            assert self._editing_game_type is not None
            config['type'] = get_type_name(self._editing_game_type)

            if self._editing_game:
                self._playlist[self._selected_index] = copy.deepcopy(config)
            else:
                # Add a new entry to the playlist.
                insert_index = min(len(self._playlist),
                                   self._selected_index + 1)
                self._playlist.insert(insert_index, copy.deepcopy(config))
                self._selected_index = insert_index

            ba.playsound(ba.getsound('gunCocking'))
            ba.app.ui.clear_main_menu_window(transition='out_right')
            ba.app.ui.set_main_menu_window(
                PlaylistEditWindow(editcontroller=self,
                                   transition='in_left').get_root_widget())
    def _set_sub_tab(self,
                     value: SubTabType,
                     region_width: float,
                     region_height: float,
                     playsound: bool = False) -> None:
        assert self._container
        if playsound:
            ba.playsound(ba.getsound('click01'))

        # Reset our selection.
        # (prevents selecting something way down the list if we switched away
        # and came back)
        self._selection = None
        self._have_user_selected_row = False

        # Reset refresh to the top and make sure everything refreshes.
        self._refresh_ui_row = 0
        

        self._sub_tab = value
        active_color = (0.6, 1.0, 0.6)
        inactive_color = (0.5, 0.4, 0.5)
        ba.textwidget(
            edit=self._join_new_party_text,
            color=active_color if value is SubTabType.NEW else inactive_color)
        ba.textwidget(
            edit=self._join_saved_party_text,
            color=active_color if value is SubTabType.SAVED else inactive_color)

        # Clear anything existing in the old sub-tab.
        for widget in self._container.get_children():
            if widget and widget not in {self._join_saved_party_text, self._join_new_party_text}:
                widget.delete()

        if value is SubTabType.NEW:
            self._build_new_party_tab(region_width, region_height)

        if value is SubTabType.SAVED:
            self._build_saved_party_tab(region_width, region_height)
    def _host_button_press(self) -> None:
        if self._waiting_for_hosting_state:
            return

        if _ba.get_account_state() != 'signed_in':
            ba.screenmessage(ba.Lstr(resource='notSignedInErrorText'))
            ba.playsound(ba.getsound('error'))
            self._refresh_sub_tab()
            return

        if self._hostingstate.unavailable_error is not None:
            ba.playsound(ba.getsound('error'))
            return

        # If we're not hosting, start.
        if self._hostingstate.party_code is None:

            # If there's a ticket cost, make sure we have enough tickets.
            if self._hostingstate.tickets_to_host_now > 0:
                ticket_count: Optional[int]
                try:
                    ticket_count = _ba.get_account_ticket_count()
                except Exception:
                    # FIXME: should add a ba.NotSignedInError we can use here.
                    ticket_count = None
                ticket_cost = self._hostingstate.tickets_to_host_now
                if ticket_count is not None and ticket_count < ticket_cost:
                    getcurrency.show_get_tickets_prompt()
                    ba.playsound(ba.getsound('error'))
                    return
            self._last_action_send_time = time.time()
            _ba.add_transaction(
                {
                    'type': 'PRIVATE_PARTY_START',
                    'config': asdict(self._hostingconfig)
                },
                callback=ba.WeakCall(self._hosting_state_response))
            _ba.run_transactions()

        else:
            self._last_action_send_time = time.time()
            _ba.add_transaction({'type': 'PRIVATE_PARTY_STOP'},
                                callback=ba.WeakCall(
                                    self._hosting_state_response))
            _ba.run_transactions()
        ba.playsound(ba.getsound('click01'))

        self._waiting_for_hosting_state = True
        self._refresh_sub_tab()
Exemple #4
0
    def handlemessage(self, msg: Any) -> Any:
        if isinstance(msg, ba.PlayerDiedMessage):

            # Augment standard behavior.
            super().handlemessage(msg)
            player: Player = msg.getplayer(Player)

            player.lives -= 1
            if player.lives < 0:
                ba.print_error(
                    "Got lives < 0 in Elim; this shouldn't happen. solo:" +
                    str(self._solo_mode))
                player.lives = 0

            # If we have any icons, update their state.
            for icon in player.icons:
                icon.handle_player_died()

            # Play big death sound on our last death
            # or for every one in solo mode.
            if self._solo_mode or player.lives == 0:
                ba.playsound(get_factory().single_player_death_sound)

            # If we hit zero lives, we're dead (and our team might be too).
            if player.lives == 0:
                # If the whole team is now dead, mark their survival time.
                if self._get_total_team_lives(player.team) == 0:
                    assert self._start_time is not None
                    player.team.survival_seconds = int(ba.time() -
                                                       self._start_time)
            else:
                # Otherwise, in regular mode, respawn.
                if not self._solo_mode:
                    self.respawn_player(player)

            # In solo, put ourself at the back of the spawn order.
            if self._solo_mode:
                player.team.spawn_order.remove(player)
                player.team.spawn_order.append(player)
Exemple #5
0
    def handlemessage(self, msg: Any) -> Any:
        if __debug__:
            self._handlemessage_sanity_check()

        if isinstance(msg, ba.DieMessage):
            if self.node:
                self.node.delete()

        elif isinstance(msg, ExplodeHitMessage):
            node = ba.get_collision_info("opposing_node")
            if node:
                assert self.node
                nodepos = self.node.position

                # new
                mag = 2000.0
                if self.blast_type == 'ice':
                    mag *= 0.5
                elif self.blast_type == 'land_mine':
                    mag *= 2.5
                elif self.blast_type == 'tnt':
                    mag *= 2.0

                node.handlemessage(
                    ba.HitMessage(pos=nodepos,
                                  velocity=(0, 0, 0),
                                  magnitude=mag,
                                  hit_type=self.hit_type,
                                  hit_subtype=self.hit_subtype,
                                  radius=self.radius,
                                  source_player=self.source_player))
                if self.blast_type == "ice":
                    ba.playsound(get_factory().freeze_sound,
                                 10,
                                 position=nodepos)
                    node.handlemessage(ba.FreezeMessage())

        else:
            super().handlemessage(msg)
Exemple #6
0
    def _on_import_response(self, response: Optional[Dict[str, Any]]) -> None:
        if response is None:
            ba.screenmessage(ba.Lstr(resource='errorText'), color=(1, 0, 0))
            ba.playsound(ba.getsound('error'))
            return

        if response['playlistType'] == 'Team Tournament':
            playlist_type_name = ba.Lstr(resource='playModes.teamsText')
        elif response['playlistType'] == 'Free-for-All':
            playlist_type_name = ba.Lstr(resource='playModes.freeForAllText')
        else:
            playlist_type_name = ba.Lstr(value=response['playlistType'])

        ba.screenmessage(ba.Lstr(resource='importPlaylistSuccessText',
                                 subs=[('${TYPE}', playlist_type_name),
                                       ('${NAME}', response['playlistName'])]),
                         color=(0, 1, 0))
        ba.playsound(ba.getsound('gunCocking'))
        if self._on_success_callback is not None:
            self._on_success_callback()
        ba.containerwidget(edit=self._root_widget,
                           transition=self._transition_out)
Exemple #7
0
    def _connect(self, textwidget: ba.Widget,
                 port_textwidget: ba.Widget) -> None:
        addr = cast(str, ba.textwidget(query=textwidget))
        if addr == '':
            ba.screenmessage(
                ba.Lstr(resource='internal.invalidAddressErrorText'),
                color=(1, 0, 0))
            ba.playsound(ba.getsound('error'))
            return
        try:
            port = int(cast(str, ba.textwidget(query=port_textwidget)))
        except ValueError:
            port = -1
        if port > 65535 or port < 0:
            ba.screenmessage(ba.Lstr(resource='internal.invalidPortErrorText'),
                             color=(1, 0, 0))
            ba.playsound(ba.getsound('error'))
            return

        _HostLookupThread(name=addr,
                          port=port,
                          call=ba.WeakCall(self._host_lookup_result)).start()
Exemple #8
0
 def _on_more_press(self) -> None:
     our_login_id = _ba.get_public_login_id()
     # our_login_id = _bs.get_account_misc_read_val_2(
     #     'resolvedAccountID', None)
     if not self._can_do_more_button or our_login_id is None:
         ba.playsound(ba.getsound('error'))
         ba.screenmessage(ba.Lstr(resource='unavailableText'),
                          color=(1, 0, 0))
         return
     if self._season is None:
         season_str = ''
     else:
         season_str = (
             '&season=' +
             ('all_time' if self._season == 'a' else self._season))
     if self._league_url_arg != '':
         league_str = '&league=' + self._league_url_arg
     else:
         league_str = ''
     ba.open_url(_ba.get_master_server_address() +
                 '/highscores?list=powerRankings&v=2' + league_str +
                 season_str + '&player=' + our_login_id)
Exemple #9
0
    def drop_shield(self) -> None:
        """Drop a shield powerup in random place"""
        # FIXME: should use map defs
        shield = PowerupBox(poweruptype='shield',
                            position=(random.uniform(-10, 10), 6,
                                      random.uniform(-5, 5))).autoretain()

        ba.playsound(self._ding_sound)

        p_light = ba.newnode('light',
                             owner=shield.node,
                             attrs={
                                 'position': (0, 0, 0),
                                 'color': (0.3, 0.0, 0.4),
                                 'radius': 0.3,
                                 'intensity': 2,
                                 'volume_intensity_scale': 10.0
                             })

        shield.node.connectattr('position', p_light, 'position')

        ba.animate(p_light, 'intensity', {0: 2, 8: 0})
Exemple #10
0
    def _smooth_update(self) -> None:
        if not self._ticket_count_text:
            self._smooth_update_timer = None
            return

        finished = False

        # if we're going down, do it immediately
        assert self._smooth_ticket_count is not None
        if int(self._smooth_ticket_count) >= self._ticket_count:
            self._smooth_ticket_count = float(self._ticket_count)
            finished = True
        else:
            # we're going up; start a sound if need be
            self._smooth_ticket_count = min(
                self._smooth_ticket_count + 1.0 * self._smooth_increase_speed,
                self._ticket_count)
            if int(self._smooth_ticket_count) >= self._ticket_count:
                finished = True
                self._smooth_ticket_count = float(self._ticket_count)
            elif self._ticking_node is None:
                with ba.Context('ui'):
                    self._ticking_node = ba.newnode(
                        'sound',
                        attrs={
                            'sound': ba.getsound('scoreIncrease'),
                            'positional': False
                        })

        ba.textwidget(edit=self._ticket_count_text,
                      text=str(int(self._smooth_ticket_count)))

        # if we've reached the target, kill the timer/sound/etc
        if finished:
            self._smooth_update_timer = None
            if self._ticking_node is not None:
                self._ticking_node.delete()
                self._ticking_node = None
                ba.playsound(ba.getsound('cashRegister2'))
Exemple #11
0
    def _purchase(self) -> None:
        from ba.internal import get_store_item_name_translated
        from bastd.ui import getcurrency
        from bastd.ui import confirm
        if self._offer['item'] == 'pro':
            _ba.purchase('pro_sale')
        elif self._offer['item'] == 'pro_fullprice':
            _ba.purchase('pro')
        elif self._is_bundle_sale:
            # With bundle sales, the price is the name of the IAP.
            _ba.purchase(self._offer['price'])
        else:
            ticket_count: Optional[int]
            try:
                ticket_count = _ba.get_account_ticket_count()
            except Exception:
                ticket_count = None
            if (ticket_count is not None
                    and ticket_count < self._offer['price']):
                getcurrency.show_get_tickets_prompt()
                ba.playsound(ba.getsound('error'))
                return

            def do_it() -> None:
                _ba.in_game_purchase('offer:' + str(self._offer['id']),
                                     self._offer['price'])

            ba.playsound(ba.getsound('swish'))
            confirm.ConfirmWindow(ba.Lstr(
                resource='store.purchaseConfirmText',
                subs=[('${ITEM}',
                       get_store_item_name_translated(self._offer['item']))]),
                                  width=400,
                                  height=120,
                                  action=do_it,
                                  ok_text=ba.Lstr(
                                      resource='store.purchaseText',
                                      fallback_resource='okText'))
Exemple #12
0
    def handlemessage(self, msg: Any) -> Any:
        assert not self.expired

        if isinstance(msg, ba.PowerupAcceptMessage):
            factory = PowerupBoxFactory.get()
            assert self.node
            if self.poweruptype == 'health':
                ba.playsound(factory.health_powerup_sound,
                             3,
                             position=self.node.position)
            ba.playsound(factory.powerup_sound, 3, position=self.node.position)
            self._powersgiven = True
            self.handlemessage(ba.DieMessage())

        elif isinstance(msg, _TouchedMessage):
            if not self._powersgiven:
                node = ba.getcollision().opposingnode
                node.handlemessage(
                    ba.PowerupMessage(self.poweruptype, sourcenode=self.node))

        elif isinstance(msg, ba.DieMessage):
            if self.node:
                if msg.immediate:
                    self.node.delete()
                else:
                    ba.animate(self.node, 'model_scale', {0: 1, 0.1: 0})
                    ba.timer(0.1, self.node.delete)

        elif isinstance(msg, ba.OutOfBoundsMessage):
            self.handlemessage(ba.DieMessage())

        elif isinstance(msg, ba.HitMessage):
            # Don't die on punches (that's annoying).
            if msg.hit_type != 'punch':
                self.handlemessage(ba.DieMessage())
        else:
            return super().handlemessage(msg)
        return None
Exemple #13
0
    def _tick(self) -> None:
        self._update_flag_state()

        # Give holding players points.
        for player in self.players:
            if player.gamedata['at_flag'] > 0:
                self.stats.player_scored(player,
                                         3,
                                         screenmessage=False,
                                         display=False)

        if self._scoring_team is None:
            scoring_team = None
        else:
            scoring_team = self._scoring_team()
        if scoring_team:

            if scoring_team.gamedata['time_remaining'] > 0:
                ba.playsound(self._tick_sound)

            scoring_team.gamedata['time_remaining'] = max(
                0, scoring_team.gamedata['time_remaining'] - 1)
            self._update_scoreboard()
            if scoring_team.gamedata['time_remaining'] > 0:
                assert self._flag is not None
                self._flag.set_score_text(
                    str(scoring_team.gamedata['time_remaining']))

            # Announce numbers we have sounds for.
            try:
                ba.playsound(self._countdownsounds[
                    scoring_team.gamedata['time_remaining']])
            except Exception:
                pass

            # winner
            if scoring_team.gamedata['time_remaining'] <= 0:
                self.end_game()
    def _save_server(self, textwidget: ba.Widget,
                 port_textwidget: ba.Widget) -> None:
        addr = cast(str, ba.textwidget(query=textwidget))
        if addr == '':
            ba.screenmessage(
                ba.Lstr(resource='internal.invalidAddressErrorText'),
                color=(1, 0, 0))
            ba.playsound(ba.getsound('error'))
            return
        try:
            port = int(cast(str, ba.textwidget(query=port_textwidget)))
        except ValueError:
            port = -1
        if port > 65535 or port < 0:
            ba.screenmessage(ba.Lstr(resource='internal.invalidPortErrorText'),
                             color=(1, 0, 0))
            ba.playsound(ba.getsound('error'))
            return
        try:
            import socket
            addr = socket.gethostbyname(addr)
        except Exception:
            addr = None
        config=ba.app.config

        if addr is not None:
          if 'Saved Servers' in config:
            config['Saved Servers'][addr+str(port)]={"addr":addr,"port":port,"name":''}
          else:
            config['Saved Servers']={}

            config['Saved Servers'][addr+str(port)]={"addr":addr,"port":port,"name":''}
          config.commit()
          ba.screenmessage("Saved Successfully",
                               color=(0, 1, 0))
        else:
          ba.screenmessage("Invalid Address",
                               color=(1, 0, 0))
    def _new_playlist(self) -> None:
        # pylint: disable=cyclic-import
        from bastd.ui.playlist.editcontroller import PlaylistEditController
        from bastd.ui.purchase import PurchaseWindow
        if not ba.app.accounts.have_pro_options():
            PurchaseWindow(items=['pro'])
            return

        # Clamp at our max playlist number.
        if len(ba.app.config[self._config_name_full]) > self._max_playlists:
            ba.screenmessage(
                ba.Lstr(translate=('serverResponses',
                                   'Max number of playlists reached.')),
                color=(1, 0, 0))
            ba.playsound(ba.getsound('error'))
            return

        # In case they cancel so we can return to this state.
        self._save_playlist_selection()

        # Kick off the edit UI.
        PlaylistEditController(sessiontype=self._sessiontype)
        ba.containerwidget(edit=self._root_widget, transition='out_left')
Exemple #16
0
    def arm(self, actor: stdbomb.Bomb):
        factory = stdbomb.BombFactory.get()
        elon_mine_lit_tex = ba.gettexture('circleNoAlpha')
        elon_mine_tex = ba.gettexture('achievementCrossHair')
        actor.texture_sequence = ba.newnode('texture_sequence',
                                            owner=actor.node,
                                            attrs={
                                                'rate':
                                                30,
                                                'input_textures':
                                                (elon_mine_lit_tex,
                                                 elon_mine_tex)
                                            })
        ba.timer(0.5, actor.texture_sequence.delete)
        ba.playsound(ba.getsound('activateBeep'), position=actor.node.position)

        actor.aim = AutoAim(actor.node, actor.owner)
        # we now make it explodable.
        ba.timer(
            0.25,
            ba.WeakCall(actor._add_material, factory.land_mine_blast_material))
        actor.texture_sequence.connectattr('output_texture', actor.node,
                                           'color_texture')
Exemple #17
0
    def _edit_soundtrack(self) -> None:
        # pylint: disable=cyclic-import
        from ba.internal import have_pro_options
        from bastd.ui import purchase
        from bastd.ui.soundtrack import edit as stedit
        if not have_pro_options():
            purchase.PurchaseWindow(items=['pro'])
            return
        if self._selected_soundtrack is None:
            return
        if self._selected_soundtrack == '__default__':
            ba.playsound(ba.getsound('error'))
            ba.screenmessage(ba.Lstr(resource=self._r +
                                     '.cantEditDefaultText'),
                             color=(1, 0, 0))
            return

        self._save_state()
        ba.containerwidget(edit=self._root_widget, transition='out_left')
        ba.app.ui.set_main_menu_window(
            stedit.SoundtrackEditWindow(
                existing_soundtrack=self._selected_soundtrack).get_root_widget(
                ))
Exemple #18
0
    def _on_egg_player_collide(self) -> None:
        if self.has_ended():
            return
        collision = ba.getcollision()
        try:
            egg = collision.sourcenode.getdelegate(Egg, True)
            player = collision.opposingnode.getdelegate(PlayerSpaz,
                                                        True).getplayer(
                                                            Player, True)
        except Exception:
            return

        player.team.score += 1

        # Displays a +1 (and adds to individual player score in
        # teams mode).
        self.stats.player_scored(player, 1, screenmessage=False)
        if self._max_eggs < 5:
            self._max_eggs += 1.0
        elif self._max_eggs < 10:
            self._max_eggs += 0.5
        elif self._max_eggs < 30:
            self._max_eggs += 0.3
        self._update_scoreboard()
        ba.playsound(self._collect_sound, 0.5, position=egg.node.position)

        # Create a flash.
        light = ba.newnode('light',
                           attrs={
                               'position': egg.node.position,
                               'height_attenuated': False,
                               'radius': 0.1,
                               'color': (1, 1, 0)
                           })
        ba.animate(light, 'intensity', {0: 0, 0.1: 1.0, 0.2: 0}, loop=False)
        ba.timer(0.200, light.delete)
        egg.handlemessage(ba.DieMessage())
Exemple #19
0
    def _restore_editor(cls, state: Dict[str, Any], musictype: str,
                        entry: Any) -> None:
        from ba.internal import get_soundtrack_entry_type
        # Apply the change and recreate the window.
        soundtrack = state['soundtrack']
        existing_entry = (None if musictype not in soundtrack else
                          soundtrack[musictype])
        if existing_entry != entry:
            ba.playsound(ba.getsound('gunCocking'))

        # Make sure this doesn't get mucked with after we get it.
        if entry is not None:
            entry = copy.deepcopy(entry)

        entry_type = get_soundtrack_entry_type(entry)
        if entry_type == 'default':
            # For 'default' entries simply exclude them from the list.
            if musictype in soundtrack:
                del soundtrack[musictype]
        else:
            soundtrack[musictype] = entry

        ba.app.main_menu_window = (cls(state,
                                       transition='in_left').get_root_widget())
    def _rename_my_replay(self, replay: str) -> None:
        new_name = None
        try:
            if not self._my_replay_rename_text:
                return
            new_name_raw = cast(
                str, ba.textwidget(query=self._my_replay_rename_text))
            new_name = new_name_raw + '.brp'

            # Ignore attempts to change it to what it already is
            # (or what it looks like to the user).
            if (replay != new_name
                    and self._get_replay_display_name(replay) != new_name_raw):
                old_name_full = (_ba.get_replays_dir() + '/' +
                                 replay).encode('utf-8')
                new_name_full = (_ba.get_replays_dir() + '/' +
                                 new_name).encode('utf-8')
                # False alarm; ba.textwidget can return non-None val.
                # pylint: disable=unsupported-membership-test
                if os.path.exists(new_name_full):
                    ba.playsound(ba.getsound('error'))
                    ba.screenmessage(
                        ba.Lstr(resource=self._r +
                                '.replayRenameErrorAlreadyExistsText'),
                        color=(1, 0, 0))
                elif any(char in new_name_raw for char in ['/', '\\', ':']):
                    ba.playsound(ba.getsound('error'))
                    ba.screenmessage(ba.Lstr(resource=self._r +
                                             '.replayRenameErrorInvalidName'),
                                     color=(1, 0, 0))
                else:
                    _ba.increment_analytics_count('Replay rename')
                    os.rename(old_name_full, new_name_full)
                    self._refresh_my_replays()
                    ba.playsound(ba.getsound('gunCocking'))
        except Exception:
            ba.print_exception(
                f"Error renaming replay '{replay}' to '{new_name}'.")
            ba.playsound(ba.getsound('error'))
            ba.screenmessage(
                ba.Lstr(resource=self._r + '.replayRenameErrorText'),
                color=(1, 0, 0),
            )

        ba.containerwidget(edit=self._my_replays_rename_window,
                           transition='out_scale')
    def handlemessage(self, msg: Any) -> Any:
        assert not self.expired

        if isinstance(msg, ba.DieMessage):
            if self.node:
                self.node.delete()

        elif isinstance(msg, ExplodeHitMessage):
            node = ba.getcollision().opposingnode
            assert self.node
            nodepos = self.node.position
            mag = 2000.0
            if self.blast_type == 'ice':
                mag *= 0.5
            elif self.blast_type == 'land_mine':
                mag *= 2.5
            elif self.blast_type == 'tnt':
                mag *= 2.0

            node.handlemessage(
                ba.HitMessage(pos=nodepos,
                              velocity=(0, 0, 0),
                              magnitude=mag,
                              hit_type=self.hit_type,
                              hit_subtype=self.hit_subtype,
                              radius=self.radius,
                              source_player=ba.existing(self._source_player)))
            if self.blast_type == 'ice':
                ba.playsound(BombFactory.get().freeze_sound,
                             10,
                             position=nodepos)
                node.handlemessage(ba.FreezeMessage())

        else:
            return super().handlemessage(msg)
        return None
Exemple #22
0
    def end_game(self) -> None:

        # Stop our on-screen timer so players can see what they got.
        assert self._timer is not None
        self._timer.stop()

        results = ba.TeamGameResults()

        # If we won, set our score to the elapsed time in milliseconds.
        # (there should just be 1 team here since this is co-op).
        # ..if we didn't win, leave scores as default (None) which means
        # we lost.
        if self._won:
            elapsed_time_ms = int((ba.time() - self._timer.starttime) * 1000.0)
            ba.cameraflash()
            ba.playsound(self._winsound)
            for team in self.teams:
                for player in team.players:
                    if player.actor:
                        player.actor.handlemessage(ba.CelebrateMessage())
                results.set_team_score(team, elapsed_time_ms)

        # Ends the activity.
        self.end(results)
Exemple #23
0
    def _do_it(self) -> None:
        from bastd.ui.soundtrack import browser as stb
        music = ba.app.music
        cfg = ba.app.config
        new_name = cast(str, ba.textwidget(query=self._text_field))
        if (new_name != self._soundtrack_name
                and new_name in cfg['Soundtracks']):
            ba.screenmessage(
                ba.Lstr(resource=self._r + '.cantSaveAlreadyExistsText'))
            ba.playsound(ba.getsound('error'))
            return
        if not new_name:
            ba.playsound(ba.getsound('error'))
            return
        if new_name == ba.Lstr(resource=self._r +
                               '.defaultSoundtrackNameText').evaluate():
            ba.screenmessage(
                ba.Lstr(resource=self._r + '.cantOverwriteDefaultText'))
            ba.playsound(ba.getsound('error'))
            return

        # Make sure config exists.
        if 'Soundtracks' not in cfg:
            cfg['Soundtracks'] = {}

        # If we had an old one, delete it.
        if (self._existing_soundtrack_name is not None
                and self._existing_soundtrack_name in cfg['Soundtracks']):
            del cfg['Soundtracks'][self._existing_soundtrack_name]
        cfg['Soundtracks'][new_name] = self._soundtrack
        cfg['Soundtrack'] = new_name

        cfg.commit()
        ba.playsound(ba.getsound('gunCocking'))
        ba.containerwidget(edit=self._root_widget, transition='out_right')

        # Resets music back to normal.
        music.set_music_play_mode(ba.MusicPlayMode.REGULAR, force_restart=True)

        ba.app.ui.set_main_menu_window(
            stb.SoundtrackBrowserWindow(
                transition='in_left').get_root_widget())
    def _on_entry_activated(self, entry: str) -> None:
        # pylint: disable=too-many-branches
        new_path = None
        try:
            assert self._path is not None
            if entry == '..':
                chunks = self._path.split('/')
                if len(chunks) > 1:
                    new_path = '/'.join(chunks[:-1])
                    if new_path == '':
                        new_path = '/'
                else:
                    ba.playsound(ba.getsound('error'))
            else:
                if self._path == '/':
                    test_path = self._path + entry
                else:
                    test_path = self._path + '/' + entry
                if os.path.isdir(test_path):
                    ba.playsound(ba.getsound('swish'))
                    new_path = test_path
                elif os.path.isfile(test_path):
                    if self._is_valid_file_path(test_path):
                        ba.playsound(ba.getsound('swish'))
                        ba.containerwidget(edit=self._root_widget,
                                           transition='out_right')
                        if self._callback is not None:
                            self._callback(test_path)
                    else:
                        ba.playsound(ba.getsound('error'))
                else:
                    print(('Error: FileSelectorWindow found non-file/dir:',
                           test_path))
        except Exception:
            ba.print_exception(
                'Error in FileSelectorWindow._on_entry_activated().')

        if new_path is not None:
            self._set_path(new_path)
Exemple #25
0
 def _purchase_check_result(self, item: str,
                            result: Optional[Dict[str, Any]]) -> None:
     if result is None:
         ba.playsound(ba.getsound('error'))
         ba.screenmessage(
             ba.Lstr(resource='internal.unavailableNoConnectionText'),
             color=(1, 0, 0))
     else:
         if result['allow']:
             self._do_purchase(item)
         else:
             if result['reason'] == 'versionTooOld':
                 ba.playsound(ba.getsound('error'))
                 ba.screenmessage(
                     ba.Lstr(resource='getTicketsWindow.versionTooOldText'),
                     color=(1, 0, 0))
             else:
                 ba.playsound(ba.getsound('error'))
                 ba.screenmessage(
                     ba.Lstr(resource='getTicketsWindow.unavailableText'),
                     color=(1, 0, 0))
Exemple #26
0
    def _on_upgrade_press(self) -> None:
        from bastd.ui import getcurrency
        if self._status is None:
            # If it appears we don't have enough tickets, offer to buy more.
            tickets = _ba.get_account_ticket_count()
            if tickets < self._cost:
                ba.playsound(ba.getsound('error'))
                getcurrency.show_get_tickets_prompt()
                return
            ba.screenmessage(ba.Lstr(resource='purchasingText'),
                             color=(0, 1, 0))
            self._status = 'pre_upgrading'

            # Now we tell the original editor to save the profile, add an
            # upgrade transaction, and then sit and wait for everything to
            # go through.
            edit_profile_window = self._edit_profile_window()
            if edit_profile_window is None:
                print('profile upgrade: original edit window gone')
                return
            success = edit_profile_window.save(transition_out=False)
            if not success:
                print('profile upgrade: error occurred saving profile')
                ba.screenmessage(ba.Lstr(resource='errorText'),
                                 color=(1, 0, 0))
                ba.playsound(ba.getsound('error'))
                return
            _ba.add_transaction({
                'type': 'UPGRADE_PROFILE',
                'name': self._name
            })
            _ba.run_transactions()
            self._status = 'upgrading'
            self._upgrade_start_time = time.time()
        else:
            ba.playsound(ba.getsound('error'))
Exemple #27
0
 def _print_already_own(self, charname: str) -> None:
     ba.screenmessage(ba.Lstr(resource=self._r + '.alreadyOwnText',
                              subs=[('${NAME}', charname)]),
                      color=(1, 0, 0))
     ba.playsound(ba.getsound('error'))
Exemple #28
0
 def _purchase_check_result(self, item: str, is_ticket_purchase: bool,
                            result: Optional[Dict[str, Any]]) -> None:
     if result is None:
         ba.playsound(ba.getsound('error'))
         ba.screenmessage(
             ba.Lstr(resource='internal.unavailableNoConnectionText'),
             color=(1, 0, 0))
     else:
         if is_ticket_purchase:
             if result['allow']:
                 price = _ba.get_account_misc_read_val(
                     'price.' + item, None)
                 if (price is None or not isinstance(price, int)
                         or price <= 0):
                     print('Error; got invalid local price of', price,
                           'for item', item)
                     ba.playsound(ba.getsound('error'))
                 else:
                     ba.playsound(ba.getsound('click01'))
                     _ba.in_game_purchase(item, price)
             else:
                 if result['reason'] == 'versionTooOld':
                     ba.playsound(ba.getsound('error'))
                     ba.screenmessage(ba.Lstr(
                         resource='getTicketsWindow.versionTooOldText'),
                                      color=(1, 0, 0))
                 else:
                     ba.playsound(ba.getsound('error'))
                     ba.screenmessage(ba.Lstr(
                         resource='getTicketsWindow.unavailableText'),
                                      color=(1, 0, 0))
         # Real in-app purchase.
         else:
             if result['allow']:
                 _ba.purchase(item)
             else:
                 if result['reason'] == 'versionTooOld':
                     ba.playsound(ba.getsound('error'))
                     ba.screenmessage(ba.Lstr(
                         resource='getTicketsWindow.versionTooOldText'),
                                      color=(1, 0, 0))
                 else:
                     ba.playsound(ba.getsound('error'))
                     ba.screenmessage(ba.Lstr(
                         resource='getTicketsWindow.unavailableText'),
                                      color=(1, 0, 0))
 def on_popup_cancel(self) -> None:
     ba.playsound(ba.getsound('swish'))
     self._on_cancel()
Exemple #30
0
def lucky_block_callback(self: stdspaz.Spaz, msg: ba.PowerupMessage):
    event_number = random.randint(1, 15)

    if event_number in (1, 2, 3):
        powerup_type = stdpowerup.PowerupBoxFactory().get_random_powerup_type()

        self.node.handlemessage(ba.PowerupMessage(poweruptype=powerup_type))
    elif event_number == 4:
        ba.camerashake(1)
        ba.emitfx(position=(self.node.position[0], self.node.position[1] + 4,
                            self.node.position[2]),
                  velocity=(0, 0, 0),
                  count=700,
                  spread=0.7,
                  chunk_type='spark')

        powerup_type = stdpowerup.PowerupBoxFactory.get(
        ).get_random_powerup_type()

        stdpowerup.PowerupBox(position=(self.node.position[0],
                                        self.node.position[1] + 4,
                                        self.node.position[2]),
                              poweruptype=powerup_type,
                              expire=True).autoretain()

        powerup_type = stdpowerup.PowerupBoxFactory.get(
        ).get_random_powerup_type()

        stdpowerup.PowerupBox(position=(self.node.position[0],
                                        self.node.position[1] + 4,
                                        self.node.position[2]),
                              poweruptype=powerup_type,
                              expire=True).autoretain()

        powerup_type = stdpowerup.PowerupBoxFactory.get(
        ).get_random_powerup_type()

        stdpowerup.PowerupBox(position=(self.node.position[0],
                                        self.node.position[1] + 4,
                                        self.node.position[2]),
                              poweruptype=powerup_type,
                              expire=True).autoretain()
    elif event_number == 5:
        stdbomb.Bomb(position=(self.node.position[0],
                               self.node.position[1] + 3,
                               self.node.position[2]),
                     source_player=self.source_player,
                     owner=self.node,
                     blast_radius=6).autoretain()
    elif event_number == 6:
        self.node.handlemessage(ba.FreezeMessage())
    elif event_number == 7:
        chunk_type = ('ice', 'rock', 'metal', 'spark', 'splinter', 'slime')

        ba.emitfx(position=self.node.position,
                  velocity=(random.random() * 2, random.random() * 2,
                            random.random() * 2),
                  count=600,
                  spread=random.random(),
                  chunk_type=random.choice(chunk_type))

        ba.camerashake(1)
        ba.playsound(ba.getsound('corkPop'))  # position=self.node.position?
    elif event_number == 8:
        position = self.node.position

        def rain_wrapper():
            p_type = stdpowerup.PowerupBoxFactory.get(
            ).get_random_powerup_type()

            new_position = (-10 + position[0] + random.random() * 20,
                            position[1] + 6,
                            -10 + position[2] + random.random() * 20)

            stdpowerup.PowerupBox(poweruptype=p_type,
                                  position=new_position).autoretain()

            if random.random() > 0.04:
                ba.timer(0.1, rain_wrapper)

        rain_wrapper()
    elif event_number == 9:
        stdbomb.Blast(position=self.node.position,
                      velocity=self.node.velocity,
                      blast_radius=1.0,
                      blast_type='normal',
                      source_player=None,
                      hit_type='punch',
                      hit_subtype='normal')
    elif event_number == 10:

        def blast(x: int, y: int, z: int) -> None:
            # add sound
            ba.NodeActor(node=ba.newnode('scorch',
                                         attrs={
                                             'position': (x, z, y),
                                             'size': 0.2,
                                             'big': False,
                                         })).autoretain()

        def smoke(x: int, y: int, z: int) -> None:
            ba.emitfx(position=(x, z, y),
                      velocity=(0, 2, 0),
                      count=1,
                      emit_type='tendrils',
                      tendril_type='smoke')
            ba.emitfx(position=(x, z, y),
                      velocity=(0, 2, 0),
                      count=int(1.0 + random.random() * 2),
                      scale=0.8,
                      spread=1.5,
                      chunk_type='spark')

        star_positions = [
            (2, 0),
            (0, 2),
            (-1.2, -1.6),
            (1.82, 0.83),
            (-1.83, 0.82),
            (1.23, -1.57),
            (-1.25, 1.56),
            (-0.65, 1.89),
            (0.82, 1.82),
            (1.27, 1.55),
            (1.82, -0.84),
            (0.31, -1.98),
            (-0.42, -1.96),
            (-1.75, -0.96),
            (-2, -0.14),
            (-0.69, -0.07),
            (-0.39, 0.82),
            (0.41, 0.82),
            (0.71, -0.06),
            (0.01, -0.62),
            (-0.99, 0.82),
            (-1.26, 0.37),
            (-0.89, -0.65),
            (-0.52, -1.05),
            (0.59, -1.07),
            (0.96, -0.8),
            (1.22, 0.35),
            (1.07, 0.82),
            (0.21, 1.39),
            (-0.17, 1.48),
            # ---
            (-1.94, 0.47),
            (-1.51, 1.31),
            (-0.95, 1.76),
            (-0.38, 1.96),
            (0.45, 1.95),
            (1.05, 1.7),
            (1.57, 1.24),
            (1.94, 0.49),
            (1.96, -0.42),
            (1.62, -1.17),
            (0.84, -1.82),
            (-0.78, -1.84),
            (-1.5, -1.33),
            (-1.91, -0.59),
            (-1.99, 0.17),
            (-1, 0.17),
            (-0.7, 0.82),
            (-0.27, 1.19),
            (0.29, 1.15),
            (0.77, 0.82),
            (1, 0.17),
            (0.84, -0.42),
            (0.31, -0.85),
            (-0.8, -1.27),
            (-1, -1),
            (-0.56, 0.33),
            (-0.47, 0.61),
            (0.52, 0.51),
            (-0.1, 0.82),
            (0.13, 0.82),
            (0.6, 0.27),
            (0.46, -0.27),
            (0.29, -0.4),
            (-0.44, -0.27),
            (-0.24, -0.42),
            (-1.36, 0.82),
            (-1.53, 0.59),
            (1.35, 0.83),
            (1.55, 0.61),
            (0.85, -1.28),
            (1.08, -1.13),
            (0.78, -0.34),
            (-0.21, -0.8),
            (0.11, 1.68)
        ]

        class Sparkling(ba.Actor):
            def __init__(self, position: Sequence[float], target: ba.Node):
                super().__init__()
                # nah; nodes not needed
                self.position = position
                self.position = (self.position[0], self.position[1] + 0.5,
                                 self.position[2])
                self.target = target

                ba.timer(0.001, ba.WeakCall(self._update))

            def _sparkle(self):
                ba.emitfx(position=self.position,
                          velocity=(0, 1, 0),
                          count=int(random.random() * 5 + 5),
                          scale=0.8,
                          spread=0.3,
                          chunk_type='spark')

            def _blast(self):
                stdbomb.Blast(position=self.position,
                              velocity=self.target.velocity,
                              blast_radius=2,
                              blast_type='normal',
                              source_player=None,
                              hit_type='punch',
                              hit_subtype='normal').autoretain()

            def _update(self):
                if not self.target:
                    del self  # commit suicide because we have no goal in our existing :(
                    return
                d = ba.Vec3(self.target.position) - ba.Vec3(self.position)

                if d.length() < 0.1:
                    self._blast()
                    del self
                    return

                d = d.normalized() * 0.04

                from math import sin, cos

                self.position = (self.position[0] + d.x +
                                 sin(ba.time() * 2) * 0.03,
                                 self.position[1] + d.y, self.position[2] +
                                 d.z + cos(ba.time() * 2) * 0.03)
                self._sparkle()

                ba.timer(0.001, ba.WeakCall(self._update))

        def sparkling(x, y, z):
            Sparkling(position=(x, z, y), target=self.node).autoretain()

        def summon_tnt(x, y, z):
            stdbomb.Bomb(bomb_type='tnt',
                         blast_radius=3,
                         position=(x, z + 4, y),
                         velocity=(0, -10, 0)).autoretain()

        scale = 1
        delta = 0.02

        op = self.node.position
        for i, (x, y) in enumerate(star_positions):
            ba.timer(
                i * delta,
                ba.Call(blast, self.node.position[0] + x * scale,
                        self.node.position[2] + y * scale,
                        self.node.position[1]))
        for i in range(4):
            ba.timer((len(star_positions)) * delta + i * 0.2,
                     ba.Call(summon_tnt, op[0], op[2], op[1]))
        ba.timer((len(star_positions)) * delta + 1.0,
                 ba.Call(sparkling, self.node.position[0],
                         self.node.position[2], self.node.position[1]))

        def last_blast():
            stdbomb.Blast(position=self.node.position,
                          velocity=(self.node.velocity[0],
                                    self.node.velocity[1] + 10,
                                    self.node.velocity[2]),
                          blast_radius=2,
                          blast_type='normal',
                          source_player=None,
                          hit_type='punch',
                          hit_subtype='normal').autoretain()

        # ba.timer(
        #     2 * len(star_positions) * delta + 0.2,
        #     last_blast)

    elif event_number == 11:
        offset = -15
        case = 1 if random.random() < 0.5 else -1
        while offset < 15:
            velocity = (case * (12 + 8 * random.random()), -0.1, 0)
            stdbomb.Bomb(bomb_type='tnt',
                         position=(self.node.position[0] - case * 10,
                                   self.node.position[1] + 3,
                                   self.node.position[2] + offset),
                         velocity=velocity).autoretain()

            offset += 1.5
    elif event_number == 12:
        color = {
            0.0: (0, 0, 3),
            0.5: (0, 3, 0),
            1.0: (3, 0, 0),
            1.5: (0, 0, 3)
        }

        # FIXME
        # ba.animate_array(self.node, 'color', 3, color, True)
        # self.node.handlemessage('celebrate', 100000000)
    elif event_number == 13:
        CompanionCube(position=(self.node.position[0],
                                self.node.position[1] + 1,
                                self.node.position[2]),
                      velocity=(0, 10, 0)).autoretain()
    elif event_number == 14:
        ba.emitfx(position=self.node.position,
                  count=100,
                  emit_type='tendrils',
                  tendril_type='smoke')

    elif event_number == 15:

        def drop_man():
            botset: stdbot.SpazBotSet
            activity = ba.getactivity()
            if not hasattr(activity, 'botset'):
                activity.botset = botset = stdbot.SpazBotSet()
            botset = activity.botset
            aoi_bounds = self.activity.globalsnode.area_of_interest_bounds
            botset.spawn_bot(
                stdbot.BrawlerBotLite,
                (random.randrange(int(aoi_bounds[0]),
                                  int(aoi_bounds[3]) + 1), aoi_bounds[4] - 1,
                 random.randrange(int(aoi_bounds[2]),
                                  int(aoi_bounds[5]) + 1)),
                spawn_time=0.001)

        def lightning_bolt(position, radius=1):
            ba.camerashake(4)
            vignette_outer = self.activity.globalsnode.vignette_outer
            # if ba.getactivity().tint is None:
            #     ba.getactivity().std_tint = ba.sharedobj('globals').vignette_outer
            #     vignette_outer = ba.sharedobj('globals').vignette_outer
            # else:
            #     vignette_outer = ba.getactivity().tint

            light = ba.newnode('light',
                               attrs={
                                   'position': position,
                                   'color': (0.4, 0.4, 0.8),
                                   'volume_intensity_scale': 1.0,
                                   'radius': radius
                               })

            ba.animate(light,
                       'intensity', {
                           0: 1,
                           50: radius,
                           150: radius / 2,
                           250: 0,
                           260: radius,
                           410: radius / 2,
                           510: 0
                       },
                       timeformat=ba.TimeFormat.MILLISECONDS,
                       suppress_format_warning=True)

            ba.animate_array(self.activity.globalsnode, 'vignette_outer', 3, {
                0: vignette_outer,
                0.2: (0.2, 0.2, 0.2),
                0.51: vignette_outer
            })

            # ba.playsound(
            #     ba.getsound('grom'),
            #     volume=10,
            #     position=(0, 10, 0))

        lightning_bolt(self.node.position)

        for time in range(15):
            ba.timer(time, drop_man)