コード例 #1
0
    def postinit(self, sessionplayer: ba.SessionPlayer) -> None:
        """Wire up a newly created player.

        (internal)
        """
        from ba._nodeactor import NodeActor

        # Sanity check; if a dataclass is created that inherits from us,
        # it will define an equality operator by default which will break
        # internal game logic. So complain loudly if we find one.
        if type(self).__eq__ is not object.__eq__:
            raise RuntimeError(
                f'Player class {type(self)} defines an equality'
                f' operator (__eq__) which will break internal'
                f' logic. Please remove it.\n'
                f'For dataclasses you can do "dataclass(eq=False)"'
                f' in the class decorator.')

        self.actor = None
        self.character = ''
        self._nodeactor: Optional[ba.NodeActor] = None
        self._sessionplayer = sessionplayer
        self.character = sessionplayer.character
        self.color = sessionplayer.color
        self.highlight = sessionplayer.highlight
        self._team = cast(TeamType, sessionplayer.sessionteam.activityteam)
        assert self._team is not None
        self._customdata = {}
        self._expired = False
        self._postinited = True
        node = _ba.newnode('player', attrs={'playerID': sessionplayer.id})
        self._nodeactor = NodeActor(node)
        sessionplayer.setnode(node)
コード例 #2
0
    def pause(self) -> None:
        """Pause the game due to a user request or menu popping up.

        If there's a foreground host-activity that says it's pausable, tell it
        to pause ..we now no longer pause if there are connected clients.
        """
        activity: Optional[ba.Activity] = _ba.get_foreground_host_activity()
        if (activity is not None and activity.allow_pausing
                and not _ba.have_connected_clients()):
            from ba import _gameutils
            from ba._language import Lstr
            from ba._nodeactor import NodeActor

            # FIXME: Shouldn't be touching scene stuff here;
            #  should just pass the request on to the host-session.
            with _ba.Context(activity):
                globs = activity.globalsnode
                if not globs.paused:
                    _ba.playsound(_ba.getsound('refWhistle'))
                    globs.paused = True

                # FIXME: This should not be an attr on Actor.
                activity.paused_text = NodeActor(
                    _ba.newnode('text',
                                attrs={
                                    'text': Lstr(resource='pausedByHostText'),
                                    'client_only': True,
                                    'flatness': 1.0,
                                    'h_align': 'center'
                                }))
コード例 #3
0
ファイル: _activity.py プロジェクト: Dmitry450/ballistica
 def create_player_node(self, player: ba.Player) -> ba.Node:
     """Create the 'player' node associated with the provided ba.Player."""
     from ba._nodeactor import NodeActor
     with _ba.Context(self):
         node = _ba.newnode('player', attrs={'playerID': player.get_id()})
         # FIXME: Should add a dedicated slot for this on ba.Player
         #  instead of cluttering up their gamedata dict.
         player.gamedata['_playernode'] = NodeActor(node)
         return node
コード例 #4
0
    def __init__(self, lobby: ba.Lobby):
        from ba._nodeactor import NodeActor
        from ba._general import WeakCall
        self._state = 0
        self._press_to_punch: Union[str,
                                    ba.Lstr] = ('C' if _ba.app.iircade_mode
                                                else _ba.charstr(
                                                    SpecialChar.LEFT_BUTTON))
        self._press_to_bomb: Union[str,
                                   ba.Lstr] = ('B' if _ba.app.iircade_mode else
                                               _ba.charstr(
                                                   SpecialChar.RIGHT_BUTTON))
        self._joinmsg = Lstr(resource='pressAnyButtonToJoinText')
        can_switch_teams = (len(lobby.sessionteams) > 1)

        # If we have a keyboard, grab keys for punch and pickup.
        # FIXME: This of course is only correct on the local device;
        #  Should change this for net games.
        keyboard = _ba.getinputdevice('Keyboard', '#1', doraise=False)
        if keyboard is not None:
            self._update_for_keyboard(keyboard)

        flatness = 1.0 if _ba.app.vr_mode else 0.0
        self._text = NodeActor(
            _ba.newnode('text',
                        attrs={
                            'position': (0, -40),
                            'h_attach': 'center',
                            'v_attach': 'top',
                            'h_align': 'center',
                            'color': (0.7, 0.7, 0.95, 1.0),
                            'flatness': flatness,
                            'text': self._joinmsg
                        }))

        if _ba.app.demo_mode or _ba.app.arcade_mode:
            self._messages = [self._joinmsg]
        else:
            msg1 = Lstr(resource='pressToSelectProfileText',
                        subs=[
                            ('${BUTTONS}', _ba.charstr(SpecialChar.UP_ARROW) +
                             ' ' + _ba.charstr(SpecialChar.DOWN_ARROW))
                        ])
            msg2 = Lstr(resource='pressToOverrideCharacterText',
                        subs=[('${BUTTONS}', Lstr(resource='bombBoldText'))])
            msg3 = Lstr(value='${A} < ${B} >',
                        subs=[('${A}', msg2), ('${B}', self._press_to_bomb)])
            self._messages = (([
                Lstr(
                    resource='pressToSelectTeamText',
                    subs=[('${BUTTONS}', _ba.charstr(SpecialChar.LEFT_ARROW) +
                           ' ' + _ba.charstr(SpecialChar.RIGHT_ARROW))],
                )
            ] if can_switch_teams else []) + [msg1] + [msg3] + [self._joinmsg])

        self._timer = _ba.Timer(4.0, WeakCall(self._update), repeat=True)
