예제 #1
0
 def on_begin(self) -> None:
     super().on_begin()
     self.setup_standard_time_limit(self.settings['Time Limit'])
     self.setup_standard_powerup_drops()
     self._flag_spawn_pos = (self.map.get_flag_position(None))
     self._spawn_flag()
     defs = self.map.defs
     self._score_regions.append(
         ba.NodeActor(
             ba.newnode('region',
                        attrs={
                            'position': defs.boxes['goal1'][0:3],
                            'scale': defs.boxes['goal1'][6:9],
                            'type': 'box',
                            'materials': (self.score_region_material, )
                        })))
     self._score_regions.append(
         ba.NodeActor(
             ba.newnode('region',
                        attrs={
                            'position': defs.boxes['goal2'][0:3],
                            'scale': defs.boxes['goal2'][6:9],
                            'type': 'box',
                            'materials': (self.score_region_material, )
                        })))
     self._update_scoreboard()
     ba.playsound(self._chant_sound)
예제 #2
0
    def on_begin(self) -> None:
        super().on_begin()

        self.setup_standard_time_limit(self._time_limit)
        self.setup_standard_powerup_drops()
        self._puck_spawn_pos = self.map.get_flag_position(None)
        self._spawn_puck()

        # Set up the two score regions.
        defs = self.map.defs
        self._score_regions = []
        self._score_regions.append(
            ba.NodeActor(
                ba.newnode('region',
                           attrs={
                               'position': defs.boxes['goal1'][0:3],
                               'scale': defs.boxes['goal1'][6:9],
                               'type': 'box',
                               'materials': [self._score_region_material]
                           })))
        self._score_regions.append(
            ba.NodeActor(
                ba.newnode('region',
                           attrs={
                               'position': defs.boxes['goal2'][0:3],
                               'scale': defs.boxes['goal2'][6:9],
                               'type': 'box',
                               'materials': [self._score_region_material]
                           })))
        self._update_scoreboard()
        ba.playsound(self._chant_sound)
예제 #3
0
    def on_transition_in(self) -> None:
        super().on_transition_in()
        self._scoreboard = Scoreboard()
        self._flag_spawn_pos = self.map.get_flag_position(None)
        self._spawn_flag()

        # Set up the two score regions.
        defs = self.map.defs
        self._score_regions.append(
            ba.NodeActor(
                ba.newnode('region',
                           attrs={
                               'position': defs.boxes['goal1'][0:3],
                               'scale': defs.boxes['goal1'][6:9],
                               'type': 'box',
                               'materials': [self._score_region_material]
                           })))
        self._score_regions.append(
            ba.NodeActor(
                ba.newnode('region',
                           attrs={
                               'position': defs.boxes['goal2'][0:3],
                               'scale': defs.boxes['goal2'][6:9],
                               'type': 'box',
                               'materials': [self._score_region_material]
                           })))
        ba.playsound(self._chant_sound)
예제 #4
0
    def _touch_return_update(self, team: ba.Team) -> None:

        # Count down only while its away from base and not being held.
        if (team.gamedata['home_flag_at_base']
                or team.gamedata['flag'].held_count > 0):
            team.gamedata['touch_return_timer_ticking'] = None
            return  # No need to return when its at home.
        if team.gamedata['touch_return_timer_ticking'] is None:
            team.gamedata['touch_return_timer_ticking'] = ba.NodeActor(
                ba.newnode('sound',
                           attrs={
                               'sound': self._ticking_sound,
                               'positional': False,
                               'loop': True
                           }))
        flag = team.gamedata['flag']
        flag.touch_return_time -= 0.1
        if flag.counter:
            flag.counter.text = '%.1f' % flag.touch_return_time
            flag.counter.color = (1, 1, 0, 1)
            flag.counter.scale = 0.02

        if flag.touch_return_time <= 0.0:
            self._award_players_touching_own_flag(team)
            flag.handlemessage(ba.DieMessage())
    def _touch_return_update(self, team: Team) -> None:
        # Count down only while its away from base and not being held.
        assert team.flag is not None
        if team.home_flag_at_base or team.flag.held_count > 0:
            team.touch_return_timer_ticking = None
            return  # No need to return when its at home.
        if team.touch_return_timer_ticking is None:
            team.touch_return_timer_ticking = ba.NodeActor(
                ba.newnode('sound',
                           attrs={
                               'sound': self._ticking_sound,
                               'positional': False,
                               'loop': True
                           }))
        flag = team.flag
        if flag.touch_return_time is not None:
            flag.touch_return_time -= 0.1
            if flag.counter:
                flag.counter.text = f'{flag.touch_return_time:.1f}'
                flag.counter.color = (1, 1, 0, 1)
                flag.counter.scale = 0.02

            if flag.touch_return_time <= 0.0:
                self._award_players_touching_own_flag(team)
                flag.handlemessage(ba.DieMessage())
예제 #6
0
 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()
예제 #7
0
    def handlemessage(self, msg: Any) -> Any:
        """ handle high-level game messages """
        if isinstance(msg, playerspaz.PlayerSpazDeathMessage):
            from bastd.actor import respawnicon

            # Respawn dead players.
            player = msg.spaz.player
            self.stats.player_was_killed(player)
            assert self.initial_player_info is not None
            respawn_time = 2.0 + len(self.initial_player_info) * 1.0

            # Respawn them shortly.
            player.gamedata['respawn_timer'] = ba.Timer(
                respawn_time, ba.Call(self.spawn_player_if_exists, player))
            player.gamedata['respawn_icon'] = respawnicon.RespawnIcon(
                player, respawn_time)

            # Augment standard behavior.
            super().handlemessage(msg)

        elif isinstance(msg, spazbot.SpazBotDeathMessage):

            # Every time a bad guy dies, spawn a new one.
            ba.timer(3.0, ba.Call(self._spawn_bot, (type(msg.badguy))))

        elif isinstance(msg, spazbot.SpazBotPunchedMessage):
            if self._preset in ['rookie', 'rookie_easy']:
                if msg.damage >= 500:
                    self._award_achievement('Super Punch')
            elif self._preset in ['pro', 'pro_easy']:
                if msg.damage >= 1000:
                    self._award_achievement('Super Mega Punch')

        # Respawn dead flags.
        elif isinstance(msg, stdflag.FlagDeathMessage):
            assert isinstance(msg.flag, FootballFlag)
            msg.flag.respawn_timer = ba.Timer(3.0, self._spawn_flag)
            self._flag_respawn_light = ba.NodeActor(
                ba.newnode('light',
                           attrs={
                               'position': self._flag_spawn_pos,
                               'height_attenuated': False,
                               'radius': 0.15,
                               'color': (1.0, 1.0, 0.3)
                           }))
            assert self._flag_respawn_light.node
            ba.animate(self._flag_respawn_light.node,
                       'intensity', {
                           0: 0,
                           0.25: 0.15,
                           0.5: 0
                       },
                       loop=True)
            ba.timer(3.0, self._flag_respawn_light.node.delete)
        else:
            super().handlemessage(msg)
예제 #8
0
 def on_transition_in(self) -> None:
     super().on_transition_in()
     self._scoreboard = Scoreboard(label=ba.Lstr(resource='scoreText'),
                                   score_split=0.5)
     self._score_region = ba.NodeActor(
         ba.newnode('region',
                    attrs={
                        'position':
                        self.map.defs.boxes['score_region'][0:3],
                        'scale': self.map.defs.boxes['score_region'][6:9],
                        'type': 'box',
                        'materials': [self._score_region_material]
                    }))
예제 #9
0
    def handlemessage(self, msg: Any) -> Any:
        """ handle high-level game messages """
        if isinstance(msg, ba.PlayerDiedMessage):
            # Augment standard behavior.
            super().handlemessage(msg)

            # Respawn them shortly.
            player = msg.getplayer(Player)
            assert self.initialplayerinfos is not None
            respawn_time = 2.0 + len(self.initialplayerinfos) * 1.0
            player.respawn_timer = ba.Timer(
                respawn_time, ba.Call(self.spawn_player_if_exists, player))
            player.respawn_icon = RespawnIcon(player, respawn_time)

        elif isinstance(msg, SpazBotDiedMessage):

            # Every time a bad guy dies, spawn a new one.
            ba.timer(3.0, ba.Call(self._spawn_bot, (type(msg.spazbot))))

        elif isinstance(msg, SpazBotPunchedMessage):
            if self._preset in ['rookie', 'rookie_easy']:
                if msg.damage >= 500:
                    self._award_achievement('Super Punch')
            elif self._preset in ['pro', 'pro_easy']:
                if msg.damage >= 1000:
                    self._award_achievement('Super Mega Punch')

        # Respawn dead flags.
        elif isinstance(msg, FlagDiedMessage):
            assert isinstance(msg.flag, FootballFlag)
            msg.flag.respawn_timer = ba.Timer(3.0, self._spawn_flag)
            self._flag_respawn_light = ba.NodeActor(
                ba.newnode('light',
                           attrs={
                               'position': self._flag_spawn_pos,
                               'height_attenuated': False,
                               'radius': 0.15,
                               'color': (1.0, 1.0, 0.3)
                           }))
            assert self._flag_respawn_light.node
            ba.animate(self._flag_respawn_light.node,
                       'intensity', {
                           0: 0,
                           0.25: 0.15,
                           0.5: 0
                       },
                       loop=True)
            ba.timer(3.0, self._flag_respawn_light.node.delete)
        else:
            return super().handlemessage(msg)
        return None
    def on_begin(self) -> None:
        super().on_begin()
        self._pow = None
        self.setup_standard_powerup_drops(enable_tnt=False)
        self._tnt_drop_timer = ba.timer(30,
                                        ba.WeakCall(self._dropPowBox),
                                        repeat=True)
        self._start_time = ba.time()
        self.setup_standard_time_limit(self._time_limit)

        if self._solo_mode:
            self._vs_text = ba.NodeActor(
                ba.newnode('text',
                           attrs={
                               'position': (0, 105),
                               'h_attach': 'center',
                               'h_align': 'center',
                               'maxwidth': 200,
                               'shadow': 0.5,
                               'vr_depth': 390,
                               'scale': 0.6,
                               'v_attach': 'bottom',
                               'color': (0.8, 0.8, 0.3, 1.0),
                               'text': ba.Lstr(resource='vsText')
                           }))

        # If balance-team-lives is on, add lives to the smaller team until
        # total lives match.
        if (isinstance(self.session, ba.DualTeamSession)
                and self._balance_total_lives and self.teams[0].players
                and self.teams[1].players):
            if self._get_total_team_lives(
                    self.teams[0]) < self._get_total_team_lives(self.teams[1]):
                lesser_team = self.teams[0]
                greater_team = self.teams[1]
            else:
                lesser_team = self.teams[1]
                greater_team = self.teams[0]
            add_index = 0
            while (self._get_total_team_lives(lesser_team) <
                   self._get_total_team_lives(greater_team)):
                lesser_team.players[add_index].lives += 1
                add_index = (add_index + 1) % len(lesser_team.players)

        self._update_icons()

        # We could check game-over conditions at explicit trigger points,
        # but lets just do the simple thing and poll it.
        ba.timer(1.0, self._update, repeat=True)
