updating few games to api 9

This commit is contained in:
vishal332008 2026-07-17 08:54:52 +05:30
parent 099ca775f1
commit 50450e14a8
17 changed files with 558 additions and 734 deletions

View file

@ -206,16 +206,26 @@
"Fleet Zone Ping Last Flush Time": 1784128904,
"Fleet Zone Pings": {
"prod": {
"bangkok.v4": 79.76979999511968,
"delhi.v4": 52.73921035118477,
"hyderabad.v4": 27.893118701544765,
"kolkata.v4": 52.23812143063419,
"mumbai.v4": 105.13554275932287,
"singapore.v4": 47.26909899909515
"bangkok.v4": 81.62017577624344,
"delhi.v4": 63.964672644626035,
"helsinki.v4": 178.44603499997902,
"hong_kong.v4": 84.84311700021863,
"hyderabad.v4": 169.17364551628094,
"jakarta.v4": 120.16353614961386,
"kolkata.v4": 171.5810691091089,
"kuala_lampur.v4": 97.94705339403097,
"manila.v4": 85.0717169996642,
"mumbai.v4": 53.889843160696806,
"seoul.v4": 113.3862230003615,
"singapore.v4": 89.7048506555974,
"taipei.v4": 91.55671799999254,
"tel_aviv.v4": 227.04064399977142,
"tokyo.v4": 119.68682299993816,
"warsaw.v4": 190.9533369998826
}
},
"Fleet Zone Pings Updated Time": {
"prod": 1784199269
"prod": 1784222852
},
"Free-for-All Playlist Randomize": true,
"Free-for-All Playlist Selection": "__default__",
@ -285,7 +295,7 @@
"Team Tournament Playlist Selection": "\u041a\u043e\u043f\u0438\u044f \u0421\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 \u043f\u043b\u0435\u0439-\u043b\u0438\u0441\u0442 \u0440\u0435\u0436\u0438\u043c\u0430 \u041a\u043e\u043c\u0430\u043d\u0434\u044b",
"Team Tournament Playlists": {},
"Teams Series Length": 7,
"launchCount": 153,
"launchCount": 155,
"lc14173": 1,
"lc14292": 1
}

View file