コード例 #5
0
 def setup_standard_time_limit(self, duration: float) -> None:
     """
     Create a standard game time-limit given the provided
     duration in seconds.
     This will be displayed at the top of the screen.
     If the time-limit expires, end_game() will be called.
     """
     from ba._nodeactor import NodeActor
     if duration <= 0.0:
         return
     self._standard_time_limit_time = int(duration)
     self._standard_time_limit_timer = _ba.Timer(
         1.0, WeakCall(self._standard_time_limit_tick), repeat=True)
     self._standard_time_limit_text = NodeActor(
         _ba.newnode('text',
                     attrs={
                         'v_attach': 'top',
                         'h_attach': 'center',
                         'h_align': 'left',
                         'color': (1.0, 1.0, 1.0, 0.5),
                         'position': (-25, -30),
                         'flatness': 1.0,
                         'scale': 0.9
                     }))
     self._standard_time_limit_text_input = NodeActor(
         _ba.newnode('timedisplay',
                     attrs={
                         'time2': duration * 1000,
                         'timemin': 0
                     }))
     self.globalsnode.connectattr('time',
                                  self._standard_time_limit_text_input.node,
                                  'time1')
     assert self._standard_time_limit_text_input.node
     assert self._standard_time_limit_text.node
     self._standard_time_limit_text_input.node.connectattr(
         'output', self._standard_time_limit_text.node, 'text')
コード例 #6
0
 def _update_life_warning(self) -> None:
     # Beep continuously if anyone is close to death.
     should_beep = False
     for player in self.players:
         if player.is_alive():
             # FIXME: Should abstract this instead of
             #  reading hitpoints directly.
             if getattr(player.actor, 'hitpoints', 999) < 200:
                 should_beep = True
                 break
     if should_beep and self._life_warning_beep is None:
         from ba._nodeactor import NodeActor
         self._life_warning_beep = NodeActor(
             _ba.newnode('sound',
                         attrs={
                             'sound': self._warn_beeps_sound,
                             'positional': False,
                             'loop': True
                         }))
     if self._life_warning_beep is not None and not should_beep:
         self._life_warning_beep = None
コード例 #7
0
ファイル: _coopgame.py プロジェクト: snow-1711/ballistica
    def _show_standard_scores_to_beat_ui(self,
                                         scores: List[Dict[str, Any]]) -> None:
        from efro.util import asserttype
        from ba._gameutils import timestring, animate
        from ba._nodeactor import NodeActor
        from ba._enums import TimeFormat
        display_type = self.get_score_type()
        if scores is not None:

            # Sort by originating date so that the most recent is first.
            scores.sort(reverse=True, key=lambda s: asserttype(s['time'], int))

            # Now make a display for the most recent challenge.
            for score in scores:
                if score['type'] == 'score_challenge':
                    tval = (score['player'] + ':  ' + timestring(
                        int(score['value']) * 10,
                        timeformat=TimeFormat.MILLISECONDS).evaluate()
                            if display_type == 'time' else str(score['value']))
                    hattach = 'center' if display_type == 'time' else 'left'
                    halign = 'center' if display_type == 'time' else 'left'
                    pos = (20, -70) if display_type == 'time' else (20, -130)
                    txt = NodeActor(
                        _ba.newnode('text',
                                    attrs={
                                        'v_attach': 'top',
                                        'h_attach': hattach,
                                        'h_align': halign,
                                        'color': (0.7, 0.4, 1, 1),
                                        'shadow': 0.5,
                                        'flatness': 1.0,
                                        'position': pos,
                                        'scale': 0.6,
                                        'text': tval
                                    })).autoretain()
                    assert txt.node is not None
                    animate(txt.node, 'scale', {1.0: 0.0, 1.1: 0.7, 1.2: 0.6})
                    break