예제 #11
0
    def handlemessage(self, msg: Any) -> Any:
        if isinstance(msg, stdflag.FlagPickedUpMessage):
            assert isinstance(msg.flag, FootballFlag)
            try:
                player = msg.node.getdelegate().getplayer()
                if player:
                    msg.flag.last_holding_player = player
                msg.flag.held_count += 1
            except Exception:
                ba.print_exception('exception in Football FlagPickedUpMessage;'
                                   " this shouldn't happen")

        elif isinstance(msg, stdflag.FlagDroppedMessage):
            assert isinstance(msg.flag, FootballFlag)
            msg.flag.held_count -= 1

        # Respawn dead players if they're still in the game.
        elif isinstance(msg, playerspaz.PlayerSpazDeathMessage):
            # Augment standard behavior.
            super().handlemessage(msg)
            self.respawn_player(msg.spaz.player)

        # Respawn dead flags.
        elif isinstance(msg, stdflag.FlagDeathMessage):
            if not self.has_ended():
                self._flag_respawn_timer = ba.Timer(3.0, self._spawn_flag)
                self._flag_respawn_light = ba.NodeActor(
                    ba.newnode('light',
                               attrs={
                                   'position': self._flag_spawn_pos,
                                   'height_attenuated': False,
                                   'radius': 0.15,
                                   'color': (1.0, 1.0, 0.3)
                               }))
                assert self._flag_respawn_light.node
                ba.animate(self._flag_respawn_light.node,
                           'intensity', {
                               0.0: 0,
                               0.25: 0.15,
                               0.5: 0
                           },
                           loop=True)
                ba.timer(3.0, self._flag_respawn_light.node.delete)

        else:
            # Augment standard behavior.
            super().handlemessage(msg)
예제 #12
0
    def handlemessage(self, msg: Any) -> Any:
        if isinstance(msg, FlagPickedUpMessage):
            assert isinstance(msg.flag, FootballFlag)
            try:
                msg.flag.last_holding_player = msg.node.getdelegate(
                    PlayerSpaz, True).getplayer(Player, True)
            except ba.NotFoundError:
                pass
            msg.flag.held_count += 1

        elif isinstance(msg, FlagDroppedMessage):
            assert isinstance(msg.flag, FootballFlag)
            msg.flag.held_count -= 1

        # Respawn dead players if they're still in the game.
        elif isinstance(msg, ba.PlayerDiedMessage):
            # Augment standard behavior.
            super().handlemessage(msg)
            self.respawn_player(msg.getplayer(Player))

        # Respawn dead flags.
        elif isinstance(msg, FlagDiedMessage):
            if not self.has_ended():
                self._flag_respawn_timer = ba.Timer(3.0, self._spawn_flag)
                self._flag_respawn_light = ba.NodeActor(
                    ba.newnode('light',
                               attrs={
                                   'position': self._flag_spawn_pos,
                                   'height_attenuated': False,
                                   'radius': 0.15,
                                   'color': (1.0, 1.0, 0.3)
                               }))
                assert self._flag_respawn_light.node
                ba.animate(self._flag_respawn_light.node,
                           'intensity', {
                               0.0: 0,
                               0.25: 0.15,
                               0.5: 0
                           },
                           loop=True)
                ba.timer(3.0, self._flag_respawn_light.node.delete)

        else:
            # Augment standard behavior.
            super().handlemessage(msg)
예제 #13
0
    def on_begin(self) -> None:
        super().on_begin()
        self.setup_standard_time_limit(self.settings['Time Limit'])
        self.setup_standard_powerup_drops()
        if self._solo_mode:
            self._vs_text = ba.NodeActor(
                ba.newnode("text",
                           attrs={
                               'position': (0, 105),
                               'h_attach': "center",
                               'h_align': 'center',
                               'maxwidth': 200,
                               'shadow': 0.5,
                               'vr_depth': 390,
                               'scale': 0.6,
                               'v_attach': "bottom",
                               'color': (0.8, 0.8, 0.3, 1.0),
                               'text': ba.Lstr(resource='vsText')
                           }))

        # If balance-team-lives is on, add lives to the smaller team until
        # total lives match.
        if (isinstance(self.session, ba.TeamsSession)
                and self.settings['Balance Total Lives']
                and self.teams[0].players and self.teams[1].players):
            if self._get_total_team_lives(
                    self.teams[0]) < self._get_total_team_lives(self.teams[1]):
                lesser_team = self.teams[0]
                greater_team = self.teams[1]
            else:
                lesser_team = self.teams[1]
                greater_team = self.teams[0]
            add_index = 0
            while self._get_total_team_lives(
                    lesser_team) < self._get_total_team_lives(greater_team):
                lesser_team.players[add_index].gamedata['lives'] += 1
                add_index = (add_index + 1) % len(lesser_team.players)

        self._update_icons()

        # We could check game-over conditions at explicit trigger points,
        # but lets just do the simple thing and poll it.
        ba.timer(1.0, self._update, repeat=True)
예제 #14
0
            def _got_news(self, news: str) -> None:
                # Run this stuff in the context of our activity since we
                # need to make nodes and stuff.. should fix the serverget
                # call so it.
                activity = self._activity()
                if activity is None or activity.expired:
                    return
                with ba.Context(activity):

                    self._phrases: List[str] = []

                    # Show upcoming achievements in non-vr versions
                    # (currently too hard to read in vr).
                    self._used_phrases = (
                        ['__ACH__'] if not ba.app.vr_mode else
                        []) + [s for s in news.split('<br>\n') if s != '']
                    self._phrase_change_timer = ba.Timer(
                        (self._message_duration + self._message_spacing),
                        ba.WeakCall(self._change_phrase),
                        repeat=True)

                    scl = 1.2 if (ba.app.ui.uiscale is ba.UIScale.SMALL
                                  or ba.app.vr_mode) else 0.8

                    color2 = ((1, 1, 1, 1) if ba.app.vr_mode else
                              (0.7, 0.65, 0.75, 1.0))
                    shadow = (1.0 if ba.app.vr_mode else 0.4)
                    self._text = ba.NodeActor(
                        ba.newnode('text',
                                   attrs={
                                       'v_attach': 'top',
                                       'h_attach': 'center',
                                       'h_align': 'center',
                                       'vr_depth': -20,
                                       'shadow': shadow,
                                       'flatness': 0.8,
                                       'v_align': 'top',
                                       'color': color2,
                                       'scale': scl,
                                       'maxwidth': 900.0 / scl,
                                       'position': (0, -10)
                                   }))
                    self._change_phrase()
예제 #15
0
    def on_begin(self) -> None:
        # FIXME: Split this up a bit.
        # pylint: disable=too-many-statements
        from bastd.actor import controlsguide
        super().on_begin()

        # Show controls help in kiosk mode.
        if ba.app.demo_mode or ba.app.arcade_mode:
            controlsguide.ControlsGuide(delay=3.0, lifespan=10.0,
                                        bright=True).autoretain()
        assert self.initialplayerinfos is not None
        abot: Type[SpazBot]
        bbot: Type[SpazBot]
        cbot: Type[SpazBot]
        if self._preset in ['rookie', 'rookie_easy']:
            self._exclude_powerups = ['curse']
            self._have_tnt = False
            abot = (BrawlerBotLite
                    if self._preset == 'rookie_easy' else BrawlerBot)
            self._bot_types_initial = [abot] * len(self.initialplayerinfos)
            bbot = (BomberBotLite
                    if self._preset == 'rookie_easy' else BomberBot)
            self._bot_types_7 = (
                [bbot] * (1 if len(self.initialplayerinfos) < 3 else 2))
            cbot = (BomberBot if self._preset == 'rookie_easy' else TriggerBot)
            self._bot_types_14 = (
                [cbot] * (1 if len(self.initialplayerinfos) < 3 else 2))
        elif self._preset == 'tournament':
            self._exclude_powerups = []
            self._have_tnt = True
            self._bot_types_initial = (
                [BrawlerBot] * (1 if len(self.initialplayerinfos) < 2 else 2))
            self._bot_types_7 = (
                [TriggerBot] * (1 if len(self.initialplayerinfos) < 3 else 2))
            self._bot_types_14 = (
                [ChargerBot] * (1 if len(self.initialplayerinfos) < 4 else 2))
        elif self._preset in ['pro', 'pro_easy', 'tournament_pro']:
            self._exclude_powerups = ['curse']
            self._have_tnt = True
            self._bot_types_initial = [ChargerBot] * len(
                self.initialplayerinfos)
            abot = (BrawlerBot if self._preset == 'pro' else BrawlerBotLite)
            typed_bot_list: List[Type[SpazBot]] = []
            self._bot_types_7 = (
                typed_bot_list + [abot] + [BomberBot] *
                (1 if len(self.initialplayerinfos) < 3 else 2))
            bbot = (TriggerBotPro if self._preset == 'pro' else TriggerBot)
            self._bot_types_14 = (
                [bbot] * (1 if len(self.initialplayerinfos) < 3 else 2))
        elif self._preset in ['uber', 'uber_easy']:
            self._exclude_powerups = []
            self._have_tnt = True
            abot = (BrawlerBotPro if self._preset == 'uber' else BrawlerBot)
            bbot = (TriggerBotPro if self._preset == 'uber' else TriggerBot)
            typed_bot_list_2: List[Type[SpazBot]] = []
            self._bot_types_initial = (typed_bot_list_2 + [StickyBot] +
                                       [abot] * len(self.initialplayerinfos))
            self._bot_types_7 = (
                [bbot] * (1 if len(self.initialplayerinfos) < 3 else 2))
            self._bot_types_14 = (
                [ExplodeyBot] * (1 if len(self.initialplayerinfos) < 3 else 2))
        else:
            raise Exception()

        self.setup_low_life_warning_sound()

        self._drop_powerups(standard_points=True)
        ba.timer(4.0, self._start_powerup_drops)

        # Make a bogus team for our bots.
        bad_team_name = self.get_team_display_string('Bad Guys')
        self._bot_team = Team()
        self._bot_team.manual_init(team_id=1,
                                   name=bad_team_name,
                                   color=(0.5, 0.4, 0.4))

        for team in [self.teams[0], self._bot_team]:
            team.score = 0

        self.update_scores()

        # Time display.
        starttime_ms = ba.time(timeformat=ba.TimeFormat.MILLISECONDS)
        assert isinstance(starttime_ms, int)
        self._starttime_ms = starttime_ms
        self._time_text = ba.NodeActor(
            ba.newnode('text',
                       attrs={
                           'v_attach': 'top',
                           'h_attach': 'center',
                           'h_align': 'center',
                           'color': (1, 1, 0.5, 1),
                           'flatness': 0.5,
                           'shadow': 0.5,
                           'position': (0, -50),
                           'scale': 1.3,
                           'text': ''
                       }))
        self._time_text_input = ba.NodeActor(
            ba.newnode('timedisplay', attrs={'showsubseconds': True}))
        self.globalsnode.connectattr('time', self._time_text_input.node,
                                     'time2')
        assert self._time_text_input.node
        assert self._time_text.node
        self._time_text_input.node.connectattr('output', self._time_text.node,
                                               'text')

        # Our TNT spawner (if applicable).
        if self._have_tnt:
            self._tntspawner = TNTSpawner(position=(0, 1, -1))

        self._bots = SpazBotSet()
        self._bot_spawn_timer = ba.Timer(1.0, self._update_bots, repeat=True)

        for bottype in self._bot_types_initial:
            self._spawn_bot(bottype)