@ -1,419 +1,515 @@
# Released under the MIT License. See LICENSE for details.
#
"""Functionality related to the end screen in dual-team mode."""
"""Elimination mini-game."""
# ba_meta require api 9
# (see https://ballistica.net/wiki/meta-tag-system)
from __future__ import annotations
from typing import TYPE_CHECKING
import logging
import babase
import bascenev1 as bs
from bascenev1lib.activity.multiteamscore import MultiTeamScoreScreenActivity
from bascenev1lib.actor.image import Image
from bascenev1lib.actor.text import Text
from bascenev1lib.actor.zoomtext import ZoomText
from bascenev1lib.actor.scoreboard import Scoreboard
from bascenev1lib.actor.spazfactory import SpazFactory
if TYPE_CHECKING:
pass
from typing import (Any, Tuple, Type, List, Sequence, Optional,
Union)
class TeamVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
"""Scorescreen between rounds of a dual-team session."""
class Icon(bs.Actor):
"""Creates in in-game icon on screen."""
def __init__(self,
player: Player,
position: Tuple[float, float],
scale: float,
show_lives: bool = True,
show_death: bool = True,
name_scale: float = 1.0,
name_maxwidth: float = 115.0,
flatness: float = 1.0,
shadow: float = 1.0):
super().__init__()
self._player = player
self._show_lives = show_lives
self._show_death = show_death
self._name_scale = name_scale
self._outline_tex = bs.gettexture('characterIconMask')
icon = player.get_icon()
self.node = bs.newnode('image',
delegate=self,
attrs={
'texture': icon['texture'],
'tint_texture': icon['tint_texture'],
'tint_color': icon['tint_color'],
'vr_depth': 400,
'tint2_color': icon['tint2_color'],
'mask_texture': self._outline_tex,
'opacity': 1.0,
'absolute_scale': True,
'attach': 'bottomCenter'
})
self._name_text = bs.newnode(
'text',
owner=self.node,
attrs={
'text': babase.Lstr(value=player.getname()),
'color': babase.safecolor(player.team.color),
'h_align': 'center',
'v_align': 'center',
'vr_depth': 410,
'maxwidth': name_maxwidth,
'shadow': shadow,
'flatness': flatness,
'h_attach': 'center',
'v_attach': 'bottom'
})
if self._show_lives:
self._lives_text = bs.newnode('text',
owner=self.node,
attrs={
'text': 'x0',
'color': (1, 1, 0.5),
'h_align': 'left',
'vr_depth': 430,
'shadow': 1.0,
'flatness': 1.0,
'h_attach': 'center',
'v_attach': 'bottom'
})
self.set_position_and_scale(position, scale)
def set_position_and_scale(self, position: Tuple[float, float],
scale: float) -> None:
"""(Re)position the icon."""
assert self.node
self.node.position = position
self.node.scale = [70.0 * scale]
self._name_text.position = (position[0], position[1] + scale * 52.0)
self._name_text.scale = 1.0 * scale * self._name_scale
if self._show_lives:
self._lives_text.position = (position[0] + scale * 10.0,
position[1] - scale * 43.0)
self._lives_text.scale = 1.0 * scale
def update_for_lives(self) -> None:
"""Update for the target player's current lives."""
if self._player:
lives = self._player.lives
else:
lives = 0
if self._show_lives:
if lives > 0:
self._lives_text.text = 'x' + str(lives - 1)
else:
self._lives_text.text = ''
if lives == 0:
self._name_text.opacity = 0.2
assert self.node
self.node.color = (0.7, 0.3, 0.3)
self.node.opacity = 0.2
def handle_player_spawned(self) -> None:
"""Our player spawned; hooray!"""
if not self.node:
return
self.node.opacity = 1.0
self.update_for_lives()
def handle_player_died(self) -> None:
"""Well poo; our player died."""
if not self.node:
return
if self._show_death:
bs.animate(
self.node, 'opacity', {
0.00: 1.0,
0.05: 0.0,
0.10: 1.0,
0.15: 0.0,
0.20: 1.0,
0.25: 0.0,
0.30: 1.0,
0.35: 0.0,
0.40: 1.0,
0.45: 0.0,
0.50: 1.0,
0.55: 0.2
})
lives = self._player.lives
if lives == 0:
bs.timer(0.6, self.update_for_lives)
def handlemessage(self, msg: Any) -> Any:
if isinstance(msg, bs.DieMessage):
self.node.delete()
return None
return super().handlemessage(msg)
class Player(bs.Player['Team']):
"""Our player type for this game."""
def __init__(self) -> None:
self.lives = 0
self.icons: List[Icon] = []
class Team(bs.Team[Player]):
"""Our team type for this game."""
def __init__(self) -> None:
self.survival_seconds: Optional[int] = None
self.spawn_order: List[Player] = []
# ba_meta export bascenev1.GameActivity
class AllianceEliminationGame(bs.TeamGameActivity[Player, Team]):
"""Game type where last player(s) left alive win."""
name = 'Alliance Elimination'
description = 'Fight in groups of duo, trio, or more.\nLast remaining alive wins.'
scoreconfig = bs.ScoreConfig(label='Survived',
scoretype=bs.ScoreType.SECONDS,
none_is_winner=True)
# Show messages when players die since it's meaningful here.
announce_player_deaths = True
allow_mid_activity_joins = False
@classmethod
def get_available_settings(
cls, sessiontype: Type[bs.Session]) -> List[bs.Setting]:
settings = [
bs.IntSetting(
'Lives Per Player',
default=1,
min_value=1,
max_value=10,
increment=1,
),
bs.IntSetting(
'Players Per Team In Arena',
default=2,
min_value=2,
max_value=10,
increment=1,
),
bs.IntChoiceSetting(
'Time Limit',
choices=[
('None', 0),
('1 Minute', 60),
('2 Minutes', 120),
('5 Minutes', 300),
('10 Minutes', 600),
('20 Minutes', 1200),
],
default=0,
),
bs.FloatChoiceSetting(
'Respawn Times',
choices=[
('Shorter', 0.25),
('Short', 0.5),
('Normal', 1.0),
('Long', 2.0),
('Longer', 4.0),
],
default=1.0,
),
bs.BoolSetting('Epic Mode', default=False),
]
if issubclass(sessiontype, bs.DualTeamSession):
settings.append(
bs.BoolSetting('Balance Total Lives', default=False))
return settings
@classmethod
def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool:
return issubclass(sessiontype, bs.DualTeamSession)
@classmethod
def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]:
return bs.app.classic.getmaps('melee')
def __init__(self, settings: dict):
super().__init__(settings=settings)
self._winner: bs.SessionTeam = settings['winner']
assert isinstance(self._winner, bs.SessionTeam)
super().__init__(settings)
self._scoreboard = Scoreboard()
self._start_time: Optional[float] = None
self._vs_text: Optional[bs.Actor] = None
self._round_end_timer: Optional[bs.Timer] = None
self._epic_mode = bool(settings['Epic Mode'])
self._lives_per_player = int(settings['Lives Per Player'])
self._time_limit = float(settings['Time Limit'])
self._balance_total_lives = bool(
settings.get('Balance Total Lives', False))
self._players_per_team_in_arena = int(
settings['Players Per Team In Arena'])
# Base class overrides:
self.slow_motion = self._epic_mode
self.default_music = (bs.MusicType.EPIC
if self._epic_mode else bs.MusicType.SURVIVAL)
def get_instance_description(self) -> Union[str, Sequence]:
return 'Last team standing wins.' if isinstance(
self.session, bs.DualTeamSession) else 'Last one standing wins.'
def get_instance_description_short(self) -> Union[str, Sequence]:
return 'last team standing wins' if isinstance(
self.session, bs.DualTeamSession) else 'last one standing wins'
def on_player_join(self, player: Player) -> None:
# No longer allowing mid-game joiners here; too easy to exploit.
if self.has_begun():
# Make sure their team has survival seconds set if they're all dead
# (otherwise blocked new ffa players are considered 'still alive'
# in score tallying).
if (self._get_total_team_lives(player.team) == 0
and player.team.survival_seconds is None):
player.team.survival_seconds = 0
bs.broadcastmessage(
babase.Lstr(resource='playerDelayedJoinText',
subs=[('${PLAYER}', player.getname(full=True))]),
color=(0, 1, 0),
)
return
player.lives = self._lives_per_player
player.team.spawn_order.append(player)
self._update_alliance_mode()
# Don't waste time doing this until begin.
if self.has_begun():
self._update_icons()
def on_begin(self) -> None:
babase.set_analytics_screen('Teams Score Screen')
super().on_begin()
self._start_time = bs.time()
self.setup_standard_time_limit(self._time_limit)
self.setup_standard_powerup_drops()
self._vs_text = bs.NodeActor(
bs.newnode('text',
attrs={
'position': (0, 92),
'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': babase.Lstr(resource='vsText')
}))
height = 130
active_team_count = len(self.teams)
vval = (height * active_team_count) / 2 - height / 2
i = 0
shift_time = 2.5
# If balance-team-lives is on, add lives to the smaller team until
# total lives match.
if (isinstance(self.session, bs.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)
# Usually we say 'Best of 7', but if the language prefers we can say
# 'First to 4'.
session = self.session
assert isinstance(session, bs.MultiTeamSession)
best_of_use_first_to_instead = 0
if best_of_use_first_to_instead:
best_txt = babase.Lstr(resource='firstToSeriesText',
subs=[('${COUNT}',
str(session.get_series_length() / 2 + 1))
])
else:
best_txt = babase.Lstr(resource='bestOfSeriesText',
subs=[('${COUNT}',
str(session.get_series_length()))])
if len(self.teams) != 2:
ZoomText(best_txt,
position=(0, 175),
shiftposition=(-250, 175),
shiftdelay=2.5,
flash=False,
trail=False,
h_align='center',
scale=0.25,
color=(0.5, 0.5, 0.5, 1.0),
jitter=3.0).autoretain()
for team in self.session.sessionteams:
bs.timer(
i * 0.15 + 0.15,
bs.WeakCallPartial(self._show_team_name, vval - i * height, team,
i * 0.2, shift_time - (i * 0.150 + 0.150)))
bs.timer(i * 0.150 + 0.5, self._score_display_sound_small.play)
scored = (team is self._winner)
delay = 0.2
if scored:
delay = 1.2
bs.timer(
i * 0.150 + 0.2,
bs.WeakCallPartial(self._show_team_old_score, vval - i * height,
team, shift_time - (i * 0.15 + 0.2)))
bs.timer(i * 0.15 + 1.5, self._score_display_sound.play)
self._update_icons()
bs.timer(
i * 0.150 + delay,
bs.WeakCallParial(self._show_team_score, vval - i * height, team,
scored, i * 0.2 + 0.1,
shift_time - (i * 0.15 + delay)))
i += 1
self.show_player_scores()
# We could check game-over conditions at explicit trigger points,
# but lets just do the simple thing and poll it.
bs.timer(1.0, self._update, repeat=True)
def _show_team_name(self, pos_v: float, team: bs.SessionTeam,
kill_delay: float, shiftdelay: float) -> None:
del kill_delay # Unused arg.
if len(self.teams) != 2:
ZoomText(
babase.Lstr(value='${A}:', subs=[('${A}', team.name)]),
position=(100, pos_v),
shiftposition=(-150, pos_v),
shiftdelay=shiftdelay,
flash=False,
trail=False,
h_align='right',
maxwidth=300,
color=team.color,
jitter=1.0,
).autoretain()
else:
ZoomText(babase.Lstr(value='${A}', subs=[('${A}', team.name)]),
position=(-250, 260) if pos_v == 65 else (250, 260),
shiftposition=(-250, 260) if pos_v == 65 else (250, 260),
shiftdelay=shiftdelay,
flash=False,
trail=False,
h_align='center',
maxwidth=300,
scale=0.45,
color=team.color,
jitter=1.0).autoretain()
def _update_alliance_mode(self) -> None:
# For both teams, find the first player on the spawn order list with
# lives remaining and spawn them if they're not alive.
for team in self.teams:
# Prune dead players from the spawn order.
players_spawned = 0
team.spawn_order = [p for p in team.spawn_order if p]
for player in team.spawn_order:
assert isinstance(player, Player)
if player.lives > 0:
if not player.is_alive():
self.spawn_player(player)
self._update_icons()
players_spawned += 1
if players_spawned >= self._players_per_team_in_arena:
break
def _show_team_old_score(self, pos_v: float, sessionteam: bs.SessionTeam,
shiftdelay: float) -> None:
def _update_icons(self) -> None:
# pylint: disable=too-many-branches
# First off, clear out all icons.
for player in self.players:
player.icons = []
if len(self.teams) != 2:
ZoomText(
str(sessionteam.customdata['score'] - 1),
position=(150, pos_v),
maxwidth=100,
color=(0.6, 0.6, 0.7),
shiftposition=(-100, pos_v),
shiftdelay=shiftdelay,
flash=False,
trail=False,
lifespan=1.0,
h_align='left',
jitter=1.0,
).autoretain()
else:
ZoomText(str(sessionteam.customdata['score'] - 1),
position=(-250, 190) if pos_v == 65 else (250, 190),
maxwidth=100,
color=(0.6, 0.6, 0.7),
shiftposition=(-250, 190) if pos_v == 65 else (250, 190),
shiftdelay=shiftdelay,
flash=False,
trail=False,
lifespan=1.0,
scale=0.56,
h_align='center',
jitter=1.0).autoretain()
# Now for each team, cycle through our available players
# adding icons.
for team in self.teams:
if team.id == 0:
xval = -60
x_offs = -78
else:
xval = 60
x_offs = 78
nplayers = self._players_per_team_in_arena
test_lives = 1
while True:
players_with_lives = [
p for p in team.spawn_order
if p and p.lives >= test_lives
]
if not players_with_lives:
break
for player in players_with_lives:
player.icons.append(
Icon(player,
position=(xval, (36 if nplayers > 0 else 25)),
scale=0.9 if nplayers > 0 else 0.5,
name_maxwidth=85 if nplayers > 0 else 75,
name_scale=0.8 if nplayers > 0 else 1.0,
flatness=0.0 if nplayers > 0 else 1.0,
shadow=0.5 if nplayers > 0 else 1.0,
show_death=True if nplayers > 0 else False,
show_lives=False))
xval += x_offs * (0.85 if nplayers > 0 else 0.56)
nplayers -= 1
test_lives += 1
def _show_team_score(self, pos_v: float, sessionteam: bs.SessionTeam,
scored: bool, kill_delay: float,
shiftdelay: float) -> None:
del kill_delay # Unused arg.
if len(self.teams) != 2:
ZoomText(
str(sessionteam.customdata['score']),
position=(150, pos_v),
maxwidth=100,
color=(1.0, 0.9, 0.5) if scored else (0.6, 0.6, 0.7),
shiftposition=(-100, pos_v),
shiftdelay=shiftdelay,
flash=scored,
trail=scored,
h_align='left',
jitter=1.0,
trailcolor=(1, 0.8, 0.0, 0),
).autoretain()
else:
ZoomText(str(sessionteam.customdata['score']),
position=(-250, 190) if pos_v == 65 else (250, 190),
maxwidth=100,
color=(1.0, 0.9, 0.5) if scored else (0.6, 0.6, 0.7),
shiftposition=(-250, 190) if pos_v == 65 else (250, 190),
shiftdelay=shiftdelay,
flash=scored,
trail=scored,
scale=0.56,
h_align='center',
jitter=1.0,
trailcolor=(1, 0.8, 0.0, 0)).autoretain()
def _get_spawn_point(self, player: Player) -> Optional[babase.Vec3]:
return None
def spawn_player(self, player: Player) -> bs.Actor:
actor = self.spawn_player_spaz(player, self._get_spawn_point(player))
# ===================================================================================================
# If we have any icons, update their state.
for icon in player.icons:
icon.handle_player_spawned()
return actor
# score board
# ====================================================================================================
def _print_lives(self, player: Player) -> None:
from bascenev1lib.actor import popuptext
def show_player_scores(self,
delay: float = 2.5,
results: bs.GameResults | None = None,
scale: float = 1.0,
x_offset: float = 0.0,
y_offset: float = 0.0) -> None:
"""Show scores for individual players."""
# pylint: disable=too-many-locals
# pylint: disable=too-many-statements
# 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:
return
ts_v_offset = 150.0 + y_offset
ts_h_offs = 80.0 + x_offset
tdelay = delay
spacing = 40
popuptext.PopupText('x' + str(player.lives - 1),
color=(1, 1, 0, 1),
offset=(0, -0.8, 0),
random_offset=0.0,
scale=1.8,
position=player.node.position).autoretain()
is_free_for_all = isinstance(self.session, bs.FreeForAllSession)
def on_player_leave(self, player: Player) -> None:
super().on_player_leave(player)
player.icons = []
is_two_team = True if len(self.session.sessionteams) == 2 else False
# Remove us from spawn-order.
if player in player.team.spawn_order:
player.team.spawn_order.remove(player)
def _get_prec_score(p_rec: bs.PlayerRecord) -> int | None:
if is_free_for_all and results is not None:
assert isinstance(results, bs.GameResults)
assert p_rec.team.activityteam is not None
val = results.get_sessionteam_score(p_rec.team)
return val
return p_rec.accumscore
# Update icons in a moment since our team will be gone from the
# list then.
bs.timer(0, self._update_icons)
def _get_prec_score_str(p_rec: bs.PlayerRecord) -> str | bs.Lstr:
if is_free_for_all and results is not None:
assert isinstance(results, bs.GameResults)
assert p_rec.team.activityteam is not None
val = results.get_sessionteam_score_str(p_rec.team)
assert val is not None
return val
return str(p_rec.accumscore)
# If the player to leave was the last in spawn order and had
# their final turn currently in-progress, mark the survival time
# for their team.
if self._get_total_team_lives(player.team) == 0:
assert self._start_time is not None
player.team.survival_seconds = int(bs.time() - self._start_time)
# stats.get_records() can return players that are no longer in
# the game.. if we're using results we have to filter those out
# (since they're not in results and that's where we pull their
# scores from)
if results is not None:
assert isinstance(results, bs.GameResults)
player_records = []
assert self.stats
valid_players = list(self.stats.get_records().items())
def _get_total_team_lives(self, team: Team) -> int:
return sum(player.lives for player in team.players)
def _get_player_score_set_entry(
player: bs.SessionPlayer) -> bs.PlayerRecord | None:
for p_rec in valid_players:
if p_rec[1].player is player:
return p_rec[1]
return None
def handlemessage(self, msg: Any) -> Any:
if isinstance(msg, bs.PlayerDiedMessage):
# Results is already sorted; just convert it into a list of
# score-set-entries.
for winnergroup in results.winnergroups:
for team in winnergroup.teams:
if len(team.players) == 1:
player_entry = _get_player_score_set_entry(
team.players[0])
if player_entry is not None:
player_records.append(player_entry)
else:
player_records = []
player_records_scores = [
(_get_prec_score(p), name, p)
for name, p in list(self.stats.get_records().items())
# Augment standard behavior.
super().handlemessage(msg)
player: Player = msg.getplayer(Player)
player.lives -= 1
if player.lives < 0:
logging.error(
"Got lives < 0 in Alliance Elimination; this shouldn't happen.")
player.lives = 0
# If we have any icons, update their state.
for icon in player.icons:
icon.handle_player_died()
# Play big death sound on our last death
# or for every one.
if player.lives == 0:
SpazFactory.get().single_player_death_sound.play()
# If we hit zero lives, we're dead (and our team might be too).
if player.lives == 0:
# If the whole team is now dead, mark their survival time.
if self._get_total_team_lives(player.team) == 0:
assert self._start_time is not None
player.team.survival_seconds = int(bs.time() -
self._start_time)
# Put ourself at the back of the spawn order.
player.team.spawn_order.remove(player)
player.team.spawn_order.append(player)
player.node.delete()
def _update(self) -> None:
# For both teams, find the first player on the spawn order
# list with lives remaining and spawn them if they're not alive.
for team in self.teams:
# Prune dead players from the spawn order.
team.spawn_order = [p for p in team.spawn_order if p]
players_spawned = 0
for player in team.spawn_order:
assert isinstance(player, Player)
if player.lives > 0:
if not player.is_alive():
self.spawn_player(player)
self._update_icons()
players_spawned += 1
if players_spawned >= self._players_per_team_in_arena:
break
# If we're down to 1 or fewer living teams, start a timer to end
# the game (allows the dust to settle and draws to occur if deaths
# are close enough).
if len(self._get_living_teams()) < 2:
self._round_end_timer = bs.Timer(0.5, self.end_game)
def _get_living_teams(self) -> List[Team]:
return [
team for team in self.teams
if len(team.players) > 0 and any(player.lives > 0
for player in team.players)
]
player_records_scores.sort(reverse=True)
# Just want living player entries.
player_records = [p[2] for p in player_records_scores if p[2]]
voffs = -140.0 + spacing * 5 * 0.5
voffs_team0 = voffs
tdelay_team0 = tdelay
def _txt(xoffs: float,
yoffs: float,
text: babase.Lstr,
h_align: Text.HAlign = Text.HAlign.RIGHT,
extrascale: float = 1.0,
maxwidth: float | None = 120.0) -> None:
Text(text,
color=(0.5, 0.5, 0.6, 0.5),
position=(ts_h_offs + xoffs * scale,
ts_v_offset + (voffs + yoffs + 4.0) * scale),
h_align=h_align,
v_align=Text.VAlign.CENTER,
scale=0.8 * scale * extrascale,
maxwidth=maxwidth,
transition=Text.Transition.IN_LEFT,
transition_delay=tdelay).autoretain()
session = self.session
assert isinstance(session, bs.MultiTeamSession)
if is_two_team:
tval = "Game " + str(session.get_game_number()) + " Results"
_txt(-75,
160,
tval,
h_align=Text.HAlign.CENTER,
extrascale=1.4,
maxwidth=None)
else:
tval = babase.Lstr(
resource='gameLeadersText',
subs=[('${COUNT}', str(session.get_game_number()))],
)
_txt(
180,
43,
tval,
h_align=Text.HAlign.CENTER,
extrascale=1.4,
maxwidth=None,
)
_txt(-15, 4, babase.Lstr(resource='playerText'), h_align=Text.HAlign.LEFT)
_txt(180, 4, babase.Lstr(resource='killsText'))
_txt(280, 4, babase.Lstr(resource='deathsText'), maxwidth=100)
score_label = 'Score' if results is None else results.score_label
translated = babase.Lstr(translate=('scoreNames', score_label))
_txt(390, 0, translated)
if is_two_team:
_txt(-595, 4, babase.Lstr(resource='playerText'),
h_align=Text.HAlign.LEFT)
_txt(-400, 4, babase.Lstr(resource='killsText'))
_txt(-300, 4, babase.Lstr(resource='deathsText'), maxwidth=100)
_txt(-190, 0, translated)
topkillcount = 0
topkilledcount = 99999
top_score = 0 if not player_records else _get_prec_score(
player_records[0])
for prec in player_records:
topkillcount = max(topkillcount, prec.accum_kill_count)
topkilledcount = min(topkilledcount, prec.accum_killed_count)
def _scoretxt(text: str | bs.Lstr,
x_offs: float,
highlight: bool,
delay2: float,
maxwidth: float = 70.0, team_id=1) -> None:
Text(text,
position=(ts_h_offs + x_offs * scale,
ts_v_offset + (
voffs + 15) * scale) if team_id == 1 else (
ts_h_offs + x_offs * scale,
ts_v_offset + (voffs_team0 + 15) * scale),
scale=scale,
color=(1.0, 0.9, 0.5, 1.0) if highlight else
(0.5, 0.5, 0.6, 0.5),
h_align=Text.HAlign.RIGHT,
v_align=Text.VAlign.CENTER,
maxwidth=maxwidth,
transition=Text.Transition.IN_LEFT,
transition_delay=(tdelay + delay2) if team_id == 1 else (
tdelay_team0 + delay2)).autoretain()
for playerrec in player_records:
if is_two_team and playerrec.team.id == 0:
tdelay_team0 += 0.05
voffs_team0 -= spacing
x_image = 617
x_text = -595
y = ts_v_offset + (voffs_team0 + 15.0) * scale
else:
tdelay += 0.05
voffs -= spacing
x_image = 12
x_text = 10.0
y = ts_v_offset + (voffs + 15.0) * scale
Image(playerrec.get_icon(),
position=(ts_h_offs - x_image * scale,
y),
scale=(30.0 * scale, 30.0 * scale),
transition=Image.Transition.IN_LEFT,
transition_delay=tdelay if playerrec.team.id == 1 else tdelay_team0).autoretain()
Text(babase.Lstr(value=playerrec.getname(full=True)),
maxwidth=160,
scale=0.75 * scale,
position=(ts_h_offs + x_text * scale,
y),
h_align=Text.HAlign.LEFT,
v_align=Text.VAlign.CENTER,
color=babase.safecolor(playerrec.team.color + (1,)),
transition=Text.Transition.IN_LEFT,
transition_delay=tdelay if playerrec.team.id == 1 else tdelay_team0).autoretain()
if is_two_team and playerrec.team.id == 0:
_scoretxt(str(playerrec.accum_kill_count), -400,
playerrec.accum_kill_count == topkillcount, 0.1,
team_id=0)
_scoretxt(str(playerrec.accum_killed_count), -300,
playerrec.accum_killed_count == topkilledcount, 0.1,
team_id=0)
_scoretxt(_get_prec_score_str(playerrec), -190,
_get_prec_score(playerrec) == top_score, 0.2, team_id=0)
else:
_scoretxt(str(playerrec.accum_kill_count), 180,
playerrec.accum_kill_count == topkillcount, 0.1)
_scoretxt(str(playerrec.accum_killed_count), 280,
playerrec.accum_killed_count == topkilledcount, 0.1)
_scoretxt(_get_prec_score_str(playerrec), 390,
_get_prec_score(playerrec) == top_score, 0.2)
# ======================== draw screen =============
class DrawScoreScreenActivity(MultiTeamScoreScreenActivity):
"""Score screen shown after a draw."""
default_music = None # Awkward silence...
def on_begin(self) -> None:
babase.set_analytics_screen('Draw Score Screen')
super().on_begin()
ZoomText(babase.Lstr(resource='drawText'),
position=(0, 200),
maxwidth=400,
shiftposition=(0, 200),
shiftdelay=2.0,
flash=False,
scale=0.7,
trail=False,
jitter=1.0).autoretain()
bs.timer(0.35, self._score_display_sound.play)
self.show_player_scores(results=self.settings_raw.get('results', None))
def end_game(self) -> None:
if self.has_ended():
return
results = bs.GameResults()
self._vs_text = None # Kill our 'vs' if its there.
for team in self.teams:
results.set_team_score(team, team.survival_seconds)
self.end(results=results)

View file

@ -1,9 +1,8 @@
# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport)
# Released under the MIT License. See LICENSE for details.
# BY Stary_Agent
"""Hockey game and support classes."""
"""Air soccer game."""
# ba_meta require api 8
# ba_meta require api 9
# (see https://ballistica.net/wiki/meta-tag-system)
from __future__ import annotations
@ -40,7 +39,7 @@ def create_slope(self):
class Puck(bs.Actor):
"""A lovely giant hockey puck."""
"""A lovely ball."""
def __init__(self, position: Sequence[float] = (0.0, 13.0, 0.0)):
super().__init__()
@ -52,7 +51,6 @@ class Puck(bs.Actor):
self.last_players_to_touch: Dict[int, Player] = {}
self.scored = False
assert activity is not None
assert isinstance(activity, HockeyGame)
pmats = [shared.object_material, activity.puck_material]
self.node = bs.newnode('prop',
delegate=self,
@ -117,7 +115,7 @@ class Team(bs.Team[Player]):
# ba_meta export bascenev1.GameActivity
class AirSoccerGame(bs.TeamGameActivity[Player, Team]):
"""Ice hockey game."""
"""Air soccer game."""
name = 'Epic Air Soccer'
description = 'Score some goals.'
@ -656,6 +654,6 @@ class CreativeThoughts(bs.Map):
try:
bs._map.register_map(CreativeThoughts)
bs.register_map(CreativeThoughts)
except:
pass

View file

@ -2,12 +2,13 @@
#
"""Elimination mini-game."""
# ba_meta require api 8
# ba_meta require api 9
# (see https://ballistica.net/wiki/meta-tag-system)
from __future__ import annotations
from typing import TYPE_CHECKING
import logging
import babase
import bascenev1 as bs
@ -184,7 +185,7 @@ class AllianceEliminationGame(bs.TeamGameActivity[Player, Team]):
@classmethod
def get_available_settings(
cls, sessiontype: Type[bs.Session]) -> List[babase.Setting]:
cls, sessiontype: Type[bs.Session]) -> List[bs.Setting]:
settings = [
bs.IntSetting(
'Lives Per Player',
@ -448,7 +449,7 @@ class AllianceEliminationGame(bs.TeamGameActivity[Player, Team]):
player.lives -= 1
if player.lives < 0:
babase.print_error(
logging.error(
"Got lives < 0 in Alliance Elimination; this shouldn't happen.")
player.lives = 0
@ -472,6 +473,7 @@ class AllianceEliminationGame(bs.TeamGameActivity[Player, Team]):
# Put ourself at the back of the spawn order.
player.team.spawn_order.remove(player)
player.team.spawn_order.append(player)
player.node.delete()
def _update(self) -> None:
# For both teams, find the first player on the spawn order

View file

@ -1,10 +1,4 @@
# Ported by your friend: Freaku
# Join BCS:
# https://discord.gg/ucyaesh
# ba_meta require api 8
# ba_meta require api 9
from __future__ import annotations
@ -37,7 +31,7 @@ class State:
enable_bomb=self.bomb,
enable_pickup=self.grab)
if self.curse:
spaz.curse_time = -1
spaz.curse_time = None
spaz.curse()
if self.bomb:
spaz.bomb_type = self.bomb
@ -82,7 +76,7 @@ class ArmsRaceGame(bs.TeamGameActivity[Player, Team]):
@classmethod
def get_available_settings(
cls, sessiontype: Type[bs.Session]) -> List[babase.Setting]:
cls, sessiontype: Type[bs.Session]) -> List[bs.Setting]:
settings = [
bs.IntChoiceSetting(
'Time Limit',
@ -149,11 +143,10 @@ class ArmsRaceGame(bs.TeamGameActivity[Player, Team]):
def on_begin(self) -> None:
super().on_begin()
self.setup_standard_time_limit(self._time_limit)
# self.setup_standard_powerup_drops()
def on_player_join(self, player):
if player.state is None:
player.state = self.states[0]
player.state = self.states[5]
self.spawn_player(player)
# overriding the default character spawning..

View file

@ -1,7 +1,6 @@
# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport)
"""Avalancha mini-game."""
# ba_meta require api 8
# ba_meta require api 9
# (see https://ballistica.net/wiki/meta-tag-system)
from __future__ import annotations
@ -26,12 +25,12 @@ randomPic = ["lakeFrigidPreview", "hockeyStadiumPreview"]
def ba_get_api_version():
return 8
return 9
def ba_get_levels():
return [
bs._level.Level(
bs.Level(
"Icy Emits",
gametype=IcyEmitsGame,
settings={},
@ -127,7 +126,7 @@ class AvalanchaGame(MeteorShowerGame):
pos = (pos[0], pos[1] + 0.4, pos[2])
dropdir = -1.0 if pos[0] > 0 else 1.0
vel = (random.randrange(-4, 4), 7.0, random.randrange(0, 4))
bs.timer(delay, babase.Call(self._drop_bomb, pos, vel))
bs.timer(delay, babase.CallPartial(self._drop_bomb, pos, vel))
delay += 0.1
self._set_meteor_timer()

View file

@ -1,19 +1,14 @@
# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport)
# Released under the MIT License. See LICENSE for details.
# ba_meta require api 8
# ba_meta require api 9
# (see https://ballistica.net/wiki/meta-tag-system)
from __future__ import annotations
from typing import TYPE_CHECKING
import babase
import bauiv1 as bui
import bascenev1 as bs
import _babase
from bascenev1lib.actor.playerspaz import PlayerSpaz
from bascenev1lib.actor.scoreboard import Scoreboard
from bascenev1lib.actor.powerupbox import PowerupBoxFactory
from bascenev1lib.gameutils import SharedObjects
from bascenev1lib.actor import playerspaz as ps
from bascenev1lib import maps
@ -558,9 +553,6 @@ class Cuadro(bs.Actor):
'materials': [self.collision,
shared.footing_material]})
# self.shield = bs.newnode('shield', attrs={'radius': 1.0, 'color': (0,10,0)})
# self.region.connectattr('position', self.shield, 'position')
position = (position[0], position[1], position[2]+0.09)
pos = list(position)
oldpos = list(position)
@ -770,5 +762,5 @@ class BasketMapV2(maps.HockeyStadium):
]
bs._map.register_map(BasketMap)
bs._map.register_map(BasketMapV2)
bs.register_map(BasketMap)
bs.register_map(BasketMapV2)

View file

@ -1,10 +1,9 @@
# Ported to api 8 by brostos using baport.(https://github.com/bombsquad-community/baport)
# BetterDeathMatch
# Made by your friend: @[Just] Freak#4999
"""Defines a very-customisable DeathMatch mini-game"""
# ba_meta require api 8
# ba_meta require api 9
from __future__ import annotations
@ -17,7 +16,7 @@ from bascenev1lib.actor.playerspaz import PlayerSpaz
from bascenev1lib.actor.scoreboard import Scoreboard
if TYPE_CHECKING:
from typing import Any, Type, List, Dict, Tuple, Union, Sequence, Optional
from typing import Any, Type, List, Union, Sequence, Optional
class Player(bs.Player['Team']):
@ -43,7 +42,7 @@ class BetterDeathMatchGame(bs.TeamGameActivity[Player, Team]):
@classmethod
def get_available_settings(
cls, sessiontype: Type[bs.Session]) -> List[babase.Setting]:
cls, sessiontype: Type[bs.Session]) -> List[bs.Setting]:
settings = [
bs.IntSetting(
'Kills to Win Per Player',
@ -138,19 +137,16 @@ class BetterDeathMatchGame(bs.TeamGameActivity[Player, Team]):
bs.MusicType.TO_THE_DEATH)
def get_instance_description(self) -> Union[str, Sequence]:
return 'Crush ${ARG1} of your enemies. byFREAK', self._score_to_win
return 'Crush ${ARG1} of your enemies.', self._score_to_win
def get_instance_description_short(self) -> Union[str, Sequence]:
return 'kill ${ARG1} enemies. byFREAK', self._score_to_win
return 'kill ${ARG1} enemies.', self._score_to_win
def on_team_join(self, team: Team) -> None:
if self.has_begun():
self._update_scoreboard()
## Run settings related: IcyFloor ##
def on_transition_in(self) -> None:
super().on_transition_in()
activity = bs.getactivity()
@ -164,7 +160,6 @@ class BetterDeathMatchGame(bs.TeamGameActivity[Player, Team]):
super().on_begin()
self.setup_standard_time_limit(self._time_limit)
## Run settings related: NightMode,Powerups ##
if self._night_mode:
bs.getactivity().globalsnode.tint = (0.5, 0.7, 1)

View file

@ -1,4 +1,3 @@
# Ported to api 8 by brostos using baport.(https://github.com/bombsquad-community/baport)
# BetterElimination
# Made by your friend: @[Just] Freak#4999
@ -7,11 +6,12 @@
"""Defines a very-customisable Elimination mini-game"""
# ba_meta require api 8
# ba_meta require api 9
from __future__ import annotations
from typing import TYPE_CHECKING
import logging
import babase
import bauiv1 as bui
@ -20,8 +20,7 @@ from bascenev1lib.actor.spazfactory import SpazFactory
from bascenev1lib.actor.scoreboard import Scoreboard
if TYPE_CHECKING:
from typing import (Any, Tuple, Dict, Type, List, Sequence, Optional,
Union)
from typing import Any, Tuple, Type, List, Sequence, Optional, Union
class Icon(bs.Actor):
@ -187,7 +186,7 @@ class BetterEliminationGame(bs.TeamGameActivity[Player, Team]):
@classmethod
def get_available_settings(
cls, sessiontype: Type[bs.Session]) -> List[babase.Setting]:
cls, sessiontype: Type[bs.Session]) -> List[bs.Setting]:
settings = [
bs.IntSetting(
'Life\'s Per Player',
@ -590,7 +589,7 @@ class BetterEliminationGame(bs.TeamGameActivity[Player, Team]):
player.lives -= 1
if player.lives < 0:
babase.print_error(
logging.error(
"Got lives < 0 in Elim; this shouldn't happen. solo:" +
str(self._solo_mode))
player.lives = 0

View file

@ -1,8 +1,6 @@
# Made by MythB
# Ported by: MysteriousBoi
# ba_meta require api 8
# ba_meta require api 9
from __future__ import annotations
from typing import TYPE_CHECKING
@ -25,8 +23,6 @@ class PuckDiedMessage:
# goalpost
class FlagKale(bs.Actor):
def __init__(self, position=(0, 2.5, 0), color=(1, 1, 1)):
super().__init__()
@ -305,8 +301,8 @@ class BBGame(bs.TeamGameActivity[Player, Team]):
def get_instance_description_short(self) -> Union[str, Sequence]:
if self._score_to_win == 1:
return 'score a goal'
return 'score ${ARG1} goals', self._score_to_win
return 'Score a goal'
return 'Score ${ARG1} goals', self._score_to_win
def on_begin(self) -> None:
super().on_begin()
@ -437,7 +433,7 @@ class BBGame(bs.TeamGameActivity[Player, Team]):
if self._grant_power:
for player in team.players:
try:
player.actor.node.handlemessage(
player.node.handlemessage(
bs.PowerupMessage('punch'))
except:
pass
@ -463,7 +459,7 @@ class BBGame(bs.TeamGameActivity[Player, Team]):
if self._grant_power:
for player in team.players:
try:
player.actor.node.handlemessage(
player.node.handlemessage(
bs.PowerupMessage('shield'))
except:
pass

View file

@ -1,4 +1,4 @@
# ba_meta require api 8
# ba_meta require api 9
# (see https://ballistica.net/wiki/meta-tag-system)
from __future__ import annotations
@ -64,7 +64,7 @@ class NewPlayerSpaz(PlayerSpaz):
self.check_avalible_bombs()
self._bomb_check_timer = bs.timer(
0.5,
bs.WeakCall(self.check_avalible_bombs),
bs.WeakCallStrict(self.check_avalible_bombs),
repeat=True)
def drop_bomb(self) -> stdbomb.Bomb | None:
@ -95,7 +95,7 @@ class NewPlayerSpaz(PlayerSpaz):
self.bomb_count -= 1
bomb.node.add_death_action(
bs.WeakCall(self.handlemessage, BombDiedMessage())
bs.WeakCallPartial(self.handlemessage, BombDiedMessage())
)
self._pick_up(bomb.node)
@ -133,7 +133,7 @@ class BombOnMyHeadGame(bs.TeamGameActivity[Player, Team]):
@classmethod
def get_available_settings(
cls, sessiontype: type[bs.Session]
) -> list[babase.Setting]:
) -> list[bs.Setting]:
settings = [
bs.IntChoiceSetting(
maxbomblimit,
@ -194,6 +194,7 @@ class BombOnMyHeadGame(bs.TeamGameActivity[Player, Team]):
self.setup_standard_time_limit(self._time_limit)
self._timer = OnScreenTimer()
self._timer.start()
bs.timer(5.0, self._check_end_game)
def spawn_player(self, player: Player) -> bs.Actor:
from babase import _math
@ -236,7 +237,7 @@ class BombOnMyHeadGame(bs.TeamGameActivity[Player, Team]):
animate(light, 'intensity', {0: 0, 0.25: 1, 0.5: 0})
bs.timer(0.5, light.delete)
bs.timer(1.0, bs.WeakCall(spaz.start_bomb_checking))
bs.timer(1.0, bs.WeakCallStrict(spaz.start_bomb_checking))
spaz.set_bomb_count(self._max_bomb_limit)
def handlemessage(self, msg: Any) -> Any:

View file

@ -1,4 +1,4 @@
# ba_meta require api 8
# ba_meta require api 9
# (see https://ballistica.net/wiki/meta-tag-system)
from __future__ import annotations
@ -52,8 +52,8 @@ class NewPlayerSpaz(PlayerSpaz):
self.super_jump_material.add_actions(
conditions=('they_have_material', shared.footing_material),
actions=(
('call', 'at_connect', babase.Call(self.jump_state, True)),
('call', 'at_disconnect', babase.Call(self.jump_state, False))
('call', 'at_connect', babase.CallPartial(self.jump_state, True)),
('call', 'at_disconnect', babase.CallPartial(self.jump_state, False))
),
)
self.node.roller_materials += (self.super_jump_material,)
@ -98,7 +98,7 @@ class BoxingGame(DeathMatchGame):
@classmethod
def get_available_settings(
cls, sessiontype: type[bs.Session]
) -> list[babase.Setting]:
) -> list[bs.Setting]:
settings = [
bs.IntSetting(
'Kills to Win Per Player',

View file

@ -1,236 +0,0 @@
from __future__ import annotations
from typing import TYPE_CHECKING
import babase
import bauiv1 as bui
import bascenev1 as bs
from bascenev1lib.gameutils import SharedObjects
from bascenev1lib.actor.playerspaz import PlayerSpaz
import random
if TYPE_CHECKING:
from typing import Any, List, Dict
class mapdefs:
points = {}
# noinspection PyDictCreation
boxes = {}
boxes['area_of_interest_bounds'] = (0.0, 1.185751251, 0.4326226188) + (
0.0, 0.0, 0.0) + (29.8180273, 11.57249038, 18.89134176)
boxes['edge_box'] = (-0.103873591, 0.4133341891, 0.4294651013) + (
0.0, 0.0, 0.0) + (22.48295719, 1.290242794, 8.990252454)
points['ffa_spawn1'] = (-0.08015551329, 0.02275111462,
-4.373674593) + (8.895057015, 1.0, 0.444350722)
points['ffa_spawn2'] = (-0.08015551329, 0.02275111462,
4.076288941) + (8.895057015, 1.0, 0.444350722)
points['flag1'] = (-10.99027878, 0.05744967453, 0.1095578275)
points['flag2'] = (11.01486398, 0.03986567039, 0.1095578275)
points['flag_default'] = (-0.1001374046, 0.04180340146, 0.1095578275)
boxes['goal1'] = (12.22454533, 1.0,
0.1087926362) + (0.0, 0.0, 0.0) + (2.0, 2.0, 12.97466313)
boxes['goal2'] = (-12.15961605, 1.0,
0.1097860203) + (0.0, 0.0, 0.0) + (2.0, 2.0, 13.11856424)
boxes['map_bounds'] = (0.0, 1.185751251, 0.4326226188) + (0.0, 0.0, 0.0) + (
42.09506485, 22.81173179, 29.76723155)
points['powerup_spawn1'] = (5.414681236, 0.9515026107, -5.037912441)
points['powerup_spawn2'] = (-5.555402285, 0.9515026107, -5.037912441)
points['powerup_spawn3'] = (5.414681236, 0.9515026107, 5.148223181)
points['powerup_spawn4'] = (-5.737266365, 0.9515026107, 5.148223181)
points['spawn1'] = (-10.03866341, 0.02275111462, 0.0) + (0.5, 1.0, 4.0)
points['spawn2'] = (9.823107149, 0.01092306765, 0.0) + (0.5, 1.0, 4.0)
points['tnt1'] = (-0.08421587483, 0.9515026107, -0.7762602271)
class BridgitMash(bs.Map):
"""Stadium map for football games."""
defs = mapdefs
defs.points['spawn1'] = (-12.03866341, 0.02275111462,
0.0) + (0.5, 1.0, 4.0)
defs.points['spawn2'] = (
12.823107149, 0.01092306765, 0.0) + (0.5, 1.0, 4.0)
defs.points["flag1"] = (-9.6, 0.747, -2.949)
defs.points["flag2"] = (9.6, 0.747, 3.15)
defs.points["flag3"] = (-9.6, 0.747, 3.15)
defs.points["flag4"] = (-0.1, 0.747, -2.949)
defs.points["flag5"] = (-0.1, 0.747, 0.152)
defs.points["flag6"] = (-0.1, 0.747, 3.15)
defs.points["flag7"] = (9.6, 0.747, -2.949)
defs.points["flag8"] = (9.6, 0.747, 0.152)
defs.points["flag9"] = (-9.6, 0.747, 0.152)
defs.points["spawn_by_flag1"] = (-9.6, 0.747, -2.949)
defs.points["spawn_by_flag2"] = (9.6, 0.747, 3.15)
defs.points["spawn_by_flag3"] = (-9.6, 0.747, 3.15)
defs.points["spawn_by_flag4"] = (-0.1, 0.747, -2.949)
defs.points["spawn_by_flag5"] = (-0.1, 0.747, 0.152)
defs.points["spawn_by_flag6"] = (-0.1, 0.747, 3.15)
defs.points["spawn_by_flag7"] = (9.6, 0.747, -2.949)
defs.points["spawn_by_flag8"] = (9.6, 0.747, 0.152)
defs.points["spawn_by_flag9"] = (-9.6, 0.747, 0.152)
name = 'Bridgit Mash'
@classmethod
def get_play_types(cls) -> list[str]:
"""Return valid play types for this map."""
return ['melee', 'football', 'team_flag', 'keep_away', 'conquest']
@classmethod
def get_preview_texture_name(cls) -> str:
return 'footballStadiumPreview'
@classmethod
def on_preload(cls) -> Any:
data: dict[str, Any] = {
'mesh': bs.getmesh('footballStadium'),
'vr_fill_mesh': bs.getmesh('footballStadiumVRFill'),
'collision_mesh': bs.getcollisionmesh('footballStadiumCollide'),
'tex': bs.gettexture('footballStadium')
}
return data
def __init__(self) -> None:
super().__init__()
shared = SharedObjects.get()
# TODO vr fill data
gnode = bs.getactivity().globalsnode
gnode.tint = (1.3, 1.2, 1.0)
gnode.ambient_color = (1.3, 1.2, 1.0)
gnode.vignette_outer = (0.57, 0.57, 0.57)
gnode.vignette_inner = (0.9, 0.9, 0.9)
gnode.vr_camera_offset = (0, -0.8, -1.1)
gnode.vr_near_clip = 0.5
cols = [(0.10, 0.3, 0.5), (0.6, 0.3, 0.6), (0.6, 0.3, 0.1),
(0.2, 0.4, 0.1), (0.4, 0.3, 0.7), (0.10, 0.3, 0.5)]
self.background = bs.newnode(
'terrain',
attrs={
'mesh': bs.getmesh('natureBackground'),
'lighting': False,
'background': True,
'color': cols[random.randrange(0, 6)]
})
self.map_extend()
def is_point_near_edge(self,
point: babase.Vec3,
running: bool = False) -> bool:
box_position = self.defs.boxes['edge_box'][0:3]
box_scale = self.defs.boxes['edge_box'][6:9]
xpos = (point.x - box_position[0]) / box_scale[0]
zpos = (point.z - box_position[2]) / box_scale[2]
return xpos < -0.5 or xpos > 0.5 or zpos < -0.5 or zpos > 0.5
def map_extend(self):
self.create_ramp(0, 0)
self.create_ramp(10.9, 0)
self.create_ramp(0, -3)
self.create_ramp(10.9, -2.8)
self.create_ramp(0, 3.0)
self.create_ramp(10.9, 3.2)
self.ground()
# _babase.prop_axis(1, 0, 0)
def ground(self):
shared = SharedObjects.get()
self._real_wall_material = bs.Material()
self._real_wall_material.add_actions(
actions=(
('modify_part_collision', 'collide', True),
('modify_part_collision', 'physical', True)
))
self.mat = bs.Material()
self.mat.add_actions(
actions=(('modify_part_collision', 'physical', False),
('modify_part_collision', 'collide', False))
)
def create_ramp(self, loc, z_marg):
# try:
# _babase.prop_axis(0, 0, 0)
# except:
# pass
shared = SharedObjects.get()
self._real_wall_material = bs.Material()
self._real_wall_material.add_actions(
actions=(
('modify_part_collision', 'collide', True),
('modify_part_collision', 'physical', True)
))
self.mat = bs.Material()
self.mat.add_actions(
actions=(('modify_part_collision', 'physical', False),
('modify_part_collision', 'collide', False))
)
spaz_collide_mat = bs.Material()
# spaz_collide_mat.add_actions(
# conditions=('they_have_material',shared.player_material),
# actions=(
# ('modify_part_collision', 'collide', True),
# ( 'call','at_connect',babase.Call(self._handle_player_pad_collide,real )),
# ),
# )
pos = (-5.3 + loc, 0.7, 1.1+z_marg)
self.ud_1_r = bs.newnode('region', attrs={'position': pos, 'scale': (
2, 1, 2), 'type': 'box', 'materials': [shared.footing_material, spaz_collide_mat]})
self.node = bs.newnode('prop',
owner=self.ud_1_r,
attrs={
'mesh': bs.getmesh('bridgitLevelTop'),
'light_mesh': bs.getmesh('powerupSimple'),
'position': (2, 7, 2),
'body': 'puck',
'shadow_size': 0.0,
'velocity': (0, 0, 0),
'color_texture': bs.gettexture('bridgitLevelColor'),
'mesh_scale': 0.72,
'reflection_scale': [1.5],
'materials': [self.mat, shared.object_material, shared.footing_material],
'density': 9000000000
})
self.node.changerotation(0, 0, 0)
mnode = bs.newnode('math',
owner=self.ud_1_r,
attrs={
'input1': (0, -2.9, 0),
'operation': 'add'
})
self.ud_1_r.connectattr('position', mnode, 'input2')
mnode.connectattr('output', self.node, 'position')
# /// region to stand long bar ===============
pos = (-9.67+loc, 0.1, 0+z_marg)
self.left_region = bs.newnode('region', attrs={'position': pos, 'scale': (2.4, 0.7, 3.2), 'type': 'box', 'materials': [
shared.footing_material, self._real_wall_material, spaz_collide_mat]})
pos = (-5.67+loc, 0.1, 0+z_marg)
self.center_region = bs.newnode('region', attrs={'position': pos, 'scale': (
8, 0.7, 1), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material, spaz_collide_mat]})
pos = (-1.3+loc, 0.1, 0+z_marg)
self.right_region = bs.newnode('region', attrs={'position': pos, 'scale': (2.4, 0.7, 3.2), 'type': 'box', 'materials': [
shared.footing_material, self._real_wall_material, spaz_collide_mat]})
def _handle_player_collide(self):
try:
player = bs.getcollision().opposingnode.getdelegate(
PlayerSpaz, True)
except bs.NotFoundError:
return
if player.is_alive():
player.shatter(True)
bs._map.register_map(BridgitMash)

View file

@ -1,9 +1,8 @@
# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport)
# Released under the MIT License. See LICENSE for details.
#
"""DeathMatch game and support classes."""
"""Cannon Fight game and support classes."""
# ba_meta require api 8
# ba_meta require api 9
# (see https://ballistica.net/wiki/meta-tag-system)
from __future__ import annotations
@ -24,9 +23,6 @@ if TYPE_CHECKING:
from typing import Any, Union, Sequence, Optional
# ba_meta export bascenev1.GameActivity
class CanonFightGame(DeathMatchGame):
"""A game type based on acquiring kills."""
@ -39,7 +35,7 @@ class CanonFightGame(DeathMatchGame):
@classmethod
def get_available_settings(
cls, sessiontype: type[bs.Session]) -> list[babase.Setting]:
cls, sessiontype: type[bs.Session]) -> list[bs.Setting]:
settings = [
bs.IntSetting(
'Kills to Win Per Player',
@ -111,7 +107,7 @@ class CanonFightGame(DeathMatchGame):
bs.MusicType.TO_THE_DEATH)
self.wtindex=0
self.wttimer = bs.timer(5, babase.Call(self.wt_), repeat=True)
self.wttimer = bs.timer(5, babase.CallStrict(self.wt_), repeat=True)
self.wthighlights=["Created by Mr.Smoothy","hey smoothy youtube","smoothy#multiverse"]
def wt_(self):
@ -155,10 +151,6 @@ class CanonFightGame(DeathMatchGame):
def handlemessage(self, msg: Any) -> Any:
if isinstance(msg, bs.PlayerDiedMessage):
# Augment standard behavior.
super().handlemessage(msg)
player = msg.getplayer(Player)
self.respawn_player(player)
@ -264,7 +256,7 @@ class CanonFightGame(DeathMatchGame):
self.fake_explosion( (-5.708631629943848, 7.437141418457031, -4.525400638580322))
Bomb(position=(-6,7.5,-4),bomb_type=type,owner=owner,source_player=source_player,velocity=(19,y,z)).autoretain()
bs.timer(0.6,babase.Call(self.launch_bomb_byA,owner,type,source_player,count-1))
bs.timer(0.6,babase.CallPartial(self.launch_bomb_byA,owner,type,source_player,count-1))
else:
return
def launch_bomb_byB(self,owner,type,source_player,count):
@ -274,7 +266,7 @@ class CanonFightGame(DeathMatchGame):
self.fake_explosion( (5.708631629943848, 7.437141418457031, -4.525400638580322))
Bomb(position=(6,7.5,-4),bomb_type=type,owner=owner,source_player=source_player,velocity=(-19,y,z)).autoretain()
bs.timer(0.6,babase.Call(self.launch_bomb_byB,owner,type,source_player,count-1))
bs.timer(0.6,babase.CallPartial(self.launch_bomb_byB,owner,type,source_player,count-1))
else:
return
@ -306,7 +298,7 @@ class CanonFightGame(DeathMatchGame):
actions=(
('modify_part_collision', 'collide', True),
('modify_part_collision', 'physical', True),
('call','at_connect',babase.Call(self._handle_canon_load_A))
('call','at_connect',babase.CallStrict(self._handle_canon_load_A))
),
)
self.ud_1_r=bs.newnode('region',attrs={'position': (-8.908631629943848, 7.337141418457031, -4.525400638580322),'scale': (2,1,1),'type': 'box','materials': [canon_load_mat ]})
@ -368,7 +360,7 @@ class CanonFightGame(DeathMatchGame):
actions=(
('modify_part_collision', 'collide', True),
('modify_part_collision', 'physical', True),
('call','at_connect',babase.Call(self._handle_canon_load_B))
('call','at_connect',babase.CallStrict(self._handle_canon_load_B))
),
)
self.ud_1_r2=bs.newnode('region',attrs={'position': (8.908631629943848+0.81, 7.327141418457031, -4.525400638580322),'scale': (2,1,1),'type': 'box','materials': [canon_load_mat ]})

View file

@ -1,4 +1,4 @@
# ba_meta require api 8
# ba_meta require api 9
# (see https://ballistica.net/wiki/meta-tag-system)
'''
@ -128,7 +128,7 @@ class CollectorGame(bs.TeamGameActivity[Player, Team]):
@classmethod
def get_available_settings(
cls, sessiontype: type[bs.Session]
) -> list[babase.Setting]:
) -> list[bs.Setting]:
settings = [
bs.IntSetting(
capsules_to_win,
@ -223,12 +223,12 @@ class CollectorGame(bs.TeamGameActivity[Player, Team]):
(
'call',
'at_connect',
babase.Call(self._handle_player_flag_region_collide, True),
babase.CallPartial(self._handle_player_flag_region_collide, True),
),
(
'call',
'at_disconnect',
babase.Call(self._handle_player_flag_region_collide, False),
babase.CallPartial(self._handle_player_flag_region_collide, False),
),
),
)

View file

@ -3,13 +3,12 @@ from __future__ import annotations
from typing import TYPE_CHECKING
import babase
import bauiv1 as bui
import bascenev1 as bs
from bascenev1lib.gameutils import SharedObjects
from bascenev1lib.actor.playerspaz import PlayerSpaz
import random
if TYPE_CHECKING:
from typing import Any, List, Dict
from typing import Any
class mapdefs:
@ -131,7 +130,6 @@ class BridgitMash(bs.Map):
self.create_ramp(0, 3.0)
self.create_ramp(10.9, 3.2)
self.ground()
# _babase.prop_axis(1, 0, 0)
def ground(self):
shared = SharedObjects.get()
@ -151,10 +149,6 @@ class BridgitMash(bs.Map):
)
def create_ramp(self, loc, z_marg):
# try:
# _babase.prop_axis(0, 0, 0)
# except:
# pass
shared = SharedObjects.get()
self._real_wall_material = bs.Material()
@ -172,13 +166,6 @@ class BridgitMash(bs.Map):
('modify_part_collision', 'collide', False))
)
spaz_collide_mat = bs.Material()
# spaz_collide_mat.add_actions(
# conditions=('they_have_material',shared.player_material),
# actions=(
# ('modify_part_collision', 'collide', True),
# ( 'call','at_connect',babase.Call(self._handle_player_pad_collide,real )),
# ),
# )
pos = (-5.3 + loc, 0.7, 1.1+z_marg)
self.ud_1_r = bs.newnode('region', attrs={'position': pos, 'scale': (
2, 1, 2), 'type': 'box', 'materials': [shared.footing_material, spaz_collide_mat]})
@ -233,4 +220,4 @@ class BridgitMash(bs.Map):
player.shatter(True)
bs._map.register_map(BridgitMash)
bs.register_map(BridgitMash)

View file

@ -33,11 +33,11 @@
"scores": 93,
"total_damage": 0.0,
"kills": 0,
"deaths": 0,
"games": 3,
"deaths": 1,
"games": 4,
"kd": 0.0,
"avg_score": 31.0,
"last_seen": "2026-07-16 15:27:54.340453",
"avg_score": 23.25,
"last_seen": "2026-07-16 16:21:28.671836",
"aid": "pb-IF5cVXEyAA=="
}
}