コード例 #8
0
ファイル: _player.py プロジェクト: ShifengHuGit/ballistica
    def postinit(self, sessionplayer: ba.SessionPlayer) -> None:
        """Wire up a newly created player.

        (internal)
        """
        from ba._nodeactor import NodeActor

        # Sanity check; if a dataclass is created that inherits from us,
        # it will define an equality operator by default which will break
        # internal game logic. So complain loudly if we find one.
        if type(self).__eq__ is not object.__eq__:
            raise RuntimeError(
                f'Player class {type(self)} defines an equality'
                f' operator (__eq__) which will break internal'
                f' logic. Please remove it.\n'
                f'For dataclasses you can do "dataclass(eq=False)"'
                f' in the class decorator.')

        self.actor = None
        self.character = ''
        self._nodeactor: Optional[ba.NodeActor] = None
        self._sessionplayer = sessionplayer
        self.character = sessionplayer.character
        self.color = sessionplayer.color
        self.highlight = sessionplayer.highlight
        self.team = sessionplayer.team.gameteam  # type: ignore
        assert self.team is not None
        self.sessiondata = sessionplayer.sessiondata
        self.gamedata = sessionplayer.gamedata

        # Create our player node in the current activity.
        # Note: do we want to save a few cycles here by managing our player
        # node manually instead of wrapping it in a NodeActor?
        node = _ba.newnode('player', attrs={'playerID': sessionplayer.id})
        self._nodeactor = NodeActor(node)
        sessionplayer.set_node(node)
コード例 #9
0
    def _show_scoreboard_info(self) -> None:
        """Create the game info display.

        This is the thing in the top left corner showing the name
        and short description of the game.
        """
        # pylint: disable=too-many-locals
        from ba._freeforallsession import FreeForAllSession
        from ba._gameutils import animate
        from ba._nodeactor import NodeActor
        sb_name = self.get_instance_scoreboard_display_string()

        # The description can be either a string or a sequence with args
        # to swap in post-translation.
        sb_desc_in = self.get_instance_description_short()
        sb_desc_l: Sequence
        if isinstance(sb_desc_in, str):
            sb_desc_l = [sb_desc_in]  # handle simple string case
        else:
            sb_desc_l = sb_desc_in
        if not isinstance(sb_desc_l[0], str):
            raise TypeError('Invalid format for instance description.')

        is_empty = (sb_desc_l[0] == '')
        subs = []
        for i in range(len(sb_desc_l) - 1):
            subs.append(('${ARG' + str(i + 1) + '}', str(sb_desc_l[i + 1])))
        translation = Lstr(translate=('gameDescriptions', sb_desc_l[0]),
                           subs=subs)
        sb_desc = translation
        vrmode = _ba.app.vr_mode
        yval = -34 if is_empty else -20
        yval -= 16
        sbpos = ((15, yval) if isinstance(self.session, FreeForAllSession) else
                 (15, yval))
        self._game_scoreboard_name_text = NodeActor(
            _ba.newnode('text',
                        attrs={
                            'text': sb_name,
                            'maxwidth': 300,
                            'position': sbpos,
                            'h_attach': 'left',
                            'vr_depth': 10,
                            'v_attach': 'top',
                            'v_align': 'bottom',
                            'color': (1.0, 1.0, 1.0, 1.0),
                            'shadow': 1.0 if vrmode else 0.6,
                            'flatness': 1.0 if vrmode else 0.5,
                            'scale': 1.1
                        }))

        assert self._game_scoreboard_name_text.node
        animate(self._game_scoreboard_name_text.node, 'opacity', {
            0: 0.0,
            1.0: 1.0
        })

        descpos = (((17, -44 +
                     10) if isinstance(self.session, FreeForAllSession) else
                    (17, -44 + 10)))
        self._game_scoreboard_description_text = NodeActor(
            _ba.newnode('text',
                        attrs={
                            'text':
                            sb_desc,
                            'maxwidth':
                            480,
                            'position':
                            descpos,
                            'scale':
                            0.7,
                            'h_attach':
                            'left',
                            'v_attach':
                            'top',
                            'v_align':
                            'top',
                            'shadow':
                            1.0 if vrmode else 0.7,
                            'flatness':
                            1.0 if vrmode else 0.8,
                            'color': (1, 1, 1, 1) if vrmode else
                            (0.9, 0.9, 0.9, 1.0)
                        }))

        assert self._game_scoreboard_description_text.node
        animate(self._game_scoreboard_description_text.node, 'opacity', {
            0: 0.0,
            1.0: 1.0
        })
