def on_begin(self) -> None: super().on_begin() shared = SharedObjects.get() self.setup_standard_time_limit(self._time_limit) self.setup_standard_powerup_drops() self._flag_spawn_pos = self.map.get_flag_position(None) Flag.project_stand(self._flag_spawn_pos) self._set_chosen_one_player(None) pos = self._flag_spawn_pos ba.timer(1.0, call=self._tick, repeat=True) mat = self._reset_region_material = ba.Material() mat.add_actions( conditions=( 'they_have_material', shared.player_material, ), actions=( ('modify_part_collision', 'collide', True), ('modify_part_collision', 'physical', False), ('call', 'at_connect', ba.WeakCall(self._handle_reset_collide)), ), ) self._reset_region = ba.newnode('region', attrs={ 'position': (pos[0], pos[1] + 0.75, pos[2]), 'scale': (0.5, 0.5, 0.5), 'type': 'sphere', 'materials': [mat] })
def on_begin(self) -> None: super().on_begin() shared = SharedObjects.get() self.setup_standard_time_limit(self._time_limit) self.setup_standard_powerup_drops() self._flag_pos = self.map.get_flag_position(None) ba.timer(1.0, self._tick, repeat=True) self._flag_state = FlagState.NEW Flag.project_stand(self._flag_pos) self._flag = Flag(position=self._flag_pos, touchable=False, color=(1, 1, 1)) self._flag_light = ba.newnode('light', attrs={ 'position': self._flag_pos, 'intensity': 0.2, 'height_attenuated': False, 'radius': 0.4, 'color': (0.2, 0.2, 0.2) }) # Flag region. flagmats = [self._flag_region_material, shared.region_material] ba.newnode('region', attrs={ 'position': self._flag_pos, 'scale': (1.8, 1.8, 1.8), 'type': 'sphere', 'materials': flagmats }) self._update_flag_state()
def on_begin(self) -> None: super().on_begin() self.setup_standard_time_limit(self._time_limit) self.setup_standard_powerup_drops() self._flag_spawn_pos = self.map.get_flag_position(None) self._spawn_flag() self._update_timer = ba.Timer(1.0, call=self._tick, repeat=True) self._update_flag_state() Flag.project_stand(self._flag_spawn_pos)
def create_team(self, sessionteam: ba.SessionTeam) -> Team: shared = SharedObjects.get() base_pos = self.map.get_flag_position(sessionteam.id) ba.newnode('light', attrs={ 'position': base_pos, 'intensity': 0.6, 'height_attenuated': False, 'volume_intensity_scale': 0.1, 'radius': 0.1, 'color': sessionteam.color }) Flag.project_stand(base_pos) flag = Flag(touchable=False, position=base_pos, color=sessionteam.color) team = Team(base_pos=base_pos, flag=flag) mat = self._base_region_materials[sessionteam.id] = ba.Material() mat.add_actions( conditions=('they_have_material', shared.player_material), actions=( ('modify_part_collision', 'collide', True), ('modify_part_collision', 'physical', False), ('call', 'at_connect', ba.Call(self._handle_base_collide, team)), ), ) ba.newnode('region', owner=flag.node, attrs={ 'position': (base_pos[0], base_pos[1] + 0.75, base_pos[2]), 'scale': (0.5, 0.5, 0.5), 'type': 'sphere', 'materials': [self._base_region_materials[sessionteam.id]] }) return team
def on_begin(self) -> None: super().on_begin() self.setup_standard_time_limit(self._time_limit) self.setup_standard_powerup_drops() # Set up flags with marker lights. for i in range(len(self.map.flag_points)): point = self.map.flag_points[i] flag = ConquestFlag(position=point, touchable=False, materials=[self._extraflagmat]) self._flags.append(flag) Flag.project_stand(point) flag.light = ba.newnode('light', owner=flag.node, attrs={ 'position': point, 'intensity': 0.25, 'height_attenuated': False, 'radius': 0.3, 'color': (1, 1, 1) }) # Give teams a flag to start with. for i in range(len(self.teams)): self._flags[i].team = self.teams[i] light = self._flags[i].light assert light node = self._flags[i].node assert node light.color = self.teams[i].color node.color = self.teams[i].color self._update_scores() # Initial joiners didn't spawn due to no flags being owned yet; # spawn them now. for player in self.players: self.spawn_player(player)
def _spawn_flag(self) -> None: ba.playsound(self._swipsound) self._flash_flag_spawn() assert self._flag_spawn_pos is not None self._flag = Flag(dropped_timeout=20, position=self._flag_spawn_pos) self._flag_state = FlagState.NEW self._flag_light = ba.newnode('light', owner=self._flag.node, attrs={ 'intensity': 0.2, 'radius': 0.3, 'color': (0.2, 0.2, 0.2) }) assert self._flag.node self._flag.node.connectattr('position', self._flag_light, 'position') self._update_flag_state()
def on_begin(self) -> None: from bastd.actor.flag import Flag super().on_begin() self.setup_standard_time_limit(self.settings_raw['Time Limit']) self.setup_standard_powerup_drops() for team in self.teams: mat = self._base_region_materials[team.get_id()] = ba.Material() mat.add_actions(conditions=('they_have_material', ba.sharedobj('player_material')), actions=(('modify_part_collision', 'collide', True), ('modify_part_collision', 'physical', False), ('call', 'at_connect', ba.Call(self._handle_base_collide, team)))) # Create a score region and flag for each team. for team in self.teams: team.gamedata['base_pos'] = self.map.get_flag_position( team.get_id()) ba.newnode('light', attrs={ 'position': team.gamedata['base_pos'], 'intensity': 0.6, 'height_attenuated': False, 'volume_intensity_scale': 0.1, 'radius': 0.1, 'color': team.color }) self.project_flag_stand(team.gamedata['base_pos']) team.gamedata['flag'] = Flag(touchable=False, position=team.gamedata['base_pos'], color=team.color) basepos = team.gamedata['base_pos'] ba.newnode('region', owner=team.gamedata['flag'].node, attrs={ 'position': (basepos[0], basepos[1] + 0.75, basepos[2]), 'scale': (0.5, 0.5, 0.5), 'type': 'sphere', 'materials': [self._base_region_materials[team.get_id()]] })
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')
def create_team(self, sessionteam: ba.SessionTeam) -> Team: # Create our team instance and its initial values. base_pos = self.map.get_flag_position(sessionteam.id) Flag.project_stand(base_pos) ba.newnode('light', attrs={ 'position': base_pos, 'intensity': 0.6, 'height_attenuated': False, 'volume_intensity_scale': 0.1, 'radius': 0.1, 'color': sessionteam.color }) base_region_mat = ba.Material() pos = base_pos base_region = ba.newnode( 'region', attrs={ 'position': (pos[0], pos[1] + 0.75, pos[2]), 'scale': (0.5, 0.5, 0.5), 'type': 'sphere', 'materials': [base_region_mat, self._all_bases_material] }) spaz_mat_no_flag_physical = ba.Material() spaz_mat_no_flag_collide = ba.Material() flagmat = ba.Material() team = Team(base_pos=base_pos, base_region_material=base_region_mat, base_region=base_region, spaz_material_no_flag_physical=spaz_mat_no_flag_physical, spaz_material_no_flag_collide=spaz_mat_no_flag_collide, flagmaterial=flagmat) # Some parts of our spazzes don't collide physically with our # flags but generate callbacks. spaz_mat_no_flag_physical.add_actions( conditions=('they_have_material', flagmat), actions=( ('modify_part_collision', 'physical', False), ('call', 'at_connect', lambda: self._handle_touching_own_flag(team, True)), ('call', 'at_disconnect', lambda: self._handle_touching_own_flag(team, False)), )) # Other parts of our spazzes don't collide with our flags at all. spaz_mat_no_flag_collide.add_actions( conditions=('they_have_material', flagmat), actions=('modify_part_collision', 'collide', False), ) # We wanna know when *any* flag enters/leaves our base. base_region_mat.add_actions( conditions=('they_have_material', FlagFactory.get().flagmaterial), actions=( ('modify_part_collision', 'collide', True), ('modify_part_collision', 'physical', False), ('call', 'at_connect', lambda: self._handle_flag_entered_base(team)), ('call', 'at_disconnect', lambda: self._handle_flag_left_base(team)), )) return team
class KingOfTheHillGame(ba.TeamGameActivity[Player, Team]): """Game where a team wins by holding a 'hill' for a set amount of time.""" name = 'King of the Hill' description = 'Secure the flag for a set length of time.' game_settings = [ ('Hold Time', { 'min_value': 10, 'default': 30, 'increment': 10 }), ('Time Limit', { 'choices': [('None', 0), ('1 Minute', 60), ('2 Minutes', 120), ('5 Minutes', 300), ('10 Minutes', 600), ('20 Minutes', 1200)], 'default': 0 }), ('Respawn Times', { 'choices': [('Shorter', 0.25), ('Short', 0.5), ('Normal', 1.0), ('Long', 2.0), ('Longer', 4.0)], 'default': 1.0 }), ] score_info = ba.ScoreInfo(label='Time Held') @classmethod def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool: return issubclass(sessiontype, ba.MultiTeamSession) @classmethod def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: return ba.getmaps('king_of_the_hill') def __init__(self, settings: Dict[str, Any]): super().__init__(settings) shared = SharedObjects.get() self._scoreboard = Scoreboard() self._swipsound = ba.getsound('swip') self._tick_sound = ba.getsound('tick') self._countdownsounds = { 10: ba.getsound('announceTen'), 9: ba.getsound('announceNine'), 8: ba.getsound('announceEight'), 7: ba.getsound('announceSeven'), 6: ba.getsound('announceSix'), 5: ba.getsound('announceFive'), 4: ba.getsound('announceFour'), 3: ba.getsound('announceThree'), 2: ba.getsound('announceTwo'), 1: ba.getsound('announceOne') } self._flag_pos: Optional[Sequence[float]] = None self._flag_state: Optional[FlagState] = None self._flag: Optional[Flag] = None self._flag_light: Optional[ba.Node] = None self._scoring_team: Optional[ReferenceType[Team]] = None self._hold_time = int(settings['Hold Time']) self._time_limit = float(settings['Time Limit']) self._flag_region_material = ba.Material() self._flag_region_material.add_actions( conditions=('they_have_material', shared.player_material), actions=( ('modify_part_collision', 'collide', True), ('modify_part_collision', 'physical', False), ('call', 'at_connect', ba.Call(self._handle_player_flag_region_collide, True)), ('call', 'at_disconnect', ba.Call(self._handle_player_flag_region_collide, False)), )) # Base class overrides. self.default_music = ba.MusicType.SCARY def get_instance_description(self) -> Union[str, Sequence]: return 'Secure the flag for ${ARG1} seconds.', self._hold_time def get_instance_description_short(self) -> Union[str, Sequence]: return 'secure the flag for ${ARG1} seconds', self._hold_time def create_team(self, sessionteam: ba.SessionTeam) -> Team: return Team(time_remaining=self._hold_time) def on_begin(self) -> None: super().on_begin() shared = SharedObjects.get() self.setup_standard_time_limit(self._time_limit) self.setup_standard_powerup_drops() self._flag_pos = self.map.get_flag_position(None) ba.timer(1.0, self._tick, repeat=True) self._flag_state = FlagState.NEW Flag.project_stand(self._flag_pos) self._flag = Flag(position=self._flag_pos, touchable=False, color=(1, 1, 1)) self._flag_light = ba.newnode('light', attrs={ 'position': self._flag_pos, 'intensity': 0.2, 'height_attenuated': False, 'radius': 0.4, 'color': (0.2, 0.2, 0.2) }) # Flag region. flagmats = [self._flag_region_material, shared.region_material] ba.newnode('region', attrs={ 'position': self._flag_pos, 'scale': (1.8, 1.8, 1.8), 'type': 'sphere', 'materials': flagmats }) self._update_flag_state() def _tick(self) -> None: self._update_flag_state() # Give holding players points. for player in self.players: if player.time_at_flag > 0: self.stats.player_scored(player, 3, screenmessage=False, display=False) if self._scoring_team is None: scoring_team = None else: scoring_team = self._scoring_team() if scoring_team: if scoring_team.time_remaining > 0: ba.playsound(self._tick_sound) scoring_team.time_remaining = max(0, scoring_team.time_remaining - 1) self._update_scoreboard() if scoring_team.time_remaining > 0: assert self._flag is not None self._flag.set_score_text(str(scoring_team.time_remaining)) # Announce numbers we have sounds for. try: ba.playsound( self._countdownsounds[scoring_team.time_remaining]) except Exception: pass # winner if scoring_team.time_remaining <= 0: self.end_game() def end_game(self) -> None: results = ba.TeamGameResults() for team in self.teams: results.set_team_score(team, self._hold_time - team.time_remaining) self.end(results=results, announce_delay=0) def _update_flag_state(self) -> None: holding_teams = set(player.team for player in self.players if player.time_at_flag) prev_state = self._flag_state assert self._flag_light assert self._flag is not None assert self._flag.node if len(holding_teams) > 1: self._flag_state = FlagState.CONTESTED self._scoring_team = None self._flag_light.color = (0.6, 0.6, 0.1) self._flag.node.color = (1.0, 1.0, 0.4) elif len(holding_teams) == 1: holding_team = list(holding_teams)[0] self._flag_state = FlagState.HELD self._scoring_team = weakref.ref(holding_team) self._flag_light.color = ba.normalized_color(holding_team.color) self._flag.node.color = holding_team.color else: self._flag_state = FlagState.UNCONTESTED self._scoring_team = None self._flag_light.color = (0.2, 0.2, 0.2) self._flag.node.color = (1, 1, 1) if self._flag_state != prev_state: ba.playsound(self._swipsound) def _handle_player_flag_region_collide(self, colliding: bool) -> None: try: player = ba.getcollision().opposingnode.getdelegate( PlayerSpaz, True).getplayer(Player, True) except ba.NotFoundError: return # Different parts of us can collide so a single value isn't enough # also don't count it if we're dead (flying heads shouldn't be able to # win the game :-) if colliding and player.is_alive(): player.time_at_flag += 1 else: player.time_at_flag = max(0, player.time_at_flag - 1) self._update_flag_state() def _update_scoreboard(self) -> None: for team in self.teams: self._scoreboard.set_team_value(team, team.time_remaining, self._hold_time, countdown=True) def handlemessage(self, msg: Any) -> Any: if isinstance(msg, ba.PlayerDiedMessage): super().handlemessage(msg) # Augment default. # No longer can count as time_at_flag once dead. player = msg.getplayer(Player) player.time_at_flag = 0 self._update_flag_state() self.respawn_player(player)