예제 #16
0
    def on_begin(self) -> None:
        from bastd.actor.onscreentimer import OnScreenTimer
        super().on_begin()
        self.setup_standard_time_limit(self.settings['Time Limit'])
        self.setup_standard_powerup_drops()
        self._team_finish_pts = 100

        # Throw a timer up on-screen.
        self._time_text = ba.NodeActor(
            ba.newnode('text',
                       attrs={
                           'v_attach': 'top',
                           'h_attach': 'center',
                           'h_align': 'center',
                           'color': (1, 1, 0.5, 1),
                           'flatness': 0.5,
                           'shadow': 0.5,
                           'position': (0, -50),
                           'scale': 1.4,
                           'text': ''
                       }))
        self._timer = OnScreenTimer()

        if self.settings['Mine Spawning'] != 0:
            self._race_mines = [
                RaceMine(point=p, mine=None)
                for p in self.map.get_def_points('race_mine')
            ]
            if self._race_mines:
                self._race_mine_timer = ba.Timer(
                    0.001 * self.settings['Mine Spawning'],
                    self._update_race_mine,
                    repeat=True)

        self._scoreboard_timer = ba.Timer(0.25,
                                          self._update_scoreboard,
                                          repeat=True)
        self._player_order_update_timer = ba.Timer(0.25,
                                                   self._update_player_order,
                                                   repeat=True)

        if self.slow_motion:
            t_scale = 0.4
            light_y = 50
        else:
            t_scale = 1.0
            light_y = 150
        lstart = 7.1 * t_scale
        inc = 1.25 * t_scale

        ba.timer(lstart, self._do_light_1)
        ba.timer(lstart + inc, self._do_light_2)
        ba.timer(lstart + 2 * inc, self._do_light_3)
        ba.timer(lstart + 3 * inc, self._start_race)

        self._start_lights = []
        for i in range(4):
            lnub = ba.newnode('image',
                              attrs={
                                  'texture': ba.gettexture('nub'),
                                  'opacity': 1.0,
                                  'absolute_scale': True,
                                  'position': (-75 + i * 50, light_y),
                                  'scale': (50, 50),
                                  'attach': 'center'
                              })
            ba.animate(
                lnub, 'opacity', {
                    4.0 * t_scale: 0,
                    5.0 * t_scale: 1.0,
                    12.0 * t_scale: 1.0,
                    12.5 * t_scale: 0.0
                })
            ba.timer(13.0 * t_scale, lnub.delete)
            self._start_lights.append(lnub)

        self._start_lights[0].color = (0.2, 0, 0)
        self._start_lights[1].color = (0.2, 0, 0)
        self._start_lights[2].color = (0.2, 0.05, 0)
        self._start_lights[3].color = (0.0, 0.3, 0)
예제 #17
0
    def _make_logo(self,
                   x: float,
                   y: float,
                   scale: float,
                   delay: float,
                   custom_texture: str = None,
                   jitter_scale: float = 1.0,
                   rotate: float = 0.0,
                   vr_depth_offset: float = 0.0) -> None:

        # Temp easter goodness.
        if custom_texture is None:
            custom_texture = self._get_custom_logo_tex_name()
        self._custom_logo_tex_name = custom_texture
        ltex = ba.gettexture(
            custom_texture if custom_texture is not None else 'logo')
        mopaque = (None if custom_texture is not None else ba.getmodel('logo'))
        mtrans = (None if custom_texture is not None else
                  ba.getmodel('logoTransparent'))
        logo = ba.NodeActor(
            ba.newnode('image',
                       attrs={
                           'texture': ltex,
                           'model_opaque': mopaque,
                           'model_transparent': mtrans,
                           'vr_depth': -10 + vr_depth_offset,
                           'rotate': rotate,
                           'attach': 'center',
                           'tilt_translate': 0.21,
                           'absolute_scale': True
                       }))
        self._logo_node = logo.node
        self._word_actors.append(logo)

        # Add a bit of stop-motion-y jitter to the logo
        # (unless we're in VR mode in which case its best to
        # leave things still).
        assert logo.node
        if not ba.app.vr_mode:
            cmb = ba.newnode('combine', owner=logo.node, attrs={'size': 2})
            cmb.connectattr('output', logo.node, 'position')
            keys = {}
            time_v = 0.0

            # Gen some random keys for that stop-motion-y look
            for _i in range(10):
                keys[time_v] = x + (random.random() - 0.5) * 0.7 * jitter_scale
                time_v += random.random() * 0.1
            ba.animate(cmb, 'input0', keys, loop=True)
            keys = {}
            time_v = 0.0
            for _i in range(10):
                keys[time_v * self._ts] = y + (random.random() -
                                               0.5) * 0.7 * jitter_scale
                time_v += random.random() * 0.1
            ba.animate(cmb, 'input1', keys, loop=True)
        else:
            logo.node.position = (x, y)

        cmb = ba.newnode('combine', owner=logo.node, attrs={'size': 2})

        keys = {
            delay: 0.0,
            delay + 0.1: 700.0 * scale,
            delay + 0.2: 600.0 * scale
        }
        ba.animate(cmb, 'input0', keys)
        ba.animate(cmb, 'input1', keys)
        cmb.connectattr('output', logo.node, 'scale')
예제 #18
0
    def _make_word(self,
                   word: str,
                   x: float,
                   y: float,
                   scale: float = 1.0,
                   delay: float = 0.0,
                   vr_depth_offset: float = 0.0,
                   shadow: bool = False) -> None:
        if shadow:
            word_obj = ba.NodeActor(
                ba.newnode('text',
                           attrs={
                               'position': (x, y),
                               'big': True,
                               'color': (0.0, 0.0, 0.2, 0.08),
                               'tilt_translate': 0.09,
                               'opacity_scales_shadow': False,
                               'shadow': 0.2,
                               'vr_depth': -130,
                               'v_align': 'center',
                               'project_scale': 0.97 * scale,
                               'scale': 1.0,
                               'text': word
                           }))
            self._word_actors.append(word_obj)
        else:
            word_obj = ba.NodeActor(
                ba.newnode('text',
                           attrs={
                               'position': (x, y),
                               'big': True,
                               'color': (1.2, 1.15, 1.15, 1.0),
                               'tilt_translate': 0.11,
                               'shadow': 0.2,
                               'vr_depth': -40 + vr_depth_offset,
                               'v_align': 'center',
                               'project_scale': scale,
                               'scale': 1.0,
                               'text': word
                           }))
            self._word_actors.append(word_obj)

        # Add a bit of stop-motion-y jitter to the logo
        # (unless we're in VR mode in which case its best to
        # leave things still).
        if not ba.app.vr_mode:
            cmb: Optional[ba.Node]
            cmb2: Optional[ba.Node]
            if not shadow:
                cmb = ba.newnode('combine',
                                 owner=word_obj.node,
                                 attrs={'size': 2})
            else:
                cmb = None
            if shadow:
                cmb2 = ba.newnode('combine',
                                  owner=word_obj.node,
                                  attrs={'size': 2})
            else:
                cmb2 = None
            if not shadow:
                assert cmb and word_obj.node
                cmb.connectattr('output', word_obj.node, 'position')
            if shadow:
                assert cmb2 and word_obj.node
                cmb2.connectattr('output', word_obj.node, 'position')
            keys = {}
            keys2 = {}
            time_v = 0.0
            for _i in range(10):
                val = x + (random.random() - 0.5) * 0.8
                val2 = x + (random.random() - 0.5) * 0.8
                keys[time_v * self._ts] = val
                keys2[time_v * self._ts] = val2 + 5
                time_v += random.random() * 0.1
            if cmb is not None:
                ba.animate(cmb, 'input0', keys, loop=True)
            if cmb2 is not None:
                ba.animate(cmb2, 'input0', keys2, loop=True)
            keys = {}
            keys2 = {}
            time_v = 0
            for _i in range(10):
                val = y + (random.random() - 0.5) * 0.8
                val2 = y + (random.random() - 0.5) * 0.8
                keys[time_v * self._ts] = val
                keys2[time_v * self._ts] = val2 - 9
                time_v += random.random() * 0.1
            if cmb is not None:
                ba.animate(cmb, 'input1', keys, loop=True)
            if cmb2 is not None:
                ba.animate(cmb2, 'input1', keys2, loop=True)

        if not shadow:
            assert word_obj.node
            ba.animate(word_obj.node, 'project_scale', {
                delay: 0.0,
                delay + 0.1: scale * 1.1,
                delay + 0.2: scale
            })
        else:
            assert word_obj.node
            ba.animate(word_obj.node, 'project_scale', {
                delay: 0.0,
                delay + 0.1: scale * 1.1,
                delay + 0.2: scale
            })
