Alliance elimination API 8

This commit is contained in:
Rikko 2023-07-02 18:58:09 +05:30
parent 9344e45bac
commit 06aec55378
2 changed files with 61 additions and 58 deletions

View file

@ -166,6 +166,7 @@
} }
], ],
"versions": { "versions": {
"2.0.0": null,
"1.1.0": { "1.1.0": {
"api_version": 7, "api_version": 7,
"commit_sha": "40b70fe", "commit_sha": "40b70fe",
@ -606,4 +607,4 @@
} }
} }
} }
} }

View file

@ -2,23 +2,25 @@
# #
"""Elimination mini-game.""" """Elimination mini-game."""
# ba_meta require api 7 # ba_meta require api 8
# (see https://ballistica.net/wiki/meta-tag-system) # (see https://ballistica.net/wiki/meta-tag-system)
from __future__ import annotations from __future__ import annotations
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
import ba import babase
from bastd.actor.spazfactory import SpazFactory import bauiv1 as bui
from bastd.actor.scoreboard import Scoreboard import bascenev1 as bs
from bascenev1lib.actor.spazfactory import SpazFactory
from bascenev1lib.actor.scoreboard import Scoreboard
if TYPE_CHECKING: if TYPE_CHECKING:
from typing import (Any, Tuple, Type, List, Sequence, Optional, from typing import (Any, Tuple, Type, List, Sequence, Optional,
Union) Union)
class Icon(ba.Actor): class Icon(bs.Actor):
"""Creates in in-game icon on screen.""" """Creates in in-game icon on screen."""
def __init__(self, def __init__(self,
@ -37,10 +39,10 @@ class Icon(ba.Actor):
self._show_lives = show_lives self._show_lives = show_lives
self._show_death = show_death self._show_death = show_death
self._name_scale = name_scale self._name_scale = name_scale
self._outline_tex = ba.gettexture('characterIconMask') self._outline_tex = bs.gettexture('characterIconMask')
icon = player.get_icon() icon = player.get_icon()
self.node = ba.newnode('image', self.node = bs.newnode('image',
delegate=self, delegate=self,
attrs={ attrs={
'texture': icon['texture'], 'texture': icon['texture'],
@ -53,12 +55,12 @@ class Icon(ba.Actor):
'absolute_scale': True, 'absolute_scale': True,
'attach': 'bottomCenter' 'attach': 'bottomCenter'
}) })
self._name_text = ba.newnode( self._name_text = bs.newnode(
'text', 'text',
owner=self.node, owner=self.node,
attrs={ attrs={
'text': ba.Lstr(value=player.getname()), 'text': babase.Lstr(value=player.getname()),
'color': ba.safecolor(player.team.color), 'color': babase.safecolor(player.team.color),
'h_align': 'center', 'h_align': 'center',
'v_align': 'center', 'v_align': 'center',
'vr_depth': 410, 'vr_depth': 410,
@ -69,7 +71,7 @@ class Icon(ba.Actor):
'v_attach': 'bottom' 'v_attach': 'bottom'
}) })
if self._show_lives: if self._show_lives:
self._lives_text = ba.newnode('text', self._lives_text = bs.newnode('text',
owner=self.node, owner=self.node,
attrs={ attrs={
'text': 'x0', 'text': 'x0',
@ -125,7 +127,7 @@ class Icon(ba.Actor):
if not self.node: if not self.node:
return return
if self._show_death: if self._show_death:
ba.animate( bs.animate(
self.node, 'opacity', { self.node, 'opacity', {
0.00: 1.0, 0.00: 1.0,
0.05: 0.0, 0.05: 0.0,
@ -142,16 +144,16 @@ class Icon(ba.Actor):
}) })
lives = self._player.lives lives = self._player.lives
if lives == 0: if lives == 0:
ba.timer(0.6, self.update_for_lives) bs.timer(0.6, self.update_for_lives)
def handlemessage(self, msg: Any) -> Any: def handlemessage(self, msg: Any) -> Any:
if isinstance(msg, ba.DieMessage): if isinstance(msg, bs.DieMessage):
self.node.delete() self.node.delete()
return None return None
return super().handlemessage(msg) return super().handlemessage(msg)
class Player(ba.Player['Team']): class Player(bs.Player['Team']):
"""Our player type for this game.""" """Our player type for this game."""
def __init__(self) -> None: def __init__(self) -> None:
@ -159,7 +161,7 @@ class Player(ba.Player['Team']):
self.icons: List[Icon] = [] self.icons: List[Icon] = []
class Team(ba.Team[Player]): class Team(bs.Team[Player]):
"""Our team type for this game.""" """Our team type for this game."""
def __init__(self) -> None: def __init__(self) -> None:
@ -167,14 +169,14 @@ class Team(ba.Team[Player]):
self.spawn_order: List[Player] = [] self.spawn_order: List[Player] = []
# ba_meta export game # ba_meta export bascenev1.GameActivity
class AllianceEliminationGame(ba.TeamGameActivity[Player, Team]): class AllianceEliminationGame(bs.TeamGameActivity[Player, Team]):
"""Game type where last player(s) left alive win.""" """Game type where last player(s) left alive win."""
name = 'Alliance Elimination' name = 'Alliance Elimination'
description = 'Fight in groups of duo, trio, or more.\nLast remaining alive wins.' description = 'Fight in groups of duo, trio, or more.\nLast remaining alive wins.'
scoreconfig = ba.ScoreConfig(label='Survived', scoreconfig = bs.ScoreConfig(label='Survived',
scoretype=ba.ScoreType.SECONDS, scoretype=bs.ScoreType.SECONDS,
none_is_winner=True) none_is_winner=True)
# Show messages when players die since it's meaningful here. # Show messages when players die since it's meaningful here.
announce_player_deaths = True announce_player_deaths = True
@ -183,23 +185,23 @@ class AllianceEliminationGame(ba.TeamGameActivity[Player, Team]):
@classmethod @classmethod
def get_available_settings( def get_available_settings(
cls, sessiontype: Type[ba.Session]) -> List[ba.Setting]: cls, sessiontype: Type[bs.Session]) -> List[babase.Setting]:
settings = [ settings = [
ba.IntSetting( bs.IntSetting(
'Lives Per Player', 'Lives Per Player',
default=1, default=1,
min_value=1, min_value=1,
max_value=10, max_value=10,
increment=1, increment=1,
), ),
ba.IntSetting( bs.IntSetting(
'Players Per Team In Arena', 'Players Per Team In Arena',
default=2, default=2,
min_value=2, min_value=2,
max_value=10, max_value=10,
increment=1, increment=1,
), ),
ba.IntChoiceSetting( bs.IntChoiceSetting(
'Time Limit', 'Time Limit',
choices=[ choices=[
('None', 0), ('None', 0),
@ -211,7 +213,7 @@ class AllianceEliminationGame(ba.TeamGameActivity[Player, Team]):
], ],
default=0, default=0,
), ),
ba.FloatChoiceSetting( bs.FloatChoiceSetting(
'Respawn Times', 'Respawn Times',
choices=[ choices=[
('Shorter', 0.25), ('Shorter', 0.25),
@ -222,27 +224,27 @@ class AllianceEliminationGame(ba.TeamGameActivity[Player, Team]):
], ],
default=1.0, default=1.0,
), ),
ba.BoolSetting('Epic Mode', default=False), bs.BoolSetting('Epic Mode', default=False),
] ]
if issubclass(sessiontype, ba.DualTeamSession): if issubclass(sessiontype, bs.DualTeamSession):
settings.append( settings.append(
ba.BoolSetting('Balance Total Lives', default=False)) bs.BoolSetting('Balance Total Lives', default=False))
return settings return settings
@classmethod @classmethod
def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool: def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool:
return issubclass(sessiontype, ba.DualTeamSession) return issubclass(sessiontype, bs.DualTeamSession)
@classmethod @classmethod
def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]:
return ba.getmaps('melee') return bs.app.classic.getmaps('melee')
def __init__(self, settings: dict): def __init__(self, settings: dict):
super().__init__(settings) super().__init__(settings)
self._scoreboard = Scoreboard() self._scoreboard = Scoreboard()
self._start_time: Optional[float] = None self._start_time: Optional[float] = None
self._vs_text: Optional[ba.Actor] = None self._vs_text: Optional[bs.Actor] = None
self._round_end_timer: Optional[ba.Timer] = None self._round_end_timer: Optional[bs.Timer] = None
self._epic_mode = bool(settings['Epic Mode']) self._epic_mode = bool(settings['Epic Mode'])
self._lives_per_player = int(settings['Lives Per Player']) self._lives_per_player = int(settings['Lives Per Player'])
self._time_limit = float(settings['Time Limit']) self._time_limit = float(settings['Time Limit'])
@ -253,16 +255,16 @@ class AllianceEliminationGame(ba.TeamGameActivity[Player, Team]):
# Base class overrides: # Base class overrides:
self.slow_motion = self._epic_mode self.slow_motion = self._epic_mode
self.default_music = (ba.MusicType.EPIC self.default_music = (bs.MusicType.EPIC
if self._epic_mode else ba.MusicType.SURVIVAL) if self._epic_mode else bs.MusicType.SURVIVAL)
def get_instance_description(self) -> Union[str, Sequence]: def get_instance_description(self) -> Union[str, Sequence]:
return 'Last team standing wins.' if isinstance( return 'Last team standing wins.' if isinstance(
self.session, ba.DualTeamSession) else 'Last one standing wins.' self.session, bs.DualTeamSession) else 'Last one standing wins.'
def get_instance_description_short(self) -> Union[str, Sequence]: def get_instance_description_short(self) -> Union[str, Sequence]:
return 'last team standing wins' if isinstance( return 'last team standing wins' if isinstance(
self.session, ba.DualTeamSession) else 'last one standing wins' self.session, bs.DualTeamSession) else 'last one standing wins'
def on_player_join(self, player: Player) -> None: def on_player_join(self, player: Player) -> None:
@ -275,8 +277,8 @@ class AllianceEliminationGame(ba.TeamGameActivity[Player, Team]):
if (self._get_total_team_lives(player.team) == 0 if (self._get_total_team_lives(player.team) == 0
and player.team.survival_seconds is None): and player.team.survival_seconds is None):
player.team.survival_seconds = 0 player.team.survival_seconds = 0
ba.screenmessage( bs.broadcastmessage(
ba.Lstr(resource='playerDelayedJoinText', babase.Lstr(resource='playerDelayedJoinText',
subs=[('${PLAYER}', player.getname(full=True))]), subs=[('${PLAYER}', player.getname(full=True))]),
color=(0, 1, 0), color=(0, 1, 0),
) )
@ -293,11 +295,11 @@ class AllianceEliminationGame(ba.TeamGameActivity[Player, Team]):
def on_begin(self) -> None: def on_begin(self) -> None:
super().on_begin() super().on_begin()
self._start_time = ba.time() self._start_time = bs.time()
self.setup_standard_time_limit(self._time_limit) self.setup_standard_time_limit(self._time_limit)
self.setup_standard_powerup_drops() self.setup_standard_powerup_drops()
self._vs_text = ba.NodeActor( self._vs_text = bs.NodeActor(
ba.newnode('text', bs.newnode('text',
attrs={ attrs={
'position': (0, 92), 'position': (0, 92),
'h_attach': 'center', 'h_attach': 'center',
@ -308,12 +310,12 @@ class AllianceEliminationGame(ba.TeamGameActivity[Player, Team]):
'scale': 0.6, 'scale': 0.6,
'v_attach': 'bottom', 'v_attach': 'bottom',
'color': (0.8, 0.8, 0.3, 1.0), 'color': (0.8, 0.8, 0.3, 1.0),
'text': ba.Lstr(resource='vsText') 'text': babase.Lstr(resource='vsText')
})) }))
# If balance-team-lives is on, add lives to the smaller team until # If balance-team-lives is on, add lives to the smaller team until
# total lives match. # total lives match.
if (isinstance(self.session, ba.DualTeamSession) if (isinstance(self.session, bs.DualTeamSession)
and self._balance_total_lives and self.teams[0].players and self._balance_total_lives and self.teams[0].players
and self.teams[1].players): and self.teams[1].players):
if self._get_total_team_lives( if self._get_total_team_lives(
@ -333,7 +335,7 @@ class AllianceEliminationGame(ba.TeamGameActivity[Player, Team]):
# We could check game-over conditions at explicit trigger points, # We could check game-over conditions at explicit trigger points,
# but lets just do the simple thing and poll it. # but lets just do the simple thing and poll it.
ba.timer(1.0, self._update, repeat=True) bs.timer(1.0, self._update, repeat=True)
def _update_alliance_mode(self) -> None: def _update_alliance_mode(self) -> None:
# For both teams, find the first player on the spawn order list with # For both teams, find the first player on the spawn order list with
@ -391,10 +393,10 @@ class AllianceEliminationGame(ba.TeamGameActivity[Player, Team]):
nplayers -= 1 nplayers -= 1
test_lives += 1 test_lives += 1
def _get_spawn_point(self, player: Player) -> Optional[ba.Vec3]: def _get_spawn_point(self, player: Player) -> Optional[babase.Vec3]:
return None return None
def spawn_player(self, player: Player) -> ba.Actor: def spawn_player(self, player: Player) -> bs.Actor:
actor = self.spawn_player_spaz(player, self._get_spawn_point(player)) actor = self.spawn_player_spaz(player, self._get_spawn_point(player))
# If we have any icons, update their state. # If we have any icons, update their state.
@ -403,7 +405,7 @@ class AllianceEliminationGame(ba.TeamGameActivity[Player, Team]):
return actor return actor
def _print_lives(self, player: Player) -> None: def _print_lives(self, player: Player) -> None:
from bastd.actor import popuptext from bascenev1lib.actor import popuptext
# We get called in a timer so it's possible our player has left/etc. # We get called in a timer so it's possible our player has left/etc.
if not player or not player.is_alive() or not player.node: if not player or not player.is_alive() or not player.node:
@ -426,20 +428,20 @@ class AllianceEliminationGame(ba.TeamGameActivity[Player, Team]):
# Update icons in a moment since our team will be gone from the # Update icons in a moment since our team will be gone from the
# list then. # list then.
ba.timer(0, self._update_icons) bs.timer(0, self._update_icons)
# If the player to leave was the last in spawn order and had # If the player to leave was the last in spawn order and had
# their final turn currently in-progress, mark the survival time # their final turn currently in-progress, mark the survival time
# for their team. # for their team.
if self._get_total_team_lives(player.team) == 0: if self._get_total_team_lives(player.team) == 0:
assert self._start_time is not None assert self._start_time is not None
player.team.survival_seconds = int(ba.time() - self._start_time) player.team.survival_seconds = int(bs.time() - self._start_time)
def _get_total_team_lives(self, team: Team) -> int: def _get_total_team_lives(self, team: Team) -> int:
return sum(player.lives for player in team.players) return sum(player.lives for player in team.players)
def handlemessage(self, msg: Any) -> Any: def handlemessage(self, msg: Any) -> Any:
if isinstance(msg, ba.PlayerDiedMessage): if isinstance(msg, bs.PlayerDiedMessage):
# Augment standard behavior. # Augment standard behavior.
super().handlemessage(msg) super().handlemessage(msg)
@ -447,7 +449,7 @@ class AllianceEliminationGame(ba.TeamGameActivity[Player, Team]):
player.lives -= 1 player.lives -= 1
if player.lives < 0: if player.lives < 0:
ba.print_error( babase.print_error(
"Got lives < 0 in Alliance Elimination; this shouldn't happen.") "Got lives < 0 in Alliance Elimination; this shouldn't happen.")
player.lives = 0 player.lives = 0
@ -458,14 +460,14 @@ class AllianceEliminationGame(ba.TeamGameActivity[Player, Team]):
# Play big death sound on our last death # Play big death sound on our last death
# or for every one. # or for every one.
if player.lives == 0: if player.lives == 0:
ba.playsound(SpazFactory.get().single_player_death_sound) SpazFactory.get().single_player_death_sound.play()
# If we hit zero lives, we're dead (and our team might be too). # If we hit zero lives, we're dead (and our team might be too).
if player.lives == 0: if player.lives == 0:
# If the whole team is now dead, mark their survival time. # If the whole team is now dead, mark their survival time.
if self._get_total_team_lives(player.team) == 0: if self._get_total_team_lives(player.team) == 0:
assert self._start_time is not None assert self._start_time is not None
player.team.survival_seconds = int(ba.time() - player.team.survival_seconds = int(bs.time() -
self._start_time) self._start_time)
# Put ourself at the back of the spawn order. # Put ourself at the back of the spawn order.
@ -493,7 +495,7 @@ class AllianceEliminationGame(ba.TeamGameActivity[Player, Team]):
# the game (allows the dust to settle and draws to occur if deaths # the game (allows the dust to settle and draws to occur if deaths
# are close enough). # are close enough).
if len(self._get_living_teams()) < 2: if len(self._get_living_teams()) < 2:
self._round_end_timer = ba.Timer(0.5, self.end_game) self._round_end_timer = bs.Timer(0.5, self.end_game)
def _get_living_teams(self) -> List[Team]: def _get_living_teams(self) -> List[Team]:
return [ return [
@ -505,7 +507,7 @@ class AllianceEliminationGame(ba.TeamGameActivity[Player, Team]):
def end_game(self) -> None: def end_game(self) -> None:
if self.has_ended(): if self.has_ended():
return return
results = ba.GameResults() results = bs.GameResults()
self._vs_text = None # Kill our 'vs' if its there. self._vs_text = None # Kill our 'vs' if its there.
for team in self.teams: for team in self.teams:
results.set_team_score(team, team.survival_seconds) results.set_team_score(team, team.survival_seconds)