コード例 #10
0
    def _setup_tournament_time_limit(self, duration: float) -> None:
        """
        Create a tournament game time-limit given the provided
        duration in seconds.
        This will be displayed at the top of the screen.
        If the time-limit expires, end_game() will be called.
        """
        from ba._nodeactor import NodeActor
        from ba._enums import TimeType
        if duration <= 0.0:
            return
        self._tournament_time_limit = int(duration)

        # We want this timer to match the server's time as close as possible,
        # so lets go with base-time. Theoretically we should do real-time but
        # then we have to mess with contexts and whatnot since its currently
        # not available in activity contexts. :-/
        self._tournament_time_limit_timer = _ba.Timer(
            1.0,
            WeakCall(self._tournament_time_limit_tick),
            repeat=True,
            timetype=TimeType.BASE)
        self._tournament_time_limit_title_text = NodeActor(
            _ba.newnode('text',
                        attrs={
                            'v_attach': 'bottom',
                            'h_attach': 'left',
                            'h_align': 'center',
                            'v_align': 'center',
                            'vr_depth': 300,
                            'maxwidth': 100,
                            'color': (1.0, 1.0, 1.0, 0.5),
                            'position': (60, 50),
                            'flatness': 1.0,
                            'scale': 0.5,
                            'text': Lstr(resource='tournamentText')
                        }))
        self._tournament_time_limit_text = NodeActor(
            _ba.newnode('text',
                        attrs={
                            'v_attach': 'bottom',
                            'h_attach': 'left',
                            'h_align': 'center',
                            'v_align': 'center',
                            'vr_depth': 300,
                            'maxwidth': 100,
                            'color': (1.0, 1.0, 1.0, 0.5),
                            'position': (60, 30),
                            'flatness': 1.0,
                            'scale': 0.9
                        }))
        self._tournament_time_limit_text_input = NodeActor(
            _ba.newnode('timedisplay',
                        attrs={
                            'timemin': 0,
                            'time2': self._tournament_time_limit * 1000
                        }))
        assert self._tournament_time_limit_text.node
        assert self._tournament_time_limit_text_input.node
        self._tournament_time_limit_text_input.node.connectattr(
            'output', self._tournament_time_limit_text.node, 'text')
コード例 #11
0
def cameraflash(duration: float = 999.0) -> None:
    """Create a strobing camera flash effect.

    Category: Gameplay Functions

    (as seen when a team wins a game)
    Duration is in seconds.
    """
    # pylint: disable=too-many-locals
    import random
    from ba._nodeactor import NodeActor
    x_spread = 10
    y_spread = 5
    positions = [[-x_spread, -y_spread], [0, -y_spread], [0, y_spread],
                 [x_spread, -y_spread], [x_spread, y_spread],
                 [-x_spread, y_spread]]
    times = [0, 2700, 1000, 1800, 500, 1400]

    # Store this on the current activity so we only have one at a time.
    # FIXME: Need a type safe way to do this.
    activity = _ba.getactivity()
    activity.camera_flash_data = []  # type: ignore
    for i in range(6):
        light = NodeActor(
            _ba.newnode('light',
                        attrs={
                            'position': (positions[i][0], 0, positions[i][1]),
                            'radius': 1.0,
                            'lights_volumes': False,
                            'height_attenuated': False,
                            'color': (0.2, 0.2, 0.8)
                        }))
        sval = 1.87
        iscale = 1.3
        tcombine = _ba.newnode('combine',
                               owner=light.node,
                               attrs={
                                   'size': 3,
                                   'input0': positions[i][0],
                                   'input1': 0,
                                   'input2': positions[i][1]
                               })
        assert light.node
        tcombine.connectattr('output', light.node, 'position')
        xval = positions[i][0]
        yval = positions[i][1]
        spd = 0.5 + random.random()
        spd2 = 0.5 + random.random()
        animate(tcombine,
                'input0', {
                    0.0: xval + 0,
                    0.069 * spd: xval + 10.0,
                    0.143 * spd: xval - 10.0,
                    0.201 * spd: xval + 0
                },
                loop=True)
        animate(tcombine,
                'input2', {
                    0.0: yval + 0,
                    0.15 * spd2: yval + 10.0,
                    0.287 * spd2: yval - 10.0,
                    0.398 * spd2: yval + 0
                },
                loop=True)
        animate(light.node,
                'intensity', {
                    0.0: 0,
                    0.02 * sval: 0,
                    0.05 * sval: 0.8 * iscale,
                    0.08 * sval: 0,
                    0.1 * sval: 0
                },
                loop=True,
                offset=times[i])
        _ba.timer((times[i] + random.randint(1, int(duration)) * 40 * sval),
                  light.node.delete,
                  timeformat=TimeFormat.MILLISECONDS)
        activity.camera_flash_data.append(light)  # type: ignore