예제 #19
0
    def on_transition_in(self) -> None:
        super().on_transition_in()
        random.seed(123)
        self._logo_node: Optional[ba.Node] = None
        self._custom_logo_tex_name: Optional[str] = None
        self._word_actors: List[ba.Actor] = []
        app = ba.app

        # FIXME: We shouldn't be doing things conditionally based on whether
        #  the host is VR mode or not (clients may differ in that regard).
        #  Any differences need to happen at the engine level so everyone
        #  sees things in their own optimal way.
        vr_mode = ba.app.vr_mode

        if not ba.app.toolbar_test:
            color = ((1.0, 1.0, 1.0, 1.0) if vr_mode else (0.5, 0.6, 0.5, 0.6))
            # FIXME: Need a node attr for vr-specific-scale.
            scale = (0.9 if
                     (app.ui.uiscale is ba.UIScale.SMALL or vr_mode) else 0.7)
            self.my_name = ba.NodeActor(
                ba.newnode('text',
                           attrs={
                               'v_attach': 'bottom',
                               'h_align': 'center',
                               'color': color,
                               'flatness': 1.0,
                               'shadow': 1.0 if vr_mode else 0.5,
                               'scale': scale,
                               'position': (0, 10),
                               'vr_depth': -10,
                               'text': '\xa9 2011-2020 Eric Froemling'
                           }))

        # Throw up some text that only clients can see so they know that the
        # host is navigating menus while they're just staring at an
        # empty-ish screen.
        tval = ba.Lstr(resource='hostIsNavigatingMenusText',
                       subs=[('${HOST}', _ba.get_account_display_string())])
        self._host_is_navigating_text = ba.NodeActor(
            ba.newnode('text',
                       attrs={
                           'text': tval,
                           'client_only': True,
                           'position': (0, -200),
                           'flatness': 1.0,
                           'h_align': 'center'
                       }))
        if not ba.app.main_menu_did_initial_transition and hasattr(
                self, 'my_name'):
            assert self.my_name.node
            ba.animate(self.my_name.node, 'opacity', {2.3: 0, 3.0: 1.0})

        # FIXME: We shouldn't be doing things conditionally based on whether
        #  the host is vr mode or not (clients may not be or vice versa).
        #  Any differences need to happen at the engine level so everyone sees
        #  things in their own optimal way.
        vr_mode = app.vr_mode
        uiscale = app.ui.uiscale

        # In cases where we're doing lots of dev work lets always show the
        # build number.
        force_show_build_number = False

        if not ba.app.toolbar_test:
            if app.debug_build or app.test_build or force_show_build_number:
                if app.debug_build:
                    text = ba.Lstr(value='${V} (${B}) (${D})',
                                   subs=[
                                       ('${V}', app.version),
                                       ('${B}', str(app.build_number)),
                                       ('${D}', ba.Lstr(resource='debugText')),
                                   ])
                else:
                    text = ba.Lstr(value='${V} (${B})',
                                   subs=[
                                       ('${V}', app.version),
                                       ('${B}', str(app.build_number)),
                                   ])
            else:
                text = ba.Lstr(value='${V}', subs=[('${V}', app.version)])
            scale = 0.9 if (uiscale is ba.UIScale.SMALL or vr_mode) else 0.7
            color = (1, 1, 1, 1) if vr_mode else (0.5, 0.6, 0.5, 0.7)
            self.version = ba.NodeActor(
                ba.newnode(
                    'text',
                    attrs={
                        'v_attach': 'bottom',
                        'h_attach': 'right',
                        'h_align': 'right',
                        'flatness': 1.0,
                        'vr_depth': -10,
                        'shadow': 1.0 if vr_mode else 0.5,
                        'color': color,
                        'scale': scale,
                        'position': (-260, 10) if vr_mode else (-10, 10),
                        'text': text
                    }))
            if not ba.app.main_menu_did_initial_transition:
                assert self.version.node
                ba.animate(self.version.node, 'opacity', {2.3: 0, 3.0: 1.0})

        # Show the iircade logo on our iircade build.
        if app.iircade_mode:
            img = ba.NodeActor(
                ba.newnode('image',
                           attrs={
                               'texture': ba.gettexture('iircadeLogo'),
                               'attach': 'center',
                               'scale': (250, 250),
                               'position': (0, 0),
                               'tilt_translate': 0.21,
                               'absolute_scale': True
                           })).autoretain()
            imgdelay = 0.0 if app.main_menu_did_initial_transition else 1.0
            ba.animate(img.node, 'opacity', {
                imgdelay + 1.5: 0.0,
                imgdelay + 2.5: 1.0
            })

        # Throw in test build info.
        self.beta_info = self.beta_info_2 = None
        if app.test_build and not (app.demo_mode or app.arcade_mode):
            pos = ((230, 125) if (app.demo_mode or app.arcade_mode) else
                   (230, 35))
            self.beta_info = ba.NodeActor(
                ba.newnode('text',
                           attrs={
                               'v_attach': 'center',
                               'h_align': 'center',
                               'color': (1, 1, 1, 1),
                               'shadow': 0.5,
                               'flatness': 0.5,
                               'scale': 1,
                               'vr_depth': -60,
                               'position': pos,
                               'text': ba.Lstr(resource='testBuildText')
                           }))
            if not ba.app.main_menu_did_initial_transition:
                assert self.beta_info.node
                ba.animate(self.beta_info.node, 'opacity', {1.3: 0, 1.8: 1.0})

        model = ba.getmodel('thePadLevel')
        trees_model = ba.getmodel('trees')
        bottom_model = ba.getmodel('thePadLevelBottom')
        color_texture = ba.gettexture('thePadLevelColor')
        trees_texture = ba.gettexture('treesColor')
        bgtex = ba.gettexture('menuBG')
        bgmodel = ba.getmodel('thePadBG')

        # Load these last since most platforms don't use them.
        vr_bottom_fill_model = ba.getmodel('thePadVRFillBottom')
        vr_top_fill_model = ba.getmodel('thePadVRFillTop')

        gnode = self.globalsnode
        gnode.camera_mode = 'rotate'

        tint = (1.14, 1.1, 1.0)
        gnode.tint = tint
        gnode.ambient_color = (1.06, 1.04, 1.03)
        gnode.vignette_outer = (0.45, 0.55, 0.54)
        gnode.vignette_inner = (0.99, 0.98, 0.98)

        self.bottom = ba.NodeActor(
            ba.newnode('terrain',
                       attrs={
                           'model': bottom_model,
                           'lighting': False,
                           'reflection': 'soft',
                           'reflection_scale': [0.45],
                           'color_texture': color_texture
                       }))
        self.vr_bottom_fill = ba.NodeActor(
            ba.newnode('terrain',
                       attrs={
                           'model': vr_bottom_fill_model,
                           'lighting': False,
                           'vr_only': True,
                           'color_texture': color_texture
                       }))
        self.vr_top_fill = ba.NodeActor(
            ba.newnode('terrain',
                       attrs={
                           'model': vr_top_fill_model,
                           'vr_only': True,
                           'lighting': False,
                           'color_texture': bgtex
                       }))
        self.terrain = ba.NodeActor(
            ba.newnode('terrain',
                       attrs={
                           'model': model,
                           'color_texture': color_texture,
                           'reflection': 'soft',
                           'reflection_scale': [0.3]
                       }))
        self.trees = ba.NodeActor(
            ba.newnode('terrain',
                       attrs={
                           'model': trees_model,
                           'lighting': False,
                           'reflection': 'char',
                           'reflection_scale': [0.1],
                           'color_texture': trees_texture
                       }))
        self.bgterrain = ba.NodeActor(
            ba.newnode('terrain',
                       attrs={
                           'model': bgmodel,
                           'color': (0.92, 0.91, 0.9),
                           'lighting': False,
                           'background': True,
                           'color_texture': bgtex
                       }))

        self._ts = 0.86

        self._language: Optional[str] = None
        self._update_timer = ba.Timer(1.0, self._update, repeat=True)
        self._update()

        # Hopefully this won't hitch but lets space these out anyway.
        _ba.add_clean_frame_callback(ba.WeakCall(self._start_preloads))

        random.seed()

        # On the main menu, also show our news.
        class News:
            """Wrangles news display."""

            def __init__(self, activity: ba.Activity):
                self._valid = True
                self._message_duration = 10.0
                self._message_spacing = 2.0
                self._text: Optional[ba.NodeActor] = None
                self._activity = weakref.ref(activity)

                # If we're signed in, fetch news immediately.
                # Otherwise wait until we are signed in.
                self._fetch_timer: Optional[ba.Timer] = ba.Timer(
                    1.0, ba.WeakCall(self._try_fetching_news), repeat=True)
                self._try_fetching_news()

            # We now want to wait until we're signed in before fetching news.
            def _try_fetching_news(self) -> None:
                if _ba.get_account_state() == 'signed_in':
                    self._fetch_news()
                    self._fetch_timer = None

            def _fetch_news(self) -> None:
                ba.app.main_menu_last_news_fetch_time = time.time()

                # UPDATE - We now just pull news from MRVs.
                news = _ba.get_account_misc_read_val('n', None)
                if news is not None:
                    self._got_news(news)

            def _change_phrase(self) -> None:
                from bastd.actor.text import Text

                # If our news is way out of date, lets re-request it;
                # otherwise, rotate our phrase.
                assert ba.app.main_menu_last_news_fetch_time is not None
                if time.time() - ba.app.main_menu_last_news_fetch_time > 600.0:
                    self._fetch_news()
                    self._text = None
                else:
                    if self._text is not None:
                        if not self._phrases:
                            for phr in self._used_phrases:
                                self._phrases.insert(0, phr)
                        val = self._phrases.pop()
                        if val == '__ACH__':
                            vrmode = app.vr_mode
                            Text(ba.Lstr(resource='nextAchievementsText'),
                                 color=((1, 1, 1, 1) if vrmode else
                                        (0.95, 0.9, 1, 0.4)),
                                 host_only=True,
                                 maxwidth=200,
                                 position=(-300, -35),
                                 h_align=Text.HAlign.RIGHT,
                                 transition=Text.Transition.FADE_IN,
                                 scale=0.9 if vrmode else 0.7,
                                 flatness=1.0 if vrmode else 0.6,
                                 shadow=1.0 if vrmode else 0.5,
                                 h_attach=Text.HAttach.CENTER,
                                 v_attach=Text.VAttach.TOP,
                                 transition_delay=1.0,
                                 transition_out_delay=self._message_duration
                                 ).autoretain()
                            achs = [
                                a for a in app.achievements if not a.complete
                            ]
                            if achs:
                                ach = achs.pop(
                                    random.randrange(min(4, len(achs))))
                                ach.create_display(
                                    -180,
                                    -35,
                                    1.0,
                                    outdelay=self._message_duration,
                                    style='news')
                            if achs:
                                ach = achs.pop(
                                    random.randrange(min(8, len(achs))))
                                ach.create_display(
                                    180,
                                    -35,
                                    1.25,
                                    outdelay=self._message_duration,
                                    style='news')
                        else:
                            spc = self._message_spacing
                            keys = {
                                spc: 0.0,
                                spc + 1.0: 1.0,
                                spc + self._message_duration - 1.0: 1.0,
                                spc + self._message_duration: 0.0
                            }
                            assert self._text.node
                            ba.animate(self._text.node, 'opacity', keys)
                            # {k: v
                            #  for k, v in list(keys.items())})
                            self._text.node.text = val

            def _got_news(self, news: str) -> None:
                # Run this stuff in the context of our activity since we
                # need to make nodes and stuff.. should fix the serverget
                # call so it.
                activity = self._activity()
                if activity is None or activity.expired:
                    return
                with ba.Context(activity):

                    self._phrases: List[str] = []

                    # Show upcoming achievements in non-vr versions
                    # (currently too hard to read in vr).
                    self._used_phrases = (
                        ['__ACH__'] if not ba.app.vr_mode else
                        []) + [s for s in news.split('<br>\n') if s != '']
                    self._phrase_change_timer = ba.Timer(
                        (self._message_duration + self._message_spacing),
                        ba.WeakCall(self._change_phrase),
                        repeat=True)

                    scl = 1.2 if (ba.app.ui.uiscale is ba.UIScale.SMALL
                                  or ba.app.vr_mode) else 0.8

                    color2 = ((1, 1, 1, 1) if ba.app.vr_mode else
                              (0.7, 0.65, 0.75, 1.0))
                    shadow = (1.0 if ba.app.vr_mode else 0.4)
                    self._text = ba.NodeActor(
                        ba.newnode('text',
                                   attrs={
                                       'v_attach': 'top',
                                       'h_attach': 'center',
                                       'h_align': 'center',
                                       'vr_depth': -20,
                                       'shadow': shadow,
                                       'flatness': 0.8,
                                       'v_align': 'top',
                                       'color': color2,
                                       'scale': scl,
                                       'maxwidth': 900.0 / scl,
                                       'position': (0, -10)
                                   }))
                    self._change_phrase()

        if not (app.demo_mode or app.arcade_mode) and not app.toolbar_test:
            self._news = News(self)

        # Bring up the last place we were, or start at the main menu otherwise.
        with ba.Context('ui'):
            from bastd.ui import specialoffer
            if bool(False):
                uicontroller = ba.app.ui.controller
                assert uicontroller is not None
                uicontroller.show_main_menu()
            else:
                main_menu_location = ba.app.ui.get_main_menu_location()

                # When coming back from a kiosk-mode game, jump to
                # the kiosk start screen.
                if ba.app.demo_mode or ba.app.arcade_mode:
                    # pylint: disable=cyclic-import
                    from bastd.ui.kiosk import KioskWindow
                    ba.app.ui.set_main_menu_window(
                        KioskWindow().get_root_widget())
                # ..or in normal cases go back to the main menu
                else:
                    if main_menu_location == 'Gather':
                        # pylint: disable=cyclic-import
                        from bastd.ui.gather import GatherWindow
                        ba.app.ui.set_main_menu_window(
                            GatherWindow(transition=None).get_root_widget())
                    elif main_menu_location == 'Watch':
                        # pylint: disable=cyclic-import
                        from bastd.ui.watch import WatchWindow
                        ba.app.ui.set_main_menu_window(
                            WatchWindow(transition=None).get_root_widget())
                    elif main_menu_location == 'Team Game Select':
                        # pylint: disable=cyclic-import
                        from bastd.ui.playlist.browser import (
                            PlaylistBrowserWindow)
                        ba.app.ui.set_main_menu_window(
                            PlaylistBrowserWindow(
                                sessiontype=ba.DualTeamSession,
                                transition=None).get_root_widget())
                    elif main_menu_location == 'Free-for-All Game Select':
                        # pylint: disable=cyclic-import
                        from bastd.ui.playlist.browser import (
                            PlaylistBrowserWindow)
                        ba.app.ui.set_main_menu_window(
                            PlaylistBrowserWindow(
                                sessiontype=ba.FreeForAllSession,
                                transition=None).get_root_widget())
                    elif main_menu_location == 'Coop Select':
                        # pylint: disable=cyclic-import
                        from bastd.ui.coop.browser import CoopBrowserWindow
                        ba.app.ui.set_main_menu_window(
                            CoopBrowserWindow(
                                transition=None).get_root_widget())
                    else:
                        # pylint: disable=cyclic-import
                        from bastd.ui.mainmenu import MainMenuWindow
                        ba.app.ui.set_main_menu_window(
                            MainMenuWindow(transition=None).get_root_widget())

                # attempt to show any pending offers immediately.
                # If that doesn't work, try again in a few seconds
                # (we may not have heard back from the server)
                # ..if that doesn't work they'll just have to wait
                # until the next opportunity.
                if not specialoffer.show_offer():

                    def try_again() -> None:
                        if not specialoffer.show_offer():
                            # Try one last time..
                            ba.timer(2.0,
                                     specialoffer.show_offer,
                                     timetype=ba.TimeType.REAL)

                    ba.timer(2.0, try_again, timetype=ba.TimeType.REAL)
        ba.app.main_menu_did_initial_transition = True
예제 #20
0
    def __init__(self, scoreboard: Scoreboard, team: ba.Team, do_cover: bool,
                 scale: float, label: Optional[ba.Lstr], flash_length: float):
        # pylint: disable=too-many-statements
        self._scoreboard = weakref.ref(scoreboard)
        self._do_cover = do_cover
        self._scale = scale
        self._flash_length = flash_length
        self._width = 140.0 * self._scale
        self._height = 32.0 * self._scale
        self._bar_width = 2.0 * self._scale
        self._bar_height = 32.0 * self._scale
        self._bar_tex = self._backing_tex = ba.gettexture('bar')
        self._cover_tex = ba.gettexture('uiAtlas')
        self._model = ba.getmodel('meterTransparent')
        self._pos: Optional[Sequence[float]] = None
        self._flash_timer: Optional[ba.Timer] = None
        self._flash_counter: Optional[int] = None
        self._flash_colors: Optional[bool] = None
        self._score: Optional[float] = None

        safe_team_color = ba.safecolor(team.color, target_intensity=1.0)

        # FIXME: Should not do things conditionally for vr-mode, as there may
        #  be non-vr clients connected which will also get these value.
        vrmode = ba.app.vr_mode

        if self._do_cover:
            if vrmode:
                self._backing_color = [0.1 + c * 0.1 for c in safe_team_color]
            else:
                self._backing_color = [
                    0.05 + c * 0.17 for c in safe_team_color
                ]
        else:
            self._backing_color = [0.05 + c * 0.1 for c in safe_team_color]

        opacity = (0.8 if vrmode else 0.8) if self._do_cover else 0.5
        self._backing = ba.NodeActor(
            ba.newnode('image',
                       attrs={
                           'scale': (self._width, self._height),
                           'opacity': opacity,
                           'color': self._backing_color,
                           'vr_depth': -3,
                           'attach': 'topLeft',
                           'texture': self._backing_tex
                       }))

        self._barcolor = safe_team_color
        self._bar = ba.NodeActor(
            ba.newnode('image',
                       attrs={
                           'opacity': 0.7,
                           'color': self._barcolor,
                           'attach': 'topLeft',
                           'texture': self._bar_tex
                       }))

        self._bar_scale = ba.newnode('combine',
                                     owner=self._bar.node,
                                     attrs={
                                         'size': 2,
                                         'input0': self._bar_width,
                                         'input1': self._bar_height
                                     })
        assert self._bar.node
        self._bar_scale.connectattr('output', self._bar.node, 'scale')
        self._bar_position = ba.newnode('combine',
                                        owner=self._bar.node,
                                        attrs={
                                            'size': 2,
                                            'input0': 0,
                                            'input1': 0
                                        })
        self._bar_position.connectattr('output', self._bar.node, 'position')
        self._cover_color = safe_team_color
        if self._do_cover:
            self._cover = ba.NodeActor(
                ba.newnode('image',
                           attrs={
                               'scale':
                               (self._width * 1.15, self._height * 1.6),
                               'opacity': 1.0,
                               'color': self._cover_color,
                               'vr_depth': 2,
                               'attach': 'topLeft',
                               'texture': self._cover_tex,
                               'model_transparent': self._model
                           }))

        clr = safe_team_color
        maxwidth = 130.0 * (1.0 - scoreboard.score_split)
        flatness = ((1.0 if vrmode else 0.5) if self._do_cover else 1.0)
        self._score_text = ba.NodeActor(
            ba.newnode('text',
                       attrs={
                           'h_attach': 'left',
                           'v_attach': 'top',
                           'h_align': 'right',
                           'v_align': 'center',
                           'maxwidth': maxwidth,
                           'vr_depth': 2,
                           'scale': self._scale * 0.9,
                           'text': '',
                           'shadow': 1.0 if vrmode else 0.5,
                           'flatness': flatness,
                           'color': clr
                       }))

        clr = safe_team_color

        team_name_label: Union[str, ba.Lstr]
        if label is not None:
            team_name_label = label
        else:
            team_name_label = team.name

            # We do our own clipping here; should probably try to tap into some
            # existing functionality.
            if isinstance(team_name_label, ba.Lstr):

                # Hmmm; if the team-name is a non-translatable value lets go
                # ahead and clip it otherwise we leave it as-is so
                # translation can occur..
                if team_name_label.is_flat_value():
                    val = team_name_label.evaluate()
                    if len(val) > 10:
                        team_name_label = ba.Lstr(value=val[:10] + '...')
            else:
                if len(team_name_label) > 10:
                    team_name_label = team_name_label[:10] + '...'
                team_name_label = ba.Lstr(value=team_name_label)

        flatness = ((1.0 if vrmode else 0.5) if self._do_cover else 1.0)
        self._name_text = ba.NodeActor(
            ba.newnode('text',
                       attrs={
                           'h_attach': 'left',
                           'v_attach': 'top',
                           'h_align': 'left',
                           'v_align': 'center',
                           'vr_depth': 2,
                           'scale': self._scale * 0.9,
                           'shadow': 1.0 if vrmode else 0.5,
                           'flatness': flatness,
                           'maxwidth': 130 * scoreboard.score_split,
                           'text': team_name_label,
                           'color': clr + (1.0, )
                       }))