コード例 #12
0
    def __init__(self, lobby: ba.Lobby):
        # pylint: disable=too-many-locals
        from ba import _input
        from ba._lang import Lstr
        from ba._nodeactor import NodeActor
        from ba._general import WeakCall
        from ba._enums import SpecialChar
        can_switch_teams = (len(lobby.teams) > 1)
        self._state = 0
        press_to_punch: Union[str,
                              ba.Lstr] = _ba.charstr(SpecialChar.LEFT_BUTTON)
        press_to_bomb: Union[str,
                             ba.Lstr] = _ba.charstr(SpecialChar.RIGHT_BUTTON)

        # If we have a keyboard, grab keys for punch and pickup.
        # FIXME: This of course is only correct on the local device;
        #  Should change this for net games.
        keyboard: Optional[ba.InputDevice] = _ba.get_input_device(
            'Keyboard', '#1', doraise=False)
        if keyboard is not None:
            punch_key = keyboard.get_button_name(
                _input.get_device_value(keyboard, 'buttonPunch'))
            press_to_punch = Lstr(resource='orText',
                                  subs=[('${A}',
                                         Lstr(value='\'${K}\'',
                                              subs=[('${K}', punch_key)])),
                                        ('${B}', press_to_punch)])
            bomb_key = keyboard.get_button_name(
                _input.get_device_value(keyboard, 'buttonBomb'))
            press_to_bomb = Lstr(resource='orText',
                                 subs=[('${A}',
                                        Lstr(value='\'${K}\'',
                                             subs=[('${K}', bomb_key)])),
                                       ('${B}', press_to_bomb)])
            join_str = Lstr(value='${A} < ${B} >',
                            subs=[('${A}',
                                   Lstr(resource='pressPunchToJoinText')),
                                  ('${B}', press_to_punch)])
        else:
            join_str = Lstr(resource='pressAnyButtonToJoinText')

        flatness = 1.0 if _ba.app.vr_mode else 0.0
        self._text = NodeActor(
            _ba.newnode('text',
                        attrs={
                            'position': (0, -40),
                            'h_attach': 'center',
                            'v_attach': 'top',
                            'h_align': 'center',
                            'color': (0.7, 0.7, 0.95, 1.0),
                            'flatness': flatness,
                            'text': join_str
                        }))

        if _ba.app.kiosk_mode:
            self._messages = [join_str]
        else:
            msg1 = Lstr(resource='pressToSelectProfileText',
                        subs=[
                            ('${BUTTONS}', _ba.charstr(SpecialChar.UP_ARROW) +
                             ' ' + _ba.charstr(SpecialChar.DOWN_ARROW))
                        ])
            msg2 = Lstr(resource='pressToOverrideCharacterText',
                        subs=[('${BUTTONS}', Lstr(resource='bombBoldText'))])
            msg3 = Lstr(value='${A} < ${B} >',
                        subs=[('${A}', msg2), ('${B}', press_to_bomb)])
            self._messages = (([
                Lstr(resource='pressToSelectTeamText',
                     subs=[('${BUTTONS}', _ba.charstr(SpecialChar.LEFT_ARROW) +
                            ' ' + _ba.charstr(SpecialChar.RIGHT_ARROW))])
            ] if can_switch_teams else []) + [msg1] + [msg3] + [join_str])

        self._timer = _ba.Timer(4.0, WeakCall(self._update), repeat=True)