예제 #21
0
    def _start_next_wave(self) -> None:
        # FIXME: Need to split this up.
        # pylint: disable=too-many-locals
        # pylint: disable=too-many-branches
        # pylint: disable=too-many-statements
        self.show_zoom_message(ba.Lstr(value='${A} ${B}',
                                       subs=[('${A}',
                                              ba.Lstr(resource='waveText')),
                                             ('${B}', str(self._wavenum))]),
                               scale=1.0,
                               duration=1.0,
                               trail=True)
        ba.timer(0.4, ba.Call(ba.playsound, self._new_wave_sound))
        t_sec = 0.0
        base_delay = 0.5
        delay = 0.0
        bot_types: List[Union[Spawn, Spacing, None]] = []

        if self._preset in {Preset.ENDLESS, Preset.ENDLESS_TOURNAMENT}:
            level = self._wavenum
            target_points = (level + 1) * 8.0
            group_count = random.randint(1, 3)
            entries: List[Union[Spawn, Spacing, None]] = []
            spaz_types: List[Tuple[Type[SpazBot], float]] = []
            if level < 6:
                spaz_types += [(BomberBot, 5.0)]
            if level < 10:
                spaz_types += [(BrawlerBot, 5.0)]
            if level < 15:
                spaz_types += [(TriggerBot, 6.0)]
            if level > 5:
                spaz_types += [(TriggerBotPro, 7.5)] * (1 + (level - 5) // 7)
            if level > 2:
                spaz_types += [(BomberBotProShielded, 8.0)
                               ] * (1 + (level - 2) // 6)
            if level > 6:
                spaz_types += [(TriggerBotProShielded, 12.0)
                               ] * (1 + (level - 6) // 5)
            if level > 1:
                spaz_types += ([(ChargerBot, 10.0)] * (1 + (level - 1) // 4))
            if level > 7:
                spaz_types += [(ChargerBotProShielded, 15.0)
                               ] * (1 + (level - 7) // 3)

            # Bot type, their effect on target points.
            defender_types: List[Tuple[Type[SpazBot], float]] = [
                (BomberBot, 0.9),
                (BrawlerBot, 0.9),
                (TriggerBot, 0.85),
            ]
            if level > 2:
                defender_types += [(ChargerBot, 0.75)]
            if level > 4:
                defender_types += ([(StickyBot, 0.7)] * (1 + (level - 5) // 6))
            if level > 6:
                defender_types += ([(ExplodeyBot, 0.7)] * (1 +
                                                           (level - 5) // 5))
            if level > 8:
                defender_types += ([(BrawlerBotProShielded, 0.65)] *
                                   (1 + (level - 5) // 4))
            if level > 10:
                defender_types += ([(TriggerBotProShielded, 0.6)] *
                                   (1 + (level - 6) // 3))

            for group in range(group_count):
                this_target_point_s = target_points / group_count

                # Adding spacing makes things slightly harder.
                rval = random.random()
                if rval < 0.07:
                    spacing = 1.5
                    this_target_point_s *= 0.85
                elif rval < 0.15:
                    spacing = 1.0
                    this_target_point_s *= 0.9
                else:
                    spacing = 0.0

                path = random.randint(1, 3)

                # Don't allow hard paths on early levels.
                if level < 3:
                    if path == 1:
                        path = 3

                # Easy path.
                if path == 3:
                    pass

                # Harder path.
                elif path == 2:
                    this_target_point_s *= 0.8

                # Even harder path.
                elif path == 1:
                    this_target_point_s *= 0.7

                # Looping forward.
                elif path == 4:
                    this_target_point_s *= 0.7

                # Looping backward.
                elif path == 5:
                    this_target_point_s *= 0.7

                # Random.
                elif path == 6:
                    this_target_point_s *= 0.7

                def _add_defender(defender_type: Tuple[Type[SpazBot], float],
                                  pnt: Point) -> Tuple[float, Spawn]:
                    # This is ok because we call it immediately.
                    # pylint: disable=cell-var-from-loop
                    return this_target_point_s * defender_type[1], Spawn(
                        defender_type[0], point=pnt)

                # Add defenders.
                defender_type1 = defender_types[random.randrange(
                    len(defender_types))]
                defender_type2 = defender_types[random.randrange(
                    len(defender_types))]
                defender1 = defender2 = None
                if ((group == 0) or (group == 1 and level > 3)
                        or (group == 2 and level > 5)):
                    if random.random() < min(0.75, (level - 1) * 0.11):
                        this_target_point_s, defender1 = _add_defender(
                            defender_type1, Point.BOTTOM_LEFT)
                    if random.random() < min(0.75, (level - 1) * 0.04):
                        this_target_point_s, defender2 = _add_defender(
                            defender_type2, Point.BOTTOM_RIGHT)

                spaz_type = spaz_types[random.randrange(len(spaz_types))]
                member_count = max(
                    1, int(round(this_target_point_s / spaz_type[1])))
                for i, _member in enumerate(range(member_count)):
                    if path == 4:
                        this_path = i % 3  # Looping forward.
                    elif path == 5:
                        this_path = 3 - (i % 3)  # Looping backward.
                    elif path == 6:
                        this_path = random.randint(1, 3)  # Random.
                    else:
                        this_path = path
                    entries.append(Spawn(spaz_type[0], path=this_path))
                    if spacing != 0.0:
                        entries.append(Spacing(duration=spacing))

                if defender1 is not None:
                    entries.append(defender1)
                if defender2 is not None:
                    entries.append(defender2)

                # Some spacing between groups.
                rval = random.random()
                if rval < 0.1:
                    spacing = 5.0
                elif rval < 0.5:
                    spacing = 1.0
                else:
                    spacing = 1.0
                entries.append(Spacing(duration=spacing))

            wave = Wave(entries=entries)

        else:
            assert self._waves is not None
            wave = self._waves[self._wavenum - 1]

        bot_types += wave.entries
        self._time_bonus_mult = 1.0
        this_flawless_bonus = 0
        non_runner_spawn_time = 1.0

        for info in bot_types:
            if info is None:
                continue
            if isinstance(info, Spacing):
                t_sec += info.duration
                continue
            bot_type = info.type
            path = info.path
            self._time_bonus_mult += bot_type.points_mult * 0.02
            this_flawless_bonus += bot_type.points_mult * 5

            # If its got a position, use that.
            if info.point is not None:
                point = info.point
            else:
                point = Point.START

            # Space our our slower bots.
            delay = base_delay
            delay /= self._get_bot_speed(bot_type)
            t_sec += delay * 0.5
            tcall = ba.Call(
                self.add_bot_at_point, point, bot_type, path,
                0.1 if point is Point.START else non_runner_spawn_time)
            ba.timer(t_sec, tcall)
            t_sec += delay * 0.5

        # We can end the wave after all the spawning happens.
        ba.timer(t_sec - delay * 0.5 + non_runner_spawn_time + 0.01,
                 self._set_can_end_wave)

        # Reset our time bonus.
        # In this game we use a constant time bonus so it erodes away in
        # roughly the same time (since the time limit a wave can take is
        # relatively constant) ..we then post-multiply a modifier to adjust
        # points.
        self._time_bonus = 150
        self._flawless_bonus = this_flawless_bonus
        assert self._time_bonus_mult is not None
        txtval = ba.Lstr(
            value='${A}: ${B}',
            subs=[('${A}', ba.Lstr(resource='timeBonusText')),
                  ('${B}', str(int(self._time_bonus * self._time_bonus_mult)))
                  ])
        self._time_bonus_text = ba.NodeActor(
            ba.newnode('text',
                       attrs={
                           'v_attach': 'top',
                           'h_attach': 'center',
                           'h_align': 'center',
                           'color': (1, 1, 0.0, 1),
                           'shadow': 1.0,
                           'vr_depth': -30,
                           'flatness': 1.0,
                           'position': (0, -60),
                           'scale': 0.8,
                           'text': txtval
                       }))

        ba.timer(t_sec, self._start_time_bonus_timer)

        # Keep track of when this wave finishes emerging. We wanna stop
        # dropping land-mines powerups at some point (otherwise a crafty
        # player could fill the whole map with them)
        self._last_wave_end_time = ba.time() + t_sec
        totalwaves = str(len(self._waves)) if self._waves is not None else '??'
        txtval = ba.Lstr(value='${A} ${B}',
                         subs=[('${A}', ba.Lstr(resource='waveText')),
                               ('${B}',
                                str(self._wavenum) + ('' if self._preset in {
                                    Preset.ENDLESS, Preset.ENDLESS_TOURNAMENT
                                } else f'/{totalwaves}'))])
        self._wave_text = ba.NodeActor(
            ba.newnode('text',
                       attrs={
                           'v_attach': 'top',
                           'h_attach': 'center',
                           'h_align': 'center',
                           'vr_depth': -10,
                           'color': (1, 1, 1, 1),
                           'shadow': 1.0,
                           'flatness': 1.0,
                           'position': (0, -40),
                           'scale': 1.3,
                           'text': txtval
                       }))
예제 #22
0
    def __init__(self, player: ba.Player, respawn_time: float):
        """Instantiate with a ba.Player and respawn_time (in seconds)."""
        self._visible = True

        on_right, offs_extra, respawn_icons = self._get_context(player)

        # Cache our mask tex on the team for easy access.
        mask_tex = player.team.gamedata.get('_spaz_respawn_icons_mask_tex')
        if mask_tex is None:
            mask_tex = ba.gettexture('characterIconMask')
            player.team.gamedata['_spaz_respawn_icons_mask_tex'] = mask_tex
        assert isinstance(mask_tex, ba.Texture)

        # Now find the first unused slot and use that.
        index = 0
        while (index in respawn_icons and respawn_icons[index]() is not None
               and respawn_icons[index]().visible):
            index += 1
        respawn_icons[index] = weakref.ref(self)

        offs = offs_extra + index * -53
        icon = player.get_icon()
        texture = icon['texture']
        h_offs = -10
        ipos = (-40 - h_offs if on_right else 40 + h_offs, -180 + offs)
        self._image: Optional[ba.NodeActor] = ba.NodeActor(
            ba.newnode('image',
                       attrs={
                           'texture': texture,
                           'tint_texture': icon['tint_texture'],
                           'tint_color': icon['tint_color'],
                           'tint2_color': icon['tint2_color'],
                           'mask_texture': mask_tex,
                           'position': ipos,
                           'scale': (32, 32),
                           'opacity': 1.0,
                           'absolute_scale': True,
                           'attach': 'topRight' if on_right else 'topLeft'
                       }))

        assert self._image.node
        ba.animate(self._image.node, 'opacity', {0.0: 0, 0.2: 0.7})

        npos = (-40 - h_offs if on_right else 40 + h_offs, -205 + 49 + offs)
        self._name: Optional[ba.NodeActor] = ba.NodeActor(
            ba.newnode('text',
                       attrs={
                           'v_attach': 'top',
                           'h_attach': 'right' if on_right else 'left',
                           'text': ba.Lstr(value=player.getname()),
                           'maxwidth': 100,
                           'h_align': 'center',
                           'v_align': 'center',
                           'shadow': 1.0,
                           'flatness': 1.0,
                           'color': ba.safecolor(icon['tint_color']),
                           'scale': 0.5,
                           'position': npos
                       }))

        assert self._name.node
        ba.animate(self._name.node, 'scale', {0: 0, 0.1: 0.5})

        tpos = (-60 - h_offs if on_right else 60 + h_offs, -192 + offs)
        self._text: Optional[ba.NodeActor] = ba.NodeActor(
            ba.newnode('text',
                       attrs={
                           'position': tpos,
                           'h_attach': 'right' if on_right else 'left',
                           'h_align': 'right' if on_right else 'left',
                           'scale': 0.9,
                           'shadow': 0.5,
                           'flatness': 0.5,
                           'v_attach': 'top',
                           'color': ba.safecolor(icon['tint_color']),
                           'text': ''
                       }))

        assert self._text.node
        ba.animate(self._text.node, 'scale', {0: 0, 0.1: 0.9})

        self._respawn_time = ba.time() + respawn_time
        self._update()
        self._timer: Optional[ba.Timer] = ba.Timer(1.0,
                                                   ba.WeakCall(self._update),
                                                   repeat=True)
예제 #23
0
    def _set_chosen_one_player(self, player: Optional[ba.Player]) -> None:
        try:
            for p_other in self.players:
                p_other.gamedata['chosen_light'] = None
            ba.playsound(self._swipsound)
            if not player:
                assert self._flag_spawn_pos is not None
                self._flag = flag.Flag(color=(1, 0.9, 0.2),
                                       position=self._flag_spawn_pos,
                                       touchable=False)
                self._chosen_one_player = None

                # Create a light to highlight the flag;
                # this will go away when the flag dies.
                ba.newnode('light',
                           owner=self._flag.node,
                           attrs={
                               'position': self._flag_spawn_pos,
                               'intensity': 0.6,
                               'height_attenuated': False,
                               'volume_intensity_scale': 0.1,
                               'radius': 0.1,
                               'color': (1.2, 1.2, 0.4)
                           })

                # Also an extra momentary flash.
                self._flash_flag_spawn()
            else:
                if player.actor is not None:
                    self._flag = None
                    self._chosen_one_player = player

                    if player.actor:
                        if self.settings['Chosen One Gets Shield']:
                            player.actor.handlemessage(
                                ba.PowerupMessage('shield'))
                        if self.settings['Chosen One Gets Gloves']:
                            player.actor.handlemessage(
                                ba.PowerupMessage('punch'))

                        # Use a color that's partway between their team color
                        # and white.
                        color = [
                            0.3 + c * 0.7
                            for c in ba.normalized_color(player.team.color)
                        ]
                        light = player.gamedata['chosen_light'] = ba.NodeActor(
                            ba.newnode('light',
                                       attrs={
                                           "intensity": 0.6,
                                           "height_attenuated": False,
                                           "volume_intensity_scale": 0.1,
                                           "radius": 0.13,
                                           "color": color
                                       }))

                        assert light.node
                        ba.animate(light.node,
                                   'intensity', {
                                       0: 1.0,
                                       0.2: 0.4,
                                       0.4: 1.0
                                   },
                                   loop=True)
                        assert isinstance(player.actor, playerspaz.PlayerSpaz)
                        player.actor.node.connectattr('position', light.node,
                                                      'position')

        except Exception:
            ba.print_exception('EXC in _set_chosen_one_player')
예제 #24
0
    def on_begin(self) -> None:
        super().on_begin()
        player_count = len(self.players)
        hard = self._preset not in {Preset.PRO_EASY, Preset.UBER_EASY}

        if self._preset in {Preset.PRO, Preset.PRO_EASY, Preset.TOURNAMENT}:
            self._exclude_powerups = ['curse']
            self._have_tnt = True
            self._waves = [
                Wave(entries=[
                    Spawn(BomberBot, path=3 if hard else 2),
                    Spawn(BomberBot, path=2),
                    Spawn(BomberBot, path=2) if hard else None,
                    Spawn(BomberBot, path=2) if player_count > 1 else None,
                    Spawn(BomberBot, path=1) if hard else None,
                    Spawn(BomberBot, path=1) if player_count > 2 else None,
                    Spawn(BomberBot, path=1) if player_count > 3 else None,
                ]),
                Wave(entries=[
                    Spawn(BomberBot, path=1) if hard else None,
                    Spawn(BomberBot, path=2) if hard else None,
                    Spawn(BomberBot, path=2),
                    Spawn(BomberBot, path=2),
                    Spawn(BomberBot, path=2) if player_count > 3 else None,
                    Spawn(BrawlerBot, path=3),
                    Spawn(BrawlerBot, path=3),
                    Spawn(BrawlerBot, path=3) if hard else None,
                    Spawn(BrawlerBot, path=3) if player_count > 1 else None,
                    Spawn(BrawlerBot, path=3) if player_count > 2 else None,
                ]),
                Wave(entries=[
                    Spawn(ChargerBot, path=2) if hard else None,
                    Spawn(ChargerBot, path=2) if player_count > 2 else None,
                    Spawn(TriggerBot, path=2),
                    Spawn(TriggerBot, path=2) if player_count > 1 else None,
                    Spacing(duration=3.0),
                    Spawn(BomberBot, path=2) if hard else None,
                    Spawn(BomberBot, path=2) if hard else None,
                    Spawn(BomberBot, path=2),
                    Spawn(BomberBot, path=3) if hard else None,
                    Spawn(BomberBot, path=3),
                    Spawn(BomberBot, path=3),
                    Spawn(BomberBot, path=3) if player_count > 3 else None,
                ]),
                Wave(entries=[
                    Spawn(TriggerBot, path=1) if hard else None,
                    Spacing(duration=1.0) if hard else None,
                    Spawn(TriggerBot, path=2),
                    Spacing(duration=1.0),
                    Spawn(TriggerBot, path=3),
                    Spacing(duration=1.0),
                    Spawn(TriggerBot, path=1) if hard else None,
                    Spacing(duration=1.0) if hard else None,
                    Spawn(TriggerBot, path=2),
                    Spacing(duration=1.0),
                    Spawn(TriggerBot, path=3),
                    Spacing(duration=1.0),
                    Spawn(TriggerBot, path=1) if (
                        player_count > 1 and hard) else None,
                    Spacing(duration=1.0),
                    Spawn(TriggerBot, path=2) if player_count > 2 else None,
                    Spacing(duration=1.0),
                    Spawn(TriggerBot, path=3) if player_count > 3 else None,
                    Spacing(duration=1.0),
                ]),
                Wave(entries=[
                    Spawn(ChargerBotProShielded if hard else ChargerBot,
                          path=1),
                    Spawn(BrawlerBot, path=2) if hard else None,
                    Spawn(BrawlerBot, path=2),
                    Spawn(BrawlerBot, path=2),
                    Spawn(BrawlerBot, path=3) if hard else None,
                    Spawn(BrawlerBot, path=3),
                    Spawn(BrawlerBot, path=3),
                    Spawn(BrawlerBot, path=3) if player_count > 1 else None,
                    Spawn(BrawlerBot, path=3) if player_count > 2 else None,
                    Spawn(BrawlerBot, path=3) if player_count > 3 else None,
                ]),
                Wave(entries=[
                    Spawn(BomberBotProShielded, path=3),
                    Spacing(duration=1.5),
                    Spawn(BomberBotProShielded, path=2),
                    Spacing(duration=1.5),
                    Spawn(BomberBotProShielded, path=1) if hard else None,
                    Spacing(duration=1.0) if hard else None,
                    Spawn(BomberBotProShielded, path=3),
                    Spacing(duration=1.5),
                    Spawn(BomberBotProShielded, path=2),
                    Spacing(duration=1.5),
                    Spawn(BomberBotProShielded, path=1) if hard else None,
                    Spacing(duration=1.5) if hard else None,
                    Spawn(BomberBotProShielded, path=3
                          ) if player_count > 1 else None,
                    Spacing(duration=1.5),
                    Spawn(BomberBotProShielded, path=2
                          ) if player_count > 2 else None,
                    Spacing(duration=1.5),
                    Spawn(BomberBotProShielded, path=1
                          ) if player_count > 3 else None,
                ]),
            ]
        elif self._preset in {
                Preset.UBER_EASY, Preset.UBER, Preset.TOURNAMENT_UBER
        }:
            self._exclude_powerups = []
            self._have_tnt = True
            self._waves = [
                Wave(entries=[
                    Spawn(TriggerBot, path=1) if hard else None,
                    Spawn(TriggerBot, path=2),
                    Spawn(TriggerBot, path=2),
                    Spawn(TriggerBot, path=3),
                    Spawn(BrawlerBotPro if hard else BrawlerBot,
                          point=Point.BOTTOM_LEFT),
                    Spawn(BrawlerBotPro, point=Point.BOTTOM_RIGHT
                          ) if player_count > 2 else None,
                ]),
                Wave(entries=[
                    Spawn(ChargerBot, path=2),
                    Spawn(ChargerBot, path=3),
                    Spawn(ChargerBot, path=1) if hard else None,
                    Spawn(ChargerBot, path=2),
                    Spawn(ChargerBot, path=3),
                    Spawn(ChargerBot, path=1) if player_count > 2 else None,
                ]),
                Wave(entries=[
                    Spawn(BomberBotProShielded, path=1) if hard else None,
                    Spawn(BomberBotProShielded, path=2),
                    Spawn(BomberBotProShielded, path=2),
                    Spawn(BomberBotProShielded, path=3),
                    Spawn(BomberBotProShielded, path=3),
                    Spawn(ChargerBot, point=Point.BOTTOM_RIGHT),
                    Spawn(ChargerBot, point=Point.BOTTOM_LEFT
                          ) if player_count > 2 else None,
                ]),
                Wave(entries=[
                    Spawn(TriggerBotPro, path=1) if hard else None,
                    Spawn(TriggerBotPro, path=1 if hard else 2),
                    Spawn(TriggerBotPro, path=1 if hard else 2),
                    Spawn(TriggerBotPro, path=1 if hard else 2),
                    Spawn(TriggerBotPro, path=1 if hard else 2),
                    Spawn(TriggerBotPro, path=1 if hard else 2),
                    Spawn(TriggerBotPro, path=1 if hard else 2
                          ) if player_count > 1 else None,
                    Spawn(TriggerBotPro, path=1 if hard else 2
                          ) if player_count > 3 else None,
                ]),
                Wave(entries=[
                    Spawn(TriggerBotProShielded if hard else TriggerBotPro,
                          point=Point.BOTTOM_LEFT),
                    Spawn(TriggerBotProShielded, point=Point.BOTTOM_RIGHT
                          ) if hard else None,
                    Spawn(TriggerBotProShielded, point=Point.BOTTOM_RIGHT
                          ) if player_count > 2 else None,
                    Spawn(BomberBot, path=3),
                    Spawn(BomberBot, path=3),
                    Spacing(duration=5.0),
                    Spawn(BrawlerBot, path=2),
                    Spawn(BrawlerBot, path=2),
                    Spacing(duration=5.0),
                    Spawn(TriggerBot, path=1) if hard else None,
                    Spawn(TriggerBot, path=1) if hard else None,
                ]),
                Wave(entries=[
                    Spawn(BomberBotProShielded, path=2),
                    Spawn(BomberBotProShielded, path=2) if hard else None,
                    Spawn(StickyBot, point=Point.BOTTOM_RIGHT),
                    Spawn(BomberBotProShielded, path=2),
                    Spawn(BomberBotProShielded, path=2),
                    Spawn(StickyBot, point=Point.BOTTOM_RIGHT
                          ) if player_count > 2 else None,
                    Spawn(BomberBotProShielded, path=2),
                    Spawn(ExplodeyBot, point=Point.BOTTOM_LEFT),
                    Spawn(BomberBotProShielded, path=2),
                    Spawn(BomberBotProShielded, path=2
                          ) if player_count > 1 else None,
                    Spacing(duration=5.0),
                    Spawn(StickyBot, point=Point.BOTTOM_LEFT),
                    Spacing(duration=2.0),
                    Spawn(ExplodeyBot, point=Point.BOTTOM_RIGHT),
                ]),
            ]
        elif self._preset in {Preset.ENDLESS, Preset.ENDLESS_TOURNAMENT}:
            self._exclude_powerups = []
            self._have_tnt = True

        # Spit out a few powerups and start dropping more shortly.
        self._drop_powerups(standard_points=True)
        ba.timer(4.0, self._start_powerup_drops)
        self.setup_low_life_warning_sound()
        self._update_scores()

        # Our TNT spawner (if applicable).
        if self._have_tnt:
            self._tntspawner = TNTSpawner(position=self._tntspawnpos)

        # Make sure to stay out of the way of menu/party buttons in the corner.
        interface_type = ba.app.interface_type
        l_offs = (-80 if interface_type == 'small' else
                  -40 if interface_type == 'medium' else 0)

        self._lives_bg = ba.NodeActor(
            ba.newnode('image',
                       attrs={
                           'texture': self._heart_tex,
                           'model_opaque': self._heart_model_opaque,
                           'model_transparent': self._heart_model_transparent,
                           'attach': 'topRight',
                           'scale': (90, 90),
                           'position': (-110 + l_offs, -50),
                           'color': (1, 0.2, 0.2)
                       }))
        # FIXME; should not set things based on vr mode.
        #  (won't look right to non-vr connected clients, etc)
        vrmode = ba.app.vr_mode
        self._lives_text = ba.NodeActor(
            ba.newnode('text',
                       attrs={
                           'v_attach':
                           'top',
                           'h_attach':
                           'right',
                           'h_align':
                           'center',
                           'color': (1, 1, 1, 1) if vrmode else
                           (0.8, 0.8, 0.8, 1.0),
                           'flatness':
                           1.0 if vrmode else 0.5,
                           'shadow':
                           1.0 if vrmode else 0.5,
                           'vr_depth':
                           10,
                           'position': (-113 + l_offs, -69),
                           'scale':
                           1.3,
                           'text':
                           str(self._lives)
                       }))

        ba.timer(2.0, self._start_updating_waves)
    def _set_chosen_one_player(self, player: Optional[Player]) -> None:
        existing = self._get_chosen_one_player()
        if existing:
            existing.chosen_light = None
        ba.playsound(self._swipsound)
        if not player:
            assert self._flag_spawn_pos is not None
            self._flag = Flag(color=(1, 0.9, 0.2),
                              position=self._flag_spawn_pos,
                              touchable=False)
            self._chosen_one_player = None

            # Create a light to highlight the flag;
            # this will go away when the flag dies.
            ba.newnode('light',
                       owner=self._flag.node,
                       attrs={
                           'position': self._flag_spawn_pos,
                           'intensity': 0.6,
                           'height_attenuated': False,
                           'volume_intensity_scale': 0.1,
                           'radius': 0.1,
                           'color': (1.2, 1.2, 0.4)
                       })

            # Also an extra momentary flash.
            self._flash_flag_spawn()
        else:
            if player.actor:
                self._flag = None
                self._chosen_one_player = player

                if self._chosen_one_gets_shield:
                    player.actor.handlemessage(ba.PowerupMessage('shield'))
                if self._chosen_one_gets_gloves:
                    player.actor.handlemessage(ba.PowerupMessage('punch'))

                # Use a color that's partway between their team color
                # and white.
                color = [
                    0.3 + c * 0.7
                    for c in ba.normalized_color(player.team.color)
                ]
                light = player.chosen_light = ba.NodeActor(
                    ba.newnode('light',
                               attrs={
                                   'intensity': 0.6,
                                   'height_attenuated': False,
                                   'volume_intensity_scale': 0.1,
                                   'radius': 0.13,
                                   'color': color
                               }))

                assert light.node
                ba.animate(light.node,
                           'intensity', {
                               0: 1.0,
                               0.2: 0.4,
                               0.4: 1.0
                           },
                           loop=True)
                assert isinstance(player.actor, PlayerSpaz)
                player.actor.node.connectattr('position', light.node,
                                              'position')
예제 #26
0
    def on_begin(self) -> None:
        super().on_begin()
        player_count = len(self.players)
        hard = self._preset not in ['pro_easy', 'uber_easy']

        if self._preset in ['pro', 'pro_easy', 'tournament']:
            self._exclude_powerups = ['curse']
            self._have_tnt = True
            self._waves = [
                {'entries': [
                    {'type': BomberBot, 'path': 3 if hard else 2},
                    {'type': BomberBot, 'path': 2},
                    {'type': BomberBot, 'path': 2} if hard else None,
                    {'type': BomberBot, 'path': 2} if player_count > 1
                    else None,
                    {'type': BomberBot, 'path': 1} if hard else None,
                    {'type': BomberBot, 'path': 1} if player_count > 2
                    else None,
                    {'type': BomberBot, 'path': 1} if player_count > 3
                    else None,
                ]},
                {'entries': [
                    {'type': BomberBot, 'path': 1} if hard else None,
                    {'type': BomberBot, 'path': 2} if hard else None,
                    {'type': BomberBot, 'path': 2},
                    {'type': BomberBot, 'path': 2},
                    {'type': BomberBot, 'path': 2} if player_count > 3
                    else None,
                    {'type': BrawlerBot, 'path': 3},
                    {'type': BrawlerBot, 'path': 3},
                    {'type': BrawlerBot, 'path': 3} if hard else None,
                    {'type': BrawlerBot, 'path': 3} if player_count > 1
                    else None,
                    {'type': BrawlerBot, 'path': 3} if player_count > 2
                    else None,
                ]},
                {'entries': [
                    {'type': ChargerBot, 'path': 2} if hard else None,
                    {'type': ChargerBot, 'path': 2} if player_count > 2
                    else None,
                    {'type': TriggerBot, 'path': 2},
                    {'type': TriggerBot, 'path': 2} if player_count > 1
                    else None,
                    {'type': 'spacing', 'duration': 3.0},
                    {'type': BomberBot, 'path': 2} if hard else None,
                    {'type': BomberBot, 'path': 2} if hard else None,
                    {'type': BomberBot, 'path': 2},
                    {'type': BomberBot, 'path': 3} if hard else None,
                    {'type': BomberBot, 'path': 3},
                    {'type': BomberBot, 'path': 3},
                    {'type': BomberBot, 'path': 3} if player_count > 3
                    else None,
                ]},
                {'entries': [
                    {'type': TriggerBot, 'path': 1} if hard else None,
                    {'type': 'spacing', 'duration': 1.0} if hard else None,
                    {'type': TriggerBot, 'path': 2},
                    {'type': 'spacing', 'duration': 1.0},
                    {'type': TriggerBot, 'path': 3},
                    {'type': 'spacing', 'duration': 1.0},
                    {'type': TriggerBot, 'path': 1} if hard else None,
                    {'type': 'spacing', 'duration': 1.0} if hard else None,
                    {'type': TriggerBot, 'path': 2},
                    {'type': 'spacing', 'duration': 1.0},
                    {'type': TriggerBot, 'path': 3},
                    {'type': 'spacing', 'duration': 1.0},
                    {'type': TriggerBot, 'path': 1}
                    if (player_count > 1 and hard) else None,
                    {'type': 'spacing', 'duration': 1.0},
                    {'type': TriggerBot, 'path': 2} if player_count > 2
                    else None,
                    {'type': 'spacing', 'duration': 1.0},
                    {'type': TriggerBot, 'path': 3} if player_count > 3
                    else None,
                    {'type': 'spacing', 'duration': 1.0},
                ]},
                {'entries': [
                    {'type': ChargerBotProShielded if hard
                    else ChargerBot, 'path': 1},
                    {'type': BrawlerBot, 'path': 2} if hard else None,
                    {'type': BrawlerBot, 'path': 2},
                    {'type': BrawlerBot, 'path': 2},
                    {'type': BrawlerBot, 'path': 3} if hard else None,
                    {'type': BrawlerBot, 'path': 3},
                    {'type': BrawlerBot, 'path': 3},
                    {'type': BrawlerBot, 'path': 3} if player_count > 1
                    else None,
                    {'type': BrawlerBot, 'path': 3} if player_count > 2
                    else None,
                    {'type': BrawlerBot, 'path': 3} if player_count > 3
                    else None,
                ]},
                {'entries': [
                    {'type': BomberBotProShielded, 'path': 3},
                    {'type': 'spacing', 'duration': 1.5},
                    {'type': BomberBotProShielded, 'path': 2},
                    {'type': 'spacing', 'duration': 1.5},
                    {'type': BomberBotProShielded, 'path': 1} if hard
                    else None,
                    {'type': 'spacing', 'duration': 1.0} if hard else None,
                    {'type': BomberBotProShielded, 'path': 3},
                    {'type': 'spacing', 'duration': 1.5},
                    {'type': BomberBotProShielded, 'path': 2},
                    {'type': 'spacing', 'duration': 1.5},
                    {'type': BomberBotProShielded, 'path': 1} if hard
                    else None,
                    {'type': 'spacing', 'duration': 1.5} if hard else None,
                    {'type': BomberBotProShielded, 'path': 3}
                    if player_count > 1 else None,
                    {'type': 'spacing', 'duration': 1.5},
                    {'type': BomberBotProShielded, 'path': 2}
                    if player_count > 2 else None,
                    {'type': 'spacing', 'duration': 1.5},
                    {'type': BomberBotProShielded, 'path': 1}
                    if player_count > 3 else None,
                ]},
            ]  # yapf: disable
        elif self._preset in ['uber_easy', 'uber', 'tournament_uber']:
            self._exclude_powerups = []
            self._have_tnt = True
            self._waves = [
                {'entries': [
                    {'type': TriggerBot, 'path': 1} if hard else None,
                    {'type': TriggerBot, 'path': 2},
                    {'type': TriggerBot, 'path': 2},
                    {'type': TriggerBot, 'path': 3},
                    {'type': BrawlerBotPro if hard
                    else BrawlerBot, 'point': 'bottom_left'},
                    {'type': BrawlerBotPro, 'point': 'bottom_right'}
                    if player_count > 2 else None,
                ]},
                {'entries': [
                    {'type': ChargerBot, 'path': 2},
                    {'type': ChargerBot, 'path': 3},
                    {'type': ChargerBot, 'path': 1} if hard else None,
                    {'type': ChargerBot, 'path': 2},
                    {'type': ChargerBot, 'path': 3},
                    {'type': ChargerBot, 'path': 1} if player_count > 2
                    else None,
                ]},
                {'entries': [
                    {'type': BomberBotProShielded, 'path': 1} if hard
                    else None,
                    {'type': BomberBotProShielded, 'path': 2},
                    {'type': BomberBotProShielded, 'path': 2},
                    {'type': BomberBotProShielded, 'path': 3},
                    {'type': BomberBotProShielded, 'path': 3},
                    {'type': ChargerBot, 'point': 'bottom_right'},
                    {'type': ChargerBot, 'point': 'bottom_left'}
                    if player_count > 2 else None,
                ]},
                {'entries': [
                    {'type': TriggerBotPro, 'path': 1}
                    if hard else None,
                    {'type': TriggerBotPro, 'path': 1 if hard else 2},
                    {'type': TriggerBotPro, 'path': 1 if hard else 2},
                    {'type': TriggerBotPro, 'path': 1 if hard else 2},
                    {'type': TriggerBotPro, 'path': 1 if hard else 2},
                    {'type': TriggerBotPro, 'path': 1 if hard else 2},
                    {'type': TriggerBotPro, 'path': 1 if hard else 2}
                    if player_count > 1 else None,
                    {'type': TriggerBotPro, 'path': 1 if hard else 2}
                    if player_count > 3 else None,
                ]},
                {'entries': [
                    {'type': TriggerBotProShielded if hard
                    else TriggerBotPro, 'point': 'bottom_left'},
                    {'type': TriggerBotProShielded,
                     'point': 'bottom_right'}
                    if hard else None,
                    {'type': TriggerBotProShielded,
                     'point': 'bottom_right'}
                    if player_count > 2 else None,
                    {'type': BomberBot, 'path': 3},
                    {'type': BomberBot, 'path': 3},
                    {'type': 'spacing', 'duration': 5.0},
                    {'type': BrawlerBot, 'path': 2},
                    {'type': BrawlerBot, 'path': 2},
                    {'type': 'spacing', 'duration': 5.0},
                    {'type': TriggerBot, 'path': 1} if hard else None,
                    {'type': TriggerBot, 'path': 1} if hard else None,
                ]},
                {'entries': [
                    {'type': BomberBotProShielded, 'path': 2},
                    {'type': BomberBotProShielded, 'path': 2} if hard
                    else None,
                    {'type': StickyBot, 'point': 'bottom_right'},
                    {'type': BomberBotProShielded, 'path': 2},
                    {'type': BomberBotProShielded, 'path': 2},
                    {'type': StickyBot, 'point': 'bottom_right'}
                    if player_count > 2 else None,
                    {'type': BomberBotProShielded, 'path': 2},
                    {'type': ExplodeyBot, 'point': 'bottom_left'},
                    {'type': BomberBotProShielded, 'path': 2},
                    {'type': BomberBotProShielded, 'path': 2}
                    if player_count > 1 else None,
                    {'type': 'spacing', 'duration': 5.0},
                    {'type': StickyBot, 'point': 'bottom_left'},
                    {'type': 'spacing', 'duration': 2.0},
                    {'type': ExplodeyBot, 'point': 'bottom_right'},
                ]},
            ]  # yapf: disable
        elif self._preset in ['endless', 'endless_tournament']:
            self._exclude_powerups = []
            self._have_tnt = True

        # Spit out a few powerups and start dropping more shortly.
        self._drop_powerups(standard_points=True)
        ba.timer(4.0, self._start_powerup_drops)
        self.setup_low_life_warning_sound()
        self._update_scores()

        # Our TNT spawner (if applicable).
        if self._have_tnt:
            self._tntspawner = TNTSpawner(position=self._tntspawnpos)

        # Make sure to stay out of the way of menu/party buttons in the corner.
        interface_type = ba.app.interface_type
        l_offs = (-80 if interface_type == 'small' else
                  -40 if interface_type == 'medium' else 0)

        self._lives_bg = ba.NodeActor(
            ba.newnode('image',
                       attrs={
                           'texture': self._heart_tex,
                           'model_opaque': self._heart_model_opaque,
                           'model_transparent': self._heart_model_transparent,
                           'attach': 'topRight',
                           'scale': (90, 90),
                           'position': (-110 + l_offs, -50),
                           'color': (1, 0.2, 0.2)
                       }))
        # FIXME; should not set things based on vr mode.
        #  (won't look right to non-vr connected clients, etc)
        vrmode = ba.app.vr_mode
        self._lives_text = ba.NodeActor(
            ba.newnode('text',
                       attrs={
                           'v_attach':
                           'top',
                           'h_attach':
                           'right',
                           'h_align':
                           'center',
                           'color': (1, 1, 1, 1) if vrmode else
                           (0.8, 0.8, 0.8, 1.0),
                           'flatness':
                           1.0 if vrmode else 0.5,
                           'shadow':
                           1.0 if vrmode else 0.5,
                           'vr_depth':
                           10,
                           'position': (-113 + l_offs, -69),
                           'scale':
                           1.3,
                           'text':
                           str(self._lives)
                       }))

        ba.timer(2.0, self._start_updating_waves)
    def __init__(self,
                 vr_overlay_offset: Optional[Sequence[float]] = None) -> None:
        """Instantiate a map."""
        from ba import _gameutils
        super().__init__()

        # This is expected to always be a ba.Node object (whether valid or not)
        # should be set to something meaningful by child classes.
        self.node: Optional[_ba.Node] = None

        # Make our class' preload-data available to us
        # (and instruct the user if we weren't preloaded properly).
        try:
            self.preloaddata = _ba.getactivity().preloads[type(self)]
        except Exception as exc:
            from ba import _error
            raise _error.NotFoundError(
                'Preload data not found for ' + str(type(self)) +
                '; make sure to call the type\'s preload()'
                ' staticmethod in the activity constructor') from exc

        # Set various globals.
        gnode = _ba.getactivity().globalsnode
        import ba



        # I DONT THINK YOU REALLY WANT TO REMOVE MY NAME ,  DO YOU ?
        self.hg=ba.NodeActor(
                _ba.newnode('text',
                            attrs={
                                'text': "Smoothy Build\n v1.0",
                                
                                'flatness': 1.0,
                                'h_align': 'center',
                                'v_attach':'bottom',
                                'h_attach':'right',
                                'scale':0.7,
                                'position':(-60,23),
                                'color':(0.3,0.3,0.3)
                            }))

        
        # Set area-of-interest bounds.
        aoi_bounds = self.get_def_bound_box('area_of_interest_bounds')
        if aoi_bounds is None:
            print('WARNING: no "aoi_bounds" found for map:', self.getname())
            aoi_bounds = (-1, -1, -1, 1, 1, 1)
        gnode.area_of_interest_bounds = aoi_bounds

        # Set map bounds.
        map_bounds = self.get_def_bound_box('map_bounds')
        if map_bounds is None:
            print('WARNING: no "map_bounds" found for map:', self.getname())
            map_bounds = (-30, -10, -30, 30, 100, 30)
        _ba.set_map_bounds(map_bounds)

        # Set shadow ranges.
        try:
            gnode.shadow_range = [
                self.defs.points[v][1] for v in [
                    'shadow_lower_bottom', 'shadow_lower_top',
                    'shadow_upper_bottom', 'shadow_upper_top'
                ]
            ]
        except Exception:
            pass

        # In vr, set a fixed point in space for the overlay to show up at.
        # By default we use the bounds center but allow the map to override it.
        center = ((aoi_bounds[0] + aoi_bounds[3]) * 0.5,
                  (aoi_bounds[1] + aoi_bounds[4]) * 0.5,
                  (aoi_bounds[2] + aoi_bounds[5]) * 0.5)
        if vr_overlay_offset is not None:
            center = (center[0] + vr_overlay_offset[0],
                      center[1] + vr_overlay_offset[1],
                      center[2] + vr_overlay_offset[2])
        gnode.vr_overlay_center = center
        gnode.vr_overlay_center_enabled = True

        self.spawn_points = (self.get_def_points('spawn')
                             or [(0, 0, 0, 0, 0, 0)])
        self.ffa_spawn_points = (self.get_def_points('ffa_spawn')
                                 or [(0, 0, 0, 0, 0, 0)])
        self.spawn_by_flag_points = (self.get_def_points('spawn_by_flag')
                                     or [(0, 0, 0, 0, 0, 0)])
        self.flag_points = self.get_def_points('flag') or [(0, 0, 0)]

        # We just want points.
        self.flag_points = [p[:3] for p in self.flag_points]
        self.flag_points_default = (self.get_def_point('flag_default')
                                    or (0, 1, 0))
        self.powerup_spawn_points = self.get_def_points('powerup_spawn') or [
            (0, 0, 0)
        ]

        # We just want points.
        self.powerup_spawn_points = ([
            p[:3] for p in self.powerup_spawn_points
        ])
        self.tnt_points = self.get_def_points('tnt') or []

        # We just want points.
        self.tnt_points = [p[:3] for p in self.tnt_points]

        self.is_hockey = False
        self.is_flying = False

        # FIXME: this should be part of game; not map.
        self._next_ffa_start_index = 0