Needs some testing

This commit is contained in:
brostosjoined 2024-01-17 23:09:18 +03:00
parent 1bce1d7d76
commit 4719c3e718
23 changed files with 2124 additions and 1626 deletions

View file

@ -68,10 +68,10 @@ class ForestMap(bs.Map):
def on_preload(cls) -> any: def on_preload(cls) -> any:
data: dict[str, any] = { data: dict[str, any] = {
'mesh': bs.getmesh('natureBackground'), 'mesh': bs.getmesh('natureBackground'),
'tex': bui.gettexture('natureBackgroundColor'), 'tex': bs.gettexture('natureBackgroundColor'),
'collision_mesh': bs.getcollisionmesh('natureBackgroundCollide'), 'collision_mesh': bs.getcollisionmesh('natureBackgroundCollide'),
'bgmesh': bs.getmesh('thePadBG'), 'bgmesh': bs.getmesh('thePadBG'),
'bgtex': bui.gettexture('menuBG') 'bgtex': bs.gettexture('menuBG')
} }
return data return data
@ -85,7 +85,7 @@ class ForestMap(bs.Map):
attrs={ attrs={
'mesh': self.preloaddata['mesh'], 'mesh': self.preloaddata['mesh'],
'color_texture': self.preloaddata['tex'], 'color_texture': self.preloaddata['tex'],
'collide_mesh': self.preloaddata['collide_mesh'], 'collision_mesh': self.preloaddata['collision_mesh'],
'materials': [shared.footing_material] 'materials': [shared.footing_material]
} }
) )

View file

@ -77,6 +77,7 @@
} }
], ],
"versions": { "versions": {
"1.0.1": null,
"1.0.0": { "1.0.0": {
"api_version": 7, "api_version": 7,
"commit_sha": "2fda676", "commit_sha": "2fda676",
@ -92,10 +93,11 @@
{ {
"name": "JoseAng3l", "name": "JoseAng3l",
"email": "", "email": "",
"discord": "! JoseANG3L#0268" "discord": "joseang3l"
} }
], ],
"versions": { "versions": {
"1.0.1": null,
"1.0.0": { "1.0.0": {
"api_version": 7, "api_version": 7,
"commit_sha": "2fda676", "commit_sha": "2fda676",
@ -111,10 +113,11 @@
{ {
"name": "JoseAng3l", "name": "JoseAng3l",
"email": "", "email": "",
"discord": "! JoseANG3L#0268" "discord": "joseang3l"
} }
], ],
"versions": { "versions": {
"1.0.1": null,
"1.0.0": { "1.0.0": {
"api_version": 7, "api_version": 7,
"commit_sha": "2fda676", "commit_sha": "2fda676",
@ -130,10 +133,11 @@
{ {
"name": "JoseAng3l", "name": "JoseAng3l",
"email": "", "email": "",
"discord": "! JoseANG3L#0268" "discord": "joseang3l"
} }
], ],
"versions": { "versions": {
"1.0.1": null,
"1.0.0": { "1.0.0": {
"api_version": 7, "api_version": 7,
"commit_sha": "2fda676", "commit_sha": "2fda676",
@ -149,7 +153,7 @@
{ {
"name": "JoseAng3l", "name": "JoseAng3l",
"email": "", "email": "",
"discord": "! JoseANG3L#0268" "discord": "joseang3l"
} }
], ],
"versions": { "versions": {
@ -178,6 +182,7 @@
} }
], ],
"versions": { "versions": {
"1.1.0": null,
"1.0.1": { "1.0.1": {
"api_version": 7, "api_version": 7,
"commit_sha": "d511c15", "commit_sha": "d511c15",
@ -199,10 +204,11 @@
{ {
"name": "Cross Joy", "name": "Cross Joy",
"email": "cross.joy.official@gmail.com", "email": "cross.joy.official@gmail.com",
"discord": "Cross Joy#0721" "discord": "crossjoy"
} }
], ],
"versions": { "versions": {
"1.0.0": null,
"2.0.0": { "2.0.0": {
"api_version": 7, "api_version": 7,
"commit_sha": "8b257b3", "commit_sha": "8b257b3",
@ -328,6 +334,7 @@
} }
], ],
"versions": { "versions": {
"1.0.1": null,
"1.0.0": { "1.0.0": {
"api_version": 7, "api_version": 7,
"commit_sha": "0841b9e", "commit_sha": "0841b9e",
@ -343,7 +350,7 @@
{ {
"name": "SEBASTIAN2059", "name": "SEBASTIAN2059",
"email": "", "email": "",
"discord": "SEBASTIAN2059#5751" "discord": "sebastian2059"
}, },
{ {
"name": "zPanxo", "name": "zPanxo",
@ -373,10 +380,11 @@
{ {
"name": "Mr.Smoothy", "name": "Mr.Smoothy",
"email": "smoothy@bombsquad.ga", "email": "smoothy@bombsquad.ga",
"discord": "mr.smoothy#5824" "discord": "mr.smoothy"
} }
], ],
"versions": { "versions": {
"1.0.1": null,
"1.0.0": { "1.0.0": {
"api_version": 7, "api_version": 7,
"commit_sha": "52094fc", "commit_sha": "52094fc",
@ -392,7 +400,7 @@
{ {
"name": "Mr.Smoothy", "name": "Mr.Smoothy",
"email": "smoothy@bombsquad.ga", "email": "smoothy@bombsquad.ga",
"discord": "mr.smoothy#5824" "discord": "mr.smoothy"
} }
], ],
"versions": { "versions": {
@ -417,10 +425,11 @@
{ {
"name": "Mr.Smoothy", "name": "Mr.Smoothy",
"email": "smoothy@bombsquad.ga", "email": "smoothy@bombsquad.ga",
"discord": "mr.smoothy#5824" "discord": "mr.smoothy"
} }
], ],
"versions": { "versions": {
"1.0.1": null,
"1.0.0": { "1.0.0": {
"api_version": 7, "api_version": 7,
"commit_sha": "2aa1e50", "commit_sha": "2aa1e50",
@ -436,7 +445,7 @@
{ {
"name": "Mr.Smoothy", "name": "Mr.Smoothy",
"email": "smoothy@bombsquad.ga", "email": "smoothy@bombsquad.ga",
"discord": "mr.smoothy#5824" "discord": "mr.smoothy"
} }
], ],
"versions": { "versions": {
@ -455,10 +464,11 @@
{ {
"name": "Mr.Smoothy", "name": "Mr.Smoothy",
"email": "smoothy@bombsquad.ga", "email": "smoothy@bombsquad.ga",
"discord": "mr.smoothy#5824" "discord": "mr.smoothy"
} }
], ],
"versions": { "versions": {
"1.0.1": null,
"1.0.0": { "1.0.0": {
"api_version": 7, "api_version": 7,
"commit_sha": "2aa1e50", "commit_sha": "2aa1e50",
@ -474,10 +484,11 @@
{ {
"name": "Mr.Smoothy", "name": "Mr.Smoothy",
"email": "smoothy@bombsquad.ga", "email": "smoothy@bombsquad.ga",
"discord": "mr.smoothy#5824" "discord": "mr.smoothy"
} }
], ],
"versions": { "versions": {
"1.0.1": null,
"1.0.0": { "1.0.0": {
"api_version": 7, "api_version": 7,
"commit_sha": "52094fc", "commit_sha": "52094fc",
@ -534,7 +545,7 @@
{ {
"name": "JoseAng3l", "name": "JoseAng3l",
"email": "", "email": "",
"discord": "! JoseANG3L#0268" "discord": "joseang3l"
} }
], ],
"versions": { "versions": {
@ -588,6 +599,7 @@
} }
], ],
"versions": { "versions": {
"1.0.1": null,
"1.0.0": { "1.0.0": {
"api_version": 7, "api_version": 7,
"commit_sha": "7219487", "commit_sha": "7219487",
@ -603,10 +615,11 @@
{ {
"name": "ThePersonMan", "name": "ThePersonMan",
"email": "", "email": "",
"discord": "ThePersonMan#0276" "discord": "the.personman"
} }
], ],
"versions": { "versions": {
"1.0.1": null,
"1.0.0": { "1.0.0": {
"api_version": 7, "api_version": 7,
"commit_sha": "7219487", "commit_sha": "7219487",
@ -622,10 +635,11 @@
{ {
"name": "Dliwk", "name": "Dliwk",
"email": "", "email": "",
"discord": "Dliwk#7961" "discord": "dliwk"
} }
], ],
"versions": { "versions": {
"1.0.1": null,
"1.0.0": { "1.0.0": {
"api_version": 7, "api_version": 7,
"commit_sha": "7219487", "commit_sha": "7219487",
@ -645,6 +659,7 @@
} }
], ],
"versions": { "versions": {
"1.0.1": null,
"1.0.0": { "1.0.0": {
"api_version": 7, "api_version": 7,
"commit_sha": "7219487", "commit_sha": "7219487",
@ -660,10 +675,11 @@
{ {
"name": "SEBASTIAN2059", "name": "SEBASTIAN2059",
"email": "", "email": "",
"discord": "SEBASTIAN2059#5751" "discord": "sebastian2059"
} }
], ],
"versions": { "versions": {
"1.0.1": null,
"1.0.0": { "1.0.0": {
"api_version": 7, "api_version": 7,
"commit_sha": "7219487", "commit_sha": "7219487",
@ -698,7 +714,7 @@
{ {
"name": "Cross Joy", "name": "Cross Joy",
"email": "cross.joy.official@gmail.com", "email": "cross.joy.official@gmail.com",
"discord": "Cross Joy#0721" "discord": "crossjoy"
} }
], ],
"versions": { "versions": {

View file

@ -1,20 +1,21 @@
# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport)
# Released under the MIT License. See LICENSE for details. # Released under the MIT License. See LICENSE for details.
# BY Stary_Agent # BY Stary_Agent
"""Hockey game and support classes.""" """Hockey game and support classes."""
# 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
import _ba import bascenev1 as bs
from bastd.actor.playerspaz import PlayerSpaz from bascenev1lib.actor.playerspaz import PlayerSpaz
from bastd.actor.scoreboard import Scoreboard from bascenev1lib.actor.scoreboard import Scoreboard
from bastd.actor.powerupbox import PowerupBoxFactory from bascenev1lib.actor.powerupbox import PowerupBoxFactory
from bastd.gameutils import SharedObjects from bascenev1lib.gameutils import SharedObjects
if TYPE_CHECKING: if TYPE_CHECKING:
from typing import Any, Sequence, Dict, Type, List, Optional, Union from typing import Any, Sequence, Dict, Type, List, Optional, Union
@ -32,13 +33,13 @@ def create_slope(self):
x = 5 x = 5
y = 12 y = 12
for i in range(0, 10): for i in range(0, 10):
ba.newnode('region', attrs={'position': (x, y, -5.52), 'scale': (0.2, 0.1, 6), bs.newnode('region', attrs={'position': (x, y, -5.52), 'scale': (0.2, 0.1, 6),
'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]})
x = x+0.3 x = x+0.3
y = y+0.1 y = y+0.1
class Puck(ba.Actor): class Puck(bs.Actor):
"""A lovely giant hockey puck.""" """A lovely giant hockey puck."""
def __init__(self, position: Sequence[float] = (0.0, 13.0, 0.0)): def __init__(self, position: Sequence[float] = (0.0, 13.0, 0.0)):
@ -53,10 +54,10 @@ class Puck(ba.Actor):
assert activity is not None assert activity is not None
assert isinstance(activity, HockeyGame) assert isinstance(activity, HockeyGame)
pmats = [shared.object_material, activity.puck_material] pmats = [shared.object_material, activity.puck_material]
self.node = ba.newnode('prop', self.node = bs.newnode('prop',
delegate=self, delegate=self,
attrs={ attrs={
'model': activity.puck_model, 'mesh': activity.puck_mesh,
'color_texture': activity.puck_tex, 'color_texture': activity.puck_tex,
'body': 'sphere', 'body': 'sphere',
'reflection': 'soft', 'reflection': 'soft',
@ -67,10 +68,10 @@ class Puck(ba.Actor):
'position': self._spawn_pos, 'position': self._spawn_pos,
'materials': pmats 'materials': pmats
}) })
ba.animate(self.node, 'model_scale', {0: 0, 0.2: 1.3, 0.26: 1}) bs.animate(self.node, 'mesh_scale', {0: 0, 0.2: 1.3, 0.26: 1})
def handlemessage(self, msg: Any) -> Any: def handlemessage(self, msg: Any) -> Any:
if isinstance(msg, ba.DieMessage): if isinstance(msg, bs.DieMessage):
assert self.node assert self.node
self.node.delete() self.node.delete()
activity = self._activity() activity = self._activity()
@ -78,11 +79,11 @@ class Puck(ba.Actor):
activity.handlemessage(PuckDiedMessage(self)) activity.handlemessage(PuckDiedMessage(self))
# If we go out of bounds, move back to where we started. # If we go out of bounds, move back to where we started.
elif isinstance(msg, ba.OutOfBoundsMessage): elif isinstance(msg, bs.OutOfBoundsMessage):
assert self.node assert self.node
self.node.position = self._spawn_pos self.node.position = self._spawn_pos
elif isinstance(msg, ba.HitMessage): elif isinstance(msg, bs.HitMessage):
assert self.node assert self.node
assert msg.force_direction is not None assert msg.force_direction is not None
self.node.handlemessage( self.node.handlemessage(
@ -103,31 +104,31 @@ class Puck(ba.Actor):
super().handlemessage(msg) 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."""
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:
self.score = 0 self.score = 0
# ba_meta export game # ba_meta export bascenev1.GameActivity
class AirSoccerGame(ba.TeamGameActivity[Player, Team]): class AirSoccerGame(bs.TeamGameActivity[Player, Team]):
"""Ice hockey game.""" """Ice hockey game."""
name = 'Epic Air Soccer' name = 'Epic Air Soccer'
description = 'Score some goals.' description = 'Score some goals.'
available_settings = [ available_settings = [
ba.IntSetting( bs.IntSetting(
'Score to Win', 'Score to Win',
min_value=1, min_value=1,
default=1, default=1,
increment=1, increment=1,
), ),
ba.IntChoiceSetting( bs.IntChoiceSetting(
'Time Limit', 'Time Limit',
choices=[ choices=[
('None', 0), ('None', 0),
@ -139,7 +140,7 @@ class AirSoccerGame(ba.TeamGameActivity[Player, Team]):
], ],
default=0, default=0,
), ),
ba.FloatChoiceSetting( bs.FloatChoiceSetting(
'Respawn Times', 'Respawn Times',
choices=[ choices=[
('Shorter', 0.1), ('Shorter', 0.1),
@ -151,14 +152,14 @@ class AirSoccerGame(ba.TeamGameActivity[Player, Team]):
default=1.0, default=1.0,
), ),
] ]
default_music = ba.MusicType.HOCKEY default_music = bs.MusicType.HOCKEY
@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 ['Creative Thoughts'] return ['Creative Thoughts']
def __init__(self, settings: dict): def __init__(self, settings: dict):
@ -166,16 +167,16 @@ class AirSoccerGame(ba.TeamGameActivity[Player, Team]):
shared = SharedObjects.get() shared = SharedObjects.get()
self.slow_motion = True self.slow_motion = True
self._scoreboard = Scoreboard() self._scoreboard = Scoreboard()
self._cheer_sound = ba.getsound('cheer') self._cheer_sound = bs.getsound('cheer')
self._chant_sound = ba.getsound('crowdChant') self._chant_sound = bs.getsound('crowdChant')
self._foghorn_sound = ba.getsound('foghorn') self._foghorn_sound = bs.getsound('foghorn')
self._swipsound = ba.getsound('swip') self._swipsound = bs.getsound('swip')
self._whistle_sound = ba.getsound('refWhistle') self._whistle_sound = bs.getsound('refWhistle')
self.puck_model = ba.getmodel('bomb') self.puck_mesh = bs.getmesh('bomb')
self.puck_tex = ba.gettexture('landMine') self.puck_tex = bs.gettexture('landMine')
self.puck_scored_tex = ba.gettexture('landMineLit') self.puck_scored_tex = bs.gettexture('landMineLit')
self._puck_sound = ba.getsound('metalHit') self._puck_sound = bs.getsound('metalHit')
self.puck_material = ba.Material() self.puck_material = bs.Material()
self.puck_material.add_actions(actions=(('modify_part_collision', self.puck_material.add_actions(actions=(('modify_part_collision',
'friction', 0.5))) 'friction', 0.5)))
self.puck_material.add_actions(conditions=('they_have_material', self.puck_material.add_actions(conditions=('they_have_material',
@ -194,7 +195,7 @@ class AirSoccerGame(ba.TeamGameActivity[Player, Team]):
shared.footing_material), shared.footing_material),
actions=('impact_sound', actions=('impact_sound',
self._puck_sound, 0.2, 5)) self._puck_sound, 0.2, 5))
self._real_wall_material = ba.Material() self._real_wall_material = bs.Material()
self._real_wall_material.add_actions( self._real_wall_material.add_actions(
actions=( actions=(
@ -210,7 +211,7 @@ class AirSoccerGame(ba.TeamGameActivity[Player, Team]):
('modify_part_collision', 'physical', True) ('modify_part_collision', 'physical', True)
)) ))
self._goal_post_material = ba.Material() self._goal_post_material = bs.Material()
self._goal_post_material.add_actions( self._goal_post_material.add_actions(
actions=( actions=(
@ -237,15 +238,15 @@ class AirSoccerGame(ba.TeamGameActivity[Player, Team]):
conditions=('they_have_material', conditions=('they_have_material',
PowerupBoxFactory.get().powerup_material), PowerupBoxFactory.get().powerup_material),
actions=(('modify_part_collision', 'physical', False), actions=(('modify_part_collision', 'physical', False),
('message', 'their_node', 'at_connect', ba.DieMessage()))) ('message', 'their_node', 'at_connect', bs.DieMessage())))
self._score_region_material = ba.Material() self._score_region_material = bs.Material()
self._score_region_material.add_actions( self._score_region_material.add_actions(
conditions=('they_have_material', self.puck_material), conditions=('they_have_material', self.puck_material),
actions=(('modify_part_collision', 'collide', actions=(('modify_part_collision', 'collide',
True), ('modify_part_collision', 'physical', False), True), ('modify_part_collision', 'physical', False),
('call', 'at_connect', self._handle_score))) ('call', 'at_connect', self._handle_score)))
self._puck_spawn_pos: Optional[Sequence[float]] = None self._puck_spawn_pos: Optional[Sequence[float]] = None
self._score_regions: Optional[List[ba.NodeActor]] = None self._score_regions: Optional[List[bs.NodeActor]] = None
self._puck: Optional[Puck] = None self._puck: Optional[Puck] = None
self._score_to_win = int(settings['Score to Win']) self._score_to_win = int(settings['Score to Win'])
self._time_limit = float(settings['Time Limit']) self._time_limit = float(settings['Time Limit'])
@ -273,8 +274,8 @@ class AirSoccerGame(ba.TeamGameActivity[Player, Team]):
defs = self.map.defs defs = self.map.defs
self._score_regions = [] self._score_regions = []
self._score_regions.append( self._score_regions.append(
ba.NodeActor( bs.NodeActor(
ba.newnode('region', bs.newnode('region',
attrs={ attrs={
'position': (17, 14.5, -5.52), 'position': (17, 14.5, -5.52),
'scale': (1, 3, 1), 'scale': (1, 3, 1),
@ -282,8 +283,8 @@ class AirSoccerGame(ba.TeamGameActivity[Player, Team]):
'materials': [self._score_region_material] 'materials': [self._score_region_material]
}))) })))
self._score_regions.append( self._score_regions.append(
ba.NodeActor( bs.NodeActor(
ba.newnode('region', bs.newnode('region',
attrs={ attrs={
'position': (-17, 14.5, -5.52), 'position': (-17, 14.5, -5.52),
'scale': (1, 3, 1), 'scale': (1, 3, 1),
@ -291,36 +292,36 @@ class AirSoccerGame(ba.TeamGameActivity[Player, Team]):
'materials': [self._score_region_material] 'materials': [self._score_region_material]
}))) })))
self._update_scoreboard() self._update_scoreboard()
ba.playsound(self._chant_sound) self._chant_sound.play()
def on_team_join(self, team: Team) -> None: def on_team_join(self, team: Team) -> None:
self._update_scoreboard() self._update_scoreboard()
def _handle_puck_player_collide(self) -> None: def _handle_puck_player_collide(self) -> None:
collision = ba.getcollision() collision = bs.getcollision()
try: try:
puck = collision.sourcenode.getdelegate(Puck, True) puck = collision.sourcenode.getdelegate(Puck, True)
player = collision.opposingnode.getdelegate(PlayerSpaz, player = collision.opposingnode.getdelegate(PlayerSpaz,
True).getplayer( True).getplayer(
Player, True) Player, True)
except ba.NotFoundError: except bs.NotFoundError:
return return
puck.last_players_to_touch[player.team.id] = player puck.last_players_to_touch[player.team.id] = player
def make_map(self): def make_map(self):
shared = SharedObjects.get() shared = SharedObjects.get()
_ba.get_foreground_host_activity()._map.leftwall.materials = [ bs.get_foreground_host_activity()._map.leftwall.materials = [
shared.footing_material, self._real_wall_material] shared.footing_material, self._real_wall_material]
_ba.get_foreground_host_activity()._map.rightwall.materials = [ bs.get_foreground_host_activity()._map.rightwall.materials = [
shared.footing_material, self._real_wall_material] shared.footing_material, self._real_wall_material]
_ba.get_foreground_host_activity()._map.topwall.materials = [ bs.get_foreground_host_activity()._map.topwall.materials = [
shared.footing_material, self._real_wall_material] shared.footing_material, self._real_wall_material]
self.floorwall = ba.newnode('region', attrs={'position': (0, 5, -5.52), 'scale': ( self.floorwall = bs.newnode('region', attrs={'position': (0, 5, -5.52), 'scale': (
35.4, 0.2, 2), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) 35.4, 0.2, 2), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]})
ba.newnode('locator', attrs={'shape': 'box', 'position': ( bs.newnode('locator', attrs={'shape': 'box', 'position': (
0, 5, -5.52), 'color': (0, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (35.4, 0.2, 2)}) 0, 5, -5.52), 'color': (0, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (35.4, 0.2, 2)})
self.create_goal_post(-16.65, 12.69) self.create_goal_post(-16.65, 12.69)
@ -343,9 +344,9 @@ class AirSoccerGame(ba.TeamGameActivity[Player, Team]):
floor += "_ " floor += "_ "
shared = SharedObjects.get() shared = SharedObjects.get()
step = {} step = {}
step["r"] = ba.newnode('region', attrs={'position': (x, y, -5.52), 'scale': ( step["r"] = bs.newnode('region', attrs={'position': (x, y, -5.52), 'scale': (
3, 0.1, 6), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) 3, 0.1, 6), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]})
ba.newnode('locator', attrs={'shape': 'box', 'position': ( bs.newnode('locator', attrs={'shape': 'box', 'position': (
x, y, -5.52), 'color': (1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (3, 0.1, 2)}) x, y, -5.52), 'color': (1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (3, 0.1, 2)})
return step return step
@ -359,10 +360,10 @@ class AirSoccerGame(ba.TeamGameActivity[Player, Team]):
floor = "" floor = ""
for i in range(0, 4): for i in range(0, 4):
floor += "_ " floor += "_ "
ba.newnode('region', attrs={'position': (x-0.2, y, -5.52), 'scale': (1.8, 0.1, 6), bs.newnode('region', attrs={'position': (x-0.2, y, -5.52), 'scale': (1.8, 0.1, 6),
'type': 'box', 'materials': [shared.footing_material, self._goal_post_material]}) 'type': 'box', 'materials': [shared.footing_material, self._goal_post_material]})
ba.newnode('locator', attrs={'shape': 'box', 'position': ( bs.newnode('locator', attrs={'shape': 'box', 'position': (
x-0.2, y, -5.52), 'color': color, 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (1.8, 0.1, 2)}) x-0.2, y, -5.52), 'color': color, 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (1.8, 0.1, 2)})
def create_vertical(self, x, y): def create_vertical(self, x, y):
@ -370,9 +371,9 @@ class AirSoccerGame(ba.TeamGameActivity[Player, Team]):
floor = "" floor = ""
for i in range(0, 4): for i in range(0, 4):
floor += "|\n" floor += "|\n"
ba.newnode('region', attrs={'position': (x, y, -5.52), 'scale': (0.1, 2.8, 1), bs.newnode('region', attrs={'position': (x, y, -5.52), 'scale': (0.1, 2.8, 1),
'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]})
ba.newnode('locator', attrs={'shape': 'box', 'position': ( bs.newnode('locator', attrs={'shape': 'box', 'position': (
x, y, -5.52), 'color': (1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (0.1, 2.8, 2)}) x, y, -5.52), 'color': (1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (0.1, 2.8, 2)})
def spawn_player_spaz(self, def spawn_player_spaz(self,
@ -402,7 +403,7 @@ class AirSoccerGame(ba.TeamGameActivity[Player, Team]):
if self._puck.scored: if self._puck.scored:
return return
region = ba.getcollision().sourcenode region = bs.getcollision().sourcenode
index = 0 index = 0
for index in range(len(self._score_regions)): for index in range(len(self._score_regions)):
if region == self._score_regions[index].node: if region == self._score_regions[index].node:
@ -416,7 +417,7 @@ class AirSoccerGame(ba.TeamGameActivity[Player, Team]):
# Tell all players to celebrate. # Tell all players to celebrate.
for player in team.players: for player in team.players:
if player.actor: if player.actor:
player.actor.handlemessage(ba.CelebrateMessage(2.0)) player.actor.handlemessage(bs.CelebrateMessage(2.0))
# If we've got the player from the scoring team that last # If we've got the player from the scoring team that last
# touched us, give them points. # touched us, give them points.
@ -431,30 +432,30 @@ class AirSoccerGame(ba.TeamGameActivity[Player, Team]):
if team.score >= self._score_to_win: if team.score >= self._score_to_win:
self.end_game() self.end_game()
ba.playsound(self._foghorn_sound) self._foghorn_sound.play()
ba.playsound(self._cheer_sound) self._cheer_sound.play()
self._puck.scored = True self._puck.scored = True
# Change puck texture to something cool # Change puck texture to something cool
self._puck.node.color_texture = self.puck_scored_tex self._puck.node.color_texture = self.puck_scored_tex
# Kill the puck (it'll respawn itself shortly). # Kill the puck (it'll respawn itself shortly).
ba.timer(1.0, self._kill_puck) bs.timer(1.0, self._kill_puck)
light = ba.newnode('light', light = bs.newnode('light',
attrs={ attrs={
'position': ba.getcollision().position, 'position': bs.getcollision().position,
'height_attenuated': False, 'height_attenuated': False,
'color': (1, 0, 0) 'color': (1, 0, 0)
}) })
ba.animate(light, 'intensity', {0: 0, 0.5: 1, 1.0: 0}, loop=True) bs.animate(light, 'intensity', {0: 0, 0.5: 1, 1.0: 0}, loop=True)
ba.timer(1.0, light.delete) bs.timer(1.0, light.delete)
ba.cameraflash(duration=10.0) bs.cameraflash(duration=10.0)
self._update_scoreboard() self._update_scoreboard()
def end_game(self) -> None: def end_game(self) -> None:
results = ba.GameResults() results = bs.GameResults()
for team in self.teams: for team in self.teams:
results.set_team_score(team, team.score) results.set_team_score(team, team.score)
self.end(results=results) self.end(results=results)
@ -467,7 +468,7 @@ class AirSoccerGame(ba.TeamGameActivity[Player, Team]):
def handlemessage(self, msg: Any) -> Any: def handlemessage(self, msg: Any) -> Any:
# Respawn dead players if they're still in the game. # Respawn dead players if they're still in the game.
if isinstance(msg, ba.PlayerDiedMessage): if isinstance(msg, bs.PlayerDiedMessage):
# Augment standard behavior... # Augment standard behavior...
super().handlemessage(msg) super().handlemessage(msg)
self.respawn_player(msg.getplayer(Player)) self.respawn_player(msg.getplayer(Player))
@ -475,23 +476,23 @@ class AirSoccerGame(ba.TeamGameActivity[Player, Team]):
# Respawn dead pucks. # Respawn dead pucks.
elif isinstance(msg, PuckDiedMessage): elif isinstance(msg, PuckDiedMessage):
if not self.has_ended(): if not self.has_ended():
ba.timer(3.0, self._spawn_puck) bs.timer(3.0, self._spawn_puck)
else: else:
super().handlemessage(msg) super().handlemessage(msg)
def _flash_puck_spawn(self) -> None: def _flash_puck_spawn(self) -> None:
light = ba.newnode('light', light = bs.newnode('light',
attrs={ attrs={
'position': self._puck_spawn_pos, 'position': self._puck_spawn_pos,
'height_attenuated': False, 'height_attenuated': False,
'color': (1, 0, 0) 'color': (1, 0, 0)
}) })
ba.animate(light, 'intensity', {0.0: 0, 0.25: 1, 0.5: 0}, loop=True) bs.animate(light, 'intensity', {0.0: 0, 0.25: 1, 0.5: 0}, loop=True)
ba.timer(1.0, light.delete) bs.timer(1.0, light.delete)
def _spawn_puck(self) -> None: def _spawn_puck(self) -> None:
ba.playsound(self._swipsound) self._swipsound.play()
ba.playsound(self._whistle_sound) self._whistle_sound.play()
self._flash_puck_spawn() self._flash_puck_spawn()
assert self._puck_spawn_pos is not None assert self._puck_spawn_pos is not None
self._puck = Puck(position=self._puck_spawn_pos) self._puck = Puck(position=self._puck_spawn_pos)
@ -541,7 +542,7 @@ class mapdefs:
0.5245740665, 0.5245740665, 0.01941146064) 0.5245740665, 0.5245740665, 0.01941146064)
class CreativeThoughts(ba.Map): class CreativeThoughts(bs.Map):
"""Freaking map by smoothy.""" """Freaking map by smoothy."""
defs = mapdefs defs = mapdefs
@ -562,26 +563,26 @@ class CreativeThoughts(ba.Map):
@classmethod @classmethod
def on_preload(cls) -> Any: def on_preload(cls) -> Any:
data: Dict[str, Any] = { data: Dict[str, Any] = {
'model': ba.getmodel('alwaysLandLevel'), 'mesh': bs.getmesh('alwaysLandLevel'),
'bottom_model': ba.getmodel('alwaysLandLevelBottom'), 'bottom_mesh': bs.getmesh('alwaysLandLevelBottom'),
'bgmodel': ba.getmodel('alwaysLandBG'), 'bgmesh': bs.getmesh('alwaysLandBG'),
'collide_model': ba.getcollidemodel('alwaysLandLevelCollide'), 'collision_mesh': bs.getcollisionmesh('alwaysLandLevelCollide'),
'tex': ba.gettexture('alwaysLandLevelColor'), 'tex': bs.gettexture('alwaysLandLevelColor'),
'bgtex': ba.gettexture('alwaysLandBGColor'), 'bgtex': bs.gettexture('alwaysLandBGColor'),
'vr_fill_mound_model': ba.getmodel('alwaysLandVRFillMound'), 'vr_fill_mound_mesh': bs.getmesh('alwaysLandVRFillMound'),
'vr_fill_mound_tex': ba.gettexture('vrFillMound') 'vr_fill_mound_tex': bs.gettexture('vrFillMound')
} }
return data return data
@classmethod @classmethod
def get_music_type(cls) -> ba.MusicType: def get_music_type(cls) -> bs.MusicType:
return ba.MusicType.FLYING return bs.MusicType.FLYING
def __init__(self) -> None: def __init__(self) -> None:
super().__init__(vr_overlay_offset=(0, -3.7, 2.5)) super().__init__(vr_overlay_offset=(0, -3.7, 2.5))
shared = SharedObjects.get() shared = SharedObjects.get()
self._fake_wall_material = ba.Material() self._fake_wall_material = bs.Material()
self._real_wall_material = ba.Material() self._real_wall_material = bs.Material()
self._fake_wall_material.add_actions( self._fake_wall_material.add_actions(
conditions=(('they_are_younger_than', 9000), 'and', conditions=(('they_are_younger_than', 9000), 'and',
('they_have_material', shared.player_material)), ('they_have_material', shared.player_material)),
@ -597,29 +598,29 @@ class CreativeThoughts(ba.Map):
('modify_part_collision', 'physical', True) ('modify_part_collision', 'physical', True)
)) ))
self.background = ba.newnode( self.background = bs.newnode(
'terrain', 'terrain',
attrs={ attrs={
'model': self.preloaddata['bgmodel'], 'mesh': self.preloaddata['bgmesh'],
'lighting': False, 'lighting': False,
'background': True, 'background': True,
'color_texture': ba.gettexture("rampageBGColor") 'color_texture': bs.gettexture("rampageBGColor")
}) })
self.leftwall = ba.newnode('region', attrs={'position': (-17.75152479, 13, -5.52), 'scale': ( self.leftwall = bs.newnode('region', attrs={'position': (-17.75152479, 13, -5.52), 'scale': (
0.1, 15.5, 2), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) 0.1, 15.5, 2), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]})
self.rightwall = ba.newnode('region', attrs={'position': (17.75, 13, -5.52), 'scale': ( self.rightwall = bs.newnode('region', attrs={'position': (17.75, 13, -5.52), 'scale': (
0.1, 15.5, 2), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) 0.1, 15.5, 2), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]})
self.topwall = ba.newnode('region', attrs={'position': (0, 21.0, -5.52), 'scale': ( self.topwall = bs.newnode('region', attrs={'position': (0, 21.0, -5.52), 'scale': (
35.4, 0.2, 2), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) 35.4, 0.2, 2), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]})
ba.newnode('locator', attrs={'shape': 'box', 'position': (-17.75152479, 13, -5.52), 'color': ( bs.newnode('locator', attrs={'shape': 'box', 'position': (-17.75152479, 13, -5.52), 'color': (
0, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (0.1, 15.5, 2)}) 0, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (0.1, 15.5, 2)})
ba.newnode('locator', attrs={'shape': 'box', 'position': (17.75, 13, -5.52), 'color': ( bs.newnode('locator', attrs={'shape': 'box', 'position': (17.75, 13, -5.52), 'color': (
0, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (0.1, 15.5, 2)}) 0, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (0.1, 15.5, 2)})
ba.newnode('locator', attrs={'shape': 'box', 'position': (0, 21.0, -5.52), 'color': ( bs.newnode('locator', attrs={'shape': 'box', 'position': (0, 21.0, -5.52), 'color': (
0, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (35.4, 0.2, 2)}) 0, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (35.4, 0.2, 2)})
gnode = ba.getactivity().globalsnode gnode = bs.getactivity().globalsnode
gnode.happy_thoughts_mode = True gnode.happy_thoughts_mode = True
gnode.shadow_offset = (0.0, 8.0, 5.0) gnode.shadow_offset = (0.0, 8.0, 5.0)
gnode.tint = (1.3, 1.23, 1.0) gnode.tint = (1.3, 1.23, 1.0)
@ -630,9 +631,9 @@ class CreativeThoughts(ba.Map):
self.is_flying = True self.is_flying = True
# throw out some tips on flying # throw out some tips on flying
txt = ba.newnode('text', txt = bs.newnode('text',
attrs={ attrs={
'text': ba.Lstr(resource='pressJumpToFlyText'), 'text': babase.Lstr(resource='pressJumpToFlyText'),
'scale': 1.2, 'scale': 1.2,
'maxwidth': 800, 'maxwidth': 800,
'position': (0, 200), 'position': (0, 200),
@ -641,7 +642,7 @@ class CreativeThoughts(ba.Map):
'h_align': 'center', 'h_align': 'center',
'v_attach': 'bottom' 'v_attach': 'bottom'
}) })
cmb = ba.newnode('combine', cmb = bs.newnode('combine',
owner=txt, owner=txt,
attrs={ attrs={
'size': 4, 'size': 4,
@ -649,12 +650,12 @@ class CreativeThoughts(ba.Map):
'input1': 0.9, 'input1': 0.9,
'input2': 0.0 'input2': 0.0
}) })
ba.animate(cmb, 'input3', {3.0: 0, 4.0: 1, 9.0: 1, 10.0: 0}) bs.animate(cmb, 'input3', {3.0: 0, 4.0: 1, 9.0: 1, 10.0: 0})
cmb.connectattr('output', txt, 'color') cmb.connectattr('output', txt, 'color')
ba.timer(10.0, txt.delete) bs.timer(10.0, txt.delete)
try: try:
ba._map.register_map(CreativeThoughts) bs._map.register_map(CreativeThoughts)
except: except:
pass pass

View file

@ -1,19 +1,22 @@
# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport)
# Released under the MIT License. See LICENSE for details. # Released under the MIT License. See LICENSE for details.
# 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
import _ba import bauiv1 as bui
from bastd.actor.playerspaz import PlayerSpaz import bascenev1 as bs
from bastd.actor.scoreboard import Scoreboard import _babase
from bastd.actor.powerupbox import PowerupBoxFactory from bascenev1lib.actor.playerspaz import PlayerSpaz
from bastd.gameutils import SharedObjects from bascenev1lib.actor.scoreboard import Scoreboard
from bastd.actor import playerspaz as ps from bascenev1lib.actor.powerupbox import PowerupBoxFactory
from bastd import maps from bascenev1lib.gameutils import SharedObjects
from bascenev1lib.actor import playerspaz as ps
from bascenev1lib import maps
if TYPE_CHECKING: if TYPE_CHECKING:
from typing import Any, Sequence, Dict, Type, List, Optional, Union from typing import Any, Sequence, Dict, Type, List, Optional, Union
@ -22,7 +25,7 @@ bsuSpaz = None
def getlanguage(text, sub: str = ''): def getlanguage(text, sub: str = ''):
lang = _ba.app.lang.language lang = bs.app.lang.language
translate = { translate = {
"Name": "Name":
{"Spanish": "Baloncesto", {"Spanish": "Baloncesto",
@ -60,7 +63,7 @@ class BallDiedMessage:
self.ball = ball self.ball = ball
class Ball(ba.Actor): class Ball(bs.Actor):
def __init__(self, position: Sequence[float] = (0.0, 1.0, 0.0)): def __init__(self, position: Sequence[float] = (0.0, 1.0, 0.0)):
super().__init__() super().__init__()
shared = SharedObjects.get() shared = SharedObjects.get()
@ -76,10 +79,10 @@ class Ball(ba.Actor):
assert isinstance(activity, BasketGame) assert isinstance(activity, BasketGame)
pmats = [shared.object_material, activity.ball_material] pmats = [shared.object_material, activity.ball_material]
self.node = ba.newnode('prop', self.node = bs.newnode('prop',
delegate=self, delegate=self,
attrs={ attrs={
'model': activity.ball_model, 'mesh': activity.ball_mesh,
'color_texture': activity.ball_tex, 'color_texture': activity.ball_tex,
'body': 'sphere', 'body': 'sphere',
'reflection': 'soft', 'reflection': 'soft',
@ -92,22 +95,22 @@ class Ball(ba.Actor):
'velocity': velocty, 'velocity': velocty,
'materials': pmats}) 'materials': pmats})
self.scale = scale = 0.25 * _scale self.scale = scale = 0.25 * _scale
ba.animate(self.node, 'model_scale', {0: 0, 0.2: scale*1.3, 0.26: scale}) bs.animate(self.node, 'mesh_scale', {0: 0, 0.2: scale*1.3, 0.26: scale})
def handlemessage(self, msg: Any) -> Any: def handlemessage(self, msg: Any) -> Any:
if isinstance(msg, ba.DieMessage): if isinstance(msg, bs.DieMessage):
assert self.node assert self.node
self.node.delete() self.node.delete()
activity = self._activity() activity = self._activity()
if activity and not msg.immediate: if activity and not msg.immediate:
activity.handlemessage(BallDiedMessage(self)) activity.handlemessage(BallDiedMessage(self))
elif isinstance(msg, ba.OutOfBoundsMessage): elif isinstance(msg, bs.OutOfBoundsMessage):
assert self.node assert self.node
self.node.position = self._spawn_pos self.node.position = self._spawn_pos
self.node.velocity = (0.0, 0.0, 0.0) self.node.velocity = (0.0, 0.0, 0.0)
elif isinstance(msg, ba.HitMessage): elif isinstance(msg, bs.HitMessage):
assert self.node assert self.node
assert msg.force_direction is not None assert msg.force_direction is not None
self.node.handlemessage( self.node.handlemessage(
@ -127,11 +130,11 @@ class Ball(ba.Actor):
super().handlemessage(msg) 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."""
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:
@ -144,21 +147,21 @@ class Points:
postes['pal_0'] = (10.64702320098877, 0.0000000000000000, 0.0000000000000000) postes['pal_0'] = (10.64702320098877, 0.0000000000000000, 0.0000000000000000)
postes['pal_1'] = (-10.64702320098877, 0.0000000000000000, 0.0000000000000000) postes['pal_1'] = (-10.64702320098877, 0.0000000000000000, 0.0000000000000000)
# ba_meta export game # ba_meta export bascenev1.GameActivity
class BasketGame(ba.TeamGameActivity[Player, Team]): class BasketGame(bs.TeamGameActivity[Player, Team]):
name = getlanguage('Name') name = getlanguage('Name')
description = getlanguage('Info') description = getlanguage('Info')
available_settings = [ available_settings = [
ba.IntSetting( bs.IntSetting(
'Score to Win', 'Score to Win',
min_value=1, min_value=1,
default=1, default=1,
increment=1, increment=1,
), ),
ba.IntChoiceSetting( bs.IntChoiceSetting(
'Time Limit', 'Time Limit',
choices=[ choices=[
('None', 0), ('None', 0),
@ -170,7 +173,7 @@ class BasketGame(ba.TeamGameActivity[Player, Team]):
], ],
default=0, default=0,
), ),
ba.FloatChoiceSetting( bs.FloatChoiceSetting(
'Respawn Times', 'Respawn Times',
choices=[ choices=[
('Shorter', 0.25), ('Shorter', 0.25),
@ -181,38 +184,38 @@ class BasketGame(ba.TeamGameActivity[Player, Team]):
], ],
default=1.0, default=1.0,
), ),
ba.BoolSetting(getlanguage('S: Powerups'), default=True), bs.BoolSetting(getlanguage('S: Powerups'), default=True),
ba.BoolSetting(getlanguage('S: Velocity'), default=False), bs.BoolSetting(getlanguage('S: Velocity'), default=False),
ba.BoolSetting('Epic Mode', default=False), bs.BoolSetting('Epic Mode', default=False),
] ]
default_music = ba.MusicType.HOCKEY default_music = bs.MusicType.HOCKEY
@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 ['BasketBall Stadium', 'BasketBall Stadium V2'] return ['BasketBall Stadium', 'BasketBall Stadium V2']
def __init__(self, settings: dict): def __init__(self, settings: dict):
super().__init__(settings) super().__init__(settings)
shared = SharedObjects.get() shared = SharedObjects.get()
self._scoreboard = Scoreboard() self._scoreboard = Scoreboard()
self._cheer_sound = ba.getsound('cheer') self._cheer_sound = bs.getsound('cheer')
self._chant_sound = ba.getsound('crowdChant') self._chant_sound = bs.getsound('crowdChant')
self._foghorn_sound = ba.getsound('foghorn') self._foghorn_sound = bs.getsound('foghorn')
self._swipsound = ba.getsound('swip') self._swipsound = bs.getsound('swip')
self._whistle_sound = ba.getsound('refWhistle') self._whistle_sound = bs.getsound('refWhistle')
self.ball_model = ba.getmodel('shield') self.ball_mesh = bs.getmesh('shield')
self.ball_tex = ba.gettexture('fontExtras3') self.ball_tex = bs.gettexture('fontExtras3')
self._ball_sound = ba.getsound('bunnyJump') self._ball_sound = bs.getsound('bunnyJump')
self._powerups = bool(settings[getlanguage('S: Powerups')]) self._powerups = bool(settings[getlanguage('S: Powerups')])
self._speed = bool(settings[getlanguage('S: Velocity')]) self._speed = bool(settings[getlanguage('S: Velocity')])
self._epic_mode = bool(settings['Epic Mode']) self._epic_mode = bool(settings['Epic Mode'])
self.slow_motion = self._epic_mode self.slow_motion = self._epic_mode
self.ball_material = ba.Material() self.ball_material = bs.Material()
self.ball_material.add_actions(actions=(('modify_part_collision', self.ball_material.add_actions(actions=(('modify_part_collision',
'friction', 0.5))) 'friction', 0.5)))
self.ball_material.add_actions(conditions=('they_have_material', self.ball_material.add_actions(conditions=('they_have_material',
@ -238,14 +241,14 @@ class BasketGame(ba.TeamGameActivity[Player, Team]):
actions=(('call', 'at_connect', actions=(('call', 'at_connect',
self._handle_ball_player_collide), )) self._handle_ball_player_collide), ))
self._score_region_material = ba.Material() self._score_region_material = bs.Material()
self._score_region_material.add_actions( self._score_region_material.add_actions(
conditions=('they_have_material', self.ball_material), conditions=('they_have_material', self.ball_material),
actions=(('modify_part_collision', 'collide', actions=(('modify_part_collision', 'collide',
True), ('modify_part_collision', 'physical', False), True), ('modify_part_collision', 'physical', False),
('call', 'at_connect', self._handle_score))) ('call', 'at_connect', self._handle_score)))
self._ball_spawn_pos: Optional[Sequence[float]] = None self._ball_spawn_pos: Optional[Sequence[float]] = None
self._score_regions: Optional[List[ba.NodeActor]] = None self._score_regions: Optional[List[bs.NodeActor]] = None
self._ball: Optional[Ball] = None self._ball: Optional[Ball] = None
self._score_to_win = int(settings['Score to Win']) self._score_to_win = int(settings['Score to Win'])
self._time_limit = float(settings['Time Limit']) self._time_limit = float(settings['Time Limit'])
@ -270,8 +273,8 @@ class BasketGame(ba.TeamGameActivity[Player, Team]):
defs = self.map.defs defs = self.map.defs
self._score_regions = [] self._score_regions = []
self._score_regions.append( self._score_regions.append(
ba.NodeActor( bs.NodeActor(
ba.newnode('region', bs.newnode('region',
attrs={ attrs={
'position': defs.boxes['goal1'][0:3], 'position': defs.boxes['goal1'][0:3],
'scale': defs.boxes['goal1'][6:9], 'scale': defs.boxes['goal1'][6:9],
@ -279,8 +282,8 @@ class BasketGame(ba.TeamGameActivity[Player, Team]):
'materials': [] 'materials': []
}))) })))
self._score_regions.append( self._score_regions.append(
ba.NodeActor( bs.NodeActor(
ba.newnode('region', bs.newnode('region',
attrs={ attrs={
'position': defs.boxes['goal2'][0:3], 'position': defs.boxes['goal2'][0:3],
'scale': defs.boxes['goal2'][6:9], 'scale': defs.boxes['goal2'][6:9],
@ -288,7 +291,7 @@ class BasketGame(ba.TeamGameActivity[Player, Team]):
'materials': [] 'materials': []
}))) })))
self._update_scoreboard() self._update_scoreboard()
ba.playsound(self._chant_sound) self._chant_sound.play()
for id, team in enumerate(self.teams): for id, team in enumerate(self.teams):
self.postes(id) self.postes(id)
@ -297,13 +300,13 @@ class BasketGame(ba.TeamGameActivity[Player, Team]):
self._update_scoreboard() self._update_scoreboard()
def _handle_ball_player_collide(self) -> None: def _handle_ball_player_collide(self) -> None:
collision = ba.getcollision() collision = bs.getcollision()
try: try:
ball = collision.sourcenode.getdelegate(Ball, True) ball = collision.sourcenode.getdelegate(Ball, True)
player = collision.opposingnode.getdelegate(PlayerSpaz, player = collision.opposingnode.getdelegate(PlayerSpaz,
True).getplayer( True).getplayer(
Player, True) Player, True)
except ba.NotFoundError: except bs.NotFoundError:
return return
ball.last_players_to_touch[player.team.id] = player ball.last_players_to_touch[player.team.id] = player
@ -318,7 +321,7 @@ class BasketGame(ba.TeamGameActivity[Player, Team]):
if self._ball.scored: if self._ball.scored:
return return
region = ba.getcollision().sourcenode region = bs.getcollision().sourcenode
index = 0 index = 0
for index in range(len(self._score_regions)): for index in range(len(self._score_regions)):
if region == self._score_regions[index].node: if region == self._score_regions[index].node:
@ -334,7 +337,7 @@ class BasketGame(ba.TeamGameActivity[Player, Team]):
for player in team.players: for player in team.players:
if player.actor: if player.actor:
player.actor.handlemessage(ba.CelebrateMessage(2.0)) player.actor.handlemessage(bs.CelebrateMessage(2.0))
if (scoring_team.id in self._ball.last_players_to_touch if (scoring_team.id in self._ball.last_players_to_touch
and self._ball.last_players_to_touch[scoring_team.id]): and self._ball.last_players_to_touch[scoring_team.id]):
@ -345,28 +348,28 @@ class BasketGame(ba.TeamGameActivity[Player, Team]):
if team.score >= self._score_to_win: if team.score >= self._score_to_win:
self.end_game() self.end_game()
# ba.playsound(self._foghorn_sound) # self._foghorn_sound.play()
ba.playsound(self._cheer_sound) self._cheer_sound.play()
self._ball.scored = True self._ball.scored = True
# Kill the ball (it'll respawn itself shortly). # Kill the ball (it'll respawn itself shortly).
ba.timer(1.0, self._kill_ball) bs.timer(1.0, self._kill_ball)
light = ba.newnode('light', light = bs.newnode('light',
attrs={ attrs={
'position': ba.getcollision().position, 'position': bs.getcollision().position,
'height_attenuated': False, 'height_attenuated': False,
'color': (1, 0, 0) 'color': (1, 0, 0)
}) })
ba.animate(light, 'intensity', {0: 0, 0.5: 1, 1.0: 0}, loop=True) bs.animate(light, 'intensity', {0: 0, 0.5: 1, 1.0: 0}, loop=True)
ba.timer(1.0, light.delete) bs.timer(1.0, light.delete)
ba.cameraflash(duration=10.0) bs.cameraflash(duration=10.0)
self._update_scoreboard() self._update_scoreboard()
def end_game(self) -> None: def end_game(self) -> None:
results = ba.GameResults() results = bs.GameResults()
for team in self.teams: for team in self.teams:
results.set_team_score(team, team.score) results.set_team_score(team, team.score)
self.end(results=results) self.end(results=results)
@ -377,7 +380,7 @@ class BasketGame(ba.TeamGameActivity[Player, Team]):
self._scoreboard.set_team_value(team, team.score, winscore) self._scoreboard.set_team_value(team, team.score, winscore)
# self.postes(id) # self.postes(id)
def spawn_player(self, player: Player) -> ba.Actor: def spawn_player(self, player: Player) -> bs.Actor:
if bsuSpaz is None: if bsuSpaz is None:
spaz = self.spawn_player_spaz(player) spaz = self.spawn_player_spaz(player)
else: else:
@ -390,12 +393,12 @@ class BasketGame(ba.TeamGameActivity[Player, Team]):
return spaz return spaz
def handlemessage(self, msg: Any) -> Any: def handlemessage(self, msg: Any) -> Any:
if isinstance(msg, ba.PlayerDiedMessage): if isinstance(msg, bs.PlayerDiedMessage):
super().handlemessage(msg) super().handlemessage(msg)
self.respawn_player(msg.getplayer(Player)) self.respawn_player(msg.getplayer(Player))
elif isinstance(msg, BallDiedMessage): elif isinstance(msg, BallDiedMessage):
if not self.has_ended(): if not self.has_ended():
ba.timer(3.0, self._spawn_ball) bs.timer(3.0, self._spawn_ball)
else: else:
super().handlemessage(msg) super().handlemessage(msg)
@ -407,24 +410,24 @@ class BasketGame(ba.TeamGameActivity[Player, Team]):
str(team_id)]).autoretain()) str(team_id)]).autoretain())
def _flash_ball_spawn(self) -> None: def _flash_ball_spawn(self) -> None:
light = ba.newnode('light', light = bs.newnode('light',
attrs={ attrs={
'position': self._ball_spawn_pos, 'position': self._ball_spawn_pos,
'height_attenuated': False, 'height_attenuated': False,
'color': (1, 0, 0) 'color': (1, 0, 0)
}) })
ba.animate(light, 'intensity', {0.0: 0, 0.25: 1, 0.5: 0}, loop=True) bs.animate(light, 'intensity', {0.0: 0, 0.25: 1, 0.5: 0}, loop=True)
ba.timer(1.0, light.delete) bs.timer(1.0, light.delete)
def _spawn_ball(self) -> None: def _spawn_ball(self) -> None:
ba.playsound(self._swipsound) self._swipsound.play()
ba.playsound(self._whistle_sound) self._whistle_sound.play()
self._flash_ball_spawn() self._flash_ball_spawn()
assert self._ball_spawn_pos is not None assert self._ball_spawn_pos is not None
self._ball = Ball(position=self._ball_spawn_pos) self._ball = Ball(position=self._ball_spawn_pos)
class Aro(ba.Actor): class Aro(bs.Actor):
def __init__(self, team: int = 0, def __init__(self, team: int = 0,
position: Sequence[float] = (0.0, 1.0, 0.0)): position: Sequence[float] = (0.0, 1.0, 0.0)):
super().__init__() super().__init__()
@ -434,16 +437,16 @@ class Aro(ba.Actor):
setattr(self, 'locs', []) setattr(self, 'locs', [])
# Material Para; Traspasar Objetos # Material Para; Traspasar Objetos
self.no_collision = ba.Material() self.no_collision = bs.Material()
self.no_collision.add_actions( self.no_collision.add_actions(
actions=(('modify_part_collision', 'collide', False))) actions=(('modify_part_collision', 'collide', False)))
self.collision = ba.Material() self.collision = bs.Material()
self.collision.add_actions( self.collision.add_actions(
actions=(('modify_part_collision', 'collide', True))) actions=(('modify_part_collision', 'collide', True)))
# Score # Score
self._score_region_material = ba.Material() self._score_region_material = bs.Material()
self._score_region_material.add_actions( self._score_region_material.add_actions(
conditions=('they_have_material', act.ball_material), conditions=('they_have_material', act.ball_material),
actions=(('modify_part_collision', 'collide', actions=(('modify_part_collision', 'collide',
@ -454,14 +457,14 @@ class Aro(ba.Actor):
self._materials_region0 = [self.collision, self._materials_region0 = [self.collision,
shared.footing_material] shared.footing_material]
model = None mesh = None
tex = ba.gettexture('null') tex = bs.gettexture('null')
pmats = [self.no_collision] pmats = [self.no_collision]
self.node = ba.newnode('prop', self.node = bs.newnode('prop',
delegate=self, delegate=self,
attrs={ attrs={
'model': model, 'mesh': mesh,
'color_texture': tex, 'color_texture': tex,
'body': 'box', 'body': 'box',
'reflection': 'soft', 'reflection': 'soft',
@ -471,17 +474,17 @@ class Aro(ba.Actor):
'materials': pmats}) 'materials': pmats})
self.scale = scale = 1.4 self.scale = scale = 1.4
ba.animate(self.node, 'model_scale', {0: 0}) bs.animate(self.node, 'mesh_scale', {0: 0})
pos = (position[0], position[1]+0.6, position[2]) pos = (position[0], position[1]+0.6, position[2])
self.regions: List[ba.Node] = [ self.regions: List[bs.Node] = [
ba.newnode('region', bs.newnode('region',
attrs={'position': position, attrs={'position': position,
'scale': (0.6, 0.05, 0.6), 'scale': (0.6, 0.05, 0.6),
'type': 'box', 'type': 'box',
'materials': self._materials_region0}), 'materials': self._materials_region0}),
ba.newnode('region', bs.newnode('region',
attrs={'position': pos, attrs={'position': pos,
'scale': (0.5, 0.3, 0.9), 'scale': (0.5, 0.3, 0.9),
'type': 'box', 'type': 'box',
@ -502,7 +505,7 @@ class Aro(ba.Actor):
while locs_count > 1: while locs_count > 1:
scale = (1.5 * 0.1 * locs_count) + 0.8 scale = (1.5 * 0.1 * locs_count) + 0.8
self.locs.append(ba.newnode('locator', self.locs.append(bs.newnode('locator',
owner=self.node, owner=self.node,
attrs={'shape': 'circleOutline', attrs={'shape': 'circleOutline',
'position': pos, 'position': pos,
@ -528,14 +531,14 @@ class Aro(ba.Actor):
act._handle_score(self.team) act._handle_score(self.team)
def handlemessage(self, msg: Any) -> Any: def handlemessage(self, msg: Any) -> Any:
if isinstance(msg, ba.DieMessage): if isinstance(msg, bs.DieMessage):
if self.node.exists(): if self.node.exists():
self.node.delete() self.node.delete()
else: else:
super().handlemessage(msg) super().handlemessage(msg)
class Cuadro(ba.Actor): class Cuadro(bs.Actor):
def __init__(self, team: int = 0, def __init__(self, team: int = 0,
position: Sequence[float] = (0.0, 1.0, 0.0)): position: Sequence[float] = (0.0, 1.0, 0.0)):
super().__init__() super().__init__()
@ -543,19 +546,19 @@ class Cuadro(ba.Actor):
shared = SharedObjects.get() shared = SharedObjects.get()
setattr(self, 'locs', []) setattr(self, 'locs', [])
self.collision = ba.Material() self.collision = bs.Material()
self.collision.add_actions( self.collision.add_actions(
actions=(('modify_part_collision', 'collide', True))) actions=(('modify_part_collision', 'collide', True)))
pos = (position[0], position[1]+0.9, position[2]+1.5) pos = (position[0], position[1]+0.9, position[2]+1.5)
self.region: ba.Node = ba.newnode('region', self.region: bs.Node = bs.newnode('region',
attrs={'position': pos, attrs={'position': pos,
'scale': (0.5, 2.7, 2.5), 'scale': (0.5, 2.7, 2.5),
'type': 'box', 'type': 'box',
'materials': [self.collision, 'materials': [self.collision,
shared.footing_material]}) shared.footing_material]})
# self.shield = ba.newnode('shield', attrs={'radius': 1.0, 'color': (0,10,0)}) # self.shield = bs.newnode('shield', attrs={'radius': 1.0, 'color': (0,10,0)})
# self.region.connectattr('position', self.shield, 'position') # self.region.connectattr('position', self.shield, 'position')
position = (position[0], position[1], position[2]+0.09) position = (position[0], position[1], position[2]+0.09)
@ -578,7 +581,7 @@ class Cuadro(ba.Actor):
pos[2] += 0.19 pos[2] += 0.19
self.locs.append( self.locs.append(
ba.newnode('locator', bs.newnode('locator',
owner=self.region, owner=self.region,
attrs={'shape': 'circle', attrs={'shape': 'circle',
'position': pos, 'position': pos,
@ -595,14 +598,14 @@ class Cuadro(ba.Actor):
count_y -= 1 count_y -= 1
def handlemessage(self, msg: Any) -> Any: def handlemessage(self, msg: Any) -> Any:
if isinstance(msg, ba.DieMessage): if isinstance(msg, bs.DieMessage):
if self.node.exists(): if self.node.exists():
self.node.delete() self.node.delete()
else: else:
super().handlemessage(msg) super().handlemessage(msg)
class Palos(ba.Actor): class Palos(bs.Actor):
def __init__(self, team: int = 0, def __init__(self, team: int = 0,
position: Sequence[float] = (0.0, 1.0, 0.0)): position: Sequence[float] = (0.0, 1.0, 0.0)):
super().__init__() super().__init__()
@ -613,26 +616,26 @@ class Palos(ba.Actor):
self.cua = None self.cua = None
# Material Para; Traspasar Objetos # Material Para; Traspasar Objetos
self.no_collision = ba.Material() self.no_collision = bs.Material()
self.no_collision.add_actions( self.no_collision.add_actions(
actions=(('modify_part_collision', 'collide', False))) actions=(('modify_part_collision', 'collide', False)))
# #
self.collision = ba.Material() self.collision = bs.Material()
self.collision.add_actions( self.collision.add_actions(
actions=(('modify_part_collision', 'collide', True))) actions=(('modify_part_collision', 'collide', True)))
# Spawn just above the provided point. # Spawn just above the provided point.
self._spawn_pos = (position[0], position[2]+2.5, position[2]) self._spawn_pos = (position[0], position[2]+2.5, position[2])
model = ba.getmodel('flagPole') mesh = bs.getmesh('flagPole')
tex = ba.gettexture('flagPoleColor') tex = bs.gettexture('flagPoleColor')
pmats = [self.no_collision] pmats = [self.no_collision]
self.node = ba.newnode('prop', self.node = bs.newnode('prop',
delegate=self, delegate=self,
attrs={ attrs={
'model': model, 'mesh': mesh,
'color_texture': tex, 'color_texture': tex,
'body': 'puck', 'body': 'puck',
'reflection': 'soft', 'reflection': 'soft',
@ -643,9 +646,9 @@ class Palos(ba.Actor):
'materials': pmats 'materials': pmats
}) })
self.scale = scale = 4.0 self.scale = scale = 4.0
ba.animate(self.node, 'model_scale', {0: scale}) bs.animate(self.node, 'mesh_scale', {0: scale})
self.loc = ba.newnode('locator', self.loc = bs.newnode('locator',
owner=self.node, owner=self.node,
attrs={'shape': 'circle', attrs={'shape': 'circle',
'position': position, 'position': position,
@ -657,7 +660,7 @@ class Palos(ba.Actor):
self._y = _y = 0.30 self._y = _y = 0.30
_x = -0.25 if team == 1 else 0.25 _x = -0.25 if team == 1 else 0.25
_pos = (position[0]+_x, position[1]-1.5 + _y, position[2]) _pos = (position[0]+_x, position[1]-1.5 + _y, position[2])
self.region = ba.newnode('region', self.region = bs.newnode('region',
attrs={ attrs={
'position': _pos, 'position': _pos,
'scale': (0.4, 8, 0.4), 'scale': (0.4, 8, 0.4),
@ -680,7 +683,7 @@ class Palos(ba.Actor):
self.cua = Cuadro(team, pos).autoretain() self.cua = Cuadro(team, pos).autoretain()
def handlemessage(self, msg: Any) -> Any: def handlemessage(self, msg: Any) -> Any:
if isinstance(msg, ba.DieMessage): if isinstance(msg, bs.DieMessage):
if self.node.exists(): if self.node.exists():
self.node.delete() self.node.delete()
else: else:
@ -698,7 +701,7 @@ class BasketMap(maps.FootballStadium):
def __init__(self) -> None: def __init__(self) -> None:
super().__init__() super().__init__()
gnode = ba.getactivity().globalsnode gnode = bs.getactivity().globalsnode
gnode.tint = [(0.806, 0.8, 1.0476), (1.3, 1.2, 1.0)][0] gnode.tint = [(0.806, 0.8, 1.0476), (1.3, 1.2, 1.0)][0]
gnode.ambient_color = (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_outer = (0.57, 0.57, 0.57)
@ -715,21 +718,21 @@ class BasketMapV2(maps.HockeyStadium):
shared = SharedObjects.get() shared = SharedObjects.get()
self.node.materials = [shared.footing_material] self.node.materials = [shared.footing_material]
self.node.collide_model = ba.getcollidemodel('footballStadiumCollide') self.node.collision_mesh = bs.getcollisionmesh('footballStadiumCollide')
self.node.model = None self.node.mesh = None
self.stands.model = None self.stands.mesh = None
self.floor.reflection = 'soft' self.floor.reflection = 'soft'
self.floor.reflection_scale = [1.6] self.floor.reflection_scale = [1.6]
self.floor.color = (1.1, 0.05, 0.8) self.floor.color = (1.1, 0.05, 0.8)
self.background = ba.newnode('terrain', self.background = bs.newnode('terrain',
attrs={'model': ba.getmodel('thePadBG'), attrs={'mesh': bs.getmesh('thePadBG'),
'lighting': False, 'lighting': False,
'background': True, 'background': True,
'color': (1.0, 0.2, 1.0), 'color': (1.0, 0.2, 1.0),
'color_texture': ba.gettexture('menuBG')}) 'color_texture': bs.gettexture('menuBG')})
gnode = ba.getactivity().globalsnode gnode = bs.getactivity().globalsnode
gnode.floor_reflection = True gnode.floor_reflection = True
gnode.debris_friction = 0.3 gnode.debris_friction = 0.3
gnode.debris_kill_height = -0.3 gnode.debris_kill_height = -0.3
@ -742,24 +745,24 @@ class BasketMapV2(maps.HockeyStadium):
self.is_hockey = False self.is_hockey = False
################## ##################
self.collision = ba.Material() self.collision = bs.Material()
self.collision.add_actions( self.collision.add_actions(
actions=(('modify_part_collision', 'collide', True))) actions=(('modify_part_collision', 'collide', True)))
self.regions: List[ba.Node] = [ self.regions: List[bs.Node] = [
ba.newnode('region', bs.newnode('region',
attrs={'position': (12.676897048950195, 0.2997918128967285, 5.583303928375244), attrs={'position': (12.676897048950195, 0.2997918128967285, 5.583303928375244),
'scale': (1.01, 12, 28), 'scale': (1.01, 12, 28),
'type': 'box', 'type': 'box',
'materials': [self.collision]}), 'materials': [self.collision]}),
ba.newnode('region', bs.newnode('region',
attrs={'position': (11.871315956115723, 0.29975247383117676, 5.711406707763672), attrs={'position': (11.871315956115723, 0.29975247383117676, 5.711406707763672),
'scale': (50, 12, 0.9), 'scale': (50, 12, 0.9),
'type': 'box', 'type': 'box',
'materials': [self.collision]}), 'materials': [self.collision]}),
ba.newnode('region', bs.newnode('region',
attrs={'position': (-12.776557922363281, 0.30036890506744385, 4.96237850189209), attrs={'position': (-12.776557922363281, 0.30036890506744385, 4.96237850189209),
'scale': (1.01, 12, 28), 'scale': (1.01, 12, 28),
'type': 'box', 'type': 'box',
@ -767,5 +770,5 @@ class BasketMapV2(maps.HockeyStadium):
] ]
ba._map.register_map(BasketMap) bs._map.register_map(BasketMap)
ba._map.register_map(BasketMapV2) bs._map.register_map(BasketMapV2)

View file

@ -1,3 +1,4 @@
# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport)
# Released under the MIT License. See LICENSE for details. # Released under the MIT License. See LICENSE for details.
# #
""" """
@ -8,24 +9,24 @@ Youtube: https://www.youtube.com/c/HeySmoothy
Website: https://bombsquad-community.web.app Website: https://bombsquad-community.web.app
Github: https://github.com/bombsquad-community Github: https://github.com/bombsquad-community
""" """
# 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
import _ba import bascenev1 as bs
from bastd.gameutils import SharedObjects from bascenev1lib.gameutils import SharedObjects
from bastd.actor.playerspaz import PlayerSpaz from bascenev1lib.actor.playerspaz import PlayerSpaz
from bastd.game.keepaway import KeepAwayGame, FlagState, Player from bascenev1lib.game.keepaway import KeepAwayGame, FlagState, Player
from bastd.actor import spaz from bascenev1lib.actor import spaz
if TYPE_CHECKING: if TYPE_CHECKING:
from typing import Any, Sequence, Dict, Type, List, Optional, Union from typing import Any, Sequence, Dict, Type, List, Optional, Union
# ba_meta export game # ba_meta export bascenev1.GameActivity
class ChooseQueen(KeepAwayGame): class ChooseQueen(KeepAwayGame):
@ -33,11 +34,11 @@ class ChooseQueen(KeepAwayGame):
description = 'Carry the queen for a set length of time' description = 'Carry the queen for a set length of time'
@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 ['Creative Thoughts'] return ['Creative Thoughts']
def get_instance_description(self) -> str | Sequence: def get_instance_description(self) -> str | Sequence:
@ -50,13 +51,13 @@ class ChooseQueen(KeepAwayGame):
super().__init__(settings) super().__init__(settings)
shared = SharedObjects.get() shared = SharedObjects.get()
self.lifts = {} self.lifts = {}
self._room_wall_material = ba.Material() self._room_wall_material = bs.Material()
self._room_wall_material.add_actions( self._room_wall_material.add_actions(
actions=( actions=(
('modify_part_collision', 'collide', False), ('modify_part_collision', 'collide', False),
('modify_part_collision', 'physical', False) ('modify_part_collision', 'physical', False)
)) ))
self._queen_material = ba.Material() self._queen_material = bs.Material()
self._queen_material.add_actions( self._queen_material.add_actions(
conditions=('they_have_material', self._room_wall_material), conditions=('they_have_material', self._room_wall_material),
actions=( actions=(
@ -74,7 +75,7 @@ class ChooseQueen(KeepAwayGame):
('modify_part_collision', 'collide', True), ('modify_part_collision', 'collide', True),
('modify_part_collision', 'physical', True) ('modify_part_collision', 'physical', True)
)) ))
self._real_wall_material = ba.Material() self._real_wall_material = bs.Material()
self._real_wall_material.add_actions( self._real_wall_material.add_actions(
actions=( actions=(
('modify_part_collision', 'collide', True), ('modify_part_collision', 'collide', True),
@ -90,17 +91,17 @@ class ChooseQueen(KeepAwayGame):
)) ))
def on_begin(self): def on_begin(self):
ba.getactivity().globalsnode.happy_thoughts_mode = True bs.getactivity().globalsnode.happy_thoughts_mode = True
super().on_begin() super().on_begin()
self.make_map() self.make_map()
def _spawn_flag(self) -> None: def _spawn_flag(self) -> None:
ba.playsound(self._swipsound) self._swipsound.play()
self._flash_flag_spawn() self._flash_flag_spawn()
assert self._flag_spawn_pos is not None assert self._flag_spawn_pos is not None
shared = SharedObjects.get() shared = SharedObjects.get()
self._flag = spaz.Spaz((0, 0, 0), character="Pixel").autoretain() self._flag = spaz.Spaz((0, 0, 0), character="Pixel").autoretain()
self._flag.handlemessage(ba.StandMessage((0, 14.63, -5.52), 93)) self._flag.handlemessage(bs.StandMessage((0, 14.63, -5.52), 93))
self._flag.node.hold_position_pressed = True self._flag.node.hold_position_pressed = True
self._flag.node.materials = (self._queen_material, shared.object_material) self._flag.node.materials = (self._queen_material, shared.object_material)
# self._flag.node.extras_material= tuple(list(self._flag.node.extras_material).append(self._queen_materia)) # self._flag.node.extras_material= tuple(list(self._flag.node.extras_material).append(self._queen_materia))
@ -108,7 +109,7 @@ class ChooseQueen(KeepAwayGame):
self._flag.hitpoints_max = 5000 self._flag.hitpoints_max = 5000
self._flag_state = FlagState.NEW self._flag_state = FlagState.NEW
self._flag_light = ba.newnode( self._flag_light = bs.newnode(
'light', 'light',
owner=self._flag.node, owner=self._flag.node,
attrs={'intensity': 0.2, 'radius': 0.3, 'color': (0.2, 0.2, 0.2)}, attrs={'intensity': 0.2, 'radius': 0.3, 'color': (0.2, 0.2, 0.2)},
@ -136,7 +137,7 @@ class ChooseQueen(KeepAwayGame):
player.actor.node.hold_node == self._flag.node player.actor.node.hold_node == self._flag.node
) )
except Exception: except Exception:
ba.print_exception('Error checking hold flag.') babase.print_exception('Error checking hold flag.')
if holdingflag: if holdingflag:
self._holding_players.append(player) self._holding_players.append(player)
player.team.holdingflag = True player.team.holdingflag = True
@ -158,43 +159,43 @@ class ChooseQueen(KeepAwayGame):
self._scoring_team = None self._scoring_team = None
if self._flag_state != prevstate: if self._flag_state != prevstate:
ba.playsound(self._swipsound) self._swipsound.play()
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)
self.respawn_player(msg.getplayer(Player)) self.respawn_player(msg.getplayer(Player))
elif isinstance(msg, (ba.PickedUpMessage, ba.DroppedMessage)): elif isinstance(msg, (bs.PickedUpMessage, bs.DroppedMessage)):
self._update_flag_state() self._update_flag_state()
else: else:
super().handlemessage(msg) super().handlemessage(msg)
def make_map(self): def make_map(self):
shared = SharedObjects.get() shared = SharedObjects.get()
_ba.get_foreground_host_activity()._map.leftwall.materials = [ bs.get_foreground_host_activity()._map.leftwall.materials = [
shared.footing_material, self._real_wall_material] shared.footing_material, self._real_wall_material]
_ba.get_foreground_host_activity()._map.rightwall.materials = [ bs.get_foreground_host_activity()._map.rightwall.materials = [
shared.footing_material, self._real_wall_material] shared.footing_material, self._real_wall_material]
_ba.get_foreground_host_activity()._map.topwall.materials = [ bs.get_foreground_host_activity()._map.topwall.materials = [
shared.footing_material, self._real_wall_material] shared.footing_material, self._real_wall_material]
self.floorwall1 = ba.newnode('region', attrs={'position': (-10, 5, -5.52), 'scale': self.floorwall1 = bs.newnode('region', attrs={'position': (-10, 5, -5.52), 'scale':
(15, 0.2, 2), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) (15, 0.2, 2), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]})
self.floorwall2 = ba.newnode('region', attrs={'position': (10, 5, -5.52), 'scale': ( self.floorwall2 = bs.newnode('region', attrs={'position': (10, 5, -5.52), 'scale': (
15, 0.2, 2), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) 15, 0.2, 2), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]})
self.wall1 = ba.newnode('region', attrs={'position': (0, 11, -6.90), 'scale': ( self.wall1 = bs.newnode('region', attrs={'position': (0, 11, -6.90), 'scale': (
35.4, 20, 1), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) 35.4, 20, 1), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]})
self.wall2 = ba.newnode('region', attrs={'position': (0, 11, -4.14), 'scale': ( self.wall2 = bs.newnode('region', attrs={'position': (0, 11, -4.14), 'scale': (
35.4, 20, 1), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) 35.4, 20, 1), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]})
ba.newnode('locator', attrs={'shape': 'box', 'position': (-10, 5, -5.52), 'color': ( bs.newnode('locator', attrs={'shape': 'box', 'position': (-10, 5, -5.52), 'color': (
0, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (15, 0.2, 2)}) 0, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (15, 0.2, 2)})
ba.newnode('locator', attrs={'shape': 'box', 'position': (10, 5, -5.52), 'color': ( bs.newnode('locator', attrs={'shape': 'box', 'position': (10, 5, -5.52), 'color': (
0, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (15, 0.2, 2)}) 0, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (15, 0.2, 2)})
self.create_static_step(0, 14.29) self.create_static_step(0, 14.29)
@ -219,25 +220,25 @@ class ChooseQueen(KeepAwayGame):
self.create_static_step(-3, 10) self.create_static_step(-3, 10)
# create queen personal room # create queen personal room
self.room_wall_left = ba.newnode('region', attrs={'position': (-3.633, 16.63, -5.52), 'scale': self.room_wall_left = bs.newnode('region', attrs={'position': (-3.633, 16.63, -5.52), 'scale':
(2, 4, 5), 'type': 'box', 'materials': [shared.footing_material, self._room_wall_material]}) (2, 4, 5), 'type': 'box', 'materials': [shared.footing_material, self._room_wall_material]})
self.room_wall_right = ba.newnode('region', attrs={'position': (3.533, 16.63, -5.52), 'scale': self.room_wall_right = bs.newnode('region', attrs={'position': (3.533, 16.63, -5.52), 'scale':
(2, 4, 5), 'type': 'box', 'materials': [shared.footing_material, self._room_wall_material]}) (2, 4, 5), 'type': 'box', 'materials': [shared.footing_material, self._room_wall_material]})
def create_static_step(self, x, y): def create_static_step(self, x, y):
shared = SharedObjects.get() shared = SharedObjects.get()
ba.newnode('region', attrs={'position': (x, y, -5.52), 'scale': (5.5, 0.1, 6), bs.newnode('region', attrs={'position': (x, y, -5.52), 'scale': (5.5, 0.1, 6),
'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]})
ba.newnode('locator', attrs={'shape': 'box', 'position': (x, y, -5.52), 'color': ( bs.newnode('locator', attrs={'shape': 'box', 'position': (x, y, -5.52), 'color': (
1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (5.5, 0.1, 2)}) 1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (5.5, 0.1, 2)})
def create_slope(self, x, y, backslash): def create_slope(self, x, y, backslash):
shared = SharedObjects.get() shared = SharedObjects.get()
for _ in range(0, 21): for _ in range(0, 21):
ba.newnode('region', attrs={'position': (x, y, -5.52), 'scale': (0.2, 0.1, 6), bs.newnode('region', attrs={'position': (x, y, -5.52), 'scale': (0.2, 0.1, 6),
'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]})
ba.newnode('locator', attrs={'shape': 'box', 'position': (x, y, -5.52), 'color': ( bs.newnode('locator', attrs={'shape': 'box', 'position': (x, y, -5.52), 'color': (
1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (0.2, 0.1, 2)}) 1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (0.2, 0.1, 2)})
if backslash: if backslash:
x = x + 0.1 x = x + 0.1
@ -291,7 +292,7 @@ class mapdefs:
0.5245740665, 0.5245740665, 0.01941146064) 0.5245740665, 0.5245740665, 0.01941146064)
class CreativeThoughts(ba.Map): class CreativeThoughts(bs.Map):
"""Freaking map by smoothy.""" """Freaking map by smoothy."""
defs = mapdefs defs = mapdefs
@ -312,26 +313,26 @@ class CreativeThoughts(ba.Map):
@classmethod @classmethod
def on_preload(cls) -> Any: def on_preload(cls) -> Any:
data: Dict[str, Any] = { data: Dict[str, Any] = {
'model': ba.getmodel('alwaysLandLevel'), 'mesh': bs.getmesh('alwaysLandLevel'),
'bottom_model': ba.getmodel('alwaysLandLevelBottom'), 'bottom_mesh': bs.getmesh('alwaysLandLevelBottom'),
'bgmodel': ba.getmodel('alwaysLandBG'), 'bgmesh': bs.getmesh('alwaysLandBG'),
'collide_model': ba.getcollidemodel('alwaysLandLevelCollide'), 'collision_mesh': bs.getcollisionmesh('alwaysLandLevelCollide'),
'tex': ba.gettexture('alwaysLandLevelColor'), 'tex': bs.gettexture('alwaysLandLevelColor'),
'bgtex': ba.gettexture('alwaysLandBGColor'), 'bgtex': bs.gettexture('alwaysLandBGColor'),
'vr_fill_mound_model': ba.getmodel('alwaysLandVRFillMound'), 'vr_fill_mound_mesh': bs.getmesh('alwaysLandVRFillMound'),
'vr_fill_mound_tex': ba.gettexture('vrFillMound') 'vr_fill_mound_tex': bs.gettexture('vrFillMound')
} }
return data return data
@classmethod @classmethod
def get_music_type(cls) -> ba.MusicType: def get_music_type(cls) -> bs.MusicType:
return ba.MusicType.FLYING return bs.MusicType.FLYING
def __init__(self) -> None: def __init__(self) -> None:
super().__init__(vr_overlay_offset=(0, -3.7, 2.5)) super().__init__(vr_overlay_offset=(0, -3.7, 2.5))
shared = SharedObjects.get() shared = SharedObjects.get()
self._fake_wall_material = ba.Material() self._fake_wall_material = bs.Material()
self._real_wall_material = ba.Material() self._real_wall_material = bs.Material()
self._fake_wall_material.add_actions( self._fake_wall_material.add_actions(
conditions=(('they_are_younger_than', 9000), 'and', conditions=(('they_are_younger_than', 9000), 'and',
('they_have_material', shared.player_material)), ('they_have_material', shared.player_material)),
@ -347,29 +348,29 @@ class CreativeThoughts(ba.Map):
('modify_part_collision', 'physical', True) ('modify_part_collision', 'physical', True)
)) ))
self.background = ba.newnode( self.background = bs.newnode(
'terrain', 'terrain',
attrs={ attrs={
'model': self.preloaddata['bgmodel'], 'mesh': self.preloaddata['bgmesh'],
'lighting': False, 'lighting': False,
'background': True, 'background': True,
'color_texture': ba.gettexture("rampageBGColor") 'color_texture': bs.gettexture("rampageBGColor")
}) })
self.leftwall = ba.newnode('region', attrs={'position': (-17.75152479, 13, -5.52), 'scale': ( self.leftwall = bs.newnode('region', attrs={'position': (-17.75152479, 13, -5.52), 'scale': (
0.1, 15.5, 2), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) 0.1, 15.5, 2), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]})
self.rightwall = ba.newnode('region', attrs={'position': (17.75, 13, -5.52), 'scale': ( self.rightwall = bs.newnode('region', attrs={'position': (17.75, 13, -5.52), 'scale': (
0.1, 15.5, 2), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) 0.1, 15.5, 2), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]})
self.topwall = ba.newnode('region', attrs={'position': (0, 21.0, -5.52), 'scale': ( self.topwall = bs.newnode('region', attrs={'position': (0, 21.0, -5.52), 'scale': (
35.4, 0.2, 2), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) 35.4, 0.2, 2), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]})
ba.newnode('locator', attrs={'shape': 'box', 'position': (-17.75152479, 13, -5.52), 'color': ( bs.newnode('locator', attrs={'shape': 'box', 'position': (-17.75152479, 13, -5.52), 'color': (
0, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (0.1, 15.5, 2)}) 0, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (0.1, 15.5, 2)})
ba.newnode('locator', attrs={'shape': 'box', 'position': (17.75, 13, -5.52), 'color': ( bs.newnode('locator', attrs={'shape': 'box', 'position': (17.75, 13, -5.52), 'color': (
0, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (0.1, 15.5, 2)}) 0, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (0.1, 15.5, 2)})
ba.newnode('locator', attrs={'shape': 'box', 'position': (0, 21.0, -5.52), 'color': ( bs.newnode('locator', attrs={'shape': 'box', 'position': (0, 21.0, -5.52), 'color': (
0, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (35.4, 0.2, 2)}) 0, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (35.4, 0.2, 2)})
gnode = ba.getactivity().globalsnode gnode = bs.getactivity().globalsnode
gnode.happy_thoughts_mode = True gnode.happy_thoughts_mode = True
gnode.shadow_offset = (0.0, 8.0, 5.0) gnode.shadow_offset = (0.0, 8.0, 5.0)
gnode.tint = (1.3, 1.23, 1.0) gnode.tint = (1.3, 1.23, 1.0)
@ -380,9 +381,9 @@ class CreativeThoughts(ba.Map):
self.is_flying = True self.is_flying = True
# throw out some tips on flying # throw out some tips on flying
txt = ba.newnode('text', txt = bs.newnode('text',
attrs={ attrs={
'text': ba.Lstr(resource='pressJumpToFlyText'), 'text': babase.Lstr(resource='pressJumpToFlyText'),
'scale': 1.2, 'scale': 1.2,
'maxwidth': 800, 'maxwidth': 800,
'position': (0, 200), 'position': (0, 200),
@ -391,7 +392,7 @@ class CreativeThoughts(ba.Map):
'h_align': 'center', 'h_align': 'center',
'v_attach': 'bottom' 'v_attach': 'bottom'
}) })
cmb = ba.newnode('combine', cmb = bs.newnode('combine',
owner=txt, owner=txt,
attrs={ attrs={
'size': 4, 'size': 4,
@ -399,12 +400,12 @@ class CreativeThoughts(ba.Map):
'input1': 0.9, 'input1': 0.9,
'input2': 0.0 'input2': 0.0
}) })
ba.animate(cmb, 'input3', {3.0: 0, 4.0: 1, 9.0: 1, 10.0: 0}) bs.animate(cmb, 'input3', {3.0: 0, 4.0: 1, 9.0: 1, 10.0: 0})
cmb.connectattr('output', txt, 'color') cmb.connectattr('output', txt, 'color')
ba.timer(10.0, txt.delete) bs.timer(10.0, txt.delete)
try: try:
ba._map.register_map(CreativeThoughts) bs._map.register_map(CreativeThoughts)
except: except:
pass pass

View file

@ -1,3 +1,4 @@
# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport)
# Released under the MIT License. See LICENSE for details. # Released under the MIT License. See LICENSE for details.
# #
""" """
@ -8,22 +9,22 @@ Youtube: https://www.youtube.com/c/HeySmoothy
Website: https://bombsquad-community.web.app Website: https://bombsquad-community.web.app
Github: https://github.com/bombsquad-community Github: https://github.com/bombsquad-community
""" """
# 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
import _ba import bascenev1 as bs
from ba._generated.enums import InputType from babase._mgen.enums import InputType
from bastd.actor.bomb import Blast from bascenev1lib.actor.bomb import Blast
from bastd.gameutils import SharedObjects from bascenev1lib.gameutils import SharedObjects
from bastd.actor.playerspaz import PlayerSpaz, PlayerType from bascenev1lib.actor.playerspaz import PlayerSpaz, PlayerT
from bastd.game.deathmatch import DeathMatchGame, Player from bascenev1lib.game.deathmatch import DeathMatchGame, Player
from bastd.actor import spaz from bascenev1lib.actor import spaz
if TYPE_CHECKING: if TYPE_CHECKING:
from typing import Any, Sequence, Dict, Type, List, Optional, Union from typing import Any, Sequence, Dict, Type, List, Optional, Union
@ -33,11 +34,11 @@ STORAGE_ATTR_NAME = f'_shared_{__name__}_factory'
# use drone as long as you want , unlike floater which dies after being idle. # use drone as long as you want , unlike floater which dies after being idle.
class Drone(ba.Actor): class Drone(bs.Actor):
def __init__(self, spaz): def __init__(self, spaz):
super().__init__() super().__init__()
shared = SharedObjects.get() shared = SharedObjects.get()
self._drone_material = ba.Material() self._drone_material = bs.Material()
self.loop_ascend = None self.loop_ascend = None
self.loop_descend = None self.loop_descend = None
self.loop_lr = None self.loop_lr = None
@ -59,45 +60,45 @@ class Drone(ba.Actor):
('they_have_material', ('they_have_material',
self._drone_material)), self._drone_material)),
actions=('modify_part_collision', 'physical', False)) actions=('modify_part_collision', 'physical', False))
self.node = ba.newnode( self.node = bs.newnode(
'prop', 'prop',
delegate=self, delegate=self,
owner=None, owner=None,
attrs={ attrs={
'position': spaz.node.position, 'position': spaz.node.position,
'model': ba.getmodel('landMine'), 'mesh': bs.getmesh('landMine'),
'light_model': ba.getmodel('landMine'), 'light_mesh': bs.getmesh('landMine'),
'body': 'landMine', 'body': 'landMine',
'body_scale': 1, 'body_scale': 1,
'model_scale': 1, 'mesh_scale': 1,
'shadow_size': 0.25, 'shadow_size': 0.25,
'density': 999999, 'density': 999999,
'gravity_scale': 0.0, 'gravity_scale': 0.0,
'color_texture': ba.gettexture('achievementCrossHair'), 'color_texture': bs.gettexture('achievementCrossHair'),
'reflection': 'soft', 'reflection': 'soft',
'reflection_scale': [0.25], 'reflection_scale': [0.25],
'materials': [shared.footing_material, self._drone_material] 'materials': [shared.footing_material, self._drone_material]
}) })
self.grab_node = ba.newnode( self.grab_node = bs.newnode(
'prop', 'prop',
owner=self.node, owner=self.node,
attrs={ attrs={
'position': (0, 0, 0), 'position': (0, 0, 0),
'body': 'sphere', 'body': 'sphere',
'model': None, 'mesh': None,
'color_texture': None, 'color_texture': None,
'body_scale': 0.2, 'body_scale': 0.2,
'reflection': 'powerup', 'reflection': 'powerup',
'density': 999999, 'density': 999999,
'reflection_scale': [1.0], 'reflection_scale': [1.0],
'model_scale': 0.2, 'mesh_scale': 0.2,
'gravity_scale': 0, 'gravity_scale': 0,
'shadow_size': 0.1, 'shadow_size': 0.1,
'is_area_of_interest': True, 'is_area_of_interest': True,
'materials': [shared.object_material, self._drone_material] 'materials': [shared.object_material, self._drone_material]
}) })
self.node.connectattr('position', self.grab_node, 'position') self.node.connectattr('position', self.grab_node, 'position')
self._rcombine = ba.newnode('combine', self._rcombine = bs.newnode('combine',
owner=self.node, owner=self.node,
attrs={ attrs={
'input0': self.spaz.node.position[0], 'input0': self.spaz.node.position[0],
@ -119,12 +120,12 @@ class Drone(ba.Actor):
def ascend(self): def ascend(self):
def loop(): def loop():
if self.node.exists(): if self.node.exists():
ba.animate(self._rcombine, 'input1', { bs.animate(self._rcombine, 'input1', {
0: self.node.position[1], 0: self.node.position[1],
1: self.node.position[1] + 2 1: self.node.position[1] + 2
}) })
loop() loop()
self.loop_ascend = ba.Timer(1, loop, repeat=True) self.loop_ascend = bs.Timer(1, loop, repeat=True)
def pause_movement(self): def pause_movement(self):
self.loop_ascend = None self.loop_ascend = None
@ -132,12 +133,12 @@ class Drone(ba.Actor):
def decend(self): def decend(self):
def loop(): def loop():
if self.node.exists(): if self.node.exists():
ba.animate(self._rcombine, 'input1', { bs.animate(self._rcombine, 'input1', {
0: self.node.position[1], 0: self.node.position[1],
1: self.node.position[1] - 2 1: self.node.position[1] - 2
}) })
loop() loop()
self.loop_ascend = ba.Timer(1, loop, repeat=True) self.loop_ascend = bs.Timer(1, loop, repeat=True)
def pause_lr(self): def pause_lr(self):
self.loop_lr = None self.loop_lr = None
@ -148,7 +149,7 @@ class Drone(ba.Actor):
def left_(self, value=-1): def left_(self, value=-1):
def loop(): def loop():
if self.node.exists(): if self.node.exists():
ba.animate(self._rcombine, 'input0', { bs.animate(self._rcombine, 'input0', {
0: self.node.position[0], 0: self.node.position[0],
1: self.node.position[0] + 2 * value 1: self.node.position[0] + 2 * value
}) })
@ -158,12 +159,12 @@ class Drone(ba.Actor):
self.x_direction = value self.x_direction = value
self.z_direction = 0 self.z_direction = 0
loop() loop()
self.loop_lr = ba.Timer(1, loop, repeat=True) self.loop_lr = bs.Timer(1, loop, repeat=True)
def right_(self, value=1): def right_(self, value=1):
def loop(): def loop():
if self.node.exists(): if self.node.exists():
ba.animate(self._rcombine, 'input0', { bs.animate(self._rcombine, 'input0', {
0: self.node.position[0], 0: self.node.position[0],
1: self.node.position[0] + 2 * value 1: self.node.position[0] + 2 * value
}) })
@ -173,12 +174,12 @@ class Drone(ba.Actor):
self.x_direction = value self.x_direction = value
self.z_direction = 0 self.z_direction = 0
loop() loop()
self.loop_lr = ba.Timer(1, loop, repeat=True) self.loop_lr = bs.Timer(1, loop, repeat=True)
def up_(self, value=1): def up_(self, value=1):
def loop(): def loop():
if self.node.exists(): if self.node.exists():
ba.animate(self._rcombine, 'input2', { bs.animate(self._rcombine, 'input2', {
0: self.node.position[2], 0: self.node.position[2],
1: self.node.position[2] - 2 * value 1: self.node.position[2] - 2 * value
}) })
@ -188,12 +189,12 @@ class Drone(ba.Actor):
self.x_direction = 0 self.x_direction = 0
self.z_direction = - value self.z_direction = - value
loop() loop()
self.loop_ud = ba.Timer(1, loop, repeat=True) self.loop_ud = bs.Timer(1, loop, repeat=True)
def down_(self, value=-1): def down_(self, value=-1):
def loop(): def loop():
if self.node.exists(): if self.node.exists():
ba.animate(self._rcombine, 'input2', { bs.animate(self._rcombine, 'input2', {
0: self.node.position[2], 0: self.node.position[2],
1: self.node.position[2] - 2 * value 1: self.node.position[2] - 2 * value
}) })
@ -203,17 +204,17 @@ class Drone(ba.Actor):
self.x_direction = 0 self.x_direction = 0
self.z_direction = - value self.z_direction = - value
loop() loop()
self.loop_ud = ba.Timer(1, loop, repeat=True) self.loop_ud = bs.Timer(1, loop, repeat=True)
def handlemessage(self, msg): def handlemessage(self, msg):
if isinstance(msg, ba.DieMessage): if isinstance(msg, bs.DieMessage):
self.node.delete() self.node.delete()
self.grab_node.delete() self.grab_node.delete()
self.loop_ascend = None self.loop_ascend = None
self.loop_ud = None self.loop_ud = None
self.loop_lr = None self.loop_lr = None
elif isinstance(msg, ba.OutOfBoundsMessage): elif isinstance(msg, bs.OutOfBoundsMessage):
self.handlemessage(ba.DieMessage()) self.handlemessage(bs.DieMessage())
else: else:
super().handlemessage(msg) super().handlemessage(msg)
@ -224,7 +225,7 @@ class RocketFactory:
"""Quake Rocket factory""" """Quake Rocket factory"""
def __init__(self) -> None: def __init__(self) -> None:
self.ball_material = ba.Material() self.ball_material = bs.Material()
self.ball_material.add_actions( self.ball_material.add_actions(
conditions=((('we_are_younger_than', 5), 'or', conditions=((('we_are_younger_than', 5), 'or',
@ -251,7 +252,7 @@ class RocketFactory:
@classmethod @classmethod
def get(cls): def get(cls):
"""Get factory if exists else create new""" """Get factory if exists else create new"""
activity = ba.getactivity() activity = bs.getactivity()
if hasattr(activity, STORAGE_ATTR_NAME): if hasattr(activity, STORAGE_ATTR_NAME):
return getattr(activity, STORAGE_ATTR_NAME) return getattr(activity, STORAGE_ATTR_NAME)
factory = cls() factory = cls()
@ -263,30 +264,30 @@ class RocketLauncher:
"""Very dangerous weapon""" """Very dangerous weapon"""
def __init__(self): def __init__(self):
self.last_shot = ba.time() self.last_shot = bs.time()
def give(self, spaz: spaz.Spaz) -> None: def give(self, spaz: spaz.Spaz) -> None:
"""Give spaz a rocket launcher""" """Give spaz a rocket launcher"""
spaz.punch_callback = self.shot spaz.punch_callback = self.shot
self.last_shot = ba.time() self.last_shot = bs.time()
# FIXME # FIXME
# noinspection PyUnresolvedReferences # noinspection PyUnresolvedReferences
def shot(self, spaz, x, z, position) -> None: def shot(self, spaz, x, z, position) -> None:
"""Release a rocket""" """Release a rocket"""
time = ba.time() time = bs.time()
if time - self.last_shot > 0.6: if time - self.last_shot > 0.6:
self.last_shot = time self.last_shot = time
direction = [x, 0, z] direction = [x, 0, z]
direction[1] = 0.0 direction[1] = 0.0
mag = 10.0 / 1 if ba.Vec3(*direction).length() == 0 else ba.Vec3(*direction).length() mag = 10.0 / 1 if babase.Vec3(*direction).length() == 0 else babase.Vec3(*direction).length()
vel = [v * mag for v in direction] vel = [v * mag for v in direction]
Rocket(position=position, Rocket(position=position,
velocity=vel, velocity=vel,
owner=spaz.getplayer(ba.Player), owner=spaz.getplayer(bs.Player),
source_player=spaz.getplayer(ba.Player), source_player=spaz.getplayer(bs.Player),
color=spaz.node.color).autoretain() color=spaz.node.color).autoretain()
@ -294,7 +295,7 @@ class ImpactMessage:
"""Rocket touched something""" """Rocket touched something"""
class Rocket(ba.Actor): class Rocket(bs.Actor):
"""Epic rocket from rocket launcher""" """Epic rocket from rocket launcher"""
def __init__(self, def __init__(self,
@ -309,16 +310,16 @@ class Rocket(ba.Actor):
self._color = color self._color = color
factory = RocketFactory.get() factory = RocketFactory.get()
self.node = ba.newnode('prop', self.node = bs.newnode('prop',
delegate=self, delegate=self,
attrs={ attrs={
'position': position, 'position': position,
'velocity': velocity, 'velocity': velocity,
'model': ba.getmodel('impactBomb'), 'mesh': bs.getmesh('impactBomb'),
'body': 'sphere', 'body': 'sphere',
'color_texture': ba.gettexture( 'color_texture': bs.gettexture(
'bunnyColor'), 'bunnyColor'),
'model_scale': 0.2, 'mesh_scale': 0.2,
'is_area_of_interest': True, 'is_area_of_interest': True,
'body_scale': 0.8, 'body_scale': 0.8,
'materials': [ 'materials': [
@ -328,17 +329,17 @@ class Rocket(ba.Actor):
self.node.extra_acceleration = (self.node.velocity[0] * 200, 0, self.node.extra_acceleration = (self.node.velocity[0] * 200, 0,
self.node.velocity[2] * 200) self.node.velocity[2] * 200)
self._life_timer = ba.Timer( self._life_timer = bs.Timer(
5, ba.WeakCall(self.handlemessage, ba.DieMessage())) 5, bs.WeakCall(self.handlemessage, bs.DieMessage()))
self._emit_timer = ba.Timer(0.001, ba.WeakCall(self.emit), repeat=True) self._emit_timer = bs.Timer(0.001, bs.WeakCall(self.emit), repeat=True)
self.base_pos_y = self.node.position[1] self.base_pos_y = self.node.position[1]
ba.camerashake(5.0) bs.camerashake(5.0)
def emit(self) -> None: def emit(self) -> None:
"""Emit a trace after rocket""" """Emit a trace after rocket"""
ba.emitfx(position=self.node.position, bs.emitfx(position=self.node.position,
scale=0.4, scale=0.4,
spread=0.01, spread=0.01,
chunk_type='spark') chunk_type='spark')
@ -346,7 +347,7 @@ class Rocket(ba.Actor):
return return
self.node.position = (self.node.position[0], self.base_pos_y, self.node.position = (self.node.position[0], self.base_pos_y,
self.node.position[2]) # ignore y self.node.position[2]) # ignore y
ba.newnode('explosion', bs.newnode('explosion',
owner=self.node, owner=self.node,
attrs={ attrs={
'position': self.node.position, 'position': self.node.position,
@ -358,9 +359,9 @@ class Rocket(ba.Actor):
"""Message handling for rocket""" """Message handling for rocket"""
super().handlemessage(msg) super().handlemessage(msg)
if isinstance(msg, ImpactMessage): if isinstance(msg, ImpactMessage):
self.node.handlemessage(ba.DieMessage()) self.node.handlemessage(bs.DieMessage())
elif isinstance(msg, ba.DieMessage): elif isinstance(msg, bs.DieMessage):
if self.node: if self.node:
Blast(position=self.node.position, Blast(position=self.node.position,
blast_radius=2, blast_radius=2,
@ -369,25 +370,25 @@ class Rocket(ba.Actor):
self.node.delete() self.node.delete()
self._emit_timer = None self._emit_timer = None
elif isinstance(msg, ba.OutOfBoundsMessage): elif isinstance(msg, bs.OutOfBoundsMessage):
self.handlemessage(ba.DieMessage()) self.handlemessage(bs.DieMessage())
# ba_meta export game # ba_meta export bascenev1.GameActivity
class ChooseQueen(DeathMatchGame): class ChooseQueen(DeathMatchGame):
name = 'Drone War' name = 'Drone War'
@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 ['Football Stadium'] return ['Football Stadium']
def spawn_player_spaz( def spawn_player_spaz(
self, self,
player: PlayerType, player: PlayerT,
position: Sequence[float] | None = None, position: Sequence[float] | None = None,
angle: float | None = None, angle: float | None = None,
) -> PlayerSpaz: ) -> PlayerSpaz:
@ -398,29 +399,29 @@ class ChooseQueen(DeathMatchGame):
def on_begin(self): def on_begin(self):
super().on_begin() super().on_begin()
shared = SharedObjects.get() shared = SharedObjects.get()
self.ground_material = ba.Material() self.ground_material = bs.Material()
self.ground_material.add_actions( self.ground_material.add_actions(
conditions=('they_have_material', shared.player_material), conditions=('they_have_material', shared.player_material),
actions=( actions=(
('modify_part_collision', 'collide', True), ('modify_part_collision', 'collide', True),
('call', 'at_connect', ba.Call(self._handle_player_collide)), ('call', 'at_connect', babase.Call(self._handle_player_collide)),
), ),
) )
pos = (0, 0.1, -5) pos = (0, 0.1, -5)
self.main_region = ba.newnode('region', attrs={'position': pos, 'scale': ( self.main_region = bs.newnode('region', attrs={'position': pos, 'scale': (
30, 0.001, 23), 'type': 'box', 'materials': [shared.footing_material, self.ground_material]}) 30, 0.001, 23), 'type': 'box', 'materials': [shared.footing_material, self.ground_material]})
def _handle_player_collide(self): def _handle_player_collide(self):
try: try:
player = ba.getcollision().opposingnode.getdelegate( player = bs.getcollision().opposingnode.getdelegate(
PlayerSpaz, True) PlayerSpaz, True)
except ba.NotFoundError: except bs.NotFoundError:
return return
if player.is_alive(): if player.is_alive():
player.shatter(True) player.shatter(True)
def spawn_drone(self, spaz): def spawn_drone(self, spaz):
with ba.Context(_ba.get_foreground_host_activity()): with bs.get_foreground_host_activity().context:
drone = Drone(spaz) drone = Drone(spaz)
r_launcher = RocketLauncher() r_launcher = RocketLauncher()

View file

@ -1,3 +1,4 @@
# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport)
""" """
Hot Potato by TheMikirog#1984 Hot Potato by TheMikirog#1984
@ -13,20 +14,23 @@
""" """
# ba_meta require api 7 # ba_meta require api 8
from __future__ import annotations from __future__ import annotations
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
# Define only what we need and nothing more # Define only what we need and nothing more
import ba from baenv import TARGET_BALLISTICA_BUILD as build_number
from bastd.actor.spaz import SpazFactory import babase
from bastd.actor.spaz import PickupMessage import bauiv1 as bui
from bastd.actor.spaz import BombDiedMessage import bascenev1 as bs
from bastd.actor.playerspaz import PlayerSpaz from bascenev1lib.actor.spaz import SpazFactory
from bastd.actor.bomb import Bomb from bascenev1lib.actor.spaz import PickupMessage
from bastd.actor.bomb import Blast from bascenev1lib.actor.spaz import BombDiedMessage
from bascenev1lib.actor.playerspaz import PlayerSpaz
from bascenev1lib.actor.bomb import Bomb
from bascenev1lib.actor.bomb import Blast
from enum import Enum from enum import Enum
import random import random
@ -72,7 +76,7 @@ class PlayerState(Enum):
# Here's the behavior of each icon. # Here's the behavior of each icon.
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,
@ -88,11 +92,11 @@ class Icon(ba.Actor):
self._player = player self._player = player
self._name_scale = name_scale self._name_scale = name_scale
self._outline_tex = ba.gettexture('characterIconMask') self._outline_tex = bui.gettexture('characterIconMask')
# Character portrait # Character portrait
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'],
@ -106,12 +110,12 @@ class Icon(ba.Actor):
'attach': 'bottomCenter' 'attach': 'bottomCenter'
}) })
# Player name # Player name
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,
@ -122,7 +126,7 @@ class Icon(ba.Actor):
'v_attach': 'bottom' 'v_attach': 'bottom'
}) })
# Status text (such as Marked!, Stunned! and You're Out!) # Status text (such as Marked!, Stunned! and You're Out!)
self._marked_text = ba.newnode( self._marked_text = bs.newnode(
'text', 'text',
owner=self.node, owner=self.node,
attrs={ attrs={
@ -137,11 +141,11 @@ class Icon(ba.Actor):
'v_attach': 'bottom' 'v_attach': 'bottom'
}) })
# Status icon overlaying the character portrait # Status icon overlaying the character portrait
self._marked_icon = ba.newnode( self._marked_icon = bs.newnode(
'text', 'text',
owner=self.node, owner=self.node,
attrs={ attrs={
'text': ba.charstr(ba.SpecialChar.HAL), 'text': babase.charstr(babase.SpecialChar.HAL),
'color': (1, 1, 1), 'color': (1, 1, 1),
'h_align': 'center', 'h_align': 'center',
'v_align': 'center', 'v_align': 'center',
@ -169,7 +173,7 @@ class Icon(ba.Actor):
self.node.color = (1.0, 1.0, 1.0) self.node.color = (1.0, 1.0, 1.0)
# Marked players get ALL of the attention - red portrait, red text and icon overlaying the portrait # Marked players get ALL of the attention - red portrait, red text and icon overlaying the portrait
elif type is PlayerState.MARKED: elif type is PlayerState.MARKED:
self._marked_icon.text = ba.charstr(ba.SpecialChar.HAL) self._marked_icon.text = babase.charstr(babase.SpecialChar.HAL)
self._marked_icon.position = (pos[0] - 1, pos[1] - 13) self._marked_icon.position = (pos[0] - 1, pos[1] - 13)
self._marked_icon.opacity = 1.0 self._marked_icon.opacity = 1.0
self._marked_text.text = 'Marked!' self._marked_text.text = 'Marked!'
@ -179,7 +183,7 @@ class Icon(ba.Actor):
self.node.color = (1.0, 0.2, 0.2) self.node.color = (1.0, 0.2, 0.2)
# Stunned players are just as important - yellow portrait, yellow text and moon icon. # Stunned players are just as important - yellow portrait, yellow text and moon icon.
elif type is PlayerState.STUNNED: elif type is PlayerState.STUNNED:
self._marked_icon.text = ba.charstr(ba.SpecialChar.MOON) self._marked_icon.text = babase.charstr(babase.SpecialChar.MOON)
self._marked_icon.position = (pos[0] - 2, pos[1] - 12) self._marked_icon.position = (pos[0] - 2, pos[1] - 12)
self._marked_icon.opacity = 1.0 self._marked_icon.opacity = 1.0
self._marked_text.text = 'Stunned!' self._marked_text.text = 'Stunned!'
@ -189,17 +193,17 @@ class Icon(ba.Actor):
# Eliminated players get special treatment. # Eliminated players get special treatment.
# We make the portrait semi-transparent, while adding some visual flair with an fading skull icon and text. # We make the portrait semi-transparent, while adding some visual flair with an fading skull icon and text.
elif type is PlayerState.ELIMINATED: elif type is PlayerState.ELIMINATED:
self._marked_icon.text = ba.charstr(ba.SpecialChar.SKULL) self._marked_icon.text = babase.charstr(babase.SpecialChar.SKULL)
self._marked_icon.position = (pos[0] - 2, pos[1] - 12) self._marked_icon.position = (pos[0] - 2, pos[1] - 12)
self._marked_text.text = 'You\'re Out!' self._marked_text.text = 'You\'re Out!'
self._marked_text.color = (0.5, 0.5, 0.5) self._marked_text.color = (0.5, 0.5, 0.5)
# Animate text and icon # Animate text and icon
animation_end_time = 1.5 if bool(self.activity.settings['Epic Mode']) else 3.0 animation_end_time = 1.5 if bool(self.activity.settings['Epic Mode']) else 3.0
ba.animate(self._marked_icon, 'opacity', { bs.animate(self._marked_icon, 'opacity', {
0: 1.0, 0: 1.0,
animation_end_time: 0.0}) animation_end_time: 0.0})
ba.animate(self._marked_text, 'opacity', { bs.animate(self._marked_text, 'opacity', {
0: 1.0, 0: 1.0,
animation_end_time: 0.0}) animation_end_time: 0.0})
@ -235,7 +239,7 @@ class PotatoPlayerSpaz(PlayerSpaz):
self.dropped_bombs = [] # we use this to track bombs thrown by the player self.dropped_bombs = [] # we use this to track bombs thrown by the player
# Define a marked light # Define a marked light
self.marked_light = ba.newnode('light', self.marked_light = bs.newnode('light',
owner=self.node, owner=self.node,
attrs={'position': self.node.position, attrs={'position': self.node.position,
'radius': 0.15, 'radius': 0.15,
@ -244,7 +248,7 @@ class PotatoPlayerSpaz(PlayerSpaz):
'color': (1.0, 0.0, 0.0)}) 'color': (1.0, 0.0, 0.0)})
# Pulsing red light when the player is Marked # Pulsing red light when the player is Marked
ba.animate(self.marked_light, 'radius', { bs.animate(self.marked_light, 'radius', {
0: 0.1, 0: 0.1,
0.3: 0.15, 0.3: 0.15,
0.6: 0.1}, 0.6: 0.1},
@ -252,12 +256,12 @@ class PotatoPlayerSpaz(PlayerSpaz):
self.node.connectattr('position_center', self.marked_light, 'position') self.node.connectattr('position_center', self.marked_light, 'position')
# Marked timer. It should be above our head, so we attach the text to the offset that's attached to the player. # Marked timer. It should be above our head, so we attach the text to the offset that's attached to the player.
self.marked_timer_offset = ba.newnode('math', owner=self.node, attrs={ self.marked_timer_offset = bs.newnode('math', owner=self.node, attrs={
'input1': (0, 1.2, 0), 'input1': (0, 1.2, 0),
'operation': 'add'}) 'operation': 'add'})
self.node.connectattr('torso_position', self.marked_timer_offset, 'input2') self.node.connectattr('torso_position', self.marked_timer_offset, 'input2')
self.marked_timer_text = ba.newnode('text', owner=self.node, attrs={ self.marked_timer_text = bs.newnode('text', owner=self.node, attrs={
'text': '', 'text': '',
'in_world': True, 'in_world': True,
'shadow': 0.4, 'shadow': 0.4,
@ -278,7 +282,7 @@ class PotatoPlayerSpaz(PlayerSpaz):
# Add our bomb to the list of our tracked bombs # Add our bomb to the list of our tracked bombs
self.dropped_bombs.append(bomb) self.dropped_bombs.append(bomb)
# Bring a light # Bring a light
bomb.bomb_marked_light = ba.newnode('light', bomb.bomb_marked_light = bs.newnode('light',
owner=bomb.node, owner=bomb.node,
attrs={'position': bomb.node.position, attrs={'position': bomb.node.position,
'radius': 0.04, 'radius': 0.04,
@ -291,7 +295,7 @@ class PotatoPlayerSpaz(PlayerSpaz):
self.set_bombs_marked() self.set_bombs_marked()
# When the bomb physics node dies, call a function. # When the bomb physics node dies, call a function.
bomb.node.add_death_action( bomb.node.add_death_action(
ba.WeakCall(self.bomb_died, bomb)) bs.WeakCall(self.bomb_died, bomb))
# Here's the function that gets called when one of the player's bombs dies. # Here's the function that gets called when one of the player's bombs dies.
# We reference the player's dropped_bombs list and remove the bomb that died. # We reference the player's dropped_bombs list and remove the bomb that died.
@ -309,7 +313,7 @@ class PotatoPlayerSpaz(PlayerSpaz):
# Since our gamemode relies heavily on players passing the mark to other players # Since our gamemode relies heavily on players passing the mark to other players
# we need to have access to this message. This gets called when the player takes damage for any reason. # we need to have access to this message. This gets called when the player takes damage for any reason.
def handlemessage(self, msg): def handlemessage(self, msg):
if isinstance(msg, ba.HitMessage): if isinstance(msg, bs.HitMessage):
# This is basically the same HitMessage code as in the original Spaz. # This is basically the same HitMessage code as in the original Spaz.
# The only difference is that there is no health bar and you can't die with punches or bombs. # The only difference is that there is no health bar and you can't die with punches or bombs.
# Also some useless or redundant code was removed. # Also some useless or redundant code was removed.
@ -326,9 +330,7 @@ class PotatoPlayerSpaz(PlayerSpaz):
# If the attacker is healthy and we're stunned, do a flash and play a sound, then ignore the rest of the code. # If the attacker is healthy and we're stunned, do a flash and play a sound, then ignore the rest of the code.
if self.source_player.state == PlayerState.STUNNED and msg._source_player != PlayerState.MARKED: if self.source_player.state == PlayerState.STUNNED and msg._source_player != PlayerState.MARKED:
self.node.handlemessage('flash') self.node.handlemessage('flash')
ba.playsound(SpazFactory.get().block_sound, SpazFactory.get().block_sound.play(1.0, position=self.node.position)
1.0,
position=self.node.position)
return True return True
# Here's all the damage and force calculations unchanged from the source. # Here's all the damage and force calculations unchanged from the source.
@ -360,11 +362,11 @@ class PotatoPlayerSpaz(PlayerSpaz):
sound = SpazFactory.get().punch_sound sound = SpazFactory.get().punch_sound
else: else:
sound = SpazFactory.get().punch_sound_weak sound = SpazFactory.get().punch_sound_weak
ba.playsound(sound, 1.0, position=self.node.position) sound.play(1.0, position=self.node.position)
# Throw up some chunks. # Throw up some chunks.
assert msg.force_direction is not None assert msg.force_direction is not None
ba.emitfx(position=msg.pos, bs.emitfx(position=msg.pos,
velocity=(msg.force_direction[0] * 0.5, velocity=(msg.force_direction[0] * 0.5,
msg.force_direction[1] * 0.5, msg.force_direction[1] * 0.5,
msg.force_direction[2] * 0.5), msg.force_direction[2] * 0.5),
@ -372,7 +374,7 @@ class PotatoPlayerSpaz(PlayerSpaz):
scale=0.3, scale=0.3,
spread=0.03) spread=0.03)
ba.emitfx(position=msg.pos, bs.emitfx(position=msg.pos,
chunk_type='sweat', chunk_type='sweat',
velocity=(msg.force_direction[0] * 1.3, velocity=(msg.force_direction[0] * 1.3,
msg.force_direction[1] * 1.3 + 5.0, msg.force_direction[1] * 1.3 + 5.0,
@ -387,7 +389,7 @@ class PotatoPlayerSpaz(PlayerSpaz):
msg.pos[1] + msg.force_direction[1] * 0.02, msg.pos[1] + msg.force_direction[1] * 0.02,
msg.pos[2] + msg.force_direction[2] * 0.02) msg.pos[2] + msg.force_direction[2] * 0.02)
flash_color = (1.0, 0.8, 0.4) flash_color = (1.0, 0.8, 0.4)
light = ba.newnode( light = bs.newnode(
'light', 'light',
attrs={ attrs={
'position': punchpos, 'position': punchpos,
@ -396,20 +398,20 @@ class PotatoPlayerSpaz(PlayerSpaz):
'height_attenuated': False, 'height_attenuated': False,
'color': flash_color 'color': flash_color
}) })
ba.timer(0.06, light.delete) bs.timer(0.06, light.delete)
flash = ba.newnode('flash', flash = bs.newnode('flash',
attrs={ attrs={
'position': punchpos, 'position': punchpos,
'size': 0.17 + 0.17 * hurtiness, 'size': 0.17 + 0.17 * hurtiness,
'color': flash_color 'color': flash_color
}) })
ba.timer(0.06, flash.delete) bs.timer(0.06, flash.delete)
# Physics collision particles. # Physics collision particles.
if msg.hit_type == 'impact': if msg.hit_type == 'impact':
assert msg.force_direction is not None assert msg.force_direction is not None
ba.emitfx(position=msg.pos, bs.emitfx(position=msg.pos,
velocity=(msg.force_direction[0] * 2.0, velocity=(msg.force_direction[0] * 2.0,
msg.force_direction[1] * 2.0, msg.force_direction[1] * 2.0,
msg.force_direction[2] * 2.0), msg.force_direction[2] * 2.0),
@ -435,9 +437,9 @@ class PotatoPlayerSpaz(PlayerSpaz):
# Let's get all collision data if we can. Otherwise cancel. # Let's get all collision data if we can. Otherwise cancel.
try: try:
collision = ba.getcollision() collision = bs.getcollision()
opposingnode = collision.opposingnode opposingnode = collision.opposingnode
except ba.NotFoundError: except bs.NotFoundError:
return True return True
# Our grabber needs to be a Spaz # Our grabber needs to be a Spaz
@ -447,9 +449,7 @@ class PotatoPlayerSpaz(PlayerSpaz):
# It's the same sound and flashing behavior as hitting a stunned player as a healthy player. # It's the same sound and flashing behavior as hitting a stunned player as a healthy player.
if (opposingnode.source_player.state == PlayerState.STUNNED and self.source_player.state != PlayerState.MARKED): if (opposingnode.source_player.state == PlayerState.STUNNED and self.source_player.state != PlayerState.MARKED):
opposingnode.handlemessage('flash') opposingnode.handlemessage('flash')
ba.playsound(SpazFactory.get().block_sound, SpazFactory.get().block_sound.play(1.0, position=opposingnode.position)
1.0,
position=opposingnode.position)
return True return True
# If they're marked and we're healthy or stunned, pass that mark along to us. # If they're marked and we're healthy or stunned, pass that mark along to us.
elif opposingnode.source_player.state in [PlayerState.REGULAR, PlayerState.STUNNED] and self.source_player.state == PlayerState.MARKED: elif opposingnode.source_player.state in [PlayerState.REGULAR, PlayerState.STUNNED] and self.source_player.state == PlayerState.MARKED:
@ -458,10 +458,10 @@ class PotatoPlayerSpaz(PlayerSpaz):
# Our work is done. Continue with the rest of the grabbing behavior as usual. # Our work is done. Continue with the rest of the grabbing behavior as usual.
super().handlemessage(msg) super().handlemessage(msg)
# Dying is important in this gamemode and as such we need to address this behavior. # Dying is important in this gamemode and as such we need to address this behavior.
elif isinstance(msg, ba.DieMessage): elif isinstance(msg, bs.DieMessage):
# If a player left the game, inform our gamemode logic. # If a player left the game, inform our gamemode logic.
if msg.how == ba.DeathType.LEFT_GAME: if msg.how == bs.DeathType.LEFT_GAME:
self.activity.player_left(self.source_player) self.activity.player_left(self.source_player)
# If a MARKED or STUNNED player dies, hide the text from the previous spaz. # If a MARKED or STUNNED player dies, hide the text from the previous spaz.
@ -470,7 +470,7 @@ class PotatoPlayerSpaz(PlayerSpaz):
self.marked_timer_text.color[1], self.marked_timer_text.color[1],
self.marked_timer_text.color[2], self.marked_timer_text.color[2],
0.0) 0.0)
ba.animate(self.marked_light, 'intensity', { bs.animate(self.marked_light, 'intensity', {
0: self.marked_light.intensity, 0: self.marked_light.intensity,
0.5: 0.0}) 0.5: 0.0})
@ -483,7 +483,7 @@ class PotatoPlayerSpaz(PlayerSpaz):
# A concept of a player is very useful to reference if we don't have a player character present (maybe they died). # A concept of a player is very useful to reference if we don't have a player character present (maybe they died).
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:
@ -535,8 +535,8 @@ class Player(ba.Player['Team']):
self.stunned_time_remaining = stun_time # Set our stun time remaining self.stunned_time_remaining = stun_time # Set our stun time remaining
# Remove our stun once the time is up # Remove our stun once the time is up
self.stunned_timer = ba.Timer(stun_time + 0.1, ba.Call(self.stun_remove)) self.stunned_timer = bs.Timer(stun_time + 0.1, babase.Call(self.stun_remove))
self.stunned_update_timer = ba.Timer(0.1, ba.Call( self.stunned_update_timer = bs.Timer(0.1, babase.Call(
self.stunned_timer_tick), repeat=True) # Call a function every 0.1 seconds self.stunned_timer_tick), repeat=True) # Call a function every 0.1 seconds
self.fall_times += 1 # Increase the amount of times we fell by one self.fall_times += 1 # Increase the amount of times we fell by one
# Change the text above the Spaz's head to total stun time # Change the text above the Spaz's head to total stun time
@ -579,8 +579,8 @@ class Player(ba.Player['Team']):
self.icon.set_marked_icon(state) # Update our icon self.icon.set_marked_icon(state) # Update our icon
# ba_meta export game # ba_meta export bascenev1.GameActivity
class HotPotato(ba.TeamGameActivity[Player, ba.Team]): class HotPotato(bs.TeamGameActivity[Player, bs.Team]):
# Let's define the basics like the name of the game, description and some tips that should appear at the start of a match. # Let's define the basics like the name of the game, description and some tips that should appear at the start of a match.
name = 'Hot Potato' name = 'Hot Potato'
@ -604,8 +604,8 @@ class HotPotato(ba.TeamGameActivity[Player, ba.Team]):
# We're gonna distribute end of match session scores based on who dies first and who survives. # We're gonna distribute end of match session scores based on who dies first and who survives.
# First place gets most points, then second, then third. # First place gets most points, then second, then third.
scoreconfig = ba.ScoreConfig(label='Place', scoreconfig = bs.ScoreConfig(label='Place',
scoretype=ba.ScoreType.POINTS, scoretype=bs.ScoreType.POINTS,
lower_is_better=True) lower_is_better=True)
# These variables are self explanatory too. # These variables are self explanatory too.
@ -614,25 +614,25 @@ class HotPotato(ba.TeamGameActivity[Player, ba.Team]):
# Let's define some settings the user can mess around with to fit their needs. # Let's define some settings the user can mess around with to fit their needs.
available_settings = [ available_settings = [
ba.IntSetting('Elimination Timer', bs.IntSetting('Elimination Timer',
min_value=5, min_value=5,
default=15, default=15,
increment=1, increment=1,
), ),
ba.BoolSetting('Marked Players use Impact Bombs', default=False), bs.BoolSetting('Marked Players use Impact Bombs', default=False),
ba.BoolSetting('Epic Mode', default=False), bs.BoolSetting('Epic Mode', default=False),
] ]
# Hot Potato is strictly a Free-For-All gamemode, so only picking the gamemode in FFA playlists. # Hot Potato is strictly a Free-For-All gamemode, so only picking the gamemode in FFA playlists.
@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.FreeForAllSession) return issubclass(sessiontype, bs.FreeForAllSession)
# Most maps should work in Hot Potato. Generally maps marked as 'melee' are the most versatile map types of them all. # Most maps should work in Hot Potato. Generally maps marked as 'melee' are the most versatile map types of them all.
# As the name implies, fisticuffs are common forms of engagement. # As the name implies, fisticuffs are common forms of engagement.
@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')
# Here we define everything the gamemode needs, like sounds and settings. # Here we define everything the gamemode needs, like sounds and settings.
def __init__(self, settings: dict): def __init__(self, settings: dict):
@ -640,22 +640,22 @@ class HotPotato(ba.TeamGameActivity[Player, ba.Team]):
self.settings = settings self.settings = settings
# Let's define all of the sounds we need. # Let's define all of the sounds we need.
self._tick_sound = ba.getsound('tick') self._tick_sound = bui.getsound('tick')
self._player_eliminated_sound = ba.getsound('playerDeath') self._player_eliminated_sound = bui.getsound('playerDeath')
# These next sounds are arrays instead of single sounds. # These next sounds are arrays instead of single sounds.
# We'll use that fact later. # We'll use that fact later.
self._danger_tick_sounds = [ba.getsound('orchestraHit'), self._danger_tick_sounds = [bui.getsound('orchestraHit'),
ba.getsound('orchestraHit2'), bui.getsound('orchestraHit2'),
ba.getsound('orchestraHit3')] bui.getsound('orchestraHit3')]
self._marked_sounds = [ba.getsound('powerdown01'), self._marked_sounds = [bui.getsound('powerdown01'),
ba.getsound('activateBeep'), bui.getsound('activateBeep'),
ba.getsound('hiss')] bui.getsound('hiss')]
# Normally play KOTH music, but switch to Epic music if we're in slow motion. # Normally play KOTH music, but switch to Epic music if we're in slow motion.
self._epic_mode = bool(settings['Epic Mode']) self._epic_mode = bool(settings['Epic Mode'])
self.slow_motion = self._epic_mode self.slow_motion = self._epic_mode
self.default_music = (ba.MusicType.EPIC if self._epic_mode else self.default_music = (bs.MusicType.EPIC if self._epic_mode else
ba.MusicType.SCARY) bs.MusicType.SCARY)
# This description appears below the title card after it comes crashing when the game begins. # This description appears below the title card after it comes crashing when the game begins.
def get_instance_description(self) -> str | Sequence: def get_instance_description(self) -> str | Sequence:
@ -680,7 +680,7 @@ class HotPotato(ba.TeamGameActivity[Player, ba.Team]):
# Returns every single marked player. # Returns every single marked player.
# This piece of info is used excensively in this gamemode, so it's advantageous to have a function to cut on # This piece of info is used excensively in this gamemode, so it's advantageous to have a function to cut on
# work and make the gamemode easier to maintain # work and make the gamemode easier to maintain
def get_marked_players(self) -> Sequence[ba.Player]: def get_marked_players(self) -> Sequence[bs.Player]:
marked_players = [] marked_players = []
for p in self.players: for p in self.players:
if p.state == PlayerState.MARKED: if p.state == PlayerState.MARKED:
@ -691,7 +691,7 @@ class HotPotato(ba.TeamGameActivity[Player, ba.Team]):
def mark(self, target: Player) -> None: def mark(self, target: Player) -> None:
target.set_state(PlayerState.MARKED) target.set_state(PlayerState.MARKED)
ba.emitfx(position=target.actor.node.position, bs.emitfx(position=target.actor.node.position,
velocity=target.actor.node.velocity, velocity=target.actor.node.velocity,
chunk_type='spark', chunk_type='spark',
count=int(20.0+random.random()*20), count=int(20.0+random.random()*20),
@ -738,7 +738,7 @@ class HotPotato(ba.TeamGameActivity[Player, ba.Team]):
sound_volume = 1.0 / marked_player_amount sound_volume = 1.0 / marked_player_amount
for target in marked_players: for target in marked_players:
ba.playsound(self._tick_sound, sound_volume, target.actor.node.position) self._tick_sound.play(sound_volume, target.actor.node.position)
target.actor.marked_timer_text.text = str(self.elimination_timer_display) target.actor.marked_timer_text.text = str(self.elimination_timer_display)
# When counting down 3, 2, 1 play some dramatic sounds # When counting down 3, 2, 1 play some dramatic sounds
@ -746,7 +746,7 @@ class HotPotato(ba.TeamGameActivity[Player, ba.Team]):
# We store our dramatic sounds in an array, so we target a specific element on the array # We store our dramatic sounds in an array, so we target a specific element on the array
# depending on time remaining. Arrays start at index 0, so we need to decrease # depending on time remaining. Arrays start at index 0, so we need to decrease
# our variable by 1 to get the element index. # our variable by 1 to get the element index.
ba.playsound(self._danger_tick_sounds[self.elimination_timer_display - 1], 1.5) self._danger_tick_sounds[self.elimination_timer_display - 1].play(1.5)
else: else:
# Elimination timer is up! Let's eliminate all marked players. # Elimination timer is up! Let's eliminate all marked players.
self.elimination_timer_display -= 1 # Decrease our timer by one second. self.elimination_timer_display -= 1 # Decrease our timer by one second.
@ -763,18 +763,18 @@ class HotPotato(ba.TeamGameActivity[Player, ba.Team]):
velocity=target.actor.node.velocity, velocity=target.actor.node.velocity,
blast_radius=3.0, blast_radius=3.0,
source_player=target).autoretain() source_player=target).autoretain()
ba.emitfx(position=target.actor.node.position, bs.emitfx(position=target.actor.node.position,
velocity=target.actor.node.velocity, velocity=target.actor.node.velocity,
count=int(16.0+random.random()*60), count=int(16.0+random.random()*60),
scale=1.5, scale=1.5,
spread=2, spread=2,
chunk_type='spark') chunk_type='spark')
target.actor.handlemessage(ba.DieMessage(how='marked_elimination')) target.actor.handlemessage(bs.DieMessage(how='marked_elimination'))
target.actor.shatter(extreme=True) target.actor.shatter(extreme=True)
self.match_placement.append(target.team) self.match_placement.append(target.team)
ba.playsound(self._player_eliminated_sound, 1.0) self._player_eliminated_sound.play(1.0)
# Let the gamemode know a Marked # Let the gamemode know a Marked
self.marked_players_died() self.marked_players_died()
@ -788,13 +788,13 @@ class HotPotato(ba.TeamGameActivity[Player, ba.Team]):
# Let's add our lone survivor to the match placement list. # Let's add our lone survivor to the match placement list.
self.match_placement.append(alive_players[0].team) self.match_placement.append(alive_players[0].team)
# Wait a while to let this sink in before we announce our victor. # Wait a while to let this sink in before we announce our victor.
self._end_game_timer = ba.Timer(1.25, ba.Call(self.end_game)) self._end_game_timer = bs.Timer(1.25, babase.Call(self.end_game))
else: else:
# There's still players remaining, so let's wait a while before marking a new player. # There's still players remaining, so let's wait a while before marking a new player.
self.new_mark_timer = ba.Timer(2.0 if self.slow_motion else 4.0, ba.Call(self.new_mark)) self.new_mark_timer = bs.Timer(2.0 if self.slow_motion else 4.0, babase.Call(self.new_mark))
# Another extensively used function that returns all alive players. # Another extensively used function that returns all alive players.
def get_alive_players(self) -> Sequence[ba.Player]: def get_alive_players(self) -> Sequence[bs.Player]:
alive_players = [] alive_players = []
for player in self.players: for player in self.players:
if player.state == PlayerState.ELIMINATED: if player.state == PlayerState.ELIMINATED:
@ -829,14 +829,14 @@ class HotPotato(ba.TeamGameActivity[Player, ba.Team]):
# Set time until marked players explode # Set time until marked players explode
self.elimination_timer_display = self.settings['Elimination Timer'] self.elimination_timer_display = self.settings['Elimination Timer']
# Set a timer that calls _eliminate_tick every second # Set a timer that calls _eliminate_tick every second
self.marked_tick_timer = ba.Timer(1.0, ba.Call(self._eliminate_tick), repeat=True) self.marked_tick_timer = bs.Timer(1.0, babase.Call(self._eliminate_tick), repeat=True)
# Mark all chosen victims and play a sound # Mark all chosen victims and play a sound
for new_victim in all_victims: for new_victim in all_victims:
# _marked_sounds is an array. # _marked_sounds is an array.
# To make a nice marked sound effect, I play multiple sounds at once # To make a nice marked sound effect, I play multiple sounds at once
# All of them are contained in the array. # All of them are contained in the array.
for sound in self._marked_sounds: for sound in self._marked_sounds:
ba.playsound(sound, 1.0, new_victim.actor.node.position) sound.play(1.0, new_victim.actor.node.position)
self.mark(new_victim) self.mark(new_victim)
# This function is called when the gamemode first loads. # This function is called when the gamemode first loads.
@ -849,10 +849,10 @@ class HotPotato(ba.TeamGameActivity[Player, ba.Team]):
# End the game if there's only one player # End the game if there's only one player
if len(self.players) < 2: if len(self.players) < 2:
self.match_placement.append(self.players[0].team) self.match_placement.append(self.players[0].team)
self._round_end_timer = ba.Timer(0.5, self.end_game) self._round_end_timer = bs.Timer(0.5, self.end_game)
else: else:
# Pick random player(s) to get marked # Pick random player(s) to get marked
self.new_mark_timer = ba.Timer(2.0 if self.slow_motion else 5.2, ba.Call(self.new_mark)) self.new_mark_timer = bs.Timer(2.0 if self.slow_motion else 5.2, babase.Call(self.new_mark))
self._update_icons() # Create player state icons self._update_icons() # Create player state icons
@ -873,17 +873,17 @@ class HotPotato(ba.TeamGameActivity[Player, ba.Team]):
# I'm gonna modify this function to move the tip text above the icons. # I'm gonna modify this function to move the tip text above the icons.
def _show_tip(self) -> None: def _show_tip(self) -> None:
from ba._gameutils import animate, GameTip from bascenev1._gameutils import animate, GameTip
from ba._generated.enums import SpecialChar from babase._mgen.enums import SpecialChar
from ba._language import Lstr from babase._language import Lstr
# If there's any tips left on the list, display one. # If there's any tips left on the list, display one.
if self.tips: if self.tips:
tip = self.tips.pop(random.randrange(len(self.tips))) tip = self.tips.pop(random.randrange(len(self.tips)))
tip_title = Lstr(value='${A}:', tip_title = Lstr(value='${A}:',
subs=[('${A}', Lstr(resource='tipText'))]) subs=[('${A}', Lstr(resource='tipText'))])
icon: ba.Texture | None = None icon: babase.Texture | None = None
sound: ba.Sound | None = None sound: babase.Sound | None = None
if isinstance(tip, GameTip): if isinstance(tip, GameTip):
icon = tip.icon icon = tip.icon
sound = tip.sound sound = tip.sound
@ -893,15 +893,15 @@ class HotPotato(ba.TeamGameActivity[Player, ba.Team]):
# Do a few replacements. # Do a few replacements.
tip_lstr = Lstr(translate=('tips', tip), tip_lstr = Lstr(translate=('tips', tip),
subs=[('${PICKUP}', subs=[('${PICKUP}',
ba.charstr(SpecialChar.TOP_BUTTON))]) babase.charstr(SpecialChar.TOP_BUTTON))])
base_position = (75, 50) base_position = (75, 50)
tip_scale = 0.8 tip_scale = 0.8
tip_title_scale = 1.2 tip_title_scale = 1.2
vrmode = ba.app.vr_mode vrmode = babase.app.vr_mode if build_number < 21282 else babase.app.env.vr
t_offs = -350.0 t_offs = -350.0
height_offs = 100.0 height_offs = 100.0
tnode = ba.newnode('text', tnode = bs.newnode('text',
attrs={ attrs={
'text': tip_lstr, 'text': tip_lstr,
'scale': tip_scale, 'scale': tip_scale,
@ -917,7 +917,7 @@ class HotPotato(ba.TeamGameActivity[Player, ba.Team]):
}) })
t2pos = (base_position[0] + t_offs - (20 if icon is None else 82), t2pos = (base_position[0] + t_offs - (20 if icon is None else 82),
base_position[1] + 2 + height_offs) base_position[1] + 2 + height_offs)
t2node = ba.newnode('text', t2node = bs.newnode('text',
owner=tnode, owner=tnode,
attrs={ attrs={
'text': tip_title, 'text': tip_title,
@ -933,7 +933,7 @@ class HotPotato(ba.TeamGameActivity[Player, ba.Team]):
}) })
if icon is not None: if icon is not None:
ipos = (base_position[0] + t_offs - 40, base_position[1] + 1 + height_offs) ipos = (base_position[0] + t_offs - 40, base_position[1] + 1 + height_offs)
img = ba.newnode('image', img = bs.newnode('image',
attrs={ attrs={
'texture': icon, 'texture': icon,
'position': ipos, 'position': ipos,
@ -945,11 +945,11 @@ class HotPotato(ba.TeamGameActivity[Player, ba.Team]):
'attach': 'bottomCenter' 'attach': 'bottomCenter'
}) })
animate(img, 'opacity', {0: 0, 1.0: 1, 4.0: 1, 5.0: 0}) animate(img, 'opacity', {0: 0, 1.0: 1, 4.0: 1, 5.0: 0})
ba.timer(5.0, img.delete) bs.timer(5.0, img.delete)
if sound is not None: if sound is not None:
ba.playsound(sound) sound.play()
combine = ba.newnode('combine', combine = bs.newnode('combine',
owner=tnode, owner=tnode,
attrs={ attrs={
'input0': 1.0, 'input0': 1.0,
@ -960,7 +960,7 @@ class HotPotato(ba.TeamGameActivity[Player, ba.Team]):
combine.connectattr('output', tnode, 'color') combine.connectattr('output', tnode, 'color')
combine.connectattr('output', t2node, 'color') combine.connectattr('output', t2node, 'color')
animate(combine, 'input3', {0: 0, 1.0: 1, 4.0: 1, 5.0: 0}) animate(combine, 'input3', {0: 0, 1.0: 1, 4.0: 1, 5.0: 0})
ba.timer(5.0, tnode.delete) bs.timer(5.0, tnode.delete)
# This function is called when a player leaves the game. # This function is called when a player leaves the game.
# This is only called when the player already joined with a character. # This is only called when the player already joined with a character.
@ -985,7 +985,7 @@ class HotPotato(ba.TeamGameActivity[Player, ba.Team]):
player.set_state(PlayerState.ELIMINATED) player.set_state(PlayerState.ELIMINATED)
# This function is called every time a player spawns # This function is called every time a player spawns
def spawn_player(self, player: Player) -> ba.Actor: def spawn_player(self, player: Player) -> bs.Actor:
position = self.map.get_ffa_start_position(self.players) position = self.map.get_ffa_start_position(self.players)
position = (position[0], position = (position[0],
position[1] - 0.3, # Move the spawn a bit lower position[1] - 0.3, # Move the spawn a bit lower
@ -993,8 +993,8 @@ class HotPotato(ba.TeamGameActivity[Player, ba.Team]):
name = player.getname() name = player.getname()
light_color = ba.normalized_color(player.color) light_color = babase.normalized_color(player.color)
display_color = ba.safecolor(player.color, target_intensity=0.75) display_color = babase.safecolor(player.color, target_intensity=0.75)
# Here we actually crate the player character # Here we actually crate the player character
spaz = PotatoPlayerSpaz(color=player.color, spaz = PotatoPlayerSpaz(color=player.color,
@ -1009,20 +1009,20 @@ class HotPotato(ba.TeamGameActivity[Player, ba.Team]):
spaz.connect_controls_to_player() spaz.connect_controls_to_player()
# Move to the stand position and add a flash of light # Move to the stand position and add a flash of light
spaz.handlemessage(ba.StandMessage(position, random.uniform(0, 360))) spaz.handlemessage(bs.StandMessage(position, random.uniform(0, 360)))
t = ba.time(ba.TimeType.BASE) t = bs.time()
ba.playsound(self._spawn_sound, 1.0, position=spaz.node.position) self._spawn_sound.play(1.0, position=spaz.node.position)
light = ba.newnode('light', attrs={'color': light_color}) light = bs.newnode('light', attrs={'color': light_color})
spaz.node.connectattr('position', light, 'position') spaz.node.connectattr('position', light, 'position')
ba.animate(light, 'intensity', {0: 0, bs.animate(light, 'intensity', {0: 0,
0.25: 1, 0.25: 1,
0.5: 0}) 0.5: 0})
ba.timer(0.5, light.delete) bs.timer(0.5, light.delete)
# Game reacts to various events # Game reacts to various events
def handlemessage(self, msg: Any) -> Any: def handlemessage(self, msg: Any) -> Any:
# This is called if the player dies. # This is called if the player dies.
if isinstance(msg, ba.PlayerDiedMessage): if isinstance(msg, bs.PlayerDiedMessage):
super().handlemessage(msg) super().handlemessage(msg)
player = msg.getplayer(Player) player = msg.getplayer(Player)
@ -1046,7 +1046,7 @@ class HotPotato(ba.TeamGameActivity[Player, ba.Team]):
# Proceed only if the game hasn't ended yet. # Proceed only if the game hasn't ended yet.
if self.has_ended(): if self.has_ended():
return return
results = ba.GameResults() results = bs.GameResults()
# By this point our match placement list should be filled with all players. # By this point our match placement list should be filled with all players.
# Players that died/left earliest should be the first entries. # Players that died/left earliest should be the first entries.
# We're gonna use array indexes to decide match placements. # We're gonna use array indexes to decide match placements.

View file

@ -1,3 +1,4 @@
# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport)
# Released under the MIT License. See LICENSE for details. # Released under the MIT License. See LICENSE for details.
# #
# By itsre3 # By itsre3
@ -6,39 +7,41 @@
# Besides that, enjoy.......!! # Besides that, enjoy.......!!
"""Provides the chosen-one mini-game.""" """Provides the chosen-one 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.flag import Flag import bauiv1 as bui
from bastd.actor.playerspaz import PlayerSpaz import bascenev1 as bs
from bastd.actor.scoreboard import Scoreboard from bascenev1lib.actor.flag import Flag
from bastd.gameutils import SharedObjects from bascenev1lib.actor.playerspaz import PlayerSpaz
from bascenev1lib.actor.scoreboard import Scoreboard
from bascenev1lib.gameutils import SharedObjects
if TYPE_CHECKING: if TYPE_CHECKING:
from typing import Any, Type, List, Dict, Optional, Sequence, Union from typing import Any, Type, List, Dict, Optional, Sequence, Union
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:
self.chosen_light: Optional[ba.NodeActor] = None self.chosen_light: Optional[bs.NodeActor] = None
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, time_remaining: int) -> None: def __init__(self, time_remaining: int) -> None:
self.time_remaining = time_remaining self.time_remaining = time_remaining
# ba_meta export game # ba_meta export bascenev1.GameActivity
class InvicibleOneGame(ba.TeamGameActivity[Player, Team]): class InvicibleOneGame(bs.TeamGameActivity[Player, Team]):
""" """
Game involving trying to remain the one 'invisible one' Game involving trying to remain the one 'invisible one'
for a set length of time while everyone else tries to for a set length of time while everyone else tries to
@ -49,15 +52,15 @@ class InvicibleOneGame(ba.TeamGameActivity[Player, Team]):
description = ('Be the invisible one for a length of time to win.\n' description = ('Be the invisible one for a length of time to win.\n'
'Kill the invisible one to become it.') 'Kill the invisible one to become it.')
available_settings = [ available_settings = [
ba.IntSetting( bs.IntSetting(
'Invicible One Time', 'Invicible One Time',
min_value=10, min_value=10,
default=30, default=30,
increment=10, increment=10,
), ),
ba.BoolSetting('Invicible one is lazy', default=True), bs.BoolSetting('Invicible one is lazy', default=True),
ba.BoolSetting('Night mode', default=False), bs.BoolSetting('Night mode', default=False),
ba.IntChoiceSetting( bs.IntChoiceSetting(
'Time Limit', 'Time Limit',
choices=[ choices=[
('None', 0), ('None', 0),
@ -69,7 +72,7 @@ class InvicibleOneGame(ba.TeamGameActivity[Player, Team]):
], ],
default=0, default=0,
), ),
ba.FloatChoiceSetting( bs.FloatChoiceSetting(
'Respawn Times', 'Respawn Times',
choices=[ choices=[
('Shorter', 0.25), ('Shorter', 0.25),
@ -80,35 +83,35 @@ class InvicibleOneGame(ba.TeamGameActivity[Player, Team]):
], ],
default=1.0, default=1.0,
), ),
ba.BoolSetting('Epic Mode', default=False), bs.BoolSetting('Epic Mode', default=False),
] ]
scoreconfig = ba.ScoreConfig(label='Time Held') scoreconfig = bs.ScoreConfig(label='Time Held')
@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('keep_away') return bs.app.classic.getmaps('keep_away')
def __init__(self, settings: dict): def __init__(self, settings: dict):
super().__init__(settings) super().__init__(settings)
self._scoreboard = Scoreboard() self._scoreboard = Scoreboard()
self._invicible_one_player: Optional[Player] = None self._invicible_one_player: Optional[Player] = None
self._swipsound = ba.getsound('swip') self._swipsound = bs.getsound('swip')
self._countdownsounds: Dict[int, ba.Sound] = { self._countdownsounds: Dict[int, babase.Sound] = {
10: ba.getsound('announceTen'), 10: bs.getsound('announceTen'),
9: ba.getsound('announceNine'), 9: bs.getsound('announceNine'),
8: ba.getsound('announceEight'), 8: bs.getsound('announceEight'),
7: ba.getsound('announceSeven'), 7: bs.getsound('announceSeven'),
6: ba.getsound('announceSix'), 6: bs.getsound('announceSix'),
5: ba.getsound('announceFive'), 5: bs.getsound('announceFive'),
4: ba.getsound('announceFour'), 4: bs.getsound('announceFour'),
3: ba.getsound('announceThree'), 3: bs.getsound('announceThree'),
2: ba.getsound('announceTwo'), 2: bs.getsound('announceTwo'),
1: ba.getsound('announceOne') 1: bs.getsound('announceOne')
} }
self._flag_spawn_pos: Optional[Sequence[float]] = None self._flag_spawn_pos: Optional[Sequence[float]] = None
self._reset_region_material: Optional[ba.Material] = None self._reset_region_material: Optional[bs.Material] = None
self._flag: Optional[Flag] = None self._flag: Optional[Flag] = None
self._reset_region: Optional[ba.Node] = None self._reset_region: Optional[bs.Node] = None
self._epic_mode = bool(settings['Epic Mode']) self._epic_mode = bool(settings['Epic Mode'])
self._invicible_one_time = int(settings['Invicible One Time']) self._invicible_one_time = int(settings['Invicible One Time'])
self._time_limit = float(settings['Time Limit']) self._time_limit = float(settings['Time Limit'])
@ -117,13 +120,13 @@ class InvicibleOneGame(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.CHOSEN_ONE) if self._epic_mode else bs.MusicType.CHOSEN_ONE)
def get_instance_description(self) -> Union[str, Sequence]: def get_instance_description(self) -> Union[str, Sequence]:
return 'Show your invisibility powers.' return 'Show your invisibility powers.'
def create_team(self, sessionteam: ba.SessionTeam) -> Team: def create_team(self, sessionteam: bs.SessionTeam) -> Team:
return Team(time_remaining=self._invicible_one_time) return Team(time_remaining=self._invicible_one_time)
def on_team_join(self, team: Team) -> None: def on_team_join(self, team: Team) -> None:
@ -143,13 +146,13 @@ class InvicibleOneGame(ba.TeamGameActivity[Player, Team]):
Flag.project_stand(self._flag_spawn_pos) Flag.project_stand(self._flag_spawn_pos)
self._set_invicible_one_player(None) self._set_invicible_one_player(None)
if self._night_mode: if self._night_mode:
gnode = ba.getactivity().globalsnode gnode = bs.getactivity().globalsnode
gnode.tint = (0.4, 0.4, 0.4) gnode.tint = (0.4, 0.4, 0.4)
pos = self._flag_spawn_pos pos = self._flag_spawn_pos
ba.timer(1.0, call=self._tick, repeat=True) bs.timer(1.0, call=self._tick, repeat=True)
mat = self._reset_region_material = ba.Material() mat = self._reset_region_material = bs.Material()
mat.add_actions( mat.add_actions(
conditions=( conditions=(
'they_have_material', 'they_have_material',
@ -159,11 +162,11 @@ class InvicibleOneGame(ba.TeamGameActivity[Player, Team]):
('modify_part_collision', 'collide', True), ('modify_part_collision', 'collide', True),
('modify_part_collision', 'physical', False), ('modify_part_collision', 'physical', False),
('call', 'at_connect', ('call', 'at_connect',
ba.WeakCall(self._handle_reset_collide)), bs.WeakCall(self._handle_reset_collide)),
), ),
) )
self._reset_region = ba.newnode('region', self._reset_region = bs.newnode('region',
attrs={ attrs={
'position': (pos[0], pos[1] + 0.75, 'position': (pos[0], pos[1] + 0.75,
pos[2]), pos[2]),
@ -185,24 +188,24 @@ class InvicibleOneGame(ba.TeamGameActivity[Player, Team]):
# Attempt to get a Player controlling a Spaz that we hit. # Attempt to get a Player controlling a Spaz that we hit.
try: try:
player = ba.getcollision().opposingnode.getdelegate( player = bs.getcollision().opposingnode.getdelegate(
PlayerSpaz, True).getplayer(Player, True) PlayerSpaz, True).getplayer(Player, True)
except ba.NotFoundError: except bs.NotFoundError:
return return
if player.is_alive(): if player.is_alive():
self._set_invicible_one_player(player) self._set_invicible_one_player(player)
def _flash_flag_spawn(self) -> None: def _flash_flag_spawn(self) -> None:
light = ba.newnode('light', light = bs.newnode('light',
attrs={ attrs={
'position': self._flag_spawn_pos, 'position': self._flag_spawn_pos,
'color': (1, 1, 1), 'color': (1, 1, 1),
'radius': 0.3, 'radius': 0.3,
'height_attenuated': False 'height_attenuated': False
}) })
ba.animate(light, 'intensity', {0: 0, 0.25: 0.5, 0.5: 0}, loop=True) bs.animate(light, 'intensity', {0: 0, 0.25: 0.5, 0.5: 0}, loop=True)
ba.timer(1.0, light.delete) bs.timer(1.0, light.delete)
def _tick(self) -> None: def _tick(self) -> None:
@ -212,7 +215,7 @@ class InvicibleOneGame(ba.TeamGameActivity[Player, Team]):
# This shouldn't happen, but just in case. # This shouldn't happen, but just in case.
if not player.is_alive(): if not player.is_alive():
ba.print_error('got dead player as chosen one in _tick') babase.print_error('got dead player as chosen one in _tick')
self._set_invicible_one_player(None) self._set_invicible_one_player(None)
else: else:
scoring_team = player.team scoring_team = player.team
@ -229,9 +232,7 @@ class InvicibleOneGame(ba.TeamGameActivity[Player, Team]):
# announce numbers we have sounds for # announce numbers we have sounds for
if scoring_team.time_remaining in self._countdownsounds: if scoring_team.time_remaining in self._countdownsounds:
ba.playsound( self._countdownsounds[scoring_team.time_remaining].play()
self._countdownsounds[scoring_team.time_remaining])
# Winner! # Winner!
if scoring_team.time_remaining <= 0: if scoring_team.time_remaining <= 0:
self.end_game() self.end_game()
@ -242,11 +243,11 @@ class InvicibleOneGame(ba.TeamGameActivity[Player, Team]):
# (Chosen-one player ceasing to exist should # (Chosen-one player ceasing to exist should
# trigger on_player_leave which resets chosen-one) # trigger on_player_leave which resets chosen-one)
if self._invicible_one_player is not None: if self._invicible_one_player is not None:
ba.print_error('got nonexistent player as chosen one in _tick') babase.print_error('got nonexistent player as chosen one in _tick')
self._set_invicible_one_player(None) self._set_invicible_one_player(None)
def end_game(self) -> None: def end_game(self) -> None:
results = ba.GameResults() results = bs.GameResults()
for team in self.teams: for team in self.teams:
results.set_team_score(team, results.set_team_score(team,
self._invicible_one_time - team.time_remaining) self._invicible_one_time - team.time_remaining)
@ -256,7 +257,7 @@ class InvicibleOneGame(ba.TeamGameActivity[Player, Team]):
existing = self._get_invicible_one_player() existing = self._get_invicible_one_player()
if existing: if existing:
existing.chosen_light = None existing.chosen_light = None
ba.playsound(self._swipsound) self._swipsound.play()
if not player: if not player:
assert self._flag_spawn_pos is not None assert self._flag_spawn_pos is not None
self._flag = Flag(color=(1, 0.9, 0.2), self._flag = Flag(color=(1, 0.9, 0.2),
@ -266,7 +267,7 @@ class InvicibleOneGame(ba.TeamGameActivity[Player, Team]):
# Create a light to highlight the flag; # Create a light to highlight the flag;
# this will go away when the flag dies. # this will go away when the flag dies.
ba.newnode('light', bs.newnode('light',
owner=self._flag.node, owner=self._flag.node,
attrs={ attrs={
'position': self._flag_spawn_pos, 'position': self._flag_spawn_pos,
@ -287,18 +288,18 @@ class InvicibleOneGame(ba.TeamGameActivity[Player, Team]):
if self._invicible_one_is_lazy: if self._invicible_one_is_lazy:
player.actor.connect_controls_to_player( player.actor.connect_controls_to_player(
enable_punch=False, enable_pickup=False, enable_bomb=False) enable_punch=False, enable_pickup=False, enable_bomb=False)
if player.actor.node.torso_model != None: if player.actor.node.torso_mesh != None:
player.actor.node.color_mask_texture = None player.actor.node.color_mask_texture = None
player.actor.node.color_texture = None player.actor.node.color_texture = None
player.actor.node.head_model = None player.actor.node.head_mesh = None
player.actor.node.torso_model = None player.actor.node.torso_mesh = None
player.actor.node.upper_arm_model = None player.actor.node.upper_arm_mesh = None
player.actor.node.forearm_model = None player.actor.node.forearm_mesh = None
player.actor.node.pelvis_model = None player.actor.node.pelvis_mesh = None
player.actor.node.toes_model = None player.actor.node.toes_mesh = None
player.actor.node.upper_leg_model = None player.actor.node.upper_leg_mesh = None
player.actor.node.lower_leg_model = None player.actor.node.lower_leg_mesh = None
player.actor.node.hand_model = None player.actor.node.hand_mesh = None
player.actor.node.style = 'cyborg' player.actor.node.style = 'cyborg'
invi_sound = [] invi_sound = []
player.actor.node.jump_sounds = invi_sound player.actor.node.jump_sounds = invi_sound
@ -311,7 +312,7 @@ class InvicibleOneGame(ba.TeamGameActivity[Player, Team]):
player.actor.node.name = '' player.actor.node.name = ''
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)
player = msg.getplayer(Player) player = msg.getplayer(Player)

View file

@ -1,17 +1,20 @@
# ba_meta require api 7 # Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport)
# ba_meta require api 8
from typing import Sequence from typing import Sequence
import ba import babase
import _ba import bauiv1 as bui
import bascenev1 as bs
import _babase
import random import random
from bastd.actor.spaz import Spaz from bascenev1lib.actor.spaz import Spaz
from bastd.actor.scoreboard import Scoreboard from bascenev1lib.actor.scoreboard import Scoreboard
class Player(ba.Player['Team']): class Player(bs.Player['Team']):
"""Our player type for this game.""" """Our player type for this game."""
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:
@ -39,7 +42,7 @@ class ChooseingSpaz(Spaz):
super().__init__(color, highlight, "Spaz", None, True, True, False, False) super().__init__(color, highlight, "Spaz", None, True, True, False, False)
self.last_player_attacked_by = None self.last_player_attacked_by = None
self.stand(pos) self.stand(pos)
self.loc = ba.newnode( self.loc = bs.newnode(
'locator', 'locator',
attrs={ attrs={
'shape': 'circleOutline', 'shape': 'circleOutline',
@ -51,37 +54,37 @@ class ChooseingSpaz(Spaz):
}, },
) )
self.node.connectattr("position", self.loc, "position") self.node.connectattr("position", self.loc, "position")
ba.animate_array(self.loc, "size", 1, keys={0: [0.5,], 1: [2,], 1.5: [0.5]}, loop=True) bs.animate_array(self.loc, "size", 1, keys={0: [0.5,], 1: [2,], 1.5: [0.5]}, loop=True)
def handlemessage(self, msg): def handlemessage(self, msg):
if isinstance(msg, ba.FreezeMessage): if isinstance(msg, bs.FreezeMessage):
return return
if isinstance(msg, ba.PowerupMessage): if isinstance(msg, bs.PowerupMessage):
if not (msg.poweruptype == "health"): if not (msg.poweruptype == "health"):
return return
super().handlemessage(msg) super().handlemessage(msg)
if isinstance(msg, ba.HitMessage): if isinstance(msg, bs.HitMessage):
self.handlemessage(ba.PowerupMessage("health")) self.handlemessage(bs.PowerupMessage("health"))
player = msg.get_source_player(Player) player = msg.get_source_player(Player)
if self.is_alive(): if self.is_alive():
self.activity.handlemessage(ChooseingSpazHitMessage(player)) self.activity.handlemessage(ChooseingSpazHitMessage(player))
self.last_player_attacked_by = player self.last_player_attacked_by = player
elif isinstance(msg, ba.DieMessage): elif isinstance(msg, bs.DieMessage):
player = self.last_player_attacked_by player = self.last_player_attacked_by
if msg.how.value != ba.DeathType.GENERIC.value: if msg.how.value != bs.DeathType.GENERIC.value:
self._dead = True self._dead = True
self.activity.handlemessage(ChooseingSpazDieMessage(player)) self.activity.handlemessage(ChooseingSpazDieMessage(player))
self.loc.delete() self.loc.delete()
def stand(self, pos=(0, 0, 0), angle=0): def stand(self, pos=(0, 0, 0), angle=0):
self.handlemessage(ba.StandMessage(pos, angle)) self.handlemessage(bs.StandMessage(pos, angle))
def recolor(self, color, highlight=(1, 1, 1)): def recolor(self, color, highlight=(1, 1, 1)):
self.node.color = color self.node.color = color
@ -89,14 +92,14 @@ class ChooseingSpaz(Spaz):
self.loc.color = color self.loc.color = color
class ChooseBilbord(ba.Actor): class ChooseBilbord(bs.Actor):
def __init__(self, player: Player, delay=0.1) -> None: def __init__(self, player: Player, delay=0.1) -> None:
super().__init__() super().__init__()
icon = player.get_icon() icon = player.get_icon()
self.scale = 100 self.scale = 100
self.node = ba.newnode( self.node = bs.newnode(
'image', 'image',
delegate=self, delegate=self,
attrs={ attrs={
@ -111,13 +114,13 @@ class ChooseBilbord(ba.Actor):
}, },
) )
self.name_node = ba.newnode( self.name_node = bs.newnode(
'text', 'text',
owner=self.node, owner=self.node,
attrs={ attrs={
'position': (60, -185), 'position': (60, -185),
'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,
@ -128,26 +131,26 @@ class ChooseBilbord(ba.Actor):
}, },
) )
ba.animate_array(self.node, "scale", keys={ bs.animate_array(self.node, "scale", keys={
0 + delay: [0, 0], 0.05 + delay: [self.scale, self.scale]}, size=1) 0 + delay: [0, 0], 0.05 + delay: [self.scale, self.scale]}, size=1)
ba.animate(self.name_node, "scale", {0 + delay: 0, 0.07 + delay: 1}) bs.animate(self.name_node, "scale", {0 + delay: 0, 0.07 + delay: 1})
def handlemessage(self, msg): def handlemessage(self, msg):
super().handlemessage(msg) super().handlemessage(msg)
if isinstance(msg, ba.DieMessage): if isinstance(msg, bs.DieMessage):
ba.animate_array(self.node, "scale", keys={0: self.node.scale, 0.05: [0, 0]}, size=1) bs.animate_array(self.node, "scale", keys={0: self.node.scale, 0.05: [0, 0]}, size=1)
ba.animate(self.name_node, "scale", {0: self.name_node.scale, 0.07: 0}) bs.animate(self.name_node, "scale", {0: self.name_node.scale, 0.07: 0})
def __delete(): def __delete():
self.node.delete() self.node.delete()
self.name_node.delete() self.name_node.delete()
ba.timer(0.2, __delete) bs.timer(0.2, __delete)
# ba_meta export game # ba_meta export bascenev1.GameActivity
class LastPunchStand(ba.TeamGameActivity[Player, Team]): class LastPunchStand(bs.TeamGameActivity[Player, Team]):
name = "Last Punch Stand" name = "Last Punch Stand"
description = "Last one punchs the choosing spaz wins" description = "Last one punchs the choosing spaz wins"
tips = [ tips = [
@ -156,11 +159,11 @@ class LastPunchStand(ba.TeamGameActivity[Player, Team]):
"evry time you punch the choosing spaz, you will get one point", "evry time you punch the choosing spaz, you will get one point",
] ]
default_music = ba.MusicType.TO_THE_DEATH default_music = bs.MusicType.TO_THE_DEATH
available_settings = [ available_settings = [
ba.FloatSetting("min time limit (in seconds)", 50.0, min_value=30.0), bs.FloatSetting("min time limit (in seconds)", 50.0, min_value=30.0),
ba.FloatSetting("max time limit (in seconds)", 160.0, 60), bs.FloatSetting("max time limit (in seconds)", 160.0, 60),
] ]
@ -203,12 +206,12 @@ class LastPunchStand(ba.TeamGameActivity[Player, Team]):
super().on_begin() super().on_begin()
time_limit = random.randint(self._min_timelimit, self._max_timelimit) time_limit = random.randint(self._min_timelimit, self._max_timelimit)
self.spaw_bot() self.spaw_bot()
ba.timer(time_limit, self.times_up) bs.timer(time_limit, self.times_up)
self.setup_standard_powerup_drops(False) self.setup_standard_powerup_drops(False)
def end_game(self) -> None: def end_game(self) -> None:
results = ba.GameResults() results = bs.GameResults()
for team in self.teams: for team in self.teams:
if self.choosed_player and (team.id == self.choosed_player.team.id): if self.choosed_player and (team.id == self.choosed_player.team.id):
team.score += 100 team.score += 100
@ -261,7 +264,7 @@ class LastPunchStand(ba.TeamGameActivity[Player, Team]):
self.spaw_bot() self.spaw_bot()
self.change_choosed_player(None) self.change_choosed_player(None)
elif isinstance(msg, ba.PlayerDiedMessage): elif isinstance(msg, bs.PlayerDiedMessage):
player = msg.getplayer(Player) player = msg.getplayer(Player)
if not (self.has_ended() or self.times_uped): if not (self.has_ended() or self.times_uped):
self.respawn_player(player, 0) self.respawn_player(player, 0)

View file

@ -1,4 +1,5 @@
# ba_meta require api 7 # Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport)
# 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
@ -6,15 +7,17 @@ from __future__ import annotations
import random import random
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
import ba import babase
from bastd.actor.bomb import Bomb import bauiv1 as bui
from bastd.actor.onscreentimer import OnScreenTimer import bascenev1 as bs
from bascenev1lib.actor.bomb import Bomb
from bascenev1lib.actor.onscreentimer import OnScreenTimer
if TYPE_CHECKING: if TYPE_CHECKING:
from typing import Any, Sequence from typing import Any, Sequence
lang = ba.app.lang.language lang = bs.app.lang.language
if lang == 'Spanish': if lang == 'Spanish':
name = 'Lluvia de Meteoritos v2' name = 'Lluvia de Meteoritos v2'
@ -48,7 +51,7 @@ else:
random_rain = 'Random Rain' random_rain = 'Random Rain'
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:
@ -56,18 +59,18 @@ class Player(ba.Player['Team']):
self.death_time: float | None = None self.death_time: float | None = None
class Team(ba.Team[Player]): class Team(bs.Team[Player]):
"""Our team type for this game.""" """Our team type for this game."""
# ba_meta export game # ba_meta export bascenev1.GameActivity
class MeteorShowerv2Game(ba.TeamGameActivity[Player, Team]): class MeteorShowerv2Game(bs.TeamGameActivity[Player, Team]):
"""Minigame involving dodging falling bombs.""" """Minigame involving dodging falling bombs."""
name = name name = name
description = 'Dodge the falling bombs.' description = 'Dodge the falling bombs.'
scoreconfig = ba.ScoreConfig( scoreconfig = bs.ScoreConfig(
label='Survived', scoretype=ba.ScoreType.MILLISECONDS, version='B' label='Survived', scoretype=bs.ScoreType.MILLISECONDS, version='B'
) )
# Print messages when players die (since its meaningful in this game). # Print messages when players die (since its meaningful in this game).
@ -79,10 +82,10 @@ class MeteorShowerv2Game(ba.TeamGameActivity[Player, Team]):
@classmethod @classmethod
def get_available_settings( def get_available_settings(
cls, sessiontype: type[ba.Session] cls, sessiontype: type[bs.Session]
) -> list[ba.Setting]: ) -> list[babase.Setting]:
settings = [ settings = [
ba.IntChoiceSetting( bs.IntChoiceSetting(
bomb_type, bomb_type,
choices=[ choices=[
('normal', 0), ('normal', 0),
@ -95,22 +98,22 @@ class MeteorShowerv2Game(ba.TeamGameActivity[Player, Team]):
], ],
default=0, default=0,
), ),
ba.BoolSetting('Epic Mode', default=False), bs.BoolSetting('Epic Mode', default=False),
] ]
return settings return settings
# We're currently hard-coded for one map. # We're currently hard-coded for one map.
@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 ['Rampage'] return ['Rampage']
# We support teams, free-for-all, and co-op sessions. # We support teams, free-for-all, and co-op sessions.
@classmethod @classmethod
def supports_session_type(cls, sessiontype: type[ba.Session]) -> bool: def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool:
return ( return (
issubclass(sessiontype, ba.DualTeamSession) issubclass(sessiontype, bs.DualTeamSession)
or issubclass(sessiontype, ba.FreeForAllSession) or issubclass(sessiontype, bs.FreeForAllSession)
or issubclass(sessiontype, ba.CoopSession) or issubclass(sessiontype, bs.CoopSession)
) )
def __init__(self, settings: dict): def __init__(self, settings: dict):
@ -138,7 +141,7 @@ class MeteorShowerv2Game(ba.TeamGameActivity[Player, Team]):
# Some base class overrides: # Some base class overrides:
self.default_music = ( self.default_music = (
ba.MusicType.EPIC if self._epic_mode else ba.MusicType.SURVIVAL bs.MusicType.EPIC if self._epic_mode else bs.MusicType.SURVIVAL
) )
if self._epic_mode: if self._epic_mode:
self.slow_motion = True self.slow_motion = True
@ -152,19 +155,19 @@ class MeteorShowerv2Game(ba.TeamGameActivity[Player, Team]):
delay = 5.0 if len(self.players) > 2 else 2.5 delay = 5.0 if len(self.players) > 2 else 2.5
if self._epic_mode: if self._epic_mode:
delay *= 0.25 delay *= 0.25
ba.timer(delay, self._decrement_meteor_time, repeat=True) bs.timer(delay, self._decrement_meteor_time, repeat=True)
# Kick off the first wave in a few seconds. # Kick off the first wave in a few seconds.
delay = 3.0 delay = 3.0
if self._epic_mode: if self._epic_mode:
delay *= 0.25 delay *= 0.25
ba.timer(delay, self._set_meteor_timer) bs.timer(delay, self._set_meteor_timer)
self._timer = OnScreenTimer() self._timer = OnScreenTimer()
self._timer.start() self._timer.start()
# Check for immediate end (if we've only got 1 player, etc). # Check for immediate end (if we've only got 1 player, etc).
ba.timer(5.0, self._check_end_game) bs.timer(5.0, self._check_end_game)
def on_player_leave(self, player: Player) -> None: def on_player_leave(self, player: Player) -> None:
# Augment default behavior. # Augment default behavior.
@ -174,7 +177,7 @@ class MeteorShowerv2Game(ba.TeamGameActivity[Player, Team]):
self._check_end_game() self._check_end_game()
# overriding the default character spawning.. # overriding the default character spawning..
def spawn_player(self, player: Player) -> ba.Actor: def spawn_player(self, player: Player) -> bs.Actor:
spaz = self.spawn_player_spaz(player) spaz = self.spawn_player_spaz(player)
# Let's reconnect this player's controls to this # Let's reconnect this player's controls to this
@ -189,12 +192,12 @@ class MeteorShowerv2Game(ba.TeamGameActivity[Player, Team]):
# Various high-level game events come through this method. # Various high-level game events come through this method.
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)
curtime = ba.time() curtime = bs.time()
# Record the player's moment of death. # Record the player's moment of death.
# assert isinstance(msg.spaz.player # assert isinstance(msg.spaz.player
@ -204,15 +207,15 @@ class MeteorShowerv2Game(ba.TeamGameActivity[Player, Team]):
# (more accurate looking). # (more accurate looking).
# In teams/ffa, allow a one-second fudge-factor so we can # In teams/ffa, allow a one-second fudge-factor so we can
# get more draws if players die basically at the same time. # get more draws if players die basically at the same time.
if isinstance(self.session, ba.CoopSession): if isinstance(self.session, bs.CoopSession):
# Teams will still show up if we check now.. check in # Teams will still show up if we check now.. check in
# the next cycle. # the next cycle.
ba.pushcall(self._check_end_game) babase.pushcall(self._check_end_game)
# Also record this for a final setting of the clock. # Also record this for a final setting of the clock.
self._last_player_death_time = curtime self._last_player_death_time = curtime
else: else:
ba.timer(1.0, self._check_end_game) bs.timer(1.0, self._check_end_game)
else: else:
# Default handler: # Default handler:
@ -229,7 +232,7 @@ class MeteorShowerv2Game(ba.TeamGameActivity[Player, Team]):
# In co-op, we go till everyone is dead.. otherwise we go # In co-op, we go till everyone is dead.. otherwise we go
# until one team remains. # until one team remains.
if isinstance(self.session, ba.CoopSession): if isinstance(self.session, bs.CoopSession):
if living_team_count <= 0: if living_team_count <= 0:
self.end_game() self.end_game()
else: else:
@ -237,7 +240,7 @@ class MeteorShowerv2Game(ba.TeamGameActivity[Player, Team]):
self.end_game() self.end_game()
def _set_meteor_timer(self) -> None: def _set_meteor_timer(self) -> None:
ba.timer( bs.timer(
(1.0 + 0.2 * random.random()) * self._meteor_time, (1.0 + 0.2 * random.random()) * self._meteor_time,
self._drop_bomb_cluster, self._drop_bomb_cluster,
) )
@ -248,10 +251,10 @@ class MeteorShowerv2Game(ba.TeamGameActivity[Player, Team]):
# and debug things. # and debug things.
loc_test = False loc_test = False
if loc_test: if loc_test:
ba.newnode('locator', attrs={'position': (8, 6, -5.5)}) bs.newnode('locator', attrs={'position': (8, 6, -5.5)})
ba.newnode('locator', attrs={'position': (8, 6, -2.3)}) bs.newnode('locator', attrs={'position': (8, 6, -2.3)})
ba.newnode('locator', attrs={'position': (-7.3, 6, -5.5)}) bs.newnode('locator', attrs={'position': (-7.3, 6, -5.5)})
ba.newnode('locator', attrs={'position': (-7.3, 6, -2.3)}) bs.newnode('locator', attrs={'position': (-7.3, 6, -2.3)})
# Drop several bombs in series. # Drop several bombs in series.
delay = 0.0 delay = 0.0
@ -269,7 +272,7 @@ class MeteorShowerv2Game(ba.TeamGameActivity[Player, Team]):
random.uniform(-3.066, -4.12), random.uniform(-3.066, -4.12),
0, 0,
) )
ba.timer(delay, ba.Call(self._drop_bomb, pos, vel)) bs.timer(delay, babase.Call(self._drop_bomb, pos, vel))
delay += 0.1 delay += 0.1
self._set_meteor_timer() self._set_meteor_timer()
@ -294,7 +297,7 @@ class MeteorShowerv2Game(ba.TeamGameActivity[Player, Team]):
self._meteor_time = max(0.01, self._meteor_time * 0.9) self._meteor_time = max(0.01, self._meteor_time * 0.9)
def end_game(self) -> None: def end_game(self) -> None:
cur_time = ba.time() cur_time = bs.time()
assert self._timer is not None assert self._timer is not None
start_time = self._timer.getstarttime() start_time = self._timer.getstarttime()
@ -325,7 +328,7 @@ class MeteorShowerv2Game(ba.TeamGameActivity[Player, Team]):
# Ok now calc game results: set a score for each team and then tell # Ok now calc game results: set a score for each team and then tell
# the game to end. # the game to end.
results = ba.GameResults() results = bs.GameResults()
# Remember that 'free-for-all' mode is simply a special form # Remember that 'free-for-all' mode is simply a special form
# of 'teams' mode where each player gets their own team, so we can # of 'teams' mode where each player gets their own team, so we can
@ -346,58 +349,58 @@ class MeteorShowerv2Game(ba.TeamGameActivity[Player, Team]):
# ba_meta export plugin # ba_meta export plugin
class MeteorShowerv2Coop(ba.Plugin): class MeteorShowerv2Coop(babase.Plugin):
def on_app_running(self) -> None: def on_app_running(self) -> None:
ba.app.add_coop_practice_level( babase.app.classic.add_coop_practice_level(
ba.Level( bs._level.Level(
normal_rain, normal_rain,
gametype=MeteorShowerv2Game, gametype=MeteorShowerv2Game,
settings={bomb_type: 0}, settings={bomb_type: 0},
preview_texture_name='rampagePreview', preview_texture_name='rampagePreview',
) )
) )
ba.app.add_coop_practice_level( babase.app.classic.add_coop_practice_level(
ba.Level( bs._level.Level(
frozen_rain, frozen_rain,
gametype=MeteorShowerv2Game, gametype=MeteorShowerv2Game,
settings={bomb_type: 1}, settings={bomb_type: 1},
preview_texture_name='rampagePreview', preview_texture_name='rampagePreview',
) )
) )
ba.app.add_coop_practice_level( babase.app.classic.add_coop_practice_level(
ba.Level( bs._level.Level(
sticky_rain, sticky_rain,
gametype=MeteorShowerv2Game, gametype=MeteorShowerv2Game,
settings={bomb_type: 2}, settings={bomb_type: 2},
preview_texture_name='rampagePreview', preview_texture_name='rampagePreview',
) )
) )
ba.app.add_coop_practice_level( babase.app.classic.add_coop_practice_level(
ba.Level( bs._level.Level(
impact_rain, impact_rain,
gametype=MeteorShowerv2Game, gametype=MeteorShowerv2Game,
settings={bomb_type: 3}, settings={bomb_type: 3},
preview_texture_name='rampagePreview', preview_texture_name='rampagePreview',
) )
) )
ba.app.add_coop_practice_level( babase.app.classic.add_coop_practice_level(
ba.Level( bs._level.Level(
mine_rain, mine_rain,
gametype=MeteorShowerv2Game, gametype=MeteorShowerv2Game,
settings={bomb_type: 4}, settings={bomb_type: 4},
preview_texture_name='rampagePreview', preview_texture_name='rampagePreview',
) )
) )
ba.app.add_coop_practice_level( babase.app.classic.add_coop_practice_level(
ba.Level( bs._level.Level(
tnt_rain, tnt_rain,
gametype=MeteorShowerv2Game, gametype=MeteorShowerv2Game,
settings={bomb_type: 5}, settings={bomb_type: 5},
preview_texture_name='rampagePreview', preview_texture_name='rampagePreview',
) )
) )
ba.app.add_coop_practice_level( babase.app.classic.add_coop_practice_level(
ba.Level( bs._level.Level(
random_rain, random_rain,
gametype=MeteorShowerv2Game, gametype=MeteorShowerv2Game,
settings={bomb_type: 6}, settings={bomb_type: 6},

View file

@ -0,0 +1,441 @@
# Usage: port_7_to_8.py <client/server type of mod> <plugin-name>
# You'll have to manually update the following:
# with ba.Context(_ba.foreground_host_activity()):
# To:
# with _ba.foreground_host_activity().context:
#
# ba.time(timeformat=ba.TimeFormat.MILLISECONDS)
# To:
# ba.time() * 1000
#
# ba.Timer((POWERUP_WEAR_OFF_TIME - 2000),ba.WeakCall(self._multi_bomb_wear_off_flash),timeformat=ba.TimeFormat.MILLISECONDS)
# To:
# ba.Timer((POWERUP_WEAR_OFF_TIME - 2000 / 1000),ba.WeakCall(self._multi_bomb_wear_off_flash))
import re
import sys
import codecs
def detect_encoding(filename):
encodings = ['utf-8', 'latin-1', 'ascii', 'cp1252']
for encoding in encodings:
try:
with open(filename, 'rb') as f:
f.read().decode(encoding)
return encoding
except UnicodeDecodeError:
pass
return None
filename = sys.argv[2]
encoding = detect_encoding(filename)
if encoding:
with open(filename, 'r', encoding=encoding) as f:
print("Porting "+ sys.argv[2])
content = f.read()
else:
print('Could not detect encoding')
content = content.replace("# ba_meta require api 7", "# ba_meta require api 8")
content = content.replace("# ba_meta export game", "# ba_meta export bascenev1.GameActivity")
content = content.replace("user_agent_string", "legacy_user_agent_string")
content = re.sub(r'^(import\s+[\w]+(\s*,\s*[\w]+)+)', lambda match: re.sub(r'\s*,\s*', '\nimport ', match.group()), content, flags=re.MULTILINE)
content = content.replace("_ba.", "_babase.")
content = content.replace("_ba.", "_babase.")
content = content.replace("ba.", "babase.")
content = content.replace("import _ba", "import _babase")
content = content.replace("from ba import", "from babase import")
content = content.replace("from _ba import", "from _babase import")
content = re.sub(r'\bimport _ba\b', "import _babase", content)
content = re.sub(r'\bimport ba(\b|\.(\w+))', "import babase\nimport bauiv1\nimport bascenev1", content)
match = re.search(r'^(import\s+[\w]+(\s*,\s*[\w]+)*)', content, flags=re.MULTILINE)
affected_methods = ["build_number", "device_name", "config_file_path", "version", "debug_build", "test_build", "data_directory", "python_directory_user", "python_directory_app", "python_directory_app_site", "api_version", "on_tv", "vr_mode","toolbar_test", "arcade_test", "headless_mode", "demo_mode", "protocol_version", "get_connection_to_host_info"]
for word in affected_methods:
if f".{word}" in content:
first_import_index = match.start()
content = content[:first_import_index] + 'from baenv import TARGET_BALLISTICA_BUILD as build_number\n' + content[first_import_index:]
content = content.replace("babase.app.ui", "bauiv1.app.ui_v1")
content = content.replace("babase.app.accounts_v1", "bauiv1.app.classic.accounts")
###################################################################################
# Comment out one of these as per your requirements, depending whether to
# stay local or if it'll also be needed to transmitted to the clients.
## For local:
if sys.argv[1] == "client":
content = content.replace("_babase.screenmessage", "bauiv1.screenmessage")
content = content.replace("babase.screenmessage", "bauiv1.screenmessage")
content = content.replace("babase.getsound", "bauiv1.getsound")
content = content.replace("_babase.gettexture", "bauiv1.gettexture")
content = content.replace("babase.gettexture", "bauiv1.gettexture")
content = content.replace("babase.getmesh", "bauiv1.getmesh")
content = content.replace("babase.getcollisionmesh", "bauiv1.getcollisionmesh")
else:
## For transmission:
content = content.replace("_babase.screenmessage", "bascenev1.broadcastmessage")
content = content.replace("babase.screenmessage", "bascenev1.broadcastmessage")
content = content.replace("babase.getsound", "bascenev1.getsound")
content = content.replace("_babase.gettexture", "bascenev1.gettexture")
content = content.replace("babase.gettexture", "bascenev1.gettexture")
content = content.replace("babase.getmesh", "bascenev1.getmesh")
content = content.replace("babase.getcollisionmesh", "bascenev1.getcollisionmesh")
###################################################################################
content = content.replace("babase.getcollidemesh", "bascenev1.getcollisionmesh")
content = content.replace("collide_mesh", "collision_mesh")
content = content.replace("babase.open_url", "bauiv1.open_url")
content = content.replace("babase.IntSetting", "bascenev1.IntSetting")
content = content.replace("babase.IntChoiceSetting", "bascenev1.IntChoiceSetting")
content = content.replace("babase.FloatChoiceSetting", "bascenev1.FloatChoiceSetting")
content = content.replace("babase.BoolSetting", "bascenev1.BoolSetting")
content = content.replace("babase.Actor", "bascenev1.Actor")
content = content.replace("babase.Player", "bascenev1.Player")
content = content.replace("babase.PlayerDiedMessage", "bascenev1.PlayerDiedMessage")
content = content.replace("babase.time", "bascenev1.time")
content = content.replace("babase.Timer", "bascenev1.Timer")
content = content.replace("babase.newnode", "bascenev1.newnode")
content = content.replace("babase.Node", "bascenev1.Node")
content = content.replace("babase.emitfx", "bascenev1.emitfx")
content = content.replace("babase.animate", "bascenev1.animate")
content = content.replace("babase.FreeForAllSession", "bascenev1.FreeForAllSession")
content = content.replace("babase.DualTeamSession", "bascenev1.DualTeamSession")
content = content.replace("babase.MultiTeamSession", "bascenev1.MultiTeamSession")
content = content.replace("babase.EndSession", "bascenev1.EndSession")
content = content.replace("babase.CoopSession", "bascenev1.CoopSession")
content = content.replace("babase.TeamGameActivity", "bascenev1.TeamGameActivity")
content = content.replace("babase.Team", "bascenev1.Team")
content = content.replace("babase.Session", "bascenev1.Session")
content = content.replace("babase.getsession", "bascenev1.getsession")
content = content.replace("babase.Material", "bascenev1.Material")
content = content.replace("babase.WeakCall", "bascenev1.WeakCall")
content = content.replace("babase.DieMessage", "bascenev1.DieMessage")
content = content.replace("babase.OutOfBoundsMessage", "bascenev1.OutOfBoundsMessage")
content = content.replace("babase.DroppedMessage", "bascenev1.DroppedMessage")
content = content.replace("babase.HitMessage", "bascenev1.HitMessage")
content = content.replace("babase.ThawMessage", "bascenev1.ThawMessage")
content = content.replace("babase.NotFoundError", "bascenev1.NotFoundError")
content = content.replace("babase.getcollision", "bascenev1.getcollision")
content = content.replace("babase.app.lang", "bascenev1.app.lang")
content = content.replace("babase.MusicType", "bascenev1.MusicType")
content = content.replace("babase.getactivity", "bascenev1.getactivity")
content = content.replace("babase.getactivity", "bascenev1.getactivity")
content = content.replace("babase.CelebrateMessage", "bascenev1.CelebrateMessage")
content = content.replace("babase.ScoreConfig", "bascenev1.ScoreConfig")
content = content.replace("babase.ScoreType", "bascenev1.ScoreType")
content = content.replace("babase.GameResults", "bascenev1.GameResults")
content = content.replace("babase.getmaps", "bascenev1.app.classic.getmaps")
content = content.replace("babase.cameraflash", "bascenev1.cameraflash")
content = content.replace("babase.getmodel", "bascenev1.getmesh")
content = content.replace("babase.Map", "bascenev1.Map")
content = content.replace("babase.DeathType", "bascenev1.DeathType")
content = content.replace("babase.GameActivity", "bascenev1.GameActivity")
content = content.replace("_babase.app.stress_test_reset_timer", "_babase.app.classic.stress_test_reset_timer")
content = content.replace("babase.app.stress_test_reset_timer", "_babase.app.classic.stress_test_reset_timer")
content = content.replace("babase._map", "bascenev1._map")
content = content.replace("babase._session.", "bascenev1._session.")
content = content.replace("babase._activity", "bascenev1._activity")
content = content.replace("_babase.get_client_public_device_uuid", "_bascenev1.get_client_public_device_uuid")
content = content.replace("babase.PickedUpMessage", "bascenev1.PickedUpMessage")
content = content.replace("babase.PowerupMessage", "bascenev1.PowerupMessage")
content = content.replace("babase.FreezeMessage", "bascenev1.FreezeMessage")
content = content.replace("with babase.ContextRef(activity):", "with activity.context:")
content = content.replace("babase.Context", "babase.ContextRef")
content = content.replace("babase._dualteamsession", "bascenev1._dualteamsession")
content = content.replace("babase._freeforallsession", "bascenev1._freeforallsession")
content = content.replace("babase._multiteamsession", "bascenev1._multiteamsession")
content = content.replace("babase._gameactivity", "bascenev1._gameactivity")
content = content.replace("babase._powerup", "bascenev1._powerup")
content = content.replace("babase.Chooser", "bascenev1.Chooser")
content = content.replace("babase._lobby", "bascenev1._lobby")
content = content.replace("babase._stats", "bascenev1._stats")
content = content.replace("babase._team", "bascenev1._team")
content = content.replace("PlayerType", "PlayerT")
content = content.replace("babase.app.spaz_appearances", "babase.app.classic.spaz_appearances")
content = content.replace("babase._coopsession", "bascenev1._coopsession")
content = content.replace("babase._servermode", "baclassic._servermode")
content = content.replace("_babase.app.server", "babase.app.classic.server")
content = content.replace("_babase.chatmessage", "bascenev1.chatmessage")
content = content.replace("_babase.disconnect_client", "_bascenev1.disconnect_client")
content = content.replace("_babase.get_game_roster", "bascenev1.get_game_roster")
content = content.replace("_babase.get_public_party_max_size", "bascenev1.get_public_party_max_size")
content = content.replace("_babase.new_host_session", "bascenev1.new_host_session")
content = content.replace("babase._playlist", "bascenev1._playlist")
content = content.replace("model", "mesh")
content = content.replace("TimeType.REAL", "use `bascenev1.apptimer` in `activity.context` instead")
content = content.replace("_babase.app.coop_session_args", "babase.app.classic.coop_session_args")
content = content.replace("_babase.app.campaigns", "babase.app.classic.campaigns")
content = content.replace("_babase.newactivity", "bascenev1.newactivity")
content = content.replace("babase.Window", "bauiv1.Window")
content = content.replace("babase.Widget", "bauiv1.Widget")
content = content.replace("babase.widget", "bauiv1.widget")
content = content.replace("babase.containerwidget", "bauiv1.containerwidget")
content = content.replace("babase.scrollwidget", "bauiv1.scrollwidget")
content = content.replace("babase.buttonwidget", "bauiv1.buttonwidget")
content = content.replace("babase.textwidget", "bauiv1.textwidget")
content = content.replace("babase.checkboxwidget", "bauiv1.checkboxwidget")
content = content.replace("babase.imagewidget", "bauiv1.imagewidget")
content = content.replace("babase.uicleanupcheck", "bauiv1.uicleanupcheck")
content = content.replace("_babase.set_public_party_max_size", "bascenev1.set_public_party_max_size")
content = content.replace("_bauiv1", "bauiv1")
content = content.replace("babase.show_damage_count", "bascenev1.show_damage_count")
content = content.replace("babase._gameutils", "bascenev1._gameutils")
content = content.replace("babase.StandMessage", "bascenev1.StandMessage")
content = content.replace("babase.PowerupAcceptMessage", "bascenev1.PowerupAcceptMessage")
content = content.replace("babase._gameutils", "bascenev1._gameutils")
content = content.replace("babase.camerashake", "bascenev1.camerashake")
content = content.replace("babase.app.add_coop_practice_level", "babase.app.classic.add_coop_practice_level")
content = content.replace("babase._campaign", "bascenev1._campaign")
content = content.replace("babase.Level", "bascenev1._level.Level")
content = content.replace("babase.app.cloud.send_message_cb", "bauiv1.app.plus.cloud.send_message_cb")
content = content.replace("_babase.get_special_widget", "bauiv1.get_special_widget")
content = content.replace(".app.platform", ".app.classic.platform")
content = content.replace(".app.subplatform", ".app.classic.subplatform")
content = content.replace(".getlog", ".get_v1_cloud_log")
# Converting `ba.playsound(abc)` to `abc.play()` is tricky.
# Do it manually in case regex substitution fails.# Do it manually in case regex substitution fails. Are you sure!!
#! FIXME May cause syntax warning on 3.12
content = re.sub(
r'babase\.playsound\(\s*([^,\n]+),\s*([^,\n]+)\)',
r'\1.play(\2)',
content,
flags=re.MULTILINE
)
content = re.sub(
r'babase\.playsound\(\s*([^,\n]+),\s*([^,\n]+),\s*position=([^,\n]+)\)',
r'\1.play(\2, position=\3)',
content,
flags=re.MULTILINE
)
content = re.sub("babase\.playsound\((.+?), (.+?), (.+?)\)", "\\1.play(\\2, \\3)", content)
content = re.sub(
r'babase\.playsound\(([^,\n]+),\s*position=([^,\n]+)\)',
r'\1.play(position=\2)',
content
)
content = re.sub("babase\.playsound\((.*)\)", "\\1.play()", content)
content = content.replace("babase.internal.add_transaction", "bauiv1.app.plus.add_v1_account_transaction")
content = content.replace("babase.internal.run_transaction", "bauiv1.app.plus.run_v1_account_transaction")
content = content.replace("_babase.add_transaction", "bauiv1.app.plus.add_v1_account_transaction")
content = content.replace("_babase.run_transactions", "bauiv1.app.plus.run_v1_account_transactions")
content = content.replace("babase._store.get_store_layout", "bauiv1.app.classic.store.get_store_layout")
content = content.replace("babase.internal.get_store_layout", "bauiv1.app.classic.store.get_store_layout")
content = content.replace("babase.internal.connect_to_party", "bascenev1.connect_to_party")
content = content.replace("babase.internal.get_default_powerup_distribution", "bascenev1._powerup.get_default_powerup_distribution")
content = content.replace("babase.internal.DEFAULT_REQUEST_TIMEOUT_SECONDS", "babase.DEFAULT_REQUEST_TIMEOUT_SECONDS")
content = content.replace("babase.internal.DEFAULT_TEAM_COLORS", "bascenev1.DEFAULT_TEAM_COLORS")
content = content.replace("babase.internal.DEFAULT_TEAM_NAMES", "bascenev1.DEFAULT_TEAM_NAMES")
content = content.replace("babase.internal.JoinActivity", "bascenev1.JoinActivity")
content = content.replace("babase.internal.LoginAdapter", "babase._login.LoginAdapter")
content = content.replace("babase.internal.PlayerProfilesChangedMessage", "bascenev1._messages.PlayerProfilesChangedMessage")
content = content.replace("babase.internal.ScoreScreenActivity", "bascenev1.ScoreScreenActivity")
content = content.replace("babase.internal.add_clean_frame_callback", "babase.add_clean_frame_callback")
content = content.replace("babase.internal.android_get_external_files_dir", "babase.android_get_external_files_dir")
content = content.replace("babase.internal.appname", "babase.appname")
content = content.replace("babase.internal.appnameupper", "babase.appnameupper")
content = content.replace("babase.internal.capture_gamepad_input", "bascenev1.capture_gamepad_input")
content = content.replace("babase.internal.capture_keyboard_input", "bascenev1.capture_keyboard_input")
content = content.replace("babase.internal.charstr", "babase.charstr")
content = content.replace("babase.internal.chatmessage", "bascenev1.chatmessage")
content = content.replace("babase.internal.commit_app_config", "bauiv1.commit_app_config")
content = content.replace("babase.internal.disconnect_client", "bascenev1.disconnect_client")
content = content.replace("babase.internal.disconnect_from_host", "bascenev1.disconnect_from_host")
content = content.replace("babase.internal.do_play_music", "babase.app.classic.music.do_play_music")
content = content.replace("babase.internal.end_host_scanning", "bascenev1.end_host_scanning")
content = content.replace("babase.internal.fade_screen", "bauiv1.fade_screen")
content = content.replace("babase.internal.filter_playlist", "bascenev1.filter_playlist")
content = content.replace("babase.internal.game_service_has_leaderboard", "_baplus.game_service_has_leaderboard")
content = content.replace("babase.internal.get_available_purchase_count", "bauiv1.app.classic.store.get_available_purchase_count")
content = content.replace("babase.internal.get_available_sale_time", "bauiv1.app.classic.store.get_available_sale_time")
content = content.replace("babase.internal.get_chat_messages", "bascenev1.get_chat_messages")
content = content.replace("babase.internal.get_clean_price", "bauiv1.app.classic.store.get_clean_price")
content = content.replace("babase.internal.get_connection_to_host_info", "bascenev1.get_connection_to_host_info_2")
content = content.replace("babase.internal.get_default_free_for_all_playlist", "bascenev1._playlist.get_default_free_for_all_playlist")
content = content.replace("babase.internal.get_default_teams_playlist", "bascenev1._playlist.get_default_teams_playlist")
content = content.replace("babase.internal.get_display_resolution", "babase.get_display_resolution")
content = content.replace("babase.internal.get_filtered_map_name", "bascenev1._map.get_filtered_map_name")
content = content.replace("babase.internal.get_foreground_host_session", "bascenev1.get_foreground_host_session")
content = content.replace("babase.internal.get_game_port", "bascenev1.get_game_port")
content = content.replace("babase.internal.get_game_roster", "bascenev1.get_game_roster")
content = content.replace("babase.internal.get_input_device_config", "bauiv1.app.classic.get_input_device_config")
content = content.replace("babase.internal.get_ip_address_type", "babase.get_ip_address_type")
content = content.replace("babase.internal.get_local_active_input_devices_count", "bascenev1.get_local_active_input_devices_count")
content = content.replace("babase.internal.get_low_level_config_value", "bauiv1.get_low_level_config_value")
content = content.replace("babase.internal.get_map_class", "bascenev1.get_map_class")
content = content.replace("babase.internal.get_map_display_string", "bascenev1.get_map_display_string")
content = content.replace("babase.internal.get_master_server_address", "bauiv1.app.plus.get_master_server_address")
content = content.replace("babase.internal.get_max_graphics_quality", "babase.get_max_graphics_quality")
content = content.replace("babase.internal.get_news_show", "_babase.app.plus.get_news_show")
content = content.replace("babase.internal.get_next_tip", "bascenev1.app.classic.get_next_tip")
content = content.replace("babase.internal.get_player_colors", "bascenev1.get_player_colors")
content = content.replace("babase.internal.get_player_profile_colors", "bascenev1.get_player_profile_colors")
content = content.replace("babase.internal.get_player_profile_icon", "bascenev1.get_player_profile_icon")
content = content.replace("babase.internal.get_price", "bauiv1.app.plus.get_price")
content = content.replace("babase.internal.get_public_party_enabled", "bascenev1.get_public_party_enabled")
content = content.replace("babase.internal.get_public_party_max_size", "bascenev1.get_public_party_max_size")
content = content.replace("babase.internal.get_purchased", "bauiv1.app.plus.get_purchased")
content = content.replace("babase.internal.get_purchases_state", "_baplus.get_purchases_state")
content = content.replace("babase.internal.get_qrcode_texture", "bauiv1.get_qrcode_texture")
content = content.replace("babase.internal.get_random_names", "bascenev1.get_random_names")
content = content.replace("babase.internal.get_remote_app_name", "bascenev1.get_remote_app_name")
content = content.replace("babase.internal.get_replay_speed_exponent", "bascenev1.get_replay_speed_exponent")
content = content.replace("babase.internal.get_replays_dir", "babase.get_replays_dir")
content = content.replace("babase.internal.get_special_widget", "bauiv1.get_special_widget")
content = content.replace("babase.internal.get_store_item", "babase.app.classic.store.get_store_item")
content = content.replace("babase.internal.get_store_item_display_size", "babase.app.classic.store.get_store_item_display_size")
content = content.replace("babase.internal.get_store_item_name_translated", "babase.app.classic.store.get_store_item_name_translated")
content = content.replace("babase.internal.get_string_height", "babase.get_string_height")
content = content.replace("babase.internal.get_string_width", "babase.get_string_width")
content = content.replace("babase.internal.get_tournament_prize_strings", "bascenev1.app.classic.get_tournament_prize_strings")
content = content.replace("babase.internal.get_trophy_string", "bascenev1.get_trophy_string")
content = content.replace("babase.internal.get_type_name", "babase.get_type_name")
content = content.replace("babase.internal.get_ui_input_device", "bascenev1.get_ui_input_device")
content = content.replace("babase.internal.get_unowned_game_types", "babase.app.classic.store.get_unowned_game_types")
content = content.replace("babase.internal.get_unowned_maps", "babase.app.classic.store.get_unowned_maps")
content = content.replace("babase.internal.get_v1_account_display_string", "bauiv1.app.plus.get_v1_account_display_string")
content = content.replace("babase.internal.get_v1_account_misc_read_val", "bauiv1.app.plus.get_v1_account_misc_read_val")
content = content.replace("babase.internal.get_v1_account_misc_read_val_2", "bauiv1.app.plus.get_v1_account_misc_read_val_2")
content = content.replace("babase.internal.get_v1_account_misc_val", "bauiv1.app.plus.get_v1_account_misc_val")
content = content.replace("babase.internal.get_v1_account_name", "bauiv1.app.plus.get_v1_account_name")
content = content.replace("babase.internal.get_v1_account_state", "bauiv1.app.plus.get_v1_account_state")
content = content.replace("babase.internal.get_v1_account_state_num", "bauiv1.app.plus.get_v1_account_state_num")
content = content.replace("babase.internal.get_v1_account_ticket_count", "bauiv1.app.plus.get_v1_account_ticket_count")
content = content.replace("babase.internal.get_v1_account_type", "bauiv1.app.plus.get_v1_account_type")
content = content.replace("babase.internal.get_v2_fleet", "_baplus.get_v2_fleet")
content = content.replace("babase.internal.getcampaign", "bauiv1.app.classic.getcampaign")
content = content.replace("babase.internal.getclass", "babase.getclass")
content = content.replace("babase.internal.getinputdevice", "bascenev1.getinputdevice")
content = content.replace("babase.internal.has_gamma_control", "babase.has_gamma_control")
content = content.replace("babase.internal.has_video_ads", "bauiv1.has_video_ads")
content = content.replace("babase.internal.have_incentivized_ad", "bauiv1.have_incentivized_ad")
content = content.replace("babase.internal.have_permission", "babase.have_permission")
content = content.replace("babase.internal.have_touchscreen_input", "bascenev1.have_touchscreen_input")
content = content.replace("babase.internal.host_scan_cycle", "bascenev1.host_scan_cycle")
content = content.replace("babase.internal.in_game_purchase", "bui.app.plus.in_game_purchase")
content = content.replace("babase.internal.increment_analytics_count", "babase.increment_analytics_count")
content = content.replace("babase.internal.is_blessed", "bui.app.plus.is_blessed")
content = content.replace("babase.internal.is_browser_likely_available", "bauiv1.is_browser_likely_available")
content = content.replace("babase.internal.is_in_replay", "bascenev1.is_in_replay")
content = content.replace("babase.internal.is_party_icon_visible", "bauiv1.is_party_icon_visible")
content = content.replace("babase.internal.is_running_on_fire_tv", "babase.is_running_on_fire_tv")
content = content.replace("babase.internal.is_xcode_build", "babase.is_xcode_build")
content = content.replace("babase.internal.json_prep", "babase.json_prep")
content = content.replace("babase.internal.lock_all_input", "babase.lock_all_input")
content = content.replace("babase.internal.mark_config_dirty", "_babase.app.plus.mark_config_dirty")
content = content.replace("babase.internal.new_host_session", "bascenev1.new_host_session")
content = content.replace("babase.internal.new_replay_session", "bascenev1.new_replay_session")
content = content.replace("babase.internal.open_file_externally", "bauiv1.open_file_externally")
content = content.replace("babase.internal.power_ranking_query", "_baplus.power_ranking_query")
content = content.replace("babase.internal.preload_map_preview_media", "bauiv1.app.classic.preload_map_preview_media")
content = content.replace("babase.internal.purchase", "_baplus.purchase")
content = content.replace("babase.internal.register_map", "bascenev1.register_map")
content = content.replace("babase.internal.release_gamepad_input", "bascenev1.release_gamepad_input")
content = content.replace("babase.internal.release_keyboard_input", "bascenev1.release_keyboard_input")
content = content.replace("babase.internal.report_achievement", "babase.app.plus.report_achievement")
content = content.replace("babase.internal.request_permission", "babase.request_permission")
content = content.replace("babase.internal.reset_achievements", "_baplus.reset_achievements")
content = content.replace("babase.internal.reset_random_player_names", "bascenev1.reset_random_player_names")
content = content.replace("babase.internal.restore_purchases", "_baplus.restore_purchases")
content = content.replace("babase.internal.run_cpu_benchmark", "baclassic._benchmark.run_cpu_benchmark")
content = content.replace("babase.internal.run_gpu_benchmark", "baclassic._benchmark.run_gpu_benchmark")
content = content.replace("babase.internal.run_media_reload_benchmark", "baclassic._benchmark.run_media_reload_benchmark")
content = content.replace("babase.internal.run_stress_test", "babase.app.classic.run_stress_test")
content = content.replace("babase.internal.set_authenticate_clients", "bascenev1.set_authenticate_clients")
content = content.replace("babase.internal.set_debug_speed_exponent", "bascenev1.set_debug_speed_exponent")
content = content.replace("babase.internal.set_low_level_config_value", "babase.set_low_level_config_value")
content = content.replace("babase.internal.set_party_icon_always_visible", "bauiv1.set_party_icon_always_visible")
content = content.replace("babase.internal.set_party_window_open", "bauiv1.set_party_window_open")
content = content.replace("babase.internal.set_public_party_enabled", "bascenev1.set_public_party_enabled")
content = content.replace("babase.internal.set_public_party_max_size", "bascenev1.set_public_party_max_size")
content = content.replace("babase.internal.set_public_party_name", "bascenev1.set_public_party_name")
content = content.replace("babase.internal.set_public_party_queue_enabled", "bascenev1.set_public_party_queue_enabled")
content = content.replace("babase.internal.set_replay_speed_exponent", "bascenev1.set_replay_speed_exponent")
content = content.replace("babase.internal.set_touchscreen_editing", "bascenev1.set_touchscreen_editing")
content = content.replace("babase.internal.set_ui_input_device", "babase.set_ui_input_device")
content = content.replace("babase.internal.should_submit_debug_info", "babase._apputils.should_submit_debug_info")
content = content.replace("babase.internal.show_online_score_ui", "bauiv1.show_online_score_ui")
content = content.replace("babase.internal.sign_in_v1", "babase.app.plus.sign_in_v1")
content = content.replace("babase.internal.sign_out_v1", "babase.app.plus.sign_out_v1")
content = content.replace("babase.internal.submit_score", "bascenev1.app.plus.submit_score")
content = content.replace("babase.internal.tournament_query", "_baplus.tournament_query")
content = content.replace("babase.internal.unlock_all_input", "babase.unlock_all_input")
content = content.replace("babase.internal.value_test", "bauiv1.app.classic.value_test")
content = content.replace("babase.internal.workspaces_in_use", "babase.workspaces_in_use")
content = content.replace("babase.internal.dump_tracebacks", "babase._apputils.dump_app_state")
content = content.replace("babase.internal.show_app_invite", "_bauiv1.show_app_invite")
content = content.replace("babase._generated", "babase._mgen")
content = content.replace("_babase.disconnect_from_host", "bascenev1.disconnect_from_host")
content = content.replace("babase.disconnect_from_host", "bascenev1.disconnect_from_host")
content = content.replace("_babase.connect_to_party", "bascenev1.connect_to_party")
content = content.replace("babase.connect_to_party", "bascenev1.connect_to_party")
content = content.replace("babase.set_party_window_open", "bauiv1.set_party_window_open")
content = content.replace("babase.set_party_window_open", "bauiv1.set_party_window_open")
content = content.replace("babase.getcollidemesh", "bascenev1.getcollisionmesh")
content = content.replace("collide_mesh", "collision_mesh")
content = content.replace("babase.FloatSetting", "bascenev1.FloatSetting")
# Removed in API 8:
# content = content.replace("babase.internal.set_telnet_access_enabled", "")
content = content.replace("babase.internal.master_server_get", "babase.app.classic.master_server_v1_get")
content = content.replace("babase.internal.master_server_post", "babase.app.classic.master_server_v1_post")
content = content.replace("babase.internal.log_dumped_tracebacks", "babase._apputils.log_dumped_app_state")
content = content.replace("babase.internal.have_outstanding_transactions", "bauiv1.app.plus.have_outstanding_v1_account_transactions")
content = content.replace("babase.internal.get_public_login_id", "bauiv1.app.plus.get_v1_account_public_login_id")
content = content.replace("babase.internal.get_input_map_hash", "bauiv1.app.classic.get_input_device_map_hash")
content = content.replace("babase.internal.get_device_value", "bauiv1.app.classic.get_input_device_mapped_value")
# Depracations
content = content.replace("babase.app.build_number", "babase.app.build_number if build_number < 21282 else babase.app.env.build_number")
content = content.replace("babase.app.device_name", "babase.app.device_name if build_number < 21282 else babase.app.env.device_name")
content = content.replace("babase.app.config_file_path", "babase.app.config_file_path if build_number < 21282 else babase.app.env.config_file_path")
content = content.replace("babase.app.version", "babase.app.version if build_number < 21282 else babase.app.env")
content = content.replace("babase.app.debug_build", "babase.app.debug_build if build_number < 21282 else babase.app.env.debug_build")
content = content.replace("babase.app.test_build", "babase.app.test_build if build_number < 21282 else babase.app.env.test_build")
content = content.replace("babase.app.data_directory", "babase.app.data_directory if build_number < 21282 else babase.app.env.data_directory")
content = content.replace("babase.app.python_directory_user", "babase.app.python_directory_user if build_number < 21282 else babase.app.env.python_directory_user")
content = content.replace("babase.app.python_directory_app", "babase.app.env")
content = content.replace("babase.app.python_directory_app_site", "babase.app.python_directory_app_site if build_number < 21282 else babase.app.env.python_directory_app_site")
content = content.replace("babase.app.api_version", "babase.app.api_version if build_number < 21282 else babase.app.env.api_version")
content = content.replace("babase.app.on_tv", "babase.app.on_tv if build_number < 21282 else babase.app.env.on_tv")
content = content.replace("babase.app.vr_mode", "babase.app.vr_mode if build_number < 21282 else babase.app.env.vr")
content = content.replace("babase.app.toolbar_test", "babase.app.toolbar_test if build_number < 21282 else babase.app.env.toolbar_test")
content = content.replace("babase.app.arcade_mode", "babase.app.arcade_mode if build_number < 21282 else babase.app.env.arcade_mode")
content = content.replace("babase.app.headless_mode", "babase.app.headless_mode if build_number < 21282 else babase.app.env.headless_mode")
content = content.replace("babase.app.demo_mode", "babase.app.demo_mode if build_number < 21282 else babase.app.env.demo_mode")
content = content.replace("babase.app.protocol_version", "babase.app.protocol_version if build_number < 21282 else babase.app.env.protocol_version")
content = content.replace("bascenev1.get_connection_to_host_info", "bascenev1.get_connection_to_host_info if build_number < 21697 else bascenev1.get_connection_to_host_info_2")
content = content.replace("babase._store", "bauiv1.app.classic.store")
# content = content.replace("babase.internal", "")
content = content.replace("bastd.ui", "bauiv1lib")
content = content.replace("bastd", "bascenev1lib")
content = content.replace("timetype=","")
content = content.replace("babase.columnwidget", "bauiv1.columnwidget")
content = content.replace("_babase.get_game_port", "bascenev1.get_game_port")
content = content.replace("_babase.get_chat_messages", "bascenev1.get_chat_messages")
content = content.replace("_babase.get_foreground_host_session", "bascenev1.get_foreground_host_session")
content = content.replace("_babase.get_foreground_host_activity", "bascenev1.get_foreground_host_activity")
content = content.replace("bascenev1.SessionPlayerNotFoundError", "babase.SessionPlayerNotFoundError")
content = content.replace("bascenev1", "bs")
content = content.replace("bauiv1", "bui")
content = content.replace("import bs", "import bascenev1 as bs")
content = content.replace("import bui", "import bauiv1 as bui")
content = content.replace("bslib", "bascenev1lib")
content = content.replace("builib", "bauiv1lib")
content = content.replace("from bs.", "from bascenev1.")
content = content.replace("from bui.", "from bauiv1.")
content = content.replace("import bascenev1 as bascenev1lib", "import bascenev1lib")
content = content.replace("import bauiv1 as bauiv1lib", "import bauiv1lib")
content = content.replace("# ba_meta export bs.GameActivity", "# ba_meta export bascenev1.GameActivity")
content = content.replace("_bs", "bs")
content = re.sub(r'bs\.Timer\(([^)]*)\bTimeType\.REAL\b([^)]*)\)', r'babase.AppTimer(\1\2)', content)
trademark = "# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport)\n"
with open(sys.argv[2], "w", encoding=encoding) as f:
f.write(trademark + content)

View file

@ -1,24 +1,27 @@
# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport)
"""Quake Game Activity""" """Quake Game Activity"""
# ba_meta require api 7 # ba_meta require api 8
from __future__ import annotations from __future__ import annotations
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
import random import random
import enum import enum
import ba import babase
import _ba import bauiv1 as bui
import bascenev1 as bs
import _babase
from bastd.actor.scoreboard import Scoreboard from bascenev1lib.actor.scoreboard import Scoreboard
from bastd.actor.powerupbox import PowerupBox from bascenev1lib.actor.powerupbox import PowerupBox
from bastd.gameutils import SharedObjects from bascenev1lib.gameutils import SharedObjects
# from rocket # from rocket
from bastd.actor.bomb import Blast from bascenev1lib.actor.bomb import Blast
# from railgun # from railgun
from bastd.actor.playerspaz import PlayerSpaz from bascenev1lib.actor.playerspaz import PlayerSpaz
from bastd.actor.spaz import Spaz from bascenev1lib.actor.spaz import Spaz
if TYPE_CHECKING: if TYPE_CHECKING:
@ -33,7 +36,7 @@ class RocketFactory:
"""Quake Rocket factory""" """Quake Rocket factory"""
def __init__(self) -> None: def __init__(self) -> None:
self.ball_material = ba.Material() self.ball_material = bs.Material()
self.ball_material.add_actions( self.ball_material.add_actions(
conditions=((('we_are_younger_than', 5), 'or', conditions=((('we_are_younger_than', 5), 'or',
@ -60,7 +63,7 @@ class RocketFactory:
@classmethod @classmethod
def get(cls): def get(cls):
"""Get factory if exists else create new""" """Get factory if exists else create new"""
activity = ba.getactivity() activity = bs.getactivity()
if hasattr(activity, STORAGE_ATTR_NAME): if hasattr(activity, STORAGE_ATTR_NAME):
return getattr(activity, STORAGE_ATTR_NAME) return getattr(activity, STORAGE_ATTR_NAME)
factory = cls() factory = cls()
@ -77,13 +80,13 @@ class RocketLauncher:
def give(self, spaz: Spaz) -> None: def give(self, spaz: Spaz) -> None:
"""Give spaz a rocket launcher""" """Give spaz a rocket launcher"""
spaz.punch_callback = self.shot spaz.punch_callback = self.shot
self.last_shot = ba.time() self.last_shot = bs.time()
# FIXME # FIXME
# noinspection PyUnresolvedReferences # noinspection PyUnresolvedReferences
def shot(self, spaz: Spaz) -> None: def shot(self, spaz: Spaz) -> None:
"""Release a rocket""" """Release a rocket"""
time = ba.time() time = bs.time()
if time - self.last_shot > 0.6: if time - self.last_shot > 0.6:
self.last_shot = time self.last_shot = time
center = spaz.node.position_center center = spaz.node.position_center
@ -92,12 +95,12 @@ class RocketLauncher:
center[2] - forward[2]] center[2] - forward[2]]
direction[1] = 0.0 direction[1] = 0.0
mag = 10.0 / ba.Vec3(*direction).length() mag = 10.0 / babase.Vec3(*direction).length()
vel = [v * mag for v in direction] vel = [v * mag for v in direction]
Rocket(position=spaz.node.position, Rocket(position=spaz.node.position,
velocity=vel, velocity=vel,
owner=spaz.getplayer(ba.Player), owner=spaz.getplayer(bs.Player),
source_player=spaz.getplayer(ba.Player), source_player=spaz.getplayer(bs.Player),
color=spaz.node.color).autoretain() color=spaz.node.color).autoretain()
@ -105,7 +108,7 @@ class ImpactMessage:
"""Rocket touched something""" """Rocket touched something"""
class Rocket(ba.Actor): class Rocket(bs.Actor):
"""Epic rocket from rocket launcher""" """Epic rocket from rocket launcher"""
def __init__(self, def __init__(self,
@ -120,16 +123,16 @@ class Rocket(ba.Actor):
self._color = color self._color = color
factory = RocketFactory.get() factory = RocketFactory.get()
self.node = ba.newnode('prop', self.node = bs.newnode('prop',
delegate=self, delegate=self,
attrs={ attrs={
'position': position, 'position': position,
'velocity': velocity, 'velocity': velocity,
'model': ba.getmodel('impactBomb'), 'mesh': bs.getmesh('impactBomb'),
'body': 'sphere', 'body': 'sphere',
'color_texture': ba.gettexture( 'color_texture': bs.gettexture(
'bunnyColor'), 'bunnyColor'),
'model_scale': 0.2, 'mesh_scale': 0.2,
'is_area_of_interest': True, 'is_area_of_interest': True,
'body_scale': 0.8, 'body_scale': 0.8,
'materials': [ 'materials': [
@ -139,17 +142,17 @@ class Rocket(ba.Actor):
self.node.extra_acceleration = (self.node.velocity[0] * 200, 0, self.node.extra_acceleration = (self.node.velocity[0] * 200, 0,
self.node.velocity[2] * 200) self.node.velocity[2] * 200)
self._life_timer = ba.Timer( self._life_timer = bs.Timer(
5, ba.WeakCall(self.handlemessage, ba.DieMessage())) 5, bs.WeakCall(self.handlemessage, bs.DieMessage()))
self._emit_timer = ba.Timer(0.001, ba.WeakCall(self.emit), repeat=True) self._emit_timer = bs.Timer(0.001, bs.WeakCall(self.emit), repeat=True)
self.base_pos_y = self.node.position[1] self.base_pos_y = self.node.position[1]
ba.camerashake(5.0) bs.camerashake(5.0)
def emit(self) -> None: def emit(self) -> None:
"""Emit a trace after rocket""" """Emit a trace after rocket"""
ba.emitfx(position=self.node.position, bs.emitfx(position=self.node.position,
scale=0.4, scale=0.4,
spread=0.01, spread=0.01,
chunk_type='spark') chunk_type='spark')
@ -157,7 +160,7 @@ class Rocket(ba.Actor):
return return
self.node.position = (self.node.position[0], self.base_pos_y, self.node.position = (self.node.position[0], self.base_pos_y,
self.node.position[2]) # ignore y self.node.position[2]) # ignore y
ba.newnode('explosion', bs.newnode('explosion',
owner=self.node, owner=self.node,
attrs={ attrs={
'position': self.node.position, 'position': self.node.position,
@ -169,9 +172,9 @@ class Rocket(ba.Actor):
"""Message handling for rocket""" """Message handling for rocket"""
super().handlemessage(msg) super().handlemessage(msg)
if isinstance(msg, ImpactMessage): if isinstance(msg, ImpactMessage):
self.node.handlemessage(ba.DieMessage()) self.node.handlemessage(bs.DieMessage())
elif isinstance(msg, ba.DieMessage): elif isinstance(msg, bs.DieMessage):
if self.node: if self.node:
Blast(position=self.node.position, Blast(position=self.node.position,
blast_radius=2, blast_radius=2,
@ -180,8 +183,8 @@ class Rocket(ba.Actor):
self.node.delete() self.node.delete()
self._emit_timer = None self._emit_timer = None
elif isinstance(msg, ba.OutOfBoundsMessage): elif isinstance(msg, bs.OutOfBoundsMessage):
self.handlemessage(ba.DieMessage()) self.handlemessage(bs.DieMessage())
# -------------------Rocket-------------------------- # -------------------Rocket--------------------------
@ -196,13 +199,13 @@ class Railgun:
def give(self, spaz: Spaz) -> None: def give(self, spaz: Spaz) -> None:
"""Give spaz a railgun""" """Give spaz a railgun"""
spaz.punch_callback = self.shot spaz.punch_callback = self.shot
self.last_shot = ba.time() self.last_shot = bs.time()
# FIXME # FIXME
# noinspection PyUnresolvedReferences # noinspection PyUnresolvedReferences
def shot(self, spaz: Spaz) -> None: def shot(self, spaz: Spaz) -> None:
"""Release a rocket""" """Release a rocket"""
time = ba.time() time = bs.time()
if time - self.last_shot > 0.6: if time - self.last_shot > 0.6:
self.last_shot = time self.last_shot = time
center = spaz.node.position_center center = spaz.node.position_center
@ -215,8 +218,8 @@ class Railgun:
RailBullet(position=spaz.node.position, RailBullet(position=spaz.node.position,
direction=direction, direction=direction,
owner=spaz.getplayer(ba.Player), owner=spaz.getplayer(bs.Player),
source_player=spaz.getplayer(ba.Player), source_player=spaz.getplayer(bs.Player),
color=spaz.node.color).autoretain() color=spaz.node.color).autoretain()
@ -227,7 +230,7 @@ class TouchedToSpazMessage:
self.spaz = spaz self.spaz = spaz
class RailBullet(ba.Actor): class RailBullet(bs.Actor):
"""Railgun bullet""" """Railgun bullet"""
def __init__(self, def __init__(self,
@ -239,23 +242,23 @@ class RailBullet(ba.Actor):
super().__init__() super().__init__()
self._color = color self._color = color
self.node = ba.newnode('light', self.node = bs.newnode('light',
delegate=self, delegate=self,
attrs={ attrs={
'position': position, 'position': position,
'color': self._color 'color': self._color
}) })
ba.animate(self.node, 'radius', {0: 0, 0.1: 0.5, 0.5: 0}) bs.animate(self.node, 'radius', {0: 0, 0.1: 0.5, 0.5: 0})
self.source_player = source_player self.source_player = source_player
self.owner = owner self.owner = owner
self._life_timer = ba.Timer( self._life_timer = bs.Timer(
0.5, ba.WeakCall(self.handlemessage, ba.DieMessage())) 0.5, bs.WeakCall(self.handlemessage, bs.DieMessage()))
pos = position pos = position
vel = tuple(i / 5 for i in ba.Vec3(direction).normalized()) vel = tuple(i / 5 for i in babase.Vec3(direction).normalized())
for _ in range(500): # Optimization :( for _ in range(500): # Optimization :(
ba.newnode('explosion', bs.newnode('explosion',
owner=self.node, owner=self.node,
attrs={ attrs={
'position': pos, 'position': pos,
@ -264,25 +267,25 @@ class RailBullet(ba.Actor):
}) })
pos = (pos[0] + vel[0], pos[1] + vel[1], pos[2] + vel[2]) pos = (pos[0] + vel[0], pos[1] + vel[1], pos[2] + vel[2])
for node in _ba.getnodes(): for node in _babase.getnodes():
if node and node.getnodetype() == 'spaz': if node and node.getnodetype() == 'spaz':
# pylint: disable=invalid-name # pylint: disable=invalid-name
m3 = ba.Vec3(position) m3 = babase.Vec3(position)
a = ba.Vec3(direction[2], direction[1], direction[0]) a = babase.Vec3(direction[2], direction[1], direction[0])
m1 = ba.Vec3(node.position) m1 = babase.Vec3(node.position)
# pylint: enable=invalid-name # pylint: enable=invalid-name
# distance between node and line # distance between node and line
dist = (a * (m1 - m3)).length() / a.length() dist = (a * (m1 - m3)).length() / a.length()
if dist < 0.3: if dist < 0.3:
if node and node != self.owner and node.getdelegate( if node and node != self.owner and node.getdelegate(
PlayerSpaz, True).getplayer( PlayerSpaz, True).getplayer(
ba.Player, True).team != self.owner.team: bs.Player, True).team != self.owner.team:
node.handlemessage(ba.FreezeMessage()) node.handlemessage(bs.FreezeMessage())
pos = self.node.position pos = self.node.position
hit_dir = (0, 10, 0) hit_dir = (0, 10, 0)
node.handlemessage( node.handlemessage(
ba.HitMessage(pos=pos, bs.HitMessage(pos=pos,
magnitude=50, magnitude=50,
velocity_magnitude=50, velocity_magnitude=50,
radius=0, radius=0,
@ -292,21 +295,21 @@ class RailBullet(ba.Actor):
def handlemessage(self, msg: Any) -> Any: def handlemessage(self, msg: Any) -> Any:
super().handlemessage(msg) super().handlemessage(msg)
if isinstance(msg, ba.DieMessage): if isinstance(msg, bs.DieMessage):
if self.node: if self.node:
self.node.delete() self.node.delete()
elif isinstance(msg, ba.OutOfBoundsMessage): elif isinstance(msg, bs.OutOfBoundsMessage):
self.handlemessage(ba.DieMessage()) self.handlemessage(bs.DieMessage())
# ------------------Railgun------------------------- # ------------------Railgun-------------------------
class Player(ba.Player['Team']): class Player(bs.Player['Team']):
"""Our player""" """Our player"""
class Team(ba.Team[Player]): class Team(bs.Team[Player]):
"""Our team""" """Our team"""
def __init__(self) -> None: def __init__(self) -> None:
@ -326,91 +329,91 @@ class ObstaclesForm(enum.Enum):
RANDOM = 2 RANDOM = 2
# ba_meta export game # ba_meta export bascenev1.GameActivity
class QuakeGame(ba.TeamGameActivity[Player, Team]): class QuakeGame(bs.TeamGameActivity[Player, Team]):
"""Quake Team Game Activity""" """Quake Team Game Activity"""
name = 'Quake' name = 'Quake'
description = 'Kill a set number of enemies to win.' description = 'Kill a set number of enemies to win.'
available_settings = [ available_settings = [
ba.IntSetting( bs.IntSetting(
'Kills to Win Per Player', 'Kills to Win Per Player',
default=15, default=15,
min_value=1, min_value=1,
increment=1, increment=1,
), ),
ba.IntChoiceSetting( bs.IntChoiceSetting(
'Time Limit', 'Time Limit',
choices=[('None', 0), ('1 Minute', 60), ('2 Minutes', 120), choices=[('None', 0), ('1 Minute', 60), ('2 Minutes', 120),
('5 Minutes', 300), ('10 Minutes', 600), ('5 Minutes', 300), ('10 Minutes', 600),
('20 Minutes', 1200)], ('20 Minutes', 1200)],
default=0, default=0,
), ),
ba.FloatChoiceSetting( bs.FloatChoiceSetting(
'Respawn Times', 'Respawn Times',
choices=[('At once', 0.0), ('Shorter', 0.25), ('Short', 0.5), choices=[('At once', 0.0), ('Shorter', 0.25), ('Short', 0.5),
('Normal', 1.0), ('Long', 2.0), ('Longer', 4.0)], ('Normal', 1.0), ('Long', 2.0), ('Longer', 4.0)],
default=1.0, default=1.0,
), ),
ba.BoolSetting( bs.BoolSetting(
'Speed', 'Speed',
default=True, default=True,
), ),
ba.BoolSetting( bs.BoolSetting(
'Enable Jump', 'Enable Jump',
default=True, default=True,
), ),
ba.BoolSetting( bs.BoolSetting(
'Enable Pickup', 'Enable Pickup',
default=True, default=True,
), ),
ba.BoolSetting( bs.BoolSetting(
'Enable Bomb', 'Enable Bomb',
default=False, default=False,
), ),
ba.BoolSetting( bs.BoolSetting(
'Obstacles', 'Obstacles',
default=True, default=True,
), ),
ba.IntChoiceSetting( bs.IntChoiceSetting(
'Obstacles Form', 'Obstacles Form',
choices=[('Cube', ObstaclesForm.CUBE.value), choices=[('Cube', ObstaclesForm.CUBE.value),
('Sphere', ObstaclesForm.SPHERE.value), ('Sphere', ObstaclesForm.SPHERE.value),
('Random', ObstaclesForm.RANDOM.value)], ('Random', ObstaclesForm.RANDOM.value)],
default=0, default=0,
), ),
ba.IntChoiceSetting( bs.IntChoiceSetting(
'Weapon Type', 'Weapon Type',
choices=[('Rocket', WeaponType.ROCKET.value), choices=[('Rocket', WeaponType.ROCKET.value),
('Railgun', WeaponType.RAILGUN.value)], ('Railgun', WeaponType.RAILGUN.value)],
default=WeaponType.ROCKET.value, default=WeaponType.ROCKET.value,
), ),
ba.BoolSetting( bs.BoolSetting(
'Obstacles Mirror Shots', 'Obstacles Mirror Shots',
default=False, default=False,
), ),
ba.IntSetting( bs.IntSetting(
'Obstacles Count', 'Obstacles Count',
default=16, default=16,
min_value=0, min_value=0,
increment=2, increment=2,
), ),
ba.BoolSetting( bs.BoolSetting(
'Random Obstacles Color', 'Random Obstacles Color',
default=True, default=True,
), ),
ba.BoolSetting( bs.BoolSetting(
'Epic Mode', 'Epic Mode',
default=False, default=False,
), ),
] ]
@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.MultiTeamSession) or issubclass( return issubclass(sessiontype, bs.MultiTeamSession) or issubclass(
sessiontype, ba.FreeForAllSession) sessiontype, bs.FreeForAllSession)
@classmethod @classmethod
def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]:
# TODO add more maps # TODO add more maps
return ['Football Stadium', 'Monkey Face', 'Doom Shroom'] return ['Football Stadium', 'Monkey Face', 'Doom Shroom']
@ -426,15 +429,15 @@ class QuakeGame(ba.TeamGameActivity[Player, Team]):
self._pickup_enabled = self.settings_raw['Enable Pickup'] self._pickup_enabled = self.settings_raw['Enable Pickup']
self._jump_enabled = self.settings_raw['Enable Jump'] self._jump_enabled = self.settings_raw['Enable Jump']
self._weapon_type = WeaponType(self.settings_raw['Weapon Type']) self._weapon_type = WeaponType(self.settings_raw['Weapon Type'])
self.default_music = (ba.MusicType.EPIC self.default_music = (bs.MusicType.EPIC
if self._epic_mode else ba.MusicType.GRAND_ROMP) if self._epic_mode else bs.MusicType.GRAND_ROMP)
self.slow_motion = self._epic_mode self.slow_motion = self._epic_mode
self.announce_player_deaths = True self.announce_player_deaths = True
self._scoreboard = Scoreboard() self._scoreboard = Scoreboard()
self._ding_sound = ba.getsound('dingSmall') self._ding_sound = bs.getsound('dingSmall')
self._shield_dropper: Optional[ba.Timer] = None self._shield_dropper: Optional[bs.Timer] = None
def get_instance_description(self) -> Union[str, Sequence]: def get_instance_description(self) -> Union[str, Sequence]:
return 'Kill ${ARG1} enemies.', self._score_to_win return 'Kill ${ARG1} enemies.', self._score_to_win
@ -445,11 +448,11 @@ class QuakeGame(ba.TeamGameActivity[Player, Team]):
self._update_scoreboard() self._update_scoreboard()
def on_begin(self) -> None: def on_begin(self) -> None:
ba.TeamGameActivity.on_begin(self) bs.TeamGameActivity.on_begin(self)
ba.getactivity().globalsnode.tint = (0.5, 0.7, 1) bs.getactivity().globalsnode.tint = (0.5, 0.7, 1)
self.drop_shield() self.drop_shield()
self._shield_dropper = ba.Timer(8, self._shield_dropper = bs.Timer(8,
ba.WeakCall(self.drop_shield), bs.WeakCall(self.drop_shield),
repeat=True) repeat=True)
self.setup_standard_time_limit(self._time_limit) self.setup_standard_time_limit(self._time_limit)
if self._obstacles_enabled: if self._obstacles_enabled:
@ -483,9 +486,9 @@ class QuakeGame(ba.TeamGameActivity[Player, Team]):
position=(random.uniform(-10, 10), 6, position=(random.uniform(-10, 10), 6,
random.uniform(-5, 5))).autoretain() random.uniform(-5, 5))).autoretain()
ba.playsound(self._ding_sound) self._ding_sound.play()
p_light = ba.newnode('light', p_light = bs.newnode('light',
owner=shield.node, owner=shield.node,
attrs={ attrs={
'position': (0, 0, 0), 'position': (0, 0, 0),
@ -497,7 +500,7 @@ class QuakeGame(ba.TeamGameActivity[Player, Team]):
shield.node.connectattr('position', p_light, 'position') shield.node.connectattr('position', p_light, 'position')
ba.animate(p_light, 'intensity', {0: 2, 8: 0}) bs.animate(p_light, 'intensity', {0: 2, 8: 0})
def spawn_player(self, player: Player) -> None: def spawn_player(self, player: Player) -> None:
spaz = self.spawn_player_spaz(player) spaz = self.spawn_player_spaz(player)
@ -511,7 +514,7 @@ class QuakeGame(ba.TeamGameActivity[Player, Team]):
enable_fly=False) enable_fly=False)
spaz.node.hockey = self._speed_enabled spaz.node.hockey = self._speed_enabled
spaz.spaz_light = ba.newnode('light', spaz.spaz_light = bs.newnode('light',
owner=spaz.node, owner=spaz.node,
attrs={ attrs={
'position': (0, 0, 0), 'position': (0, 0, 0),
@ -524,8 +527,8 @@ class QuakeGame(ba.TeamGameActivity[Player, Team]):
spaz.node.connectattr('position', spaz.spaz_light, 'position') spaz.node.connectattr('position', spaz.spaz_light, 'position')
def handlemessage(self, msg: Any) -> Any: def handlemessage(self, msg: Any) -> Any:
if isinstance(msg, ba.PlayerDiedMessage): if isinstance(msg, bs.PlayerDiedMessage):
ba.TeamGameActivity.handlemessage(self, msg) bs.TeamGameActivity.handlemessage(self, msg)
player = msg.getplayer(Player) player = msg.getplayer(Player)
self.respawn_player(player) self.respawn_player(player)
killer = msg.getkillerplayer(Player) killer = msg.getkillerplayer(Player)
@ -535,20 +538,20 @@ class QuakeGame(ba.TeamGameActivity[Player, Team]):
# handle team-kills # handle team-kills
if killer.team is player.team: if killer.team is player.team:
# in free-for-all, killing yourself loses you a point # in free-for-all, killing yourself loses you a point
if isinstance(self.session, ba.FreeForAllSession): if isinstance(self.session, bs.FreeForAllSession):
new_score = player.team.score - 1 new_score = player.team.score - 1
new_score = max(0, new_score) new_score = max(0, new_score)
player.team.score = new_score player.team.score = new_score
# in teams-mode it gives a point to the other team # in teams-mode it gives a point to the other team
else: else:
ba.playsound(self._ding_sound) self._ding_sound.play()
for team in self.teams: for team in self.teams:
if team is not killer.team: if team is not killer.team:
team.score += 1 team.score += 1
# killing someone on another team nets a kill # killing someone on another team nets a kill
else: else:
killer.team.score += 1 killer.team.score += 1
ba.playsound(self._ding_sound) self._ding_sound.play()
# in FFA show our score since its hard to find on # in FFA show our score since its hard to find on
# the scoreboard # the scoreboard
assert killer.actor is not None assert killer.actor is not None
@ -564,10 +567,10 @@ class QuakeGame(ba.TeamGameActivity[Player, Team]):
# (allows the dust to clear and draws to occur if # (allows the dust to clear and draws to occur if
# deaths are close enough) # deaths are close enough)
if any(team.score >= self._score_to_win for team in self.teams): if any(team.score >= self._score_to_win for team in self.teams):
ba.timer(0.5, self.end_game) bs.timer(0.5, self.end_game)
else: else:
ba.TeamGameActivity.handlemessage(self, msg) bs.TeamGameActivity.handlemessage(self, msg)
def _update_scoreboard(self) -> None: def _update_scoreboard(self) -> None:
for team in self.teams: for team in self.teams:
@ -575,51 +578,51 @@ class QuakeGame(ba.TeamGameActivity[Player, Team]):
self._score_to_win) self._score_to_win)
def end_game(self) -> None: def end_game(self) -> None:
results = ba.GameResults() results = bs.GameResults()
for team in self.teams: for team in self.teams:
results.set_team_score(team, team.score) results.set_team_score(team, team.score)
self.end(results=results) self.end(results=results)
class Obstacle(ba.Actor): class Obstacle(bs.Actor):
"""Scene object""" """Scene object"""
def __init__(self, def __init__(self,
position, position,
form=ObstaclesForm.CUBE, form=ObstaclesForm.CUBE,
mirror=False) -> None: mirror=False) -> None:
ba.Actor.__init__(self) bs.Actor.__init__(self)
if form == ObstaclesForm.CUBE: if form == ObstaclesForm.CUBE:
model = 'tnt' mesh = 'tnt'
body = 'crate' body = 'crate'
elif form == ObstaclesForm.SPHERE: elif form == ObstaclesForm.SPHERE:
model = 'bomb' mesh = 'bomb'
body = 'sphere' body = 'sphere'
else: # ObstaclesForm.RANDOM: else: # ObstaclesForm.RANDOM:
model = random.choice(['tnt', 'bomb']) mesh = random.choice(['tnt', 'bomb'])
body = 'sphere' if model == 'bomb' else 'crate' body = 'sphere' if mesh == 'bomb' else 'crate'
self.node = ba.newnode( self.node = bs.newnode(
'prop', 'prop',
delegate=self, delegate=self,
attrs={ attrs={
'position': 'position':
position, position,
'model': 'mesh':
ba.getmodel(model), bs.getmesh(mesh),
'body': 'body':
body, body,
'body_scale': 'body_scale':
1.3, 1.3,
'model_scale': 'mesh_scale':
1.3, 1.3,
'reflection': 'reflection':
'powerup', 'powerup',
'reflection_scale': [0.7], 'reflection_scale': [0.7],
'color_texture': 'color_texture':
ba.gettexture('bunnyColor'), bs.gettexture('bunnyColor'),
'materials': [SharedObjects.get().footing_material] 'materials': [SharedObjects.get().footing_material]
if mirror else [ if mirror else [
SharedObjects.get().object_material, SharedObjects.get().object_material,
@ -628,15 +631,15 @@ class Obstacle(ba.Actor):
}) })
def handlemessage(self, msg: Any) -> Any: def handlemessage(self, msg: Any) -> Any:
if isinstance(msg, ba.DieMessage): if isinstance(msg, bs.DieMessage):
if self.node: if self.node:
self.node.delete() self.node.delete()
elif isinstance(msg, ba.OutOfBoundsMessage): elif isinstance(msg, bs.OutOfBoundsMessage):
if self.node: if self.node:
self.handlemessage(ba.DieMessage()) self.handlemessage(bs.DieMessage())
elif isinstance(msg, ba.HitMessage): elif isinstance(msg, bs.HitMessage):
self.node.handlemessage('impulse', msg.pos[0], msg.pos[1], self.node.handlemessage('impulse', msg.pos[0], msg.pos[1],
msg.pos[2], msg.velocity[0], msg.pos[2], msg.velocity[0],
msg.velocity[1], msg.velocity[2], msg.velocity[1], msg.velocity[2],

View file

@ -1,43 +1,43 @@
# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport)
# Released under the MIT License. See LICENSE for details. # Released under the MIT License. See LICENSE for details.
# #
"""DeathMatch game and support classes.""" """DeathMatch game and support classes."""
# 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
import _ba import bascenev1 as bs
from bastd.actor.playerspaz import PlayerSpaz from bascenev1lib.actor.playerspaz import PlayerSpaz
from bastd.actor.scoreboard import Scoreboard from bascenev1lib.gameutils import SharedObjects
from bastd.gameutils import SharedObjects from bascenev1lib.game.deathmatch import DeathMatchGame, Player
from bastd.game.deathmatch import DeathMatchGame, Player, Team from bascenev1lib.gameutils import SharedObjects
from bastd.gameutils import SharedObjects
if TYPE_CHECKING: if TYPE_CHECKING:
from typing import Any, Sequence, Dict, Type, List, Optional, Union from typing import Any, Sequence, Dict, Type, List, Optional, Union
# ba_meta export game # ba_meta export bascenev1.GameActivity
class ShimlaGame(DeathMatchGame): class ShimlaGame(DeathMatchGame):
name = 'Shimla' name = 'Shimla'
@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 ['Creative Thoughts'] return ['Creative Thoughts']
def __init__(self, settings: dict): def __init__(self, settings: dict):
super().__init__(settings) super().__init__(settings)
shared = SharedObjects.get() shared = SharedObjects.get()
self.lifts = {} self.lifts = {}
self._real_wall_material = ba.Material() self._real_wall_material = bs.Material()
self._real_wall_material.add_actions( self._real_wall_material.add_actions(
actions=( actions=(
@ -53,7 +53,7 @@ class ShimlaGame(DeathMatchGame):
('modify_part_collision', 'physical', True) ('modify_part_collision', 'physical', True)
)) ))
self._lift_material = ba.Material() self._lift_material = bs.Material()
self._lift_material.add_actions( self._lift_material.add_actions(
actions=( actions=(
@ -71,14 +71,14 @@ class ShimlaGame(DeathMatchGame):
) )
def on_begin(self): def on_begin(self):
ba.getactivity().globalsnode.happy_thoughts_mode = False bs.getactivity().globalsnode.happy_thoughts_mode = False
super().on_begin() super().on_begin()
self.make_map() self.make_map()
ba.timer(2, self.disable_fly) bs.timer(2, self.disable_fly)
def disable_fly(self): def disable_fly(self):
activity = _ba.get_foreground_host_activity() activity = bs.get_foreground_host_activity()
for players in activity.players: for players in activity.players:
players.actor.node.fly = False players.actor.node.fly = False
@ -102,29 +102,29 @@ class ShimlaGame(DeathMatchGame):
def make_map(self): def make_map(self):
shared = SharedObjects.get() shared = SharedObjects.get()
_ba.get_foreground_host_activity()._map.leftwall.materials = [ bs.get_foreground_host_activity()._map.leftwall.materials = [
shared.footing_material, self._real_wall_material] shared.footing_material, self._real_wall_material]
_ba.get_foreground_host_activity()._map.rightwall.materials = [ bs.get_foreground_host_activity()._map.rightwall.materials = [
shared.footing_material, self._real_wall_material] shared.footing_material, self._real_wall_material]
_ba.get_foreground_host_activity()._map.topwall.materials = [ bs.get_foreground_host_activity()._map.topwall.materials = [
shared.footing_material, self._real_wall_material] shared.footing_material, self._real_wall_material]
self.floorwall1 = ba.newnode('region', attrs={'position': (-10, 5, -5.52), 'scale': self.floorwall1 = bs.newnode('region', attrs={'position': (-10, 5, -5.52), 'scale':
(15, 0.2, 2), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) (15, 0.2, 2), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]})
self.floorwall2 = ba.newnode('region', attrs={'position': (10, 5, -5.52), 'scale': ( self.floorwall2 = bs.newnode('region', attrs={'position': (10, 5, -5.52), 'scale': (
15, 0.2, 2), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) 15, 0.2, 2), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]})
self.wall1 = ba.newnode('region', attrs={'position': (0, 11, -6.90), 'scale': ( self.wall1 = bs.newnode('region', attrs={'position': (0, 11, -6.90), 'scale': (
35.4, 20, 1), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) 35.4, 20, 1), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]})
self.wall2 = ba.newnode('region', attrs={'position': (0, 11, -4.14), 'scale': ( self.wall2 = bs.newnode('region', attrs={'position': (0, 11, -4.14), 'scale': (
35.4, 20, 1), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) 35.4, 20, 1), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]})
ba.newnode('locator', attrs={'shape': 'box', 'position': (-10, 5, -5.52), 'color': ( bs.newnode('locator', attrs={'shape': 'box', 'position': (-10, 5, -5.52), 'color': (
0, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (15, 0.2, 2)}) 0, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (15, 0.2, 2)})
ba.newnode('locator', attrs={'shape': 'box', 'position': (10, 5, -5.52), 'color': ( bs.newnode('locator', attrs={'shape': 'box', 'position': (10, 5, -5.52), 'color': (
0, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (15, 0.2, 2)}) 0, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (15, 0.2, 2)})
self.create_lift(-16.65, 8) self.create_lift(-16.65, 8)
@ -151,32 +151,32 @@ class ShimlaGame(DeathMatchGame):
shared = SharedObjects.get() shared = SharedObjects.get()
ba.newnode('region', attrs={'position': (x, y, -5.52), 'scale': (5.5, 0.1, 6), bs.newnode('region', attrs={'position': (x, y, -5.52), 'scale': (5.5, 0.1, 6),
'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]})
ba.newnode('locator', attrs={'shape': 'box', 'position': (x, y, -5.52), 'color': ( bs.newnode('locator', attrs={'shape': 'box', 'position': (x, y, -5.52), 'color': (
1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (5.5, 0.1, 2)}) 1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (5.5, 0.1, 2)})
def create_lift(self, x, y): def create_lift(self, x, y):
shared = SharedObjects.get() shared = SharedObjects.get()
color = (0.7, 0.6, 0.5) color = (0.7, 0.6, 0.5)
floor = ba.newnode('region', attrs={'position': (x, y, -5.52), 'scale': ( floor = bs.newnode('region', attrs={'position': (x, y, -5.52), 'scale': (
1.8, 0.1, 2), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material, self._lift_material]}) 1.8, 0.1, 2), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material, self._lift_material]})
cleaner = ba.newnode('region', attrs={'position': (x, y, -5.52), 'scale': ( cleaner = bs.newnode('region', attrs={'position': (x, y, -5.52), 'scale': (
2, 0.3, 2), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) 2, 0.3, 2), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]})
lift = ba.newnode('locator', attrs={'shape': 'box', 'position': ( lift = bs.newnode('locator', attrs={'shape': 'box', 'position': (
x, y, -5.52), 'color': color, 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (1.8, 3.7, 2)}) x, y, -5.52), 'color': color, 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (1.8, 3.7, 2)})
_tcombine = ba.newnode('combine', _tcombine = bs.newnode('combine',
owner=floor, owner=floor,
attrs={ attrs={
'input0': x, 'input0': x,
'input2': -5.5, 'input2': -5.5,
'size': 3 'size': 3
}) })
mnode = ba.newnode('math', mnode = bs.newnode('math',
owner=lift, owner=lift,
attrs={ attrs={
'input1': (0, 2, 0), 'input1': (0, 2, 0),
@ -184,7 +184,7 @@ class ShimlaGame(DeathMatchGame):
}) })
_tcombine.connectattr('output', mnode, 'input2') _tcombine.connectattr('output', mnode, 'input2')
_cleaner_combine = ba.newnode('combine', _cleaner_combine = bs.newnode('combine',
owner=cleaner, owner=cleaner,
attrs={ attrs={
'input1': 5.6, 'input1': 5.6,
@ -192,10 +192,10 @@ class ShimlaGame(DeathMatchGame):
'size': 3 'size': 3
}) })
_cleaner_combine.connectattr('output', cleaner, 'position') _cleaner_combine.connectattr('output', cleaner, 'position')
ba.animate(_tcombine, 'input1', { bs.animate(_tcombine, 'input1', {
0: 5.1, 0: 5.1,
}) })
ba.animate(_cleaner_combine, 'input0', { bs.animate(_cleaner_combine, 'input0', {
0: -19 if x < 0 else 19, 0: -19 if x < 0 else 19,
}) })
@ -205,29 +205,29 @@ class ShimlaGame(DeathMatchGame):
"cleaner": _cleaner_combine, 'leftLift': x < 0} "cleaner": _cleaner_combine, 'leftLift': x < 0}
def _handle_lift(self): def _handle_lift(self):
region = ba.getcollision().sourcenode region = bs.getcollision().sourcenode
lift = self.lifts[region] lift = self.lifts[region]
def clean(lift): def clean(lift):
ba.animate(lift["cleaner"], 'input0', { bs.animate(lift["cleaner"], 'input0', {
0: -19 if lift["leftLift"] else 19, 0: -19 if lift["leftLift"] else 19,
2: -16 if lift["leftLift"] else 16, 2: -16 if lift["leftLift"] else 16,
4.3: -19 if lift["leftLift"] else 19 4.3: -19 if lift["leftLift"] else 19
}) })
if lift["state"] == "origin": if lift["state"] == "origin":
lift["state"] = "transition" lift["state"] = "transition"
ba.animate(lift["lift"], 'input1', { bs.animate(lift["lift"], 'input1', {
0: 5.1, 0: 5.1,
1.3: 5.1, 1.3: 5.1,
6: 5+12, 6: 5+12,
9: 5+12, 9: 5+12,
15: 5.1 15: 5.1
}) })
ba.timer(16, ba.Call(lambda lift: lift.update({'state': 'end'}), lift)) bs.timer(16, babase.Call(lambda lift: lift.update({'state': 'end'}), lift))
ba.timer(12, ba.Call(clean, lift)) bs.timer(12, babase.Call(clean, lift))
def _handle_lift_disconnect(self): def _handle_lift_disconnect(self):
region = ba.getcollision().sourcenode region = bs.getcollision().sourcenode
lift = self.lifts[region] lift = self.lifts[region]
if lift["state"] == 'end': if lift["state"] == 'end':
lift["state"] = "origin" lift["state"] = "origin"
@ -236,9 +236,9 @@ class ShimlaGame(DeathMatchGame):
shared = SharedObjects.get() shared = SharedObjects.get()
for i in range(0, 21): for i in range(0, 21):
ba.newnode('region', attrs={'position': (x, y, -5.52), 'scale': (0.2, 0.1, 6), bs.newnode('region', attrs={'position': (x, y, -5.52), 'scale': (0.2, 0.1, 6),
'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]})
ba.newnode('locator', attrs={'shape': 'box', 'position': (x, y, -5.52), 'color': ( bs.newnode('locator', attrs={'shape': 'box', 'position': (x, y, -5.52), 'color': (
1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (0.2, 0.1, 2)}) 1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (0.2, 0.1, 2)})
if backslash: if backslash:
x = x+0.1 x = x+0.1
@ -292,7 +292,7 @@ class mapdefs:
0.5245740665, 0.5245740665, 0.01941146064) 0.5245740665, 0.5245740665, 0.01941146064)
class CreativeThoughts(ba.Map): class CreativeThoughts(bs.Map):
"""Freaking map by smoothy.""" """Freaking map by smoothy."""
defs = mapdefs defs = mapdefs
@ -313,26 +313,26 @@ class CreativeThoughts(ba.Map):
@classmethod @classmethod
def on_preload(cls) -> Any: def on_preload(cls) -> Any:
data: Dict[str, Any] = { data: Dict[str, Any] = {
'model': ba.getmodel('alwaysLandLevel'), 'mesh': bs.getmesh('alwaysLandLevel'),
'bottom_model': ba.getmodel('alwaysLandLevelBottom'), 'bottom_mesh': bs.getmesh('alwaysLandLevelBottom'),
'bgmodel': ba.getmodel('alwaysLandBG'), 'bgmesh': bs.getmesh('alwaysLandBG'),
'collide_model': ba.getcollidemodel('alwaysLandLevelCollide'), 'collision_mesh': bs.getcollisionmesh('alwaysLandLevelCollide'),
'tex': ba.gettexture('alwaysLandLevelColor'), 'tex': bs.gettexture('alwaysLandLevelColor'),
'bgtex': ba.gettexture('alwaysLandBGColor'), 'bgtex': bs.gettexture('alwaysLandBGColor'),
'vr_fill_mound_model': ba.getmodel('alwaysLandVRFillMound'), 'vr_fill_mound_mesh': bs.getmesh('alwaysLandVRFillMound'),
'vr_fill_mound_tex': ba.gettexture('vrFillMound') 'vr_fill_mound_tex': bs.gettexture('vrFillMound')
} }
return data return data
@classmethod @classmethod
def get_music_type(cls) -> ba.MusicType: def get_music_type(cls) -> bs.MusicType:
return ba.MusicType.FLYING return bs.MusicType.FLYING
def __init__(self) -> None: def __init__(self) -> None:
super().__init__(vr_overlay_offset=(0, -3.7, 2.5)) super().__init__(vr_overlay_offset=(0, -3.7, 2.5))
shared = SharedObjects.get() shared = SharedObjects.get()
self._fake_wall_material = ba.Material() self._fake_wall_material = bs.Material()
self._real_wall_material = ba.Material() self._real_wall_material = bs.Material()
self._fake_wall_material.add_actions( self._fake_wall_material.add_actions(
conditions=(('they_are_younger_than', 9000), 'and', conditions=(('they_are_younger_than', 9000), 'and',
('they_have_material', shared.player_material)), ('they_have_material', shared.player_material)),
@ -348,29 +348,29 @@ class CreativeThoughts(ba.Map):
('modify_part_collision', 'physical', True) ('modify_part_collision', 'physical', True)
)) ))
self.background = ba.newnode( self.background = bs.newnode(
'terrain', 'terrain',
attrs={ attrs={
'model': self.preloaddata['bgmodel'], 'mesh': self.preloaddata['bgmesh'],
'lighting': False, 'lighting': False,
'background': True, 'background': True,
'color_texture': ba.gettexture("rampageBGColor") 'color_texture': bs.gettexture("rampageBGColor")
}) })
self.leftwall = ba.newnode('region', attrs={'position': (-17.75152479, 13, -5.52), 'scale': ( self.leftwall = bs.newnode('region', attrs={'position': (-17.75152479, 13, -5.52), 'scale': (
0.1, 15.5, 2), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) 0.1, 15.5, 2), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]})
self.rightwall = ba.newnode('region', attrs={'position': (17.75, 13, -5.52), 'scale': ( self.rightwall = bs.newnode('region', attrs={'position': (17.75, 13, -5.52), 'scale': (
0.1, 15.5, 2), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) 0.1, 15.5, 2), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]})
self.topwall = ba.newnode('region', attrs={'position': (0, 21.0, -5.52), 'scale': ( self.topwall = bs.newnode('region', attrs={'position': (0, 21.0, -5.52), 'scale': (
35.4, 0.2, 2), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) 35.4, 0.2, 2), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]})
ba.newnode('locator', attrs={'shape': 'box', 'position': (-17.75152479, 13, -5.52), 'color': ( bs.newnode('locator', attrs={'shape': 'box', 'position': (-17.75152479, 13, -5.52), 'color': (
0, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (0.1, 15.5, 2)}) 0, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (0.1, 15.5, 2)})
ba.newnode('locator', attrs={'shape': 'box', 'position': (17.75, 13, -5.52), 'color': ( bs.newnode('locator', attrs={'shape': 'box', 'position': (17.75, 13, -5.52), 'color': (
0, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (0.1, 15.5, 2)}) 0, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (0.1, 15.5, 2)})
ba.newnode('locator', attrs={'shape': 'box', 'position': (0, 21.0, -5.52), 'color': ( bs.newnode('locator', attrs={'shape': 'box', 'position': (0, 21.0, -5.52), 'color': (
0, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (35.4, 0.2, 2)}) 0, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (35.4, 0.2, 2)})
gnode = ba.getactivity().globalsnode gnode = bs.getactivity().globalsnode
gnode.happy_thoughts_mode = True gnode.happy_thoughts_mode = True
gnode.shadow_offset = (0.0, 8.0, 5.0) gnode.shadow_offset = (0.0, 8.0, 5.0)
gnode.tint = (1.3, 1.23, 1.0) gnode.tint = (1.3, 1.23, 1.0)
@ -381,9 +381,9 @@ class CreativeThoughts(ba.Map):
self.is_flying = True self.is_flying = True
# throw out some tips on flying # throw out some tips on flying
txt = ba.newnode('text', txt = bs.newnode('text',
attrs={ attrs={
'text': ba.Lstr(resource='pressJumpToFlyText'), 'text': babase.Lstr(resource='pressJumpToFlyText'),
'scale': 1.2, 'scale': 1.2,
'maxwidth': 800, 'maxwidth': 800,
'position': (0, 200), 'position': (0, 200),
@ -392,7 +392,7 @@ class CreativeThoughts(ba.Map):
'h_align': 'center', 'h_align': 'center',
'v_attach': 'bottom' 'v_attach': 'bottom'
}) })
cmb = ba.newnode('combine', cmb = bs.newnode('combine',
owner=txt, owner=txt,
attrs={ attrs={
'size': 4, 'size': 4,
@ -400,12 +400,12 @@ class CreativeThoughts(ba.Map):
'input1': 0.9, 'input1': 0.9,
'input2': 0.0 'input2': 0.0
}) })
ba.animate(cmb, 'input3', {3.0: 0, 4.0: 1, 9.0: 1, 10.0: 0}) bs.animate(cmb, 'input3', {3.0: 0, 4.0: 1, 9.0: 1, 10.0: 0})
cmb.connectattr('output', txt, 'color') cmb.connectattr('output', txt, 'color')
ba.timer(10.0, txt.delete) bs.timer(10.0, txt.delete)
try: try:
ba._map.register_map(CreativeThoughts) bs._map.register_map(CreativeThoughts)
except: except:
pass pass

View file

@ -1,6 +1,7 @@
# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport)
# SimonSays # SimonSays
# you had really better do what Simon says... # you had really better do what Simon says...
# ba_meta require api 7 # ba_meta require api 8
from __future__ import annotations from __future__ import annotations
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
@ -8,19 +9,21 @@ from typing import TYPE_CHECKING
if TYPE_CHECKING: if TYPE_CHECKING:
from typing import Any, Union, Sequence from typing import Any, Union, Sequence
from ba import _gameutils from bascenev1 import _gameutils
import ba import babase
import bauiv1 as bui
import bascenev1 as bs
import random import random
class CustomText(ba.Actor): class CustomText(bs.Actor):
"""Text that pops up above a position to denote something special. """Text that pops up above a position to denote something special.
category: Gameplay Classes category: Gameplay Classes
""" """
def __init__(self, def __init__(self,
text: Union[str, ba.Lstr], text: Union[str, babase.Lstr],
position: Sequence[float] = (0.0, 0.0, 0.0), position: Sequence[float] = (0.0, 0.0, 0.0),
color: Sequence[float] = (1.0, 1.0, 1.0, 1.0), color: Sequence[float] = (1.0, 1.0, 1.0, 1.0),
random_offset: float = 0.5, random_offset: float = 0.5,
@ -34,7 +37,7 @@ class CustomText(ba.Actor):
(0.5 - random.random()), position[1] + offset[0] + (0.5 - random.random()), position[1] + offset[0] +
random_offset * (0.5 - random.random()), position[2] + random_offset * (0.5 - random.random()), position[2] +
offset[0] + random_offset * (0.5 - random.random())) offset[0] + random_offset * (0.5 - random.random()))
self.node = ba.newnode('text', self.node = bs.newnode('text',
attrs={ attrs={
'text': text, 'text': text,
'in_world': True, 'in_world': True,
@ -42,27 +45,27 @@ class CustomText(ba.Actor):
'flatness': 1.0, 'flatness': 1.0,
'h_align': 'center'}, delegate=self) 'h_align': 'center'}, delegate=self)
lifespan = duration lifespan = duration
ba.animate( bs.animate(
self.node, 'scale', { self.node, 'scale', {
0: 0.0, 0: 0.0,
lifespan * 0.11: 0.020 * 0.7 * scale, lifespan * 0.11: 0.020 * 0.7 * scale,
lifespan * 0.16: 0.013 * 0.7 * scale, lifespan * 0.16: 0.013 * 0.7 * scale,
lifespan * 0.25: 0.014 * 0.7 * scale lifespan * 0.25: 0.014 * 0.7 * scale
}) })
self._tcombine = ba.newnode('combine', self._tcombine = bs.newnode('combine',
owner=self.node, owner=self.node,
attrs={ attrs={
'input0': pos[0], 'input0': pos[0],
'input2': pos[2], 'input2': pos[2],
'size': 3 'size': 3
}) })
ba.animate(self._tcombine, 'input1', { bs.animate(self._tcombine, 'input1', {
0: pos[1] + 1.5, 0: pos[1] + 1.5,
lifespan: pos[1] + 2.0 lifespan: pos[1] + 2.0
}) })
self._tcombine.connectattr('output', self.node, 'position') self._tcombine.connectattr('output', self.node, 'position')
# fade our opacity in/out # fade our opacity in/out
self._combine = ba.newnode('combine', self._combine = bs.newnode('combine',
owner=self.node, owner=self.node,
attrs={ attrs={
'input0': color[0], 'input0': color[0],
@ -71,64 +74,64 @@ class CustomText(ba.Actor):
'size': 4 'size': 4
}) })
for i in range(4): for i in range(4):
ba.animate( bs.animate(
self._combine, 'input' + str(i), { self._combine, 'input' + str(i), {
0.13 * lifespan: color[i], 0.13 * lifespan: color[i],
0.18 * lifespan: 4.0 * color[i], 0.18 * lifespan: 4.0 * color[i],
0.22 * lifespan: color[i]}) 0.22 * lifespan: color[i]})
ba.animate(self._combine, 'input3', { bs.animate(self._combine, 'input3', {
0: 0, 0: 0,
0.1 * lifespan: color[3], 0.1 * lifespan: color[3],
0.7 * lifespan: color[3], 0.7 * lifespan: color[3],
lifespan: 0}) lifespan: 0})
self._combine.connectattr('output', self.node, 'color') self._combine.connectattr('output', self.node, 'color')
self._die_timer = ba.Timer( self._die_timer = bs.Timer(
lifespan, ba.WeakCall(self.handlemessage, ba.DieMessage())) lifespan, bs.WeakCall(self.handlemessage, bs.DieMessage()))
def handlemessage(self, msg: Any) -> Any: def handlemessage(self, msg: Any) -> Any:
assert not self.expired assert not self.expired
if isinstance(msg, ba.DieMessage): if isinstance(msg, bs.DieMessage):
if self.node: if self.node:
self.node.delete() self.node.delete()
else: else:
super().handlemessage(msg) 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:
self.score = 0 self.score = 0
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:
self.score = 0 self.score = 0
# ba_meta export game # ba_meta export bascenev1.GameActivity
class SimonSays(ba.TeamGameActivity[Player, Team]): class SimonSays(bs.TeamGameActivity[Player, Team]):
name = "Simon Says" name = "Simon Says"
description = "You have to better do what Simon says!" description = "You have to better do what Simon says!"
@classmethod @classmethod
def get_available_settings(cls, sessiontype: Type[ba.Session]) -> List[ba.Setting]: def get_available_settings(cls, sessiontype: Type[bs.Session]) -> List[babase.Setting]:
settings = [ settings = [
ba.BoolSetting("Epic Mode", default=False), bs.BoolSetting("Epic Mode", default=False),
ba.BoolSetting("Enable Jumping", default=False), bs.BoolSetting("Enable Jumping", default=False),
ba.BoolSetting("Enable Punching", default=False), bs.BoolSetting("Enable Punching", default=False),
ba.BoolSetting("Enable Picking Up", default=False), bs.BoolSetting("Enable Picking Up", default=False),
ba.IntChoiceSetting("Timer Speed", bs.IntChoiceSetting("Timer Speed",
choices=[("Snaily", 1200), choices=[("Snaily", 1200),
("Slow", 900), ("Slow", 900),
("Normal", 655), ("Normal", 655),
("Fast", 544), ("Fast", 544),
("Turbo", 460)], default=655), ("Turbo", 460)], default=655),
ba.FloatChoiceSetting("Text Duration", bs.FloatChoiceSetting("Text Duration",
choices=[("Slow", 2.5), choices=[("Slow", 2.5),
("Normal", 1.5), ("Normal", 1.5),
("Mediocre", 1.0), ("Mediocre", 1.0),
@ -136,12 +139,12 @@ class SimonSays(ba.TeamGameActivity[Player, Team]):
return settings return settings
@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 ["Courtyard"] return ["Courtyard"]
@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.FreeForAllSession) return issubclass(sessiontype, bs.FreeForAllSession)
def __init__(self, settings: dict): def __init__(self, settings: dict):
super().__init__(settings) super().__init__(settings)
@ -157,7 +160,7 @@ class SimonSays(ba.TeamGameActivity[Player, Team]):
self.counter_loop = None self.counter_loop = None
self.time = 5000 self.time = 5000
self._r1 = 2 self._r1 = 2
self.ct_text = ba.newnode('text', attrs={ self.ct_text = bs.newnode('text', attrs={
'in_world': True, 'in_world': True,
'text': '......', 'text': '......',
'shadow': 1.0, 'shadow': 1.0,
@ -165,44 +168,44 @@ class SimonSays(ba.TeamGameActivity[Player, Team]):
'flatness': 0.5, 'flatness': 0.5,
'position': (-5.627144702, 3.3275475, -9.572879116), 'position': (-5.627144702, 3.3275475, -9.572879116),
'scale': 0.05}) 'scale': 0.05})
self.n1 = ba.newnode('locator', attrs={'shape': 'circle', 'position': (-4, 0, -6), self.n1 = bs.newnode('locator', attrs={'shape': 'circle', 'position': (-4, 0, -6),
'color': (1, 0, 0), 'opacity': 0.5, 'color': (1, 0, 0), 'opacity': 0.5,
'draw_beauty': True, 'additive': True}) 'draw_beauty': True, 'additive': True})
self.n2 = ba.newnode('locator', attrs={'shape': 'circle', 'position': (0, 0, -6), self.n2 = bs.newnode('locator', attrs={'shape': 'circle', 'position': (0, 0, -6),
'color': (0, 1, 0), 'opacity': 0.5, 'color': (0, 1, 0), 'opacity': 0.5,
'draw_beauty': True, 'additive': True}) 'draw_beauty': True, 'additive': True})
self.n3 = ba.newnode('locator', attrs={'shape': 'circle', 'position': (4, 0, -6), self.n3 = bs.newnode('locator', attrs={'shape': 'circle', 'position': (4, 0, -6),
'color': (0, 0, 1), 'opacity': 0.5, 'color': (0, 0, 1), 'opacity': 0.5,
'draw_beauty': True, 'additive': True}) 'draw_beauty': True, 'additive': True})
self.n4 = ba.newnode('locator', attrs={'shape': 'circle', 'position': (-4, 0, -2), self.n4 = bs.newnode('locator', attrs={'shape': 'circle', 'position': (-4, 0, -2),
'color': (1, 1, 0), 'opacity': 0.5, 'color': (1, 1, 0), 'opacity': 0.5,
'draw_beauty': True, 'additive': True}) 'draw_beauty': True, 'additive': True})
self.n5 = ba.newnode('locator', attrs={'shape': 'circle', 'position': (0, 0, -2), self.n5 = bs.newnode('locator', attrs={'shape': 'circle', 'position': (0, 0, -2),
'color': (0, 1, 1), 'opacity': 0.5, 'color': (0, 1, 1), 'opacity': 0.5,
'draw_beauty': True, 'additive': True}) 'draw_beauty': True, 'additive': True})
self.n6 = ba.newnode('locator', attrs={'shape': 'circle', 'position': (4, 0, -2), self.n6 = bs.newnode('locator', attrs={'shape': 'circle', 'position': (4, 0, -2),
'color': (1, 0, 1), 'opacity': 0.5, 'color': (1, 0, 1), 'opacity': 0.5,
'draw_beauty': True, 'additive': True}) 'draw_beauty': True, 'additive': True})
self.n7 = ba.newnode('locator', attrs={'shape': 'circle', 'position': (-4, 0, 2), self.n7 = bs.newnode('locator', attrs={'shape': 'circle', 'position': (-4, 0, 2),
'color': (.5, .5, .5), 'opacity': 0.5, 'color': (.5, .5, .5), 'opacity': 0.5,
'draw_beauty': True, 'additive': True}) 'draw_beauty': True, 'additive': True})
self.n8 = ba.newnode('locator', attrs={'shape': 'circle', 'position': (0, 0, 2), self.n8 = bs.newnode('locator', attrs={'shape': 'circle', 'position': (0, 0, 2),
'color': (.5, .325, 0), 'opacity': 0.5, 'color': (.5, .325, 0), 'opacity': 0.5,
'draw_beauty': True, 'additive': True}) 'draw_beauty': True, 'additive': True})
self.n9 = ba.newnode('locator', attrs={'shape': 'circle', 'position': (4, 0, 2), self.n9 = bs.newnode('locator', attrs={'shape': 'circle', 'position': (4, 0, 2),
'color': (1, 1, 1), 'opacity': 0.5, 'color': (1, 1, 1), 'opacity': 0.5,
'draw_beauty': True, 'additive': True}) 'draw_beauty': True, 'additive': True})
self.options = ["red", "green", "blue", "yellow", "teal", "purple", "gray", "orange", self.options = ["red", "green", "blue", "yellow", "teal", "purple", "gray", "orange",
"white", "top", "bottom", "middle row", "left", "right", "center column", "outside"] "white", "top", "bottom", "middle row", "left", "right", "center column", "outside"]
self.default_music = ba.MusicType.FLAG_CATCHER self.default_music = bs.MusicType.FLAG_CATCHER
def get_instance_description(self) -> str: def get_instance_description(self) -> str:
return 'Follow the commands... but only when \"Simon says!"' return 'Follow the commands... but only when \"Simon says!"'
def on_player_join(self, player: Player) -> None: def on_player_join(self, player: Player) -> None:
if self.has_begun(): if self.has_begun():
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),)
return return
@ -227,11 +230,11 @@ class SimonSays(ba.TeamGameActivity[Player, Team]):
player.score = 0 player.score = 0
# check for immediate end if theres only 1 player # check for immediate end if theres only 1 player
if len(self.players) == 1: if len(self.players) == 1:
ba.timer(4000, lambda: self.check_end(), timeformat=ba.TimeFormat.MILLISECONDS) bs.timer(4000/1000, lambda: self.check_end())
else: else:
ba.timer(6000, self.call_round, timeformat=ba.TimeFormat.MILLISECONDS) bs.timer(6000/1000, self.call_round)
def spawn_player(self, player: PlayerType) -> ba.Actor: def spawn_player(self, player: PlayerT) -> bs.Actor:
assert player assert player
spaz = self.spawn_player_spaz(player, position=( spaz = self.spawn_player_spaz(player, position=(
0 + random.uniform(-3.6, 3.6), 2.9, -2 + random.uniform(-3.6, 3.6))) 0 + random.uniform(-3.6, 3.6), 2.9, -2 + random.uniform(-3.6, 3.6)))
@ -291,12 +294,11 @@ class SimonSays(ba.TeamGameActivity[Player, Team]):
self.string = "0" self.string = "0"
self.ct_text.text = self.string self.ct_text.text = self.string
self.counter_loop = None self.counter_loop = None
ba.timer(1, dummy_check, timeformat=ba.TimeFormat.MILLISECONDS) bs.timer(1/1000, dummy_check)
else: else:
self.ct_text.text = str(self.now) self.ct_text.text = str(self.now)
ba.playsound(ba.getsound('tick')) bs.getsound('tick').play()
self.counter_loop = ba.Timer(self.speed, set_counter, self.counter_loop = bs.Timer(self.speed/1000, set_counter, repeat=True)
timeformat=ba.TimeFormat.MILLISECONDS, repeat=True)
def check_round(self) -> None: def check_round(self) -> None:
if self.ended: if self.ended:
@ -307,8 +309,8 @@ class SimonSays(ba.TeamGameActivity[Player, Team]):
player.actor.node.position_center) else False player.actor.node.position_center) else False
if ((self.simon and safe == False) or ((not self.simon) and safe == True)): if ((self.simon and safe == False) or ((not self.simon) and safe == True)):
player.team.score = self.round_num player.team.score = self.round_num
player.actor.handlemessage(ba.DieMessage()) player.actor.handlemessage(bs.DieMessage())
ba.timer(1633, self.call_round, timeformat=ba.TimeFormat.MILLISECONDS) bs.timer(1633/1000, self.call_round)
def in_circle(self, pos) -> None: def in_circle(self, pos) -> None:
circles = [] circles = []
@ -349,14 +351,14 @@ class SimonSays(ba.TeamGameActivity[Player, Team]):
return circles return circles
def handlemessage(self, msg) -> None: def handlemessage(self, msg) -> None:
if isinstance(msg, ba.PlayerDiedMessage): if isinstance(msg, bs.PlayerDiedMessage):
self.check_end() self.check_end()
else: else:
super().handlemessage(msg) super().handlemessage(msg)
def end_game(self) -> None: def end_game(self) -> None:
self.ended = True self.ended = True
results = ba.GameResults() results = bs.GameResults()
for team in self.teams: for team in self.teams:
results.set_team_score(team, team.score) results.set_team_score(team, team.score)
self.end(results=results) self.end(results=results)
@ -367,4 +369,4 @@ class SimonSays(ba.TeamGameActivity[Player, Team]):
if player.is_alive(): if player.is_alive():
i += 1 i += 1
if i <= 2: if i <= 2:
ba.timer(0.6, lambda: self.end_game()) bs.timer(0.6, lambda: self.end_game())

View file

@ -1,3 +1,4 @@
# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport)
# Released under the MIT License. See LICENSE for details. # Released under the MIT License. See LICENSE for details.
# y me (: itsre3 # y me (: itsre3
# =>2<= # =>2<=
@ -5,7 +6,7 @@
# #
"""Defines Race mini-game.""" """Defines Race 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
@ -14,17 +15,17 @@ import random
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from dataclasses import dataclass from dataclasses import dataclass
import ba import babase
import _ba import bascenev1 as bs
from bastd.actor.bomb import Bomb from bascenev1lib.actor.bomb import Bomb
from bastd.actor.playerspaz import PlayerSpaz from bascenev1lib.actor.playerspaz import PlayerSpaz
from bastd.actor.scoreboard import Scoreboard from bascenev1lib.actor.scoreboard import Scoreboard
from bastd.gameutils import SharedObjects from bascenev1lib.gameutils import SharedObjects
if TYPE_CHECKING: if TYPE_CHECKING:
from typing import (Any, Type, Tuple, List, Sequence, Optional, Dict, from typing import (Any, Type, Tuple, List, Sequence, Optional, Dict,
Union) Union)
from bastd.actor.onscreentimer import OnScreenTimer from bascenev1lib.actor.onscreentimer import OnScreenTimer
@dataclass @dataclass
@ -34,7 +35,7 @@ class RaceMine:
mine: Optional[Bomb] mine: Optional[Bomb]
class RaceRegion(ba.Actor): class RaceRegion(bs.Actor):
"""Region used to track progress during a race.""" """Region used to track progress during a race."""
def __init__(self, pt: Sequence[float], index: int): def __init__(self, pt: Sequence[float], index: int):
@ -43,7 +44,7 @@ class RaceRegion(ba.Actor):
assert isinstance(activity, RaceGame) assert isinstance(activity, RaceGame)
self.pos = pt self.pos = pt
self.index = index self.index = index
self.node = ba.newnode( self.node = bs.newnode(
'region', 'region',
delegate=self, delegate=self,
attrs={ attrs={
@ -54,11 +55,11 @@ class RaceRegion(ba.Actor):
}) })
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:
self.distance_txt: Optional[ba.Node] = None self.distance_txt: Optional[bs.Node] = None
self.last_region = 0 self.last_region = 0
self.lap = 0 self.lap = 0
self.distance = 0.0 self.distance = 0.0
@ -66,7 +67,7 @@ class Player(ba.Player['Team']):
self.rank: Optional[int] = None self.rank: Optional[int] = None
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:
@ -75,22 +76,22 @@ class Team(ba.Team[Player]):
self.finished = False self.finished = False
# ba_meta export game # ba_meta export bascenev1.GameActivity
class SleepRaceGame(ba.TeamGameActivity[Player, Team]): class SleepRaceGame(bs.TeamGameActivity[Player, Team]):
"""Game of racing around a track.""" """Game of racing around a track."""
name = 'Sleep Race' name = 'Sleep Race'
description = 'Can you run while sleeping?' description = 'Can you run while sleeping?'
scoreconfig = ba.ScoreConfig(label='Time', scoreconfig = bs.ScoreConfig(label='Time',
lower_is_better=True, lower_is_better=True,
scoretype=ba.ScoreType.MILLISECONDS) scoretype=bs.ScoreType.MILLISECONDS)
@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('Laps', min_value=1, default=2, increment=1), bs.IntSetting('Laps', min_value=1, default=2, increment=1),
ba.IntChoiceSetting( bs.IntChoiceSetting(
'Time Limit', 'Time Limit',
default=0, default=0,
choices=[ choices=[
@ -102,7 +103,7 @@ class SleepRaceGame(ba.TeamGameActivity[Player, Team]):
('20 Minutes', 1200), ('20 Minutes', 1200),
], ],
), ),
ba.IntChoiceSetting( bs.IntChoiceSetting(
'Mine Spawning', 'Mine Spawning',
default=4000, default=4000,
choices=[ choices=[
@ -112,7 +113,7 @@ class SleepRaceGame(ba.TeamGameActivity[Player, Team]):
('2 Seconds', 2000), ('2 Seconds', 2000),
], ],
), ),
ba.IntChoiceSetting( bs.IntChoiceSetting(
'Bomb Spawning', 'Bomb Spawning',
choices=[ choices=[
('None', 0), ('None', 0),
@ -123,7 +124,7 @@ class SleepRaceGame(ba.TeamGameActivity[Player, Team]):
], ],
default=2000, default=2000,
), ),
ba.IntChoiceSetting( bs.IntChoiceSetting(
'Knockout Time', 'Knockout Time',
choices=[ choices=[
('8 Seconds', 8000), ('8 Seconds', 8000),
@ -131,48 +132,48 @@ class SleepRaceGame(ba.TeamGameActivity[Player, Team]):
], ],
default=5000, default=5000,
), ),
ba.BoolSetting('Epic Mode', default=False), bs.BoolSetting('Epic Mode', default=False),
ba.BoolSetting('Credits', default=True), bs.BoolSetting('Credits', default=True),
] ]
# We have some specific settings in teams mode. # We have some specific settings in teams mode.
if issubclass(sessiontype, ba.DualTeamSession): if issubclass(sessiontype, bs.DualTeamSession):
settings.append( settings.append(
ba.BoolSetting('Entire Team Must Finish', default=False)) bs.BoolSetting('Entire Team Must Finish', 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.MultiTeamSession) return issubclass(sessiontype, bs.MultiTeamSession)
@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('race') return bs.app.classic.getmaps('race')
def __init__(self, settings: dict): def __init__(self, settings: dict):
self._race_started = False self._race_started = False
super().__init__(settings) super().__init__(settings)
self._scoreboard = Scoreboard() self._scoreboard = Scoreboard()
self._score_sound = ba.getsound('score') self._score_sound = bs.getsound('score')
self._swipsound = ba.getsound('swip') self._swipsound = bs.getsound('swip')
self._last_team_time: Optional[float] = None self._last_team_time: Optional[float] = None
self._front_race_region: Optional[int] = None self._front_race_region: Optional[int] = None
self._nub_tex = ba.gettexture('nub') self._nub_tex = bs.gettexture('nub')
self._beep_1_sound = ba.getsound('raceBeep1') self._beep_1_sound = bs.getsound('raceBeep1')
self._beep_2_sound = ba.getsound('raceBeep2') self._beep_2_sound = bs.getsound('raceBeep2')
self.race_region_material: Optional[ba.Material] = None self.race_region_material: Optional[bs.Material] = None
self._regions: List[RaceRegion] = [] self._regions: List[RaceRegion] = []
self._team_finish_pts: Optional[int] = None self._team_finish_pts: Optional[int] = None
self._time_text: Optional[ba.Actor] = None self._time_text: Optional[bs.Actor] = None
self._cd_text: Optional[ba.Actor] = None self._cd_text: Optional[bs.Actor] = None
self._timer: Optional[OnScreenTimer] = None self._timer: Optional[OnScreenTimer] = None
self._race_mines: Optional[List[RaceMine]] = None self._race_mines: Optional[List[RaceMine]] = None
self._race_mine_timer: Optional[ba.Timer] = None self._race_mine_timer: Optional[bs.Timer] = None
self._scoreboard_timer: Optional[ba.Timer] = None self._scoreboard_timer: Optional[bs.Timer] = None
self._player_order_update_timer: Optional[ba.Timer] = None self._player_order_update_timer: Optional[bs.Timer] = None
self._start_lights: Optional[List[ba.Node]] = None self._start_lights: Optional[List[bs.Node]] = None
self._bomb_spawn_timer: Optional[ba.Timer] = None self._bomb_spawn_timer: Optional[bs.Timer] = None
self._knockout_timer: Optional[ba.Timer] = None self._knockout_timer: Optional[bs.Timer] = None
self._laps = int(settings['Laps']) self._laps = int(settings['Laps'])
self._entire_team_must_finish = bool( self._entire_team_must_finish = bool(
settings.get('Entire Team Must Finish', False)) settings.get('Entire Team Must Finish', False))
@ -185,11 +186,11 @@ class SleepRaceGame(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_RACE self.default_music = (bs.MusicType.EPIC_RACE
if self._epic_mode else ba.MusicType.RACE) if self._epic_mode else bs.MusicType.RACE)
def get_instance_description(self) -> Union[str, Sequence]: def get_instance_description(self) -> Union[str, Sequence]:
if (isinstance(self.session, ba.DualTeamSession) if (isinstance(self.session, bs.DualTeamSession)
and self._entire_team_must_finish): and self._entire_team_must_finish):
t_str = ' Your entire team has to finish.' t_str = ' Your entire team has to finish.'
else: else:
@ -208,7 +209,7 @@ class SleepRaceGame(ba.TeamGameActivity[Player, Team]):
super().on_transition_in() super().on_transition_in()
shared = SharedObjects.get() shared = SharedObjects.get()
pts = self.map.get_def_points('race_point') pts = self.map.get_def_points('race_point')
mat = self.race_region_material = ba.Material() mat = self.race_region_material = bs.Material()
mat.add_actions(conditions=('they_have_material', mat.add_actions(conditions=('they_have_material',
shared.player_material), shared.player_material),
actions=( actions=(
@ -224,28 +225,28 @@ class SleepRaceGame(ba.TeamGameActivity[Player, Team]):
assert isinstance(player.actor, PlayerSpaz) assert isinstance(player.actor, PlayerSpaz)
assert player.actor.node assert player.actor.node
pos = player.actor.node.position pos = player.actor.node.position
light = ba.newnode('light', light = bs.newnode('light',
attrs={ attrs={
'position': pos, 'position': pos,
'color': (1, 1, 0), 'color': (1, 1, 0),
'height_attenuated': False, 'height_attenuated': False,
'radius': 0.4 'radius': 0.4
}) })
ba.timer(0.5, light.delete) bs.timer(0.5, light.delete)
ba.animate(light, 'intensity', {0: 0, 0.1: 1.0 * scale, 0.5: 0}) bs.animate(light, 'intensity', {0: 0, 0.1: 1.0 * scale, 0.5: 0})
def _handle_race_point_collide(self) -> None: def _handle_race_point_collide(self) -> None:
# FIXME: Tidy this up. # FIXME: Tidy this up.
# pylint: disable=too-many-statements # pylint: disable=too-many-statements
# pylint: disable=too-many-branches # pylint: disable=too-many-branches
# pylint: disable=too-many-nested-blocks # pylint: disable=too-many-nested-blocks
collision = ba.getcollision() collision = bs.getcollision()
try: try:
region = collision.sourcenode.getdelegate(RaceRegion, True) region = collision.sourcenode.getdelegate(RaceRegion, True)
player = collision.opposingnode.getdelegate(PlayerSpaz, player = collision.opposingnode.getdelegate(PlayerSpaz,
True).getplayer( True).getplayer(
Player, True) Player, True)
except ba.NotFoundError: except bs.NotFoundError:
return return
last_region = player.last_region last_region = player.last_region
@ -259,8 +260,8 @@ class SleepRaceGame(ba.TeamGameActivity[Player, Team]):
if this_region > last_region + 2: if this_region > last_region + 2:
if player.is_alive(): if player.is_alive():
assert player.actor assert player.actor
player.actor.handlemessage(ba.DieMessage()) player.actor.handlemessage(bs.DieMessage())
ba.screenmessage(ba.Lstr( bs.broadcastmessage(babase.Lstr(
translate=('statements', 'Killing ${NAME} for' translate=('statements', 'Killing ${NAME} for'
' skipping part of the track!'), ' skipping part of the track!'),
subs=[('${NAME}', player.getname(full=True))]), subs=[('${NAME}', player.getname(full=True))]),
@ -279,7 +280,7 @@ class SleepRaceGame(ba.TeamGameActivity[Player, Team]):
# In teams mode with all-must-finish on, the team lap # In teams mode with all-must-finish on, the team lap
# value is the min of all team players. # value is the min of all team players.
# Otherwise its the max. # Otherwise its the max.
if isinstance(self.session, ba.DualTeamSession if isinstance(self.session, bs.DualTeamSession
) and self._entire_team_must_finish: ) and self._entire_team_must_finish:
team.lap = min([p.lap for p in team.players]) team.lap = min([p.lap for p in team.players])
else: else:
@ -290,7 +291,7 @@ class SleepRaceGame(ba.TeamGameActivity[Player, Team]):
# In teams mode, hand out points based on the order # In teams mode, hand out points based on the order
# players come in. # players come in.
if isinstance(self.session, ba.DualTeamSession): if isinstance(self.session, bs.DualTeamSession):
assert self._team_finish_pts is not None assert self._team_finish_pts is not None
if self._team_finish_pts > 0: if self._team_finish_pts > 0:
self.stats.player_scored(player, self.stats.player_scored(player,
@ -303,7 +304,7 @@ class SleepRaceGame(ba.TeamGameActivity[Player, Team]):
player.finished = True player.finished = True
assert player.actor assert player.actor
player.actor.handlemessage( player.actor.handlemessage(
ba.DieMessage(immediate=True)) bs.DieMessage(immediate=True))
# Makes sure noone behind them passes them in rank # Makes sure noone behind them passes them in rank
# while finishing. # while finishing.
@ -311,26 +312,26 @@ class SleepRaceGame(ba.TeamGameActivity[Player, Team]):
# If the whole team has finished the race. # If the whole team has finished the race.
if team.lap == self._laps: if team.lap == self._laps:
ba.playsound(self._score_sound) self._score_sound.play()
player.team.finished = True player.team.finished = True
assert self._timer is not None assert self._timer is not None
elapsed = ba.time() - self._timer.getstarttime() elapsed = bs.time() - self._timer.getstarttime()
self._last_team_time = player.team.time = elapsed self._last_team_time = player.team.time = elapsed
self._check_end_game() self._check_end_game()
# Team has yet to finish. # Team has yet to finish.
else: else:
ba.playsound(self._swipsound) self._swipsound.play()
# They've just finished a lap but not the race. # They've just finished a lap but not the race.
else: else:
ba.playsound(self._swipsound) self._swipsound.play()
self._flash_player(player, 0.3) self._flash_player(player, 0.3)
# Print their lap number over their head. # Print their lap number over their head.
try: try:
assert isinstance(player.actor, PlayerSpaz) assert isinstance(player.actor, PlayerSpaz)
mathnode = ba.newnode('math', mathnode = bs.newnode('math',
owner=player.actor.node, owner=player.actor.node,
attrs={ attrs={
'input1': (0, 1.9, 0), 'input1': (0, 1.9, 0),
@ -338,12 +339,12 @@ class SleepRaceGame(ba.TeamGameActivity[Player, Team]):
}) })
player.actor.node.connectattr( player.actor.node.connectattr(
'torso_position', mathnode, 'input2') 'torso_position', mathnode, 'input2')
tstr = ba.Lstr(resource='lapNumberText', tstr = babase.Lstr(resource='lapNumberText',
subs=[('${CURRENT}', subs=[('${CURRENT}',
str(player.lap + 1)), str(player.lap + 1)),
('${TOTAL}', str(self._laps)) ('${TOTAL}', str(self._laps))
]) ])
txtnode = ba.newnode('text', txtnode = bs.newnode('text',
owner=mathnode, owner=mathnode,
attrs={ attrs={
'text': tstr, 'text': tstr,
@ -353,15 +354,15 @@ class SleepRaceGame(ba.TeamGameActivity[Player, Team]):
'h_align': 'center' 'h_align': 'center'
}) })
mathnode.connectattr('output', txtnode, 'position') mathnode.connectattr('output', txtnode, 'position')
ba.animate(txtnode, 'scale', { bs.animate(txtnode, 'scale', {
0.0: 0, 0.0: 0,
0.2: 0.019, 0.2: 0.019,
2.0: 0.019, 2.0: 0.019,
2.2: 0 2.2: 0
}) })
ba.timer(2.3, mathnode.delete) bs.timer(2.3, mathnode.delete)
except Exception: except Exception:
ba.print_exception('Error printing lap.') babase.print_exception('Error printing lap.')
def on_team_join(self, team: Team) -> None: def on_team_join(self, team: Team) -> None:
self._update_scoreboard() self._update_scoreboard()
@ -372,9 +373,9 @@ class SleepRaceGame(ba.TeamGameActivity[Player, Team]):
# A player leaving disqualifies the team if 'Entire Team Must Finish' # A player leaving disqualifies the team if 'Entire Team Must Finish'
# is on (otherwise in teams mode everyone could just leave except the # is on (otherwise in teams mode everyone could just leave except the
# leading player to win). # leading player to win).
if (isinstance(self.session, ba.DualTeamSession) if (isinstance(self.session, bs.DualTeamSession)
and self._entire_team_must_finish): and self._entire_team_must_finish):
ba.screenmessage(ba.Lstr( bs.broadcastmessage(babase.Lstr(
translate=('statements', translate=('statements',
'${TEAM} is disqualified because ${PLAYER} left'), '${TEAM} is disqualified because ${PLAYER} left'),
subs=[('${TEAM}', player.team.name), subs=[('${TEAM}', player.team.name),
@ -383,18 +384,18 @@ class SleepRaceGame(ba.TeamGameActivity[Player, Team]):
player.team.finished = True player.team.finished = True
player.team.time = None player.team.time = None
player.team.lap = 0 player.team.lap = 0
ba.playsound(ba.getsound('boo')) bs.getsound('boo').play()
for otherplayer in player.team.players: for otherplayer in player.team.players:
otherplayer.lap = 0 otherplayer.lap = 0
otherplayer.finished = True otherplayer.finished = True
try: try:
if otherplayer.actor is not None: if otherplayer.actor is not None:
otherplayer.actor.handlemessage(ba.DieMessage()) otherplayer.actor.handlemessage(bs.DieMessage())
except Exception: except Exception:
ba.print_exception('Error sending DieMessage.') babase.print_exception('Error sending DieMessage.')
# Defer so team/player lists will be updated. # Defer so team/player lists will be updated.
ba.pushcall(self._check_end_game) babase.pushcall(self._check_end_game)
def _update_scoreboard(self) -> None: def _update_scoreboard(self) -> None:
for team in self.teams: for team in self.teams:
@ -402,7 +403,7 @@ class SleepRaceGame(ba.TeamGameActivity[Player, Team]):
if not distances: if not distances:
teams_dist = 0.0 teams_dist = 0.0
else: else:
if (isinstance(self.session, ba.DualTeamSession) if (isinstance(self.session, bs.DualTeamSession)
and self._entire_team_must_finish): and self._entire_team_must_finish):
teams_dist = min(distances) teams_dist = min(distances)
else: else:
@ -415,14 +416,14 @@ class SleepRaceGame(ba.TeamGameActivity[Player, Team]):
show_value=False) show_value=False)
def on_begin(self) -> None: def on_begin(self) -> None:
from bastd.actor.onscreentimer import OnScreenTimer from bascenev1lib.actor.onscreentimer import OnScreenTimer
super().on_begin() super().on_begin()
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._team_finish_pts = 100 self._team_finish_pts = 100
if self._credits: if self._credits:
self._cd_text = ba.NodeActor( self._cd_text = bs.NodeActor(
ba.newnode('text', bs.newnode('text',
attrs={ attrs={
'position': (0, 0), 'position': (0, 0),
'h_attach': 'center', 'h_attach': 'center',
@ -437,8 +438,8 @@ class SleepRaceGame(ba.TeamGameActivity[Player, Team]):
})) }))
# Throw a timer up on-screen. # Throw a timer up on-screen.
self._time_text = ba.NodeActor( self._time_text = bs.NodeActor(
ba.newnode('text', bs.newnode('text',
attrs={ attrs={
'v_attach': 'top', 'v_attach': 'top',
'h_attach': 'center', 'h_attach': 'center',
@ -458,14 +459,14 @@ class SleepRaceGame(ba.TeamGameActivity[Player, Team]):
for p in self.map.get_def_points('race_mine') for p in self.map.get_def_points('race_mine')
] ]
if self._race_mines: if self._race_mines:
self._race_mine_timer = ba.Timer(0.001 * self._mine_spawning, self._race_mine_timer = bs.Timer(0.001 * self._mine_spawning,
self._update_race_mine, self._update_race_mine,
repeat=True) repeat=True)
self._scoreboard_timer = ba.Timer(0.25, self._scoreboard_timer = bs.Timer(0.25,
self._update_scoreboard, self._update_scoreboard,
repeat=True) repeat=True)
self._player_order_update_timer = ba.Timer(0.25, self._player_order_update_timer = bs.Timer(0.25,
self._update_player_order, self._update_player_order,
repeat=True) repeat=True)
@ -478,30 +479,30 @@ class SleepRaceGame(ba.TeamGameActivity[Player, Team]):
lstart = 7.1 * t_scale lstart = 7.1 * t_scale
inc = 1.25 * t_scale inc = 1.25 * t_scale
ba.timer(lstart, self._do_light_1) bs.timer(lstart, self._do_light_1)
ba.timer(lstart + inc, self._do_light_2) bs.timer(lstart + inc, self._do_light_2)
ba.timer(lstart + 2 * inc, self._do_light_3) bs.timer(lstart + 2 * inc, self._do_light_3)
ba.timer(lstart + 3 * inc, self._start_race) bs.timer(lstart + 3 * inc, self._start_race)
self._start_lights = [] self._start_lights = []
for i in range(4): for i in range(4):
lnub = ba.newnode('image', lnub = bs.newnode('image',
attrs={ attrs={
'texture': ba.gettexture('nub'), 'texture': bs.gettexture('nub'),
'opacity': 1.0, 'opacity': 1.0,
'absolute_scale': True, 'absolute_scale': True,
'position': (-75 + i * 50, light_y), 'position': (-75 + i * 50, light_y),
'scale': (50, 50), 'scale': (50, 50),
'attach': 'center' 'attach': 'center'
}) })
ba.animate( bs.animate(
lnub, 'opacity', { lnub, 'opacity', {
4.0 * t_scale: 0, 4.0 * t_scale: 0,
5.0 * t_scale: 1.0, 5.0 * t_scale: 1.0,
12.0 * t_scale: 1.0, 12.0 * t_scale: 1.0,
12.5 * t_scale: 0.0 12.5 * t_scale: 0.0
}) })
ba.timer(13.0 * t_scale, lnub.delete) bs.timer(13.0 * t_scale, lnub.delete)
self._start_lights.append(lnub) self._start_lights.append(lnub)
self._start_lights[0].color = (0.2, 0, 0) self._start_lights[0].color = (0.2, 0, 0)
@ -512,45 +513,45 @@ class SleepRaceGame(ba.TeamGameActivity[Player, Team]):
def _do_light_1(self) -> None: def _do_light_1(self) -> None:
assert self._start_lights is not None assert self._start_lights is not None
self._start_lights[0].color = (1.0, 0, 0) self._start_lights[0].color = (1.0, 0, 0)
ba.playsound(self._beep_1_sound) self._beep_1_sound.play()
def _do_light_2(self) -> None: def _do_light_2(self) -> None:
assert self._start_lights is not None assert self._start_lights is not None
self._start_lights[1].color = (1.0, 0, 0) self._start_lights[1].color = (1.0, 0, 0)
ba.playsound(self._beep_1_sound) self._beep_1_sound.play()
def _do_light_3(self) -> None: def _do_light_3(self) -> None:
assert self._start_lights is not None assert self._start_lights is not None
self._start_lights[2].color = (1.0, 0.3, 0) self._start_lights[2].color = (1.0, 0.3, 0)
ba.playsound(self._beep_1_sound) self._beep_1_sound.play()
def _start_race(self) -> None: def _start_race(self) -> None:
assert self._start_lights is not None assert self._start_lights is not None
self._start_lights[3].color = (0.0, 1.0, 0) self._start_lights[3].color = (0.0, 1.0, 0)
ba.playsound(self._beep_2_sound) self._beep_2_sound.play()
for player in self.players: for player in self.players:
if player.actor is not None: if player.actor is not None:
try: try:
assert isinstance(player.actor, PlayerSpaz) assert isinstance(player.actor, PlayerSpaz)
player.actor.connect_controls_to_player() player.actor.connect_controls_to_player()
except Exception: except Exception:
ba.print_exception('Error in race player connects.') babase.print_exception('Error in race player connects.')
assert self._timer is not None assert self._timer is not None
self._timer.start() self._timer.start()
if self._bomb_spawning != 0: if self._bomb_spawning != 0:
self._bomb_spawn_timer = ba.Timer(0.001 * self._bomb_spawning, self._bomb_spawn_timer = bs.Timer(0.001 * self._bomb_spawning,
self._spawn_bomb, self._spawn_bomb,
repeat=True) repeat=True)
def knock_players(): def knock_players():
activity = _ba.get_foreground_host_activity() activity = bs.get_foreground_host_activity()
gnode = ba.getactivity().globalsnode gnode = bs.getactivity().globalsnode
for players in activity.players: for players in activity.players:
gnode.tint = (0.5, 0.5, 0.5) gnode.tint = (0.5, 0.5, 0.5)
node = players.actor.node node = players.actor.node
node.handlemessage('knockout', 600.0) node.handlemessage('knockout', 600.0)
self.text_offset = ba.newnode('math', self.text_offset = bs.newnode('math',
owner=node, owner=node,
attrs={'input1': (-0.5, 0.5, 0.25), attrs={'input1': (-0.5, 0.5, 0.25),
'operation': 'add'}) 'operation': 'add'})
@ -558,7 +559,7 @@ class SleepRaceGame(ba.TeamGameActivity[Player, Team]):
'torso_position', 'torso_position',
self.text_offset, self.text_offset,
'input2') 'input2')
self.text = ba.newnode('text', self.text = bs.newnode('text',
owner=node, owner=node,
attrs={ attrs={
'h_align': 'right', 'h_align': 'right',
@ -571,12 +572,12 @@ class SleepRaceGame(ba.TeamGameActivity[Player, Team]):
'output', 'output',
self.text, self.text,
'position') 'position')
ba.animate(self.text, 'scale', {0: 0.0, 1.0: 0.01}) bs.animate(self.text, 'scale', {0: 0.0, 1.0: 0.01})
ba.timer(2, self.text.delete) bs.timer(2, self.text.delete)
if self._knockout_time != 0: if self._knockout_time != 0:
knock_time = 0.001 * self._knockout_time knock_time = 0.001 * self._knockout_time
self._knockout_timer = ba.Timer(knock_time, self._knockout_timer = bs.Timer(knock_time,
knock_players, knock_players,
repeat=True) repeat=True)
@ -586,18 +587,18 @@ class SleepRaceGame(ba.TeamGameActivity[Player, Team]):
# Calc all player distances. # Calc all player distances.
for player in self.players: for player in self.players:
pos: Optional[ba.Vec3] pos: Optional[babase.Vec3]
try: try:
pos = player.position pos = player.position
except ba.NotFoundError: except bs.NotFoundError:
pos = None pos = None
if pos is not None: if pos is not None:
r_index = player.last_region r_index = player.last_region
rg1 = self._regions[r_index] rg1 = self._regions[r_index]
r1pt = ba.Vec3(rg1.pos[:3]) r1pt = babase.Vec3(rg1.pos[:3])
rg2 = self._regions[0] if r_index == len( rg2 = self._regions[0] if r_index == len(
self._regions) - 1 else self._regions[r_index + 1] self._regions) - 1 else self._regions[r_index + 1]
r2pt = ba.Vec3(rg2.pos[:3]) r2pt = babase.Vec3(rg2.pos[:3])
r2dist = (pos - r2pt).length() r2dist = (pos - r2pt).length()
amt = 1.0 - (r2dist / (r2pt - r1pt).length()) amt = 1.0 - (r2dist / (r2pt - r1pt).length())
amt = player.lap + (r_index + amt) * (1.0 / len(self._regions)) amt = player.lap + (r_index + amt) * (1.0 / len(self._regions))
@ -628,8 +629,8 @@ class SleepRaceGame(ba.TeamGameActivity[Player, Team]):
(-region_scale * pos[5], region_scale * pos[5])) (-region_scale * pos[5], region_scale * pos[5]))
pos = (pos[0] + random.uniform(*x_range), pos[1] + 1.0, pos = (pos[0] + random.uniform(*x_range), pos[1] + 1.0,
pos[2] + random.uniform(*z_range)) pos[2] + random.uniform(*z_range))
ba.timer(random.uniform(0.0, 2.0), bs.timer(random.uniform(0.0, 2.0),
ba.WeakCall(self._spawn_bomb_at_pos, pos)) bs.WeakCall(self._spawn_bomb_at_pos, pos))
def _spawn_bomb_at_pos(self, pos: Sequence[float]) -> None: def _spawn_bomb_at_pos(self, pos: Sequence[float]) -> None:
if self.has_ended(): if self.has_ended():
@ -645,15 +646,15 @@ class SleepRaceGame(ba.TeamGameActivity[Player, Team]):
def _flash_mine(self, i: int) -> None: def _flash_mine(self, i: int) -> None:
assert self._race_mines is not None assert self._race_mines is not None
rmine = self._race_mines[i] rmine = self._race_mines[i]
light = ba.newnode('light', light = bs.newnode('light',
attrs={ attrs={
'position': rmine.point[:3], 'position': rmine.point[:3],
'color': (1, 0.2, 0.2), 'color': (1, 0.2, 0.2),
'radius': 0.1, 'radius': 0.1,
'height_attenuated': False 'height_attenuated': False
}) })
ba.animate(light, 'intensity', {0.0: 0, 0.1: 1.0, 0.2: 0}, loop=True) bs.animate(light, 'intensity', {0.0: 0, 0.1: 1.0, 0.2: 0}, loop=True)
ba.timer(1.0, light.delete) bs.timer(1.0, light.delete)
def _update_race_mine(self) -> None: def _update_race_mine(self) -> None:
assert self._race_mines is not None assert self._race_mines is not None
@ -667,9 +668,9 @@ class SleepRaceGame(ba.TeamGameActivity[Player, Team]):
assert rmine is not None assert rmine is not None
if not rmine.mine: if not rmine.mine:
self._flash_mine(m_index) self._flash_mine(m_index)
ba.timer(0.95, ba.Call(self._make_mine, m_index)) bs.timer(0.95, babase.Call(self._make_mine, m_index))
def spawn_player(self, player: Player) -> ba.Actor: def spawn_player(self, player: Player) -> bs.Actor:
if player.team.finished: if player.team.finished:
# FIXME: This is not type-safe! # FIXME: This is not type-safe!
# This call is expected to always return an Actor! # This call is expected to always return an Actor!
@ -692,7 +693,7 @@ class SleepRaceGame(ba.TeamGameActivity[Player, Team]):
# Prevent controlling of characters before the start of the race. # Prevent controlling of characters before the start of the race.
if not self._race_started: if not self._race_started:
spaz.disconnect_controls_from_player() spaz.disconnect_controls_from_player()
mathnode = ba.newnode('math', mathnode = bs.newnode('math',
owner=spaz.node, owner=spaz.node,
attrs={ attrs={
'input1': (0, 1.4, 0), 'input1': (0, 1.4, 0),
@ -700,7 +701,7 @@ class SleepRaceGame(ba.TeamGameActivity[Player, Team]):
}) })
spaz.node.connectattr('torso_position', mathnode, 'input2') spaz.node.connectattr('torso_position', mathnode, 'input2')
distance_txt = ba.newnode('text', distance_txt = bs.newnode('text',
owner=spaz.node, owner=spaz.node,
attrs={ attrs={
'text': '', 'text': '',
@ -730,14 +731,14 @@ class SleepRaceGame(ba.TeamGameActivity[Player, Team]):
# In teams mode its over as soon as any team finishes the race # In teams mode its over as soon as any team finishes the race
# FIXME: The get_ffa_point_awards code looks dangerous. # FIXME: The get_ffa_point_awards code looks dangerous.
if isinstance(session, ba.DualTeamSession): if isinstance(session, bs.DualTeamSession):
self.end_game() self.end_game()
else: else:
# In ffa we keep the race going while there's still any points # In ffa we keep the race going while there's still any points
# to be handed out. Find out how many points we have to award # to be handed out. Find out how many points we have to award
# and how many teams have finished, and once that matches # and how many teams have finished, and once that matches
# we're done. # we're done.
assert isinstance(session, ba.FreeForAllSession) assert isinstance(session, bs.FreeForAllSession)
points_to_award = len(session.get_ffa_point_awards()) points_to_award = len(session.get_ffa_point_awards())
if teams_completed >= points_to_award - teams_completed: if teams_completed >= points_to_award - teams_completed:
self.end_game() self.end_game()
@ -754,7 +755,7 @@ class SleepRaceGame(ba.TeamGameActivity[Player, Team]):
endtime=None if self._last_team_time is None else ( endtime=None if self._last_team_time is None else (
self._timer.getstarttime() + self._last_team_time)) self._timer.getstarttime() + self._last_team_time))
results = ba.GameResults() results = bs.GameResults()
for team in self.teams: for team in self.teams:
if team.time is not None: if team.time is not None:
@ -768,10 +769,10 @@ class SleepRaceGame(ba.TeamGameActivity[Player, Team]):
# odd to be announcing that now. # odd to be announcing that now.
self.end(results=results, self.end(results=results,
announce_winning_team=isinstance(self.session, announce_winning_team=isinstance(self.session,
ba.DualTeamSession)) bs.DualTeamSession))
def handlemessage(self, msg: Any) -> Any: def handlemessage(self, msg: Any) -> Any:
if isinstance(msg, ba.PlayerDiedMessage): if isinstance(msg, bs.PlayerDiedMessage):
# Augment default behavior. # Augment default behavior.
super().handlemessage(msg) super().handlemessage(msg)
player = msg.getplayer(Player) player = msg.getplayer(Player)

View file

@ -1,19 +1,22 @@
# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport)
# snake # snake
# Released under the MIT License. See LICENSE for details. # Released under the MIT License. See LICENSE for details.
# #
"""Snake game by SEBASTIAN2059""" """Snake game by SEBASTIAN2059"""
# 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.playerspaz import PlayerSpaz import bauiv1 as bui
from bastd.actor.scoreboard import Scoreboard import bascenev1 as bs
from bastd.actor import bomb as stdbomb from bascenev1lib.actor.playerspaz import PlayerSpaz
from bascenev1lib.actor.scoreboard import Scoreboard
from bascenev1lib.actor import bomb as stdbomb
if TYPE_CHECKING: if TYPE_CHECKING:
from typing import Any, Type, List, Dict, Tuple, Union, Sequence, Optional from typing import Any, Type, List, Dict, Tuple, Union, Sequence, Optional
@ -29,7 +32,7 @@ class ScoreMessage:
return self.player return self.player
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:
@ -38,14 +41,14 @@ class Player(ba.Player['Team']):
self.actived = None self.actived = None
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:
self.score = 0 self.score = 0
lang = ba.app.lang.language lang = bs.app.lang.language
if lang == 'Spanish': if lang == 'Spanish':
description = 'Sobrevive a un número determinado de minas para ganar.' description = 'Sobrevive a un número determinado de minas para ganar.'
join_description = 'Corre y no te dejes matar.' join_description = 'Corre y no te dejes matar.'
@ -65,15 +68,15 @@ class Custom_Mine(stdbomb.Bomb):
source_player=source_player) source_player=source_player)
def handlemessage(self, msg: Any) -> Any: def handlemessage(self, msg: Any) -> Any:
if isinstance(msg, ba.HitMessage): if isinstance(msg, bs.HitMessage):
return return
else: else:
super().handlemessage(msg) super().handlemessage(msg)
# ba_meta export game # ba_meta export bascenev1.GameActivity
class SnakeGame(ba.TeamGameActivity[Player, Team]): class SnakeGame(bs.TeamGameActivity[Player, Team]):
"""A game type based on acquiring kills.""" """A game type based on acquiring kills."""
name = 'Snake' name = 'Snake'
@ -84,15 +87,15 @@ class SnakeGame(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(
'Score to Win', 'Score to Win',
min_value=40, min_value=40,
default=80, default=80,
increment=5, increment=5,
), ),
ba.IntChoiceSetting( bs.IntChoiceSetting(
'Time Limit', 'Time Limit',
choices=[ choices=[
('None', 0), ('None', 0),
@ -104,7 +107,7 @@ class SnakeGame(ba.TeamGameActivity[Player, Team]):
], ],
default=0, default=0,
), ),
ba.FloatChoiceSetting( bs.FloatChoiceSetting(
'Respawn Times', 'Respawn Times',
choices=[ choices=[
('Shorter', 0.25), ('Shorter', 0.25),
@ -115,27 +118,27 @@ class SnakeGame(ba.TeamGameActivity[Player, Team]):
], ],
default=1.0, default=1.0,
), ),
ba.BoolSetting('Epic Mode', default=False), bs.BoolSetting('Epic Mode', 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)
or issubclass(sessiontype, ba.FreeForAllSession)) or issubclass(sessiontype, bs.FreeForAllSession))
@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._score_to_win: Optional[int] = None self._score_to_win: Optional[int] = None
self._dingsound = ba.getsound('dingSmall') self._dingsound = bs.getsound('dingSmall')
self._beep_1_sound = ba.getsound('raceBeep1') self._beep_1_sound = bs.getsound('raceBeep1')
self._beep_2_sound = ba.getsound('raceBeep2') self._beep_2_sound = bs.getsound('raceBeep2')
self._epic_mode = bool(settings['Epic Mode']) self._epic_mode = bool(settings['Epic Mode'])
self._kills_to_win_per_player = int( self._kills_to_win_per_player = int(
@ -146,8 +149,8 @@ class SnakeGame(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 if self._epic_mode else self.default_music = (bs.MusicType.EPIC if self._epic_mode else
ba.MusicType.TO_THE_DEATH) bs.MusicType.TO_THE_DEATH)
def get_instance_description(self) -> Union[str, Sequence]: def get_instance_description(self) -> Union[str, Sequence]:
return join_description return join_description
@ -178,30 +181,30 @@ class SnakeGame(ba.TeamGameActivity[Player, Team]):
lstart = 7.1 * t_scale lstart = 7.1 * t_scale
inc = 1.25 * t_scale inc = 1.25 * t_scale
ba.timer(lstart, self._do_light_1) bs.timer(lstart, self._do_light_1)
ba.timer(lstart + inc, self._do_light_2) bs.timer(lstart + inc, self._do_light_2)
ba.timer(lstart + 2 * inc, self._do_light_3) bs.timer(lstart + 2 * inc, self._do_light_3)
ba.timer(lstart + 3 * inc, self._start_race) bs.timer(lstart + 3 * inc, self._start_race)
self._start_lights = [] self._start_lights = []
for i in range(4): for i in range(4):
lnub = ba.newnode('image', lnub = bs.newnode('image',
attrs={ attrs={
'texture': ba.gettexture('nub'), 'texture': bs.gettexture('nub'),
'opacity': 1.0, 'opacity': 1.0,
'absolute_scale': True, 'absolute_scale': True,
'position': (-75 + i * 50, light_y), 'position': (-75 + i * 50, light_y),
'scale': (50, 50), 'scale': (50, 50),
'attach': 'center' 'attach': 'center'
}) })
ba.animate( bs.animate(
lnub, 'opacity', { lnub, 'opacity', {
4.0 * t_scale: 0, 4.0 * t_scale: 0,
5.0 * t_scale: 1.0, 5.0 * t_scale: 1.0,
12.0 * t_scale: 1.0, 12.0 * t_scale: 1.0,
12.5 * t_scale: 0.0 12.5 * t_scale: 0.0
}) })
ba.timer(13.0 * t_scale, lnub.delete) bs.timer(13.0 * t_scale, lnub.delete)
self._start_lights.append(lnub) self._start_lights.append(lnub)
self._start_lights[0].color = (0.2, 0, 0) self._start_lights[0].color = (0.2, 0, 0)
@ -212,22 +215,22 @@ class SnakeGame(ba.TeamGameActivity[Player, Team]):
def _do_light_1(self) -> None: def _do_light_1(self) -> None:
assert self._start_lights is not None assert self._start_lights is not None
self._start_lights[0].color = (1.0, 0, 0) self._start_lights[0].color = (1.0, 0, 0)
ba.playsound(self._beep_1_sound) self._beep_1_sound.play()
def _do_light_2(self) -> None: def _do_light_2(self) -> None:
assert self._start_lights is not None assert self._start_lights is not None
self._start_lights[1].color = (1.0, 0, 0) self._start_lights[1].color = (1.0, 0, 0)
ba.playsound(self._beep_1_sound) self._beep_1_sound.play()
def _do_light_3(self) -> None: def _do_light_3(self) -> None:
assert self._start_lights is not None assert self._start_lights is not None
self._start_lights[2].color = (1.0, 0.3, 0) self._start_lights[2].color = (1.0, 0.3, 0)
ba.playsound(self._beep_1_sound) self._beep_1_sound.play()
def _start_race(self) -> None: def _start_race(self) -> None:
assert self._start_lights is not None assert self._start_lights is not None
self._start_lights[3].color = (0.0, 1.0, 0) self._start_lights[3].color = (0.0, 1.0, 0)
ba.playsound(self._beep_2_sound) self._beep_2_sound.play()
self._started = True self._started = True
@ -235,7 +238,7 @@ class SnakeGame(ba.TeamGameActivity[Player, Team]):
self.generate_mines(player) self.generate_mines(player)
# overriding the default character spawning.. # overriding the default character spawning..
def spawn_player(self, player: Player) -> ba.Actor: def spawn_player(self, player: Player) -> bs.Actor:
spaz = self.spawn_player_spaz(player) spaz = self.spawn_player_spaz(player)
# Let's reconnect this player's controls to this # Let's reconnect this player's controls to this
@ -252,7 +255,7 @@ class SnakeGame(ba.TeamGameActivity[Player, Team]):
def generate_mines(self, player: Player): def generate_mines(self, player: Player):
try: try:
player.actived = ba.Timer(0.5, ba.Call(self.spawn_mine, player), repeat=True) player.actived = bs.Timer(0.5, babase.Call(self.spawn_mine, player), repeat=True)
except Exception as e: except Exception as e:
print('Exception -> ' + str(e)) print('Exception -> ' + str(e))
@ -271,7 +274,7 @@ class SnakeGame(ba.TeamGameActivity[Player, Team]):
def arm(): def arm():
mine.arm() mine.arm()
ba.timer(0.5, arm) bs.timer(0.5, arm)
player.mines.append(mine) player.mines.append(mine)
if len(player.mines) > 15: if len(player.mines) > 15:
@ -286,7 +289,7 @@ class SnakeGame(ba.TeamGameActivity[Player, Team]):
self.handlemessage(ScoreMessage(player)) self.handlemessage(ScoreMessage(player))
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)
@ -304,7 +307,7 @@ class SnakeGame(ba.TeamGameActivity[Player, Team]):
assert self._score_to_win is not None assert self._score_to_win is not None
if any(team.score >= self._score_to_win for team in self.teams): if any(team.score >= self._score_to_win for team in self.teams):
self.end_game() # ba.timer(0.5, self.end_game) self.end_game() # bs.timer(0.5, self.end_game)
else: else:
return super().handlemessage(msg) return super().handlemessage(msg)
return None return None
@ -315,7 +318,7 @@ class SnakeGame(ba.TeamGameActivity[Player, Team]):
self._score_to_win) self._score_to_win)
def end_game(self) -> None: def end_game(self) -> None:
results = ba.GameResults() results = bs.GameResults()
for team in self.teams: for team in self.teams:
results.set_team_score(team, team.score) results.set_team_score(team, team.score)
self.end(results=results) self.end(results=results)

View file

@ -1,8 +1,9 @@
# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport)
# Released under the MIT License. See LICENSE for details. # Released under the MIT License. See LICENSE for details.
# #
"""Defines Race mini-game.""" """Defines Race 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
@ -11,16 +12,18 @@ import random
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from dataclasses import dataclass from dataclasses import dataclass
import ba import babase
from bastd.actor.bomb import Bomb, Blast, ExplodeHitMessage import bauiv1 as bui
from bastd.actor.playerspaz import PlayerSpaz import bascenev1 as bs
from bastd.actor.scoreboard import Scoreboard from bascenev1lib.actor.bomb import Bomb, Blast, ExplodeHitMessage
from bastd.gameutils import SharedObjects from bascenev1lib.actor.playerspaz import PlayerSpaz
from bascenev1lib.actor.scoreboard import Scoreboard
from bascenev1lib.gameutils import SharedObjects
if TYPE_CHECKING: if TYPE_CHECKING:
from typing import (Any, Type, Tuple, List, Sequence, Optional, Dict, from typing import (Any, Type, Tuple, List, Sequence, Optional, Dict,
Union) Union)
from bastd.actor.onscreentimer import OnScreenTimer from bascenev1lib.actor.onscreentimer import OnScreenTimer
class NewBlast(Blast): class NewBlast(Blast):
@ -38,7 +41,7 @@ class RaceMine:
mine: Optional[Bomb] mine: Optional[Bomb]
class RaceRegion(ba.Actor): class RaceRegion(bs.Actor):
"""Region used to track progress during a race.""" """Region used to track progress during a race."""
def __init__(self, pt: Sequence[float], index: int): def __init__(self, pt: Sequence[float], index: int):
@ -47,7 +50,7 @@ class RaceRegion(ba.Actor):
assert isinstance(activity, RaceGame) assert isinstance(activity, RaceGame)
self.pos = pt self.pos = pt
self.index = index self.index = index
self.node = ba.newnode( self.node = bs.newnode(
'region', 'region',
delegate=self, delegate=self,
attrs={ attrs={
@ -58,11 +61,11 @@ class RaceRegion(ba.Actor):
}) })
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:
self.distance_txt: Optional[ba.Node] = None self.distance_txt: Optional[bs.Node] = None
self.last_region = 0 self.last_region = 0
self.lap = 0 self.lap = 0
self.distance = 0.0 self.distance = 0.0
@ -70,7 +73,7 @@ class Player(ba.Player['Team']):
self.rank: Optional[int] = None self.rank: Optional[int] = None
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:
@ -79,22 +82,22 @@ class Team(ba.Team[Player]):
self.finished = False self.finished = False
# ba_meta export game # ba_meta export bascenev1.GameActivity
class SquidRaceGame(ba.TeamGameActivity[Player, Team]): class SquidRaceGame(bs.TeamGameActivity[Player, Team]):
"""Game of racing around a track.""" """Game of racing around a track."""
name = 'Squid Race' name = 'Squid Race'
description = 'Run real fast!' description = 'Run real fast!'
scoreconfig = ba.ScoreConfig(label='Time', scoreconfig = bs.ScoreConfig(label='Time',
lower_is_better=True, lower_is_better=True,
scoretype=ba.ScoreType.MILLISECONDS) scoretype=bs.ScoreType.MILLISECONDS)
@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('Laps', min_value=1, default=3, increment=1), bs.IntSetting('Laps', min_value=1, default=3, increment=1),
ba.IntChoiceSetting( bs.IntChoiceSetting(
'Time Limit', 'Time Limit',
default=0, default=0,
choices=[ choices=[
@ -106,7 +109,7 @@ class SquidRaceGame(ba.TeamGameActivity[Player, Team]):
('20 Minutes', 1200), ('20 Minutes', 1200),
], ],
), ),
ba.IntChoiceSetting( bs.IntChoiceSetting(
'Mine Spawning', 'Mine Spawning',
default=4000, default=4000,
choices=[ choices=[
@ -116,7 +119,7 @@ class SquidRaceGame(ba.TeamGameActivity[Player, Team]):
('2 Seconds', 2000), ('2 Seconds', 2000),
], ],
), ),
ba.IntChoiceSetting( bs.IntChoiceSetting(
'Bomb Spawning', 'Bomb Spawning',
choices=[ choices=[
('None', 0), ('None', 0),
@ -127,49 +130,49 @@ class SquidRaceGame(ba.TeamGameActivity[Player, Team]):
], ],
default=2000, default=2000,
), ),
ba.BoolSetting('Epic Mode', default=False), bs.BoolSetting('Epic Mode', default=False),
] ]
# We have some specific settings in teams mode. # We have some specific settings in teams mode.
if issubclass(sessiontype, ba.DualTeamSession): if issubclass(sessiontype, bs.DualTeamSession):
settings.append( settings.append(
ba.BoolSetting('Entire Team Must Finish', default=False)) bs.BoolSetting('Entire Team Must Finish', 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.MultiTeamSession) return issubclass(sessiontype, bs.MultiTeamSession)
@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('race') return bs.app.classic.getmaps('race')
def __init__(self, settings: dict): def __init__(self, settings: dict):
self._race_started = False self._race_started = False
super().__init__(settings) super().__init__(settings)
self._scoreboard = Scoreboard() self._scoreboard = Scoreboard()
self._score_sound = ba.getsound('score') self._score_sound = bs.getsound('score')
self._swipsound = ba.getsound('swip') self._swipsound = bs.getsound('swip')
self._last_team_time: Optional[float] = None self._last_team_time: Optional[float] = None
self._front_race_region: Optional[int] = None self._front_race_region: Optional[int] = None
self._nub_tex = ba.gettexture('nub') self._nub_tex = bs.gettexture('nub')
self._beep_1_sound = ba.getsound('raceBeep1') self._beep_1_sound = bs.getsound('raceBeep1')
self._beep_2_sound = ba.getsound('raceBeep2') self._beep_2_sound = bs.getsound('raceBeep2')
self.race_region_material: Optional[ba.Material] = None self.race_region_material: Optional[bs.Material] = None
self._regions: List[RaceRegion] = [] self._regions: List[RaceRegion] = []
self._team_finish_pts: Optional[int] = None self._team_finish_pts: Optional[int] = None
self._time_text: Optional[ba.Actor] = None self._time_text: Optional[bs.Actor] = None
self._timer: Optional[OnScreenTimer] = None self._timer: Optional[OnScreenTimer] = None
self._race_mines: Optional[List[RaceMine]] = None self._race_mines: Optional[List[RaceMine]] = None
self._race_mine_timer: Optional[ba.Timer] = None self._race_mine_timer: Optional[bs.Timer] = None
self._scoreboard_timer: Optional[ba.Timer] = None self._scoreboard_timer: Optional[bs.Timer] = None
self._player_order_update_timer: Optional[ba.Timer] = None self._player_order_update_timer: Optional[bs.Timer] = None
self._start_lights: Optional[List[ba.Node]] = None self._start_lights: Optional[List[bs.Node]] = None
self._squid_lights: Optional[List[ba.Node]] = None self._squid_lights: Optional[List[bs.Node]] = None
self._countdown_timer: int = 0 self._countdown_timer: int = 0
self._sq_mode: str = 'Easy' self._sq_mode: str = 'Easy'
self._tick_timer: Optional[ba.Timer] = None self._tick_timer: Optional[bs.Timer] = None
self._bomb_spawn_timer: Optional[ba.Timer] = None self._bomb_spawn_timer: Optional[bs.Timer] = None
self._laps = int(settings['Laps']) self._laps = int(settings['Laps'])
self._entire_team_must_finish = bool( self._entire_team_must_finish = bool(
settings.get('Entire Team Must Finish', False)) settings.get('Entire Team Must Finish', False))
@ -179,25 +182,25 @@ class SquidRaceGame(ba.TeamGameActivity[Player, Team]):
self._epic_mode = bool(settings['Epic Mode']) self._epic_mode = bool(settings['Epic Mode'])
self._countdownsounds = { self._countdownsounds = {
10: ba.getsound('announceTen'), 10: bs.getsound('announceTen'),
9: ba.getsound('announceNine'), 9: bs.getsound('announceNine'),
8: ba.getsound('announceEight'), 8: bs.getsound('announceEight'),
7: ba.getsound('announceSeven'), 7: bs.getsound('announceSeven'),
6: ba.getsound('announceSix'), 6: bs.getsound('announceSix'),
5: ba.getsound('announceFive'), 5: bs.getsound('announceFive'),
4: ba.getsound('announceFour'), 4: bs.getsound('announceFour'),
3: ba.getsound('announceThree'), 3: bs.getsound('announceThree'),
2: ba.getsound('announceTwo'), 2: bs.getsound('announceTwo'),
1: ba.getsound('announceOne') 1: bs.getsound('announceOne')
} }
# Base class overrides. # Base class overrides.
self.slow_motion = self._epic_mode self.slow_motion = self._epic_mode
self.default_music = (ba.MusicType.EPIC_RACE self.default_music = (bs.MusicType.EPIC_RACE
if self._epic_mode else ba.MusicType.RACE) if self._epic_mode else bs.MusicType.RACE)
def get_instance_description(self) -> Union[str, Sequence]: def get_instance_description(self) -> Union[str, Sequence]:
if (isinstance(self.session, ba.DualTeamSession) if (isinstance(self.session, bs.DualTeamSession)
and self._entire_team_must_finish): and self._entire_team_must_finish):
t_str = ' Your entire team has to finish.' t_str = ' Your entire team has to finish.'
else: else:
@ -216,7 +219,7 @@ class SquidRaceGame(ba.TeamGameActivity[Player, Team]):
super().on_transition_in() super().on_transition_in()
shared = SharedObjects.get() shared = SharedObjects.get()
pts = self.map.get_def_points('race_point') pts = self.map.get_def_points('race_point')
mat = self.race_region_material = ba.Material() mat = self.race_region_material = bs.Material()
mat.add_actions(conditions=('they_have_material', mat.add_actions(conditions=('they_have_material',
shared.player_material), shared.player_material),
actions=( actions=(
@ -232,28 +235,28 @@ class SquidRaceGame(ba.TeamGameActivity[Player, Team]):
assert isinstance(player.actor, PlayerSpaz) assert isinstance(player.actor, PlayerSpaz)
assert player.actor.node assert player.actor.node
pos = player.actor.node.position pos = player.actor.node.position
light = ba.newnode('light', light = bs.newnode('light',
attrs={ attrs={
'position': pos, 'position': pos,
'color': (1, 1, 0), 'color': (1, 1, 0),
'height_attenuated': False, 'height_attenuated': False,
'radius': 0.4 'radius': 0.4
}) })
ba.timer(0.5, light.delete) bs.timer(0.5, light.delete)
ba.animate(light, 'intensity', {0: 0, 0.1: 1.0 * scale, 0.5: 0}) bs.animate(light, 'intensity', {0: 0, 0.1: 1.0 * scale, 0.5: 0})
def _handle_race_point_collide(self) -> None: def _handle_race_point_collide(self) -> None:
# FIXME: Tidy this up. # FIXME: Tidy this up.
# pylint: disable=too-many-statements # pylint: disable=too-many-statements
# pylint: disable=too-many-branches # pylint: disable=too-many-branches
# pylint: disable=too-many-nested-blocks # pylint: disable=too-many-nested-blocks
collision = ba.getcollision() collision = bs.getcollision()
try: try:
region = collision.sourcenode.getdelegate(RaceRegion, True) region = collision.sourcenode.getdelegate(RaceRegion, True)
player = collision.opposingnode.getdelegate(PlayerSpaz, player = collision.opposingnode.getdelegate(PlayerSpaz,
True).getplayer( True).getplayer(
Player, True) Player, True)
except ba.NotFoundError: except bs.NotFoundError:
return return
last_region = player.last_region last_region = player.last_region
@ -267,8 +270,8 @@ class SquidRaceGame(ba.TeamGameActivity[Player, Team]):
if this_region > last_region + 2: if this_region > last_region + 2:
if player.is_alive(): if player.is_alive():
assert player.actor assert player.actor
player.actor.handlemessage(ba.DieMessage()) player.actor.handlemessage(bs.DieMessage())
ba.screenmessage(ba.Lstr( bs.broadcastmessage(babase.Lstr(
translate=('statements', 'Killing ${NAME} for' translate=('statements', 'Killing ${NAME} for'
' skipping part of the track!'), ' skipping part of the track!'),
subs=[('${NAME}', player.getname(full=True))]), subs=[('${NAME}', player.getname(full=True))]),
@ -287,7 +290,7 @@ class SquidRaceGame(ba.TeamGameActivity[Player, Team]):
# In teams mode with all-must-finish on, the team lap # In teams mode with all-must-finish on, the team lap
# value is the min of all team players. # value is the min of all team players.
# Otherwise its the max. # Otherwise its the max.
if isinstance(self.session, ba.DualTeamSession if isinstance(self.session, bs.DualTeamSession
) and self._entire_team_must_finish: ) and self._entire_team_must_finish:
team.lap = min([p.lap for p in team.players]) team.lap = min([p.lap for p in team.players])
else: else:
@ -298,7 +301,7 @@ class SquidRaceGame(ba.TeamGameActivity[Player, Team]):
# In teams mode, hand out points based on the order # In teams mode, hand out points based on the order
# players come in. # players come in.
if isinstance(self.session, ba.DualTeamSession): if isinstance(self.session, bs.DualTeamSession):
assert self._team_finish_pts is not None assert self._team_finish_pts is not None
if self._team_finish_pts > 0: if self._team_finish_pts > 0:
self.stats.player_scored(player, self.stats.player_scored(player,
@ -311,7 +314,7 @@ class SquidRaceGame(ba.TeamGameActivity[Player, Team]):
player.finished = True player.finished = True
assert player.actor assert player.actor
player.actor.handlemessage( player.actor.handlemessage(
ba.DieMessage(immediate=True)) bs.DieMessage(immediate=True))
# Makes sure noone behind them passes them in rank # Makes sure noone behind them passes them in rank
# while finishing. # while finishing.
@ -319,25 +322,25 @@ class SquidRaceGame(ba.TeamGameActivity[Player, Team]):
# If the whole team has finished the race. # If the whole team has finished the race.
if team.lap == self._laps: if team.lap == self._laps:
ba.playsound(self._score_sound) self._score_sound.play()
player.team.finished = True player.team.finished = True
assert self._timer is not None assert self._timer is not None
elapsed = ba.time() - self._timer.getstarttime() elapsed = bs.time() - self._timer.getstarttime()
self._last_team_time = player.team.time = elapsed self._last_team_time = player.team.time = elapsed
# Team has yet to finish. # Team has yet to finish.
else: else:
ba.playsound(self._swipsound) self._swipsound.play()
# They've just finished a lap but not the race. # They've just finished a lap but not the race.
else: else:
ba.playsound(self._swipsound) self._swipsound.play()
self._flash_player(player, 0.3) self._flash_player(player, 0.3)
# Print their lap number over their head. # Print their lap number over their head.
try: try:
assert isinstance(player.actor, PlayerSpaz) assert isinstance(player.actor, PlayerSpaz)
mathnode = ba.newnode('math', mathnode = bs.newnode('math',
owner=player.actor.node, owner=player.actor.node,
attrs={ attrs={
'input1': (0, 1.9, 0), 'input1': (0, 1.9, 0),
@ -345,12 +348,12 @@ class SquidRaceGame(ba.TeamGameActivity[Player, Team]):
}) })
player.actor.node.connectattr( player.actor.node.connectattr(
'torso_position', mathnode, 'input2') 'torso_position', mathnode, 'input2')
tstr = ba.Lstr(resource='lapNumberText', tstr = babase.Lstr(resource='lapNumberText',
subs=[('${CURRENT}', subs=[('${CURRENT}',
str(player.lap + 1)), str(player.lap + 1)),
('${TOTAL}', str(self._laps)) ('${TOTAL}', str(self._laps))
]) ])
txtnode = ba.newnode('text', txtnode = bs.newnode('text',
owner=mathnode, owner=mathnode,
attrs={ attrs={
'text': tstr, 'text': tstr,
@ -360,15 +363,15 @@ class SquidRaceGame(ba.TeamGameActivity[Player, Team]):
'h_align': 'center' 'h_align': 'center'
}) })
mathnode.connectattr('output', txtnode, 'position') mathnode.connectattr('output', txtnode, 'position')
ba.animate(txtnode, 'scale', { bs.animate(txtnode, 'scale', {
0.0: 0, 0.0: 0,
0.2: 0.019, 0.2: 0.019,
2.0: 0.019, 2.0: 0.019,
2.2: 0 2.2: 0
}) })
ba.timer(2.3, mathnode.delete) bs.timer(2.3, mathnode.delete)
except Exception: except Exception:
ba.print_exception('Error printing lap.') babase.print_exception('Error printing lap.')
def on_team_join(self, team: Team) -> None: def on_team_join(self, team: Team) -> None:
self._update_scoreboard() self._update_scoreboard()
@ -377,8 +380,8 @@ class SquidRaceGame(ba.TeamGameActivity[Player, Team]):
# Don't allow joining after we start # Don't allow joining after we start
# (would enable leave/rejoin tomfoolery). # (would enable leave/rejoin tomfoolery).
if self.has_begun(): if self.has_begun():
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),
) )
@ -391,9 +394,9 @@ class SquidRaceGame(ba.TeamGameActivity[Player, Team]):
# A player leaving disqualifies the team if 'Entire Team Must Finish' # A player leaving disqualifies the team if 'Entire Team Must Finish'
# is on (otherwise in teams mode everyone could just leave except the # is on (otherwise in teams mode everyone could just leave except the
# leading player to win). # leading player to win).
if (isinstance(self.session, ba.DualTeamSession) if (isinstance(self.session, bs.DualTeamSession)
and self._entire_team_must_finish): and self._entire_team_must_finish):
ba.screenmessage(ba.Lstr( bs.broadcastmessage(babase.Lstr(
translate=('statements', translate=('statements',
'${TEAM} is disqualified because ${PLAYER} left'), '${TEAM} is disqualified because ${PLAYER} left'),
subs=[('${TEAM}', player.team.name), subs=[('${TEAM}', player.team.name),
@ -402,18 +405,18 @@ class SquidRaceGame(ba.TeamGameActivity[Player, Team]):
player.team.finished = True player.team.finished = True
player.team.time = None player.team.time = None
player.team.lap = 0 player.team.lap = 0
ba.playsound(ba.getsound('boo')) bs.getsound('boo').play()
for otherplayer in player.team.players: for otherplayer in player.team.players:
otherplayer.lap = 0 otherplayer.lap = 0
otherplayer.finished = True otherplayer.finished = True
try: try:
if otherplayer.actor is not None: if otherplayer.actor is not None:
otherplayer.actor.handlemessage(ba.DieMessage()) otherplayer.actor.handlemessage(bs.DieMessage())
except Exception: except Exception:
ba.print_exception('Error sending DieMessage.') babase.print_exception('Error sending DieMessage.')
# Defer so team/player lists will be updated. # Defer so team/player lists will be updated.
ba.pushcall(self._check_end_game) babase.pushcall(self._check_end_game)
def _update_scoreboard(self) -> None: def _update_scoreboard(self) -> None:
for team in self.teams: for team in self.teams:
@ -421,7 +424,7 @@ class SquidRaceGame(ba.TeamGameActivity[Player, Team]):
if not distances: if not distances:
teams_dist = 0.0 teams_dist = 0.0
else: else:
if (isinstance(self.session, ba.DualTeamSession) if (isinstance(self.session, bs.DualTeamSession)
and self._entire_team_must_finish): and self._entire_team_must_finish):
teams_dist = min(distances) teams_dist = min(distances)
else: else:
@ -434,15 +437,15 @@ class SquidRaceGame(ba.TeamGameActivity[Player, Team]):
show_value=False) show_value=False)
def on_begin(self) -> None: def on_begin(self) -> None:
from bastd.actor.onscreentimer import OnScreenTimer from bascenev1lib.actor.onscreentimer import OnScreenTimer
super().on_begin() super().on_begin()
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._team_finish_pts = 100 self._team_finish_pts = 100
# Throw a timer up on-screen. # Throw a timer up on-screen.
self._time_text = ba.NodeActor( self._time_text = bs.NodeActor(
ba.newnode('text', bs.newnode('text',
attrs={ attrs={
'v_attach': 'top', 'v_attach': 'top',
'h_attach': 'center', 'h_attach': 'center',
@ -462,14 +465,14 @@ class SquidRaceGame(ba.TeamGameActivity[Player, Team]):
for p in self.map.get_def_points('race_mine') for p in self.map.get_def_points('race_mine')
] ]
if self._race_mines: if self._race_mines:
self._race_mine_timer = ba.Timer(0.001 * self._mine_spawning, self._race_mine_timer = bs.Timer(0.001 * self._mine_spawning,
self._update_race_mine, self._update_race_mine,
repeat=True) repeat=True)
self._scoreboard_timer = ba.Timer(0.25, self._scoreboard_timer = bs.Timer(0.25,
self._update_scoreboard, self._update_scoreboard,
repeat=True) repeat=True)
self._player_order_update_timer = ba.Timer(0.25, self._player_order_update_timer = bs.Timer(0.25,
self._update_player_order, self._update_player_order,
repeat=True) repeat=True)
@ -482,30 +485,30 @@ class SquidRaceGame(ba.TeamGameActivity[Player, Team]):
lstart = 7.1 * t_scale lstart = 7.1 * t_scale
inc = 1.25 * t_scale inc = 1.25 * t_scale
ba.timer(lstart, self._do_light_1) bs.timer(lstart, self._do_light_1)
ba.timer(lstart + inc, self._do_light_2) bs.timer(lstart + inc, self._do_light_2)
ba.timer(lstart + 2 * inc, self._do_light_3) bs.timer(lstart + 2 * inc, self._do_light_3)
ba.timer(lstart + 3 * inc, self._start_race) bs.timer(lstart + 3 * inc, self._start_race)
self._start_lights = [] self._start_lights = []
for i in range(4): for i in range(4):
lnub = ba.newnode('image', lnub = bs.newnode('image',
attrs={ attrs={
'texture': ba.gettexture('nub'), 'texture': bs.gettexture('nub'),
'opacity': 1.0, 'opacity': 1.0,
'absolute_scale': True, 'absolute_scale': True,
'position': (-75 + i * 50, light_y), 'position': (-75 + i * 50, light_y),
'scale': (50, 50), 'scale': (50, 50),
'attach': 'center' 'attach': 'center'
}) })
ba.animate( bs.animate(
lnub, 'opacity', { lnub, 'opacity', {
4.0 * t_scale: 0, 4.0 * t_scale: 0,
5.0 * t_scale: 1.0, 5.0 * t_scale: 1.0,
12.0 * t_scale: 1.0, 12.0 * t_scale: 1.0,
12.5 * t_scale: 0.0 12.5 * t_scale: 0.0
}) })
ba.timer(13.0 * t_scale, lnub.delete) bs.timer(13.0 * t_scale, lnub.delete)
self._start_lights.append(lnub) self._start_lights.append(lnub)
self._start_lights[0].color = (0.2, 0, 0) self._start_lights[0].color = (0.2, 0, 0)
@ -515,16 +518,16 @@ class SquidRaceGame(ba.TeamGameActivity[Player, Team]):
self._squid_lights = [] self._squid_lights = []
for i in range(2): for i in range(2):
lnub = ba.newnode('image', lnub = bs.newnode('image',
attrs={ attrs={
'texture': ba.gettexture('nub'), 'texture': bs.gettexture('nub'),
'opacity': 1.0, 'opacity': 1.0,
'absolute_scale': True, 'absolute_scale': True,
'position': (-33 + i * 65, 220), 'position': (-33 + i * 65, 220),
'scale': (60, 60), 'scale': (60, 60),
'attach': 'center' 'attach': 'center'
}) })
ba.animate( bs.animate(
lnub, 'opacity', { lnub, 'opacity', {
4.0 * t_scale: 0, 4.0 * t_scale: 0,
5.0 * t_scale: 1.0}) 5.0 * t_scale: 1.0})
@ -532,12 +535,12 @@ class SquidRaceGame(ba.TeamGameActivity[Player, Team]):
self._squid_lights[0].color = (0.2, 0, 0) self._squid_lights[0].color = (0.2, 0, 0)
self._squid_lights[1].color = (0.0, 0.3, 0) self._squid_lights[1].color = (0.0, 0.3, 0)
ba.timer(1.0, self._check_squid_end, repeat=True) bs.timer(1.0, self._check_squid_end, repeat=True)
self._squidgame_countdown() self._squidgame_countdown()
def _squidgame_countdown(self) -> None: def _squidgame_countdown(self) -> None:
self._countdown_timer = 80 * self._laps # 80 self._countdown_timer = 80 * self._laps # 80
ba.newnode( bs.newnode(
'image', 'image',
attrs={ attrs={
'opacity': 0.7, 'opacity': 0.7,
@ -545,8 +548,8 @@ class SquidRaceGame(ba.TeamGameActivity[Player, Team]):
'attach': 'topCenter', 'attach': 'topCenter',
'position': (-220, -40), 'position': (-220, -40),
'scale': (135, 45), 'scale': (135, 45),
'texture': ba.gettexture('bar')}) 'texture': bs.gettexture('bar')})
ba.newnode( bs.newnode(
'image', 'image',
attrs={ attrs={
'opacity': 1.0, 'opacity': 1.0,
@ -554,9 +557,9 @@ class SquidRaceGame(ba.TeamGameActivity[Player, Team]):
'attach': 'topCenter', 'attach': 'topCenter',
'position': (-220, -38), 'position': (-220, -38),
'scale': (155, 65), 'scale': (155, 65),
'texture': ba.gettexture('uiAtlas'), 'texture': bs.gettexture('uiAtlas'),
'model_transparent': ba.getmodel('meterTransparent')}) 'mesh_transparent': bs.getmesh('meterTransparent')})
self._sgcountdown_text = ba.newnode( self._sgcountdown_text = bs.newnode(
'text', 'text',
attrs={ attrs={
'v_attach': 'top', 'v_attach': 'top',
@ -576,14 +579,14 @@ class SquidRaceGame(ba.TeamGameActivity[Player, Team]):
self._squid_game_all_die() self._squid_game_all_die()
if self._countdown_timer == 20: if self._countdown_timer == 20:
self._sq_mode = 'Hard' self._sq_mode = 'Hard'
ba.playsound(ba.getsound('alarm')) bs.getsound('alarm').play()
if self._countdown_timer == 40: if self._countdown_timer == 40:
self._sq_mode = 'Normal' self._sq_mode = 'Normal'
if self._countdown_timer <= 20: if self._countdown_timer <= 20:
self._sgcountdown_text.color = (1.2, 0.0, 0.0) self._sgcountdown_text.color = (1.2, 0.0, 0.0)
self._sgcountdown_text.scale = 1.2 self._sgcountdown_text.scale = 1.2
if self._countdown_timer in self._countdownsounds: if self._countdown_timer in self._countdownsounds:
ba.playsound(self._countdownsounds[self._countdown_timer]) self._countdownsounds[self._countdown_timer].play()
else: else:
self._sgcountdown_text.color = (1.0, 1.0, 1.0) self._sgcountdown_text.color = (1.0, 1.0, 1.0)
self._sgcountdown_text.text = str(self._countdown_timer)+"s" self._sgcountdown_text.text = str(self._countdown_timer)+"s"
@ -592,14 +595,14 @@ class SquidRaceGame(ba.TeamGameActivity[Player, Team]):
for player in self.players: for player in self.players:
if player.is_alive(): if player.is_alive():
player.actor._cursed = True player.actor._cursed = True
player.actor.handlemessage(ba.DieMessage()) player.actor.handlemessage(bs.DieMessage())
NewBlast( NewBlast(
position=player.actor.node.position, position=player.actor.node.position,
velocity=player.actor.node.velocity, velocity=player.actor.node.velocity,
blast_radius=3.0, blast_radius=3.0,
blast_type='normal').autoretain() blast_type='normal').autoretain()
player.actor.handlemessage( player.actor.handlemessage(
ba.HitMessage( bs.HitMessage(
pos=player.actor.node.position, pos=player.actor.node.position,
velocity=player.actor.node.velocity, velocity=player.actor.node.velocity,
magnitude=2000, magnitude=2000,
@ -612,8 +615,8 @@ class SquidRaceGame(ba.TeamGameActivity[Player, Team]):
def _do_ticks(self) -> None: def _do_ticks(self) -> None:
def do_ticks(): def do_ticks():
if self._ticks: if self._ticks:
ba.playsound(ba.getsound('tick')) bs.getsound('tick').play()
self._tick_timer = ba.timer(1.0, do_ticks, repeat=True) self._tick_timer = bs.timer(1.0, do_ticks, repeat=True)
def _start_squid_game(self) -> None: def _start_squid_game(self) -> None:
easy = [4.5, 5, 5.5, 6] easy = [4.5, 5, 5.5, 6]
@ -623,30 +626,30 @@ class SquidRaceGame(ba.TeamGameActivity[Player, Team]):
hard if self._sq_mode == 'Hard' else hard if self._sq_mode == 'Hard' else
normal if self._sq_mode == 'Normal' else easy) normal if self._sq_mode == 'Normal' else easy)
# if random_number == 6: # if random_number == 6:
# ba.playsound(ba.getsound('lrlg_06s')) # bs.getsound('lrlg_06s').play()
# elif random_number == 5.5: # elif random_number == 5.5:
# ba.playsound(ba.getsound('lrlg_055s')) # bs.getsound('lrlg_055s').play()
# elif random_number == 5: # elif random_number == 5:
# ba.playsound(ba.getsound('lrlg_05s')) # bs.getsound('lrlg_05s').play()
# elif random_number == 4.5: # elif random_number == 4.5:
# ba.playsound(ba.getsound('lrlg_045s')) # bs.getsound('lrlg_045s').play()
# elif random_number == 4: # elif random_number == 4:
# ba.playsound(ba.getsound('lrlg_04s')) # bs.getsound('lrlg_04s').play()
# elif random_number == 3.5: # elif random_number == 3.5:
# ba.playsound(ba.getsound('lrlg_035s')) # bs.getsound('lrlg_035s').play()
# elif random_number == 3: # elif random_number == 3:
# ba.playsound(ba.getsound('lrlg_03s')) # bs.getsound('lrlg_03s').play()
self._squid_lights[0].color = (0.2, 0, 0) self._squid_lights[0].color = (0.2, 0, 0)
self._squid_lights[1].color = (0.0, 1.0, 0) self._squid_lights[1].color = (0.0, 1.0, 0)
self._do_delete = False self._do_delete = False
self._ticks = True self._ticks = True
ba.timer(random_number, self._stop_squid_game) bs.timer(random_number, self._stop_squid_game)
def _stop_squid_game(self) -> None: def _stop_squid_game(self) -> None:
self._ticks = False self._ticks = False
self._squid_lights[0].color = (1.0, 0, 0) self._squid_lights[0].color = (1.0, 0, 0)
self._squid_lights[1].color = (0.0, 0.3, 0) self._squid_lights[1].color = (0.0, 0.3, 0)
ba.timer(0.2, self._check_delete) bs.timer(0.2, self._check_delete)
def _check_delete(self) -> None: def _check_delete(self) -> None:
for player in self.players: for player in self.players:
@ -654,7 +657,7 @@ class SquidRaceGame(ba.TeamGameActivity[Player, Team]):
player.customdata['position'] = None player.customdata['position'] = None
player.customdata['position'] = player.actor.node.position player.customdata['position'] = player.actor.node.position
self._do_delete = True self._do_delete = True
ba.timer(3.0 if self._sq_mode == 'Hard' else 4.0, bs.timer(3.0 if self._sq_mode == 'Hard' else 4.0,
self._start_squid_game) self._start_squid_game)
def _start_delete(self) -> None: def _start_delete(self) -> None:
@ -684,14 +687,14 @@ class SquidRaceGame(ba.TeamGameActivity[Player, Team]):
current_posz in posz_list) or not ( current_posz in posz_list) or not (
current_posy in posy_list): current_posy in posy_list):
player.actor._cursed = True player.actor._cursed = True
player.actor.handlemessage(ba.DieMessage()) player.actor.handlemessage(bs.DieMessage())
NewBlast( NewBlast(
position=player.actor.node.position, position=player.actor.node.position,
velocity=player.actor.node.velocity, velocity=player.actor.node.velocity,
blast_radius=3.0, blast_radius=3.0,
blast_type='normal').autoretain() blast_type='normal').autoretain()
player.actor.handlemessage( player.actor.handlemessage(
ba.HitMessage( bs.HitMessage(
pos=player.actor.node.position, pos=player.actor.node.position,
velocity=player.actor.node.velocity, velocity=player.actor.node.velocity,
magnitude=2000, magnitude=2000,
@ -713,34 +716,34 @@ class SquidRaceGame(ba.TeamGameActivity[Player, Team]):
def _do_light_1(self) -> None: def _do_light_1(self) -> None:
assert self._start_lights is not None assert self._start_lights is not None
self._start_lights[0].color = (1.0, 0, 0) self._start_lights[0].color = (1.0, 0, 0)
ba.playsound(self._beep_1_sound) self._beep_1_sound.play()
def _do_light_2(self) -> None: def _do_light_2(self) -> None:
assert self._start_lights is not None assert self._start_lights is not None
self._start_lights[1].color = (1.0, 0, 0) self._start_lights[1].color = (1.0, 0, 0)
ba.playsound(self._beep_1_sound) self._beep_1_sound.play()
def _do_light_3(self) -> None: def _do_light_3(self) -> None:
assert self._start_lights is not None assert self._start_lights is not None
self._start_lights[2].color = (1.0, 0.3, 0) self._start_lights[2].color = (1.0, 0.3, 0)
ba.playsound(self._beep_1_sound) self._beep_1_sound.play()
def _start_race(self) -> None: def _start_race(self) -> None:
assert self._start_lights is not None assert self._start_lights is not None
self._start_lights[3].color = (0.0, 1.0, 0) self._start_lights[3].color = (0.0, 1.0, 0)
ba.playsound(self._beep_2_sound) self._beep_2_sound.play()
for player in self.players: for player in self.players:
if player.actor is not None: if player.actor is not None:
try: try:
assert isinstance(player.actor, PlayerSpaz) assert isinstance(player.actor, PlayerSpaz)
player.actor.connect_controls_to_player() player.actor.connect_controls_to_player()
except Exception: except Exception:
ba.print_exception('Error in race player connects.') babase.print_exception('Error in race player connects.')
assert self._timer is not None assert self._timer is not None
self._timer.start() self._timer.start()
if self._bomb_spawning != 0: if self._bomb_spawning != 0:
self._bomb_spawn_timer = ba.Timer(0.001 * self._bomb_spawning, self._bomb_spawn_timer = bs.Timer(0.001 * self._bomb_spawning,
self._spawn_bomb, self._spawn_bomb,
repeat=True) repeat=True)
@ -748,25 +751,25 @@ class SquidRaceGame(ba.TeamGameActivity[Player, Team]):
self._squid_lights[1].color = (0.0, 1.0, 0) self._squid_lights[1].color = (0.0, 1.0, 0)
self._start_squid_game() self._start_squid_game()
self._do_ticks() self._do_ticks()
ba.timer(0.2, self._start_delete, repeat=True) bs.timer(0.2, self._start_delete, repeat=True)
ba.timer(1.0, self._update_sgcountdown, repeat=True) bs.timer(1.0, self._update_sgcountdown, repeat=True)
def _update_player_order(self) -> None: def _update_player_order(self) -> None:
# Calc all player distances. # Calc all player distances.
for player in self.players: for player in self.players:
pos: Optional[ba.Vec3] pos: Optional[babase.Vec3]
try: try:
pos = player.position pos = player.position
except ba.NotFoundError: except bs.NotFoundError:
pos = None pos = None
if pos is not None: if pos is not None:
r_index = player.last_region r_index = player.last_region
rg1 = self._regions[r_index] rg1 = self._regions[r_index]
r1pt = ba.Vec3(rg1.pos[:3]) r1pt = babase.Vec3(rg1.pos[:3])
rg2 = self._regions[0] if r_index == len( rg2 = self._regions[0] if r_index == len(
self._regions) - 1 else self._regions[r_index + 1] self._regions) - 1 else self._regions[r_index + 1]
r2pt = ba.Vec3(rg2.pos[:3]) r2pt = babase.Vec3(rg2.pos[:3])
r2dist = (pos - r2pt).length() r2dist = (pos - r2pt).length()
amt = 1.0 - (r2dist / (r2pt - r1pt).length()) amt = 1.0 - (r2dist / (r2pt - r1pt).length())
amt = player.lap + (r_index + amt) * (1.0 / len(self._regions)) amt = player.lap + (r_index + amt) * (1.0 / len(self._regions))
@ -797,8 +800,8 @@ class SquidRaceGame(ba.TeamGameActivity[Player, Team]):
(-region_scale * pos[5], region_scale * pos[5])) (-region_scale * pos[5], region_scale * pos[5]))
pos = (pos[0] + random.uniform(*x_range), pos[1] + 1.0, pos = (pos[0] + random.uniform(*x_range), pos[1] + 1.0,
pos[2] + random.uniform(*z_range)) pos[2] + random.uniform(*z_range))
ba.timer(random.uniform(0.0, 2.0), bs.timer(random.uniform(0.0, 2.0),
ba.WeakCall(self._spawn_bomb_at_pos, pos)) bs.WeakCall(self._spawn_bomb_at_pos, pos))
def _spawn_bomb_at_pos(self, pos: Sequence[float]) -> None: def _spawn_bomb_at_pos(self, pos: Sequence[float]) -> None:
if self.has_ended(): if self.has_ended():
@ -814,15 +817,15 @@ class SquidRaceGame(ba.TeamGameActivity[Player, Team]):
def _flash_mine(self, i: int) -> None: def _flash_mine(self, i: int) -> None:
assert self._race_mines is not None assert self._race_mines is not None
rmine = self._race_mines[i] rmine = self._race_mines[i]
light = ba.newnode('light', light = bs.newnode('light',
attrs={ attrs={
'position': rmine.point[:3], 'position': rmine.point[:3],
'color': (1, 0.2, 0.2), 'color': (1, 0.2, 0.2),
'radius': 0.1, 'radius': 0.1,
'height_attenuated': False 'height_attenuated': False
}) })
ba.animate(light, 'intensity', {0.0: 0, 0.1: 1.0, 0.2: 0}, loop=True) bs.animate(light, 'intensity', {0.0: 0, 0.1: 1.0, 0.2: 0}, loop=True)
ba.timer(1.0, light.delete) bs.timer(1.0, light.delete)
def _update_race_mine(self) -> None: def _update_race_mine(self) -> None:
assert self._race_mines is not None assert self._race_mines is not None
@ -836,9 +839,9 @@ class SquidRaceGame(ba.TeamGameActivity[Player, Team]):
assert rmine is not None assert rmine is not None
if not rmine.mine: if not rmine.mine:
self._flash_mine(m_index) self._flash_mine(m_index)
ba.timer(0.95, ba.Call(self._make_mine, m_index)) bs.timer(0.95, babase.Call(self._make_mine, m_index))
def spawn_player(self, player: Player) -> ba.Actor: def spawn_player(self, player: Player) -> bs.Actor:
if player.team.finished: if player.team.finished:
# FIXME: This is not type-safe! # FIXME: This is not type-safe!
# This call is expected to always return an Actor! # This call is expected to always return an Actor!
@ -863,7 +866,7 @@ class SquidRaceGame(ba.TeamGameActivity[Player, Team]):
if not self._race_started: if not self._race_started:
spaz.disconnect_controls_from_player() spaz.disconnect_controls_from_player()
mathnode = ba.newnode('math', mathnode = bs.newnode('math',
owner=spaz.node, owner=spaz.node,
attrs={ attrs={
'input1': (0, 1.4, 0), 'input1': (0, 1.4, 0),
@ -871,7 +874,7 @@ class SquidRaceGame(ba.TeamGameActivity[Player, Team]):
}) })
spaz.node.connectattr('torso_position', mathnode, 'input2') spaz.node.connectattr('torso_position', mathnode, 'input2')
distance_txt = ba.newnode('text', distance_txt = bs.newnode('text',
owner=spaz.node, owner=spaz.node,
attrs={ attrs={
'text': '', 'text': '',
@ -902,14 +905,14 @@ class SquidRaceGame(ba.TeamGameActivity[Player, Team]):
# In teams mode its over as soon as any team finishes the race # In teams mode its over as soon as any team finishes the race
# FIXME: The get_ffa_point_awards code looks dangerous. # FIXME: The get_ffa_point_awards code looks dangerous.
if isinstance(session, ba.DualTeamSession): if isinstance(session, bs.DualTeamSession):
self.end_game() self.end_game()
else: else:
# In ffa we keep the race going while there's still any points # In ffa we keep the race going while there's still any points
# to be handed out. Find out how many points we have to award # to be handed out. Find out how many points we have to award
# and how many teams have finished, and once that matches # and how many teams have finished, and once that matches
# we're done. # we're done.
assert isinstance(session, ba.FreeForAllSession) assert isinstance(session, bs.FreeForAllSession)
points_to_award = len(session.get_ffa_point_awards()) points_to_award = len(session.get_ffa_point_awards())
if teams_completed >= points_to_award - teams_completed: if teams_completed >= points_to_award - teams_completed:
self.end_game() self.end_game()
@ -926,7 +929,7 @@ class SquidRaceGame(ba.TeamGameActivity[Player, Team]):
endtime=None if self._last_team_time is None else ( endtime=None if self._last_team_time is None else (
self._timer.getstarttime() + self._last_team_time)) self._timer.getstarttime() + self._last_team_time))
results = ba.GameResults() results = bs.GameResults()
for team in self.teams: for team in self.teams:
if team.time is not None: if team.time is not None:
@ -940,10 +943,10 @@ class SquidRaceGame(ba.TeamGameActivity[Player, Team]):
# odd to be announcing that now. # odd to be announcing that now.
self.end(results=results, self.end(results=results,
announce_winning_team=isinstance(self.session, announce_winning_team=isinstance(self.session,
ba.DualTeamSession)) bs.DualTeamSession))
def handlemessage(self, msg: Any) -> Any: def handlemessage(self, msg: Any) -> Any:
if isinstance(msg, ba.PlayerDiedMessage): if isinstance(msg, bs.PlayerDiedMessage):
# Augment default behavior. # Augment default behavior.
super().handlemessage(msg) super().handlemessage(msg)
else: else:

View file

@ -1,5 +1,6 @@
# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport)
# ba_meta require api 7 # ba_meta require api 8
""" """
TheSpazGame - Mini game where all characters looks identical , identify enemies and kill them. TheSpazGame - Mini game where all characters looks identical , identify enemies and kill them.
Author: Mr.Smoothy Author: Mr.Smoothy
@ -12,9 +13,11 @@ from __future__ import annotations
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
import ba import babase
from bastd.game.elimination import EliminationGame, Player import bauiv1 as bui
from bastd.actor.spazfactory import SpazFactory import bascenev1 as bs
from bascenev1lib.game.elimination import EliminationGame, Player
from bascenev1lib.actor.spazfactory import SpazFactory
import random import random
if TYPE_CHECKING: if TYPE_CHECKING:
@ -23,14 +26,14 @@ if TYPE_CHECKING:
CHARACTER = 'Spaz' CHARACTER = 'Spaz'
# ba_meta export game # ba_meta export bascenev1.GameActivity
class TheSpazGame(EliminationGame): class TheSpazGame(EliminationGame):
name = 'TheSpazGame' name = 'TheSpazGame'
description = 'Enemy Spaz AmongUs. Kill them all' description = 'Enemy Spaz AmongUs. Kill them all'
scoreconfig = ba.ScoreConfig( scoreconfig = bs.ScoreConfig(
label='Survived', scoretype=ba.ScoreType.SECONDS, none_is_winner=True label='Survived', scoretype=bs.ScoreType.SECONDS, none_is_winner=True
) )
announce_player_deaths = False announce_player_deaths = False
@ -39,17 +42,17 @@ class TheSpazGame(EliminationGame):
@classmethod @classmethod
def get_available_settings( def get_available_settings(
cls, sessiontype: type[ba.Session] cls, sessiontype: type[bs.Session]
) -> list[ba.Setting]: ) -> 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.IntChoiceSetting( bs.IntChoiceSetting(
'Time Limit', 'Time Limit',
choices=[ choices=[
('None', 0), ('None', 0),
@ -61,31 +64,31 @@ class TheSpazGame(EliminationGame):
], ],
default=0, default=0,
), ),
ba.FloatChoiceSetting( bs.FloatChoiceSetting(
'Respawn Times', 'Respawn Times',
choices=[ choices=[
('Shorter', 0.15) ('Shorter', 0.15)
], ],
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(ba.BoolSetting('Solo Mode', default=False)) settings.append(bs.BoolSetting('Solo Mode', default=False))
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) or issubclass( return issubclass(sessiontype, bs.DualTeamSession) or issubclass(
sessiontype, ba.FreeForAllSession sessiontype, bs.FreeForAllSession
) )
@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 get_instance_description(self) -> str | Sequence: def get_instance_description(self) -> str | Sequence:
return ( return (
@ -101,7 +104,7 @@ class TheSpazGame(EliminationGame):
super().__init__(settings) super().__init__(settings)
self._solo_mode = False self._solo_mode = False
def spawn_player(self, player: Player) -> ba.Actor: def spawn_player(self, player: Player) -> bs.Actor:
p = [-6, -4.3, -2.6, -0.9, 0.8, 2.5, 4.2, 5.9] p = [-6, -4.3, -2.6, -0.9, 0.8, 2.5, 4.2, 5.9]
q = [-4, -2.3, -0.6, 1.1, 2.8, 4.5] q = [-4, -2.3, -0.6, 1.1, 2.8, 4.5]

View file

@ -1,4 +1,4 @@
"""UFO Boss Fight v1.0: """UFO Boss Fight v2.0:
Made by Cross Joy""" Made by Cross Joy"""
# Anyone who wanna help me in giving suggestion/ fix bugs/ by creating PR, # Anyone who wanna help me in giving suggestion/ fix bugs/ by creating PR,
@ -8,21 +8,28 @@ Made by Cross Joy"""
# My Discord Id: Cross Joy#0721 # My Discord Id: Cross Joy#0721
# My BS Discord Server: https://discford.gg/JyBY6haARJ # My BS Discord Server: https://discford.gg/JyBY6haARJ
# 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)
# ---------------------------------------
# Update v2.0
# updated to api 8
# ---------------------------------------
from __future__ import annotations from __future__ import annotations
import random import random
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
import ba
import _ba import babase
from bastd.actor.playerspaz import PlayerSpaz import bascenev1 as bs
from bastd.actor.spaz import Spaz from bascenev1lib.actor.playerspaz import PlayerSpaz
from bastd.actor.bomb import Blast, Bomb from bascenev1lib.actor.spaz import Spaz
from bastd.actor.onscreentimer import OnScreenTimer from bascenev1lib.actor.bomb import Blast, Bomb
from bastd.actor.spazbot import SpazBotSet, StickyBot from bascenev1lib.actor.onscreentimer import OnScreenTimer
from bastd.gameutils import SharedObjects from bascenev1lib.actor.spazbot import SpazBotSet, StickyBot
from bascenev1lib.gameutils import SharedObjects
if TYPE_CHECKING: if TYPE_CHECKING:
from typing import Any, Sequence, Union, Callable from typing import Any, Sequence, Union, Callable
@ -32,17 +39,17 @@ class UFODiedMessage:
ufo: UFO ufo: UFO
"""The UFO that was killed.""" """The UFO that was killed."""
killerplayer: ba.Player | None killerplayer: bs.Player | None
"""The ba.Player that killed it (or None).""" """The bs.Player that killed it (or None)."""
how: ba.DeathType how: bs.DeathType
"""The particular type of death.""" """The particular type of death."""
def __init__( def __init__(
self, self,
ufo: UFO, ufo: UFO,
killerplayer: ba.Player | None, killerplayer: bs.Player | None,
how: ba.DeathType, how: bs.DeathType,
): ):
"""Instantiate with given values.""" """Instantiate with given values."""
self.spazbot = ufo self.spazbot = ufo
@ -57,7 +64,7 @@ class RoboBot(StickyBot):
highlight = (3, 3, 3) highlight = (3, 3, 3)
class UFO(ba.Actor): class UFO(bs.Actor):
""" """
New AI for Boss New AI for Boss
""" """
@ -65,7 +72,7 @@ class UFO(ba.Actor):
# pylint: disable=too-many-public-methods # pylint: disable=too-many-public-methods
# pylint: disable=too-many-locals # pylint: disable=too-many-locals
node: ba.Node node: bs.Node
def __init__(self, hitpoints: int = 5000): def __init__(self, hitpoints: int = 5000):
@ -74,32 +81,29 @@ class UFO(ba.Actor):
self.update_callback: Callable[[UFO], Any] | None = None self.update_callback: Callable[[UFO], Any] | None = None
activity = self.activity activity = self.activity
assert isinstance(activity, ba.GameActivity) assert isinstance(activity, bs.GameActivity)
self.platform_material = ba.Material() self.platform_material = bs.Material()
self.platform_material.add_actions( self.platform_material.add_actions(
conditions=('they_have_material', shared.footing_material), conditions=('they_have_material', shared.footing_material),
actions=( actions=(
'modify_part_collision', 'collide', True)) 'modify_part_collision', 'collide', True))
self.ice_material = ba.Material() self.ice_material = bs.Material()
self.ice_material.add_actions( self.ice_material.add_actions(
actions=('modify_part_collision', 'friction', 0.0)) actions=('modify_part_collision', 'friction', 0.0))
self._player_pts: list[tuple[ba.Vec3, ba.Vec3]] | None = None self._player_pts: list[tuple[bs.Vec3, bs.Vec3]] | None = None
self._ufo_update_timer: ba.Timer | None = None self._ufo_update_timer: bs.Timer | None = None
self.last_player_attacked_by: ba.Player | None = None self.last_player_attacked_by: bs.Player | None = None
self.last_attacked_time = 0.0 self.last_attacked_time = 0.0
self.last_attacked_type: tuple[str, str] | None = None self.last_attacked_type: tuple[str, str] | None = None
self.to_target: ba.Vec3 = ba.Vec3(0, 0, 0) self.to_target: bs.Vec3 = bs.Vec3(0, 0, 0)
self.dist = (0, 0, 0) self.dist = (0, 0, 0)
self._bots = SpazBotSet() self._bots = SpazBotSet()
self.frozen = False self.frozen = False
self.y_pos = 3
self.xz_pos = 1
self.bot_count = 3 self.bot_count = 3
self.bot_dur_froze = False
self.hitpoints = hitpoints self.hitpoints = hitpoints
self.hitpoints_max = hitpoints self.hitpoints_max = hitpoints
@ -108,18 +112,18 @@ class UFO(ba.Actor):
self._height = 35 self._height = 35
self._bar_width = 240 self._bar_width = 240
self._bar_height = 35 self._bar_height = 35
self._bar_tex = self._backing_tex = ba.gettexture('bar') self._bar_tex = self._backing_tex = bs.gettexture('bar')
self._cover_tex = ba.gettexture('uiAtlas') self._cover_tex = bs.gettexture('uiAtlas')
self._model = ba.getmodel('meterTransparent') self._mesh = bs.getmesh('meterTransparent')
self.bar_posx = -120 self.bar_posx = -120
self._last_hit_time: int | None = None self._last_hit_time: int | None = None
self.impact_scale = 1.0 self.impact_scale = 1.0
self._num_times_hit = 0 self._num_times_hit = 0
self._sucker_mat = ba.Material() self._sucker_mat = bs.Material()
self.ufo_material = ba.Material() self.ufo_material = bs.Material()
self.ufo_material.add_actions( self.ufo_material.add_actions(
conditions=('they_have_material', conditions=('they_have_material',
shared.player_material), shared.player_material),
@ -135,21 +139,20 @@ class UFO(ba.Actor):
self.ufo_material)), self.ufo_material)),
actions=('modify_part_collision', 'physical', False)) actions=('modify_part_collision', 'physical', False))
activity = _ba.get_foreground_host_activity() activity = bs.get_foreground_host_activity()
with ba.Context(activity):
point = activity.map.get_flag_position(None) point = activity.map.get_flag_position(None)
boss_spawn_pos = (point[0], point[1] + 1, point[2]) boss_spawn_pos = (point[0], point[1] + 1, point[2])
self.node = ba.newnode('prop', delegate=self, attrs={ self.node = bs.newnode('prop', delegate=self, attrs={
'position': boss_spawn_pos, 'position': boss_spawn_pos,
'velocity': (2, 0, 0), 'velocity': (2, 0, 0),
'color_texture': ba.gettexture('achievementFootballShutout'), 'color_texture': bs.gettexture('achievementFootballShutout'),
'model': ba.getmodel('landMine'), 'mesh': bs.getmesh('landMine'),
# 'light_model': ba.getmodel('powerupSimple'), # 'light_mesh': bs.getmesh('powerupSimple'),
'model_scale': 3.3, 'mesh_scale': 3.3,
'body': 'landMine', 'body': 'landMine',
'body_scale': 3.3, 'body_scale': 3.3,
'gravity_scale': 0.05, 'gravity_scale': 0.2,
'density': 1, 'density': 1,
'reflection': 'soft', 'reflection': 'soft',
'reflection_scale': [0.25], 'reflection_scale': [0.25],
@ -159,7 +162,7 @@ class UFO(ba.Actor):
True, True,
'materials': [shared.footing_material, shared.object_material]}) 'materials': [shared.footing_material, shared.object_material]})
self.holder = ba.newnode('region', attrs={ self.holder = bs.newnode('region', attrs={
'position': ( 'position': (
boss_spawn_pos[0], boss_spawn_pos[1] - 0.25, boss_spawn_pos[0], boss_spawn_pos[1] - 0.25,
boss_spawn_pos[2]), boss_spawn_pos[2]),
@ -168,7 +171,7 @@ class UFO(ba.Actor):
'materials': (self.platform_material, self.ice_material, 'materials': (self.platform_material, self.ice_material,
shared.object_material)}) shared.object_material)})
self.suck_anim = ba.newnode('locator', self.suck_anim = bs.newnode('locator',
owner=self.node, owner=self.node,
attrs={'shape': 'circleOutline', attrs={'shape': 'circleOutline',
'position': ( 'position': (
@ -181,7 +184,7 @@ class UFO(ba.Actor):
'additive': True}) 'additive': True})
def suck_anim(): def suck_anim():
ba.animate_array(self.suck_anim, 'position', 3, bs.animate_array(self.suck_anim, 'position', 3,
{0: ( {0: (
self.node.position[0], self.node.position[0],
self.node.position[1] - 5, self.node.position[1] - 5,
@ -194,7 +197,7 @@ class UFO(ba.Actor):
self.node.position[ self.node.position[
2] + self.to_target.z / 2)}) 2] + self.to_target.z / 2)})
self.suck_timer = ba.Timer(0.5, suck_anim, repeat=True) self.suck_timer = bs.Timer(0.5, suck_anim, repeat=True)
self.blocks = [] self.blocks = []
@ -209,14 +212,14 @@ class UFO(ba.Actor):
)) ))
# self.sucker = ba.newnode('region', attrs={ # self.sucker = bs.newnode('region', attrs={
# 'position': ( # 'position': (
# boss_spawn_pos[0], boss_spawn_pos[1] - 2, boss_spawn_pos[2]), # boss_spawn_pos[0], boss_spawn_pos[1] - 2, boss_spawn_pos[2]),
# 'scale': [2, 10, 2], # 'scale': [2, 10, 2],
# 'type': 'box', # 'type': 'box',
# 'materials': self._sucker_mat, }) # 'materials': self._sucker_mat, })
self.suck = ba.newnode('region', self.suck = bs.newnode('region',
attrs={'position': ( attrs={'position': (
boss_spawn_pos[0], boss_spawn_pos[1] - 2, boss_spawn_pos[0], boss_spawn_pos[1] - 2,
boss_spawn_pos[2]), boss_spawn_pos[2]),
@ -227,27 +230,26 @@ class UFO(ba.Actor):
self.node.connectattr('position', self.holder, 'position') self.node.connectattr('position', self.holder, 'position')
self.node.connectattr('position', self.suck, 'position') self.node.connectattr('position', self.suck, 'position')
ba.animate(self.node, 'model_scale', { bs.animate(self.node, 'mesh_scale', {
0: 0, 0: 0,
0.2: self.node.model_scale * 1.1, 0.2: self.node.mesh_scale * 1.1,
0.26: self.node.model_scale}) 0.26: self.node.mesh_scale})
self.shield_deco = ba.newnode('shield', owner=self.node, self.shield_deco = bs.newnode('shield', owner=self.node,
attrs={'color': (4, 4, 4), attrs={'color': (4, 4, 4),
'radius': 1.2}) 'radius': 1.2})
self.node.connectattr('position', self.shield_deco, 'position') self.node.connectattr('position', self.shield_deco, 'position')
self._scoreboard() self._scoreboard()
self._update() self._update()
self.drop_bomb_timer = ba.Timer(1.5, ba.Call(self._drop_bomb), self.drop_bomb_timer = bs.Timer(1.5, bs.Call(self._drop_bomb),
repeat=True) repeat=True)
self.drop_bots_timer = ba.Timer(15.0, ba.Call(self._drop_bots), repeat=True) self.drop_bots_timer = bs.Timer(15.0, bs.Call(self._drop_bots), repeat=True)
def _drop_bots(self) -> None: def _drop_bots(self) -> None:
p = self.node.position p = self.node.position
if not self.frozen:
for i in range(self.bot_count): for i in range(self.bot_count):
ba.timer( bs.timer(
1.0 + i, 1.0 + i,
lambda: self._bots.spawn_bot( lambda: self._bots.spawn_bot(
RoboBot, pos=(self.node.position[0], RoboBot, pos=(self.node.position[0],
@ -255,13 +257,10 @@ class UFO(ba.Actor):
self.node.position[2]), spawn_time=0.0 self.node.position[2]), spawn_time=0.0
), ),
) )
else:
self.bot_dur_froze = True
def _drop_bomb(self) -> None: def _drop_bomb(self) -> None:
t = self.to_target t = self.to_target
p = self.node.position p = self.node.position
if not self.frozen:
if abs(self.dist[0]) < 2 and abs(self.dist[2]) < 2: if abs(self.dist[0]) < 2 and abs(self.dist[2]) < 2:
Bomb(position=(p[0], p[1] - 0.5, p[2]), Bomb(position=(p[0], p[1] - 0.5, p[2]),
velocity=(t[0] * 5, 0, t[2] * 5), velocity=(t[0] * 5, 0, t[2] * 5),
@ -285,11 +284,11 @@ class UFO(ba.Actor):
bomb_type='impact').autoretain() bomb_type='impact').autoretain()
def _levitate(self): def _levitate(self):
node = ba.getcollision().opposingnode node = bs.getcollision().opposingnode
if node.exists(): if node.exists():
p = node.getdelegate(Spaz, True) p = node.getdelegate(Spaz, True)
def raise_player(player: ba.Player): def raise_player(player: bs.Player):
if player.is_alive(): if player.is_alive():
node = player.node node = player.node
try: try:
@ -298,12 +297,13 @@ class UFO(ba.Actor):
node.position[2], 0, 5, 0, 3, 10, 0, node.position[2], 0, 5, 0, 3, 10, 0,
0, 0, 5, 0) 0, 0, 5, 0)
except: except:
pass pass
if not self.frozen: if not self.frozen:
for i in range(7): for i in range(7):
ba.timer(0.05 + i / 20, ba.Call(raise_player, p)) bs.timer(0.05 + i / 20, bs.Call(raise_player, p))
def on_punched(self, damage: int) -> None: def on_punched(self, damage: int) -> None:
"""Called when this spaz gets punched.""" """Called when this spaz gets punched."""
@ -315,24 +315,22 @@ class UFO(ba.Actor):
damage = abs(msg.magnitude) damage = abs(msg.magnitude)
if msg.hit_type == 'explosion': if msg.hit_type == 'explosion':
damage /= 20 damage /= 20
else:
damage /= 5
self.hitpoints -= int(damage) self.hitpoints -= int(damage)
if self.hitpoints <= 0: if self.hitpoints <= 0:
self.handlemessage(ba.DieMessage()) self.handlemessage(bs.DieMessage())
def _get_target_player_pt(self) -> tuple[ def _get_target_player_pt(self) -> tuple[
ba.Vec3 | None, ba.Vec3 | None]: bs.Vec3 | None, bs.Vec3 | None]:
"""Returns the position and velocity of our target. """Returns the position and velocity of our target.
Both values will be None in the case of no target. Both values will be None in the case of no target.
""" """
assert self.node assert self.node
botpt = ba.Vec3(self.node.position) botpt = bs.Vec3(self.node.position)
closest_dist: float | None = None closest_dist: float | None = None
closest_vel: ba.Vec3 | None = None closest_vel: bs.Vec3 | None = None
closest: ba.Vec3 | None = None closest: bs.Vec3 | None = None
assert self._player_pts is not None assert self._player_pts is not None
for plpt, plvel in self._player_pts: for plpt, plvel in self._player_pts:
dist = (plpt - botpt).length() dist = (plpt - botpt).length()
@ -349,12 +347,12 @@ class UFO(ba.Actor):
assert closest_vel is not None assert closest_vel is not None
assert closest is not None assert closest is not None
return ( return (
ba.Vec3(closest[0], closest[1], closest[2]), bs.Vec3(closest[0], closest[1], closest[2]),
ba.Vec3(closest_vel[0], closest_vel[1], closest_vel[2]), bs.Vec3(closest_vel[0], closest_vel[1], closest_vel[2]),
) )
return None, None return None, None
def set_player_points(self, pts: list[tuple[ba.Vec3, ba.Vec3]]) -> None: def set_player_points(self, pts: list[tuple[bs.Vec3, bs.Vec3]]) -> None:
"""Provide the spaz-bot with the locations of its enemies.""" """Provide the spaz-bot with the locations of its enemies."""
self._player_pts = pts self._player_pts = pts
@ -368,13 +366,13 @@ class UFO(ba.Actor):
Category: Gameplay Functions Category: Gameplay Functions
""" """
lifespan = 1.0 lifespan = 1.0
app = ba.app app = bs.app
# FIXME: Should never vary game elements based on local config. # FIXME: Should never vary game elements based on local config.
# (connected clients may have differing configs so they won't # (connected clients may have differing configs so they won't
# get the intended results). # get the intended results).
do_big = app.ui.uiscale is ba.UIScale.SMALL or app.vr_mode do_big = app.ui.uiscale is bs.UIScale.SMALL or app.vr_mode
txtnode = ba.newnode('text', txtnode = bs.newnode('text',
attrs={ attrs={
'text': damage, 'text': damage,
'in_world': True, 'in_world': True,
@ -385,7 +383,7 @@ class UFO(ba.Actor):
'scale': 0.035 if do_big else 0.03 'scale': 0.035 if do_big else 0.03
}) })
# Translate upward. # Translate upward.
tcombine = ba.newnode('combine', owner=txtnode, attrs={'size': 3}) tcombine = bs.newnode('combine', owner=txtnode, attrs={'size': 3})
tcombine.connectattr('output', txtnode, 'position') tcombine.connectattr('output', txtnode, 'position')
v_vals = [] v_vals = []
pval = 0.0 pval = 0.0
@ -397,25 +395,25 @@ class UFO(ba.Actor):
vval *= 0.5 vval *= 0.5
p_start = position[0] p_start = position[0]
p_dir = direction[0] p_dir = direction[0]
ba.animate(tcombine, 'input0', bs.animate(tcombine, 'input0',
{i[0] * lifespan: p_start + p_dir * i[1] {i[0] * lifespan: p_start + p_dir * i[1]
for i in v_vals}) for i in v_vals})
p_start = position[1] p_start = position[1]
p_dir = direction[1] p_dir = direction[1]
ba.animate(tcombine, 'input1', bs.animate(tcombine, 'input1',
{i[0] * lifespan: p_start + p_dir * i[1] {i[0] * lifespan: p_start + p_dir * i[1]
for i in v_vals}) for i in v_vals})
p_start = position[2] p_start = position[2]
p_dir = direction[2] p_dir = direction[2]
ba.animate(tcombine, 'input2', bs.animate(tcombine, 'input2',
{i[0] * lifespan: p_start + p_dir * i[1] {i[0] * lifespan: p_start + p_dir * i[1]
for i in v_vals}) for i in v_vals})
ba.animate(txtnode, 'opacity', {0.7 * lifespan: 1.0, lifespan: 0.0}) bs.animate(txtnode, 'opacity', {0.7 * lifespan: 1.0, lifespan: 0.0})
ba.timer(lifespan, txtnode.delete) bs.timer(lifespan, txtnode.delete)
def _scoreboard(self) -> None: def _scoreboard(self) -> None:
self._backing = ba.NodeActor( self._backing = bs.NodeActor(
ba.newnode('image', bs.newnode('image',
attrs={ attrs={
'position': (self.bar_posx + self._width / 2, -100), 'position': (self.bar_posx + self._width / 2, -100),
'scale': (self._width, self._height), 'scale': (self._width, self._height),
@ -427,15 +425,15 @@ class UFO(ba.Actor):
'attach': 'topCenter', 'attach': 'topCenter',
'texture': self._backing_tex 'texture': self._backing_tex
})) }))
self._bar = ba.NodeActor( self._bar = bs.NodeActor(
ba.newnode('image', bs.newnode('image',
attrs={ attrs={
'opacity': 1.0, 'opacity': 1.0,
'color': (0.5, 0.5, 0.5), 'color': (0.5, 0.5, 0.5),
'attach': 'topCenter', 'attach': 'topCenter',
'texture': self._bar_tex 'texture': self._bar_tex
})) }))
self._bar_scale = ba.newnode('combine', self._bar_scale = bs.newnode('combine',
owner=self._bar.node, owner=self._bar.node,
attrs={ attrs={
'size': 2, 'size': 2,
@ -443,7 +441,7 @@ class UFO(ba.Actor):
'input1': self._bar_height 'input1': self._bar_height
}) })
self._bar_scale.connectattr('output', self._bar.node, 'scale') self._bar_scale.connectattr('output', self._bar.node, 'scale')
self._bar_position = ba.newnode( self._bar_position = bs.newnode(
'combine', 'combine',
owner=self._bar.node, owner=self._bar.node,
attrs={ attrs={
@ -452,8 +450,8 @@ class UFO(ba.Actor):
'input1': -100 'input1': -100
}) })
self._bar_position.connectattr('output', self._bar.node, 'position') self._bar_position.connectattr('output', self._bar.node, 'position')
self._cover = ba.NodeActor( self._cover = bs.NodeActor(
ba.newnode('image', bs.newnode('image',
attrs={ attrs={
'position': (self.bar_posx + 120, -100), 'position': (self.bar_posx + 120, -100),
'scale': 'scale':
@ -465,10 +463,10 @@ class UFO(ba.Actor):
'vr_depth': 2, 'vr_depth': 2,
'attach': 'topCenter', 'attach': 'topCenter',
'texture': self._cover_tex, 'texture': self._cover_tex,
'model_transparent': self._model 'mesh_transparent': self._mesh
})) }))
self._score_text = ba.NodeActor( self._score_text = bs.NodeActor(
ba.newnode('text', bs.newnode('text',
attrs={ attrs={
'position': (self.bar_posx + 120, -100), 'position': (self.bar_posx + 120, -100),
'h_attach': 'center', 'h_attach': 'center',
@ -487,35 +485,36 @@ class UFO(ba.Actor):
self._score_text.node.text = str(self.hitpoints) self._score_text.node.text = str(self.hitpoints)
self._bar_width = self.hitpoints * self._width_max / self.hitpoints_max self._bar_width = self.hitpoints * self._width_max / self.hitpoints_max
cur_width = self._bar_scale.input0 cur_width = self._bar_scale.input0
ba.animate(self._bar_scale, 'input0', { bs.animate(self._bar_scale, 'input0', {
0.0: cur_width, 0.0: cur_width,
0.1: self._bar_width 0.1: self._bar_width
}) })
cur_x = self._bar_position.input0 cur_x = self._bar_position.input0
ba.animate(self._bar_position, 'input0', { bs.animate(self._bar_position, 'input0', {
0.0: cur_x, 0.0: cur_x,
0.1: self.bar_posx + self._bar_width / 2 0.1: self.bar_posx + self._bar_width / 2
}) })
if self.hitpoints > self.hitpoints_max * 3 / 4: if self.hitpoints > self.hitpoints_max * 3 / 4:
ba.animate_array(self.shield_deco, 'color', 3, bs.animate_array(self.shield_deco, 'color', 3,
{0: self.shield_deco.color, 0.2: (4, 4, 4)}) {0: self.shield_deco.color, 0.2: (4, 4, 4)})
elif self.hitpoints > self.hitpoints_max * 1 / 2: elif self.hitpoints > self.hitpoints_max * 1 / 2:
ba.animate_array(self.shield_deco, 'color', 3, bs.animate_array(self.shield_deco, 'color', 3,
{0: self.shield_deco.color, 0.2: (3, 3, 5)}) {0: self.shield_deco.color, 0.2: (3, 3, 5)})
self.bot_count = 4 self.bot_count = 4
elif self.hitpoints > self.hitpoints_max * 1 / 4: elif self.hitpoints > self.hitpoints_max * 1 / 4:
ba.animate_array(self.shield_deco, 'color', 3, bs.animate_array(self.shield_deco, 'color', 3,
{0: self.shield_deco.color, 0.2: (1, 5, 1)}) {0: self.shield_deco.color, 0.2: (1, 5, 1)})
self.bot_count = 5 self.bot_count = 5
else: else:
ba.animate_array(self.shield_deco, 'color', 3, bs.animate_array(self.shield_deco, 'color', 3,
{0: self.shield_deco.color, 0.2: (5, 0.2, 0.2)}) {0: self.shield_deco.color, 0.2: (5, 0.2, 0.2)})
self.bot_count = 6 self.bot_count = 6
def update_ai(self) -> None: def update_ai(self) -> None:
"""Should be called periodically to update the spaz' AI.""" """Should be called periodically to update the spaz' AI."""
# pylint: disable=too-many-branches # pylint: disable=too-many-branches
@ -530,10 +529,10 @@ class UFO(ba.Actor):
return return
pos = self.node.position pos = self.node.position
our_pos = ba.Vec3(pos[0], pos[1] - self.y_pos, pos[2]) our_pos = bs.Vec3(pos[0], pos[1] - 3, pos[2])
target_pt_raw: ba.Vec3 | None target_pt_raw: bs.Vec3 | None
target_vel: ba.Vec3 | None target_vel: bs.Vec3 | None
target_pt_raw, target_vel = self._get_target_player_pt() target_pt_raw, target_vel = self._get_target_player_pt()
@ -562,15 +561,12 @@ class UFO(ba.Actor):
setattr(self.node, 'extra_acceleration', setattr(self.node, 'extra_acceleration',
(0, self.to_target.y * 80 + 70, (0, self.to_target.y * 80 + 70,
0)) 0))
else: elif not self.frozen:
setattr(self.node, 'velocity', setattr(self.node, 'velocity',
(self.to_target.x * self.xz_pos, (self.to_target.x, self.to_target.y, self.to_target.z))
self.to_target.y,
self.to_target.z * self.xz_pos))
setattr(self.node, 'extra_acceleration', setattr(self.node, 'extra_acceleration',
(self.to_target.x * self.xz_pos, (self.to_target.x, self.to_target.y * 80 + 70,
self.to_target.y * 80 + 70, self.to_target.z))
self.to_target.z * self.xz_pos))
def on_expire(self) -> None: def on_expire(self) -> None:
super().on_expire() super().on_expire()
@ -579,14 +575,14 @@ class UFO(ba.Actor):
# no chance of them keeping activities or other things alive. # no chance of them keeping activities or other things alive.
self.update_callback = None self.update_callback = None
def animate_model(self) -> None: def animate_mesh(self) -> None:
if not self.node: if not self.node:
return None return None
# ba.animate(self.node, 'model_scale', { # bs.animate(self.node, 'mesh_scale', {
# 0: self.node.model_scale, # 0: self.node.mesh_scale,
# 0.08: self.node.model_scale * 0.9, # 0.08: self.node.mesh_scale * 0.9,
# 0.15: self.node.model_scale}) # 0.15: self.node.mesh_scale})
ba.emitfx(position=self.node.position, bs.emitfx(position=self.node.position,
velocity=self.node.velocity, velocity=self.node.velocity,
count=int(6 + random.random() * 10), count=int(6 + random.random() * 10),
scale=0.5, scale=0.5,
@ -597,15 +593,15 @@ class UFO(ba.Actor):
# pylint: disable=too-many-branches # pylint: disable=too-many-branches
assert not self.expired assert not self.expired
if isinstance(msg, ba.HitMessage): if isinstance(msg, bs.HitMessage):
# Don't die on punches (that's annoying). # Don't die on punches (that's annoying).
self.animate_model() self.animate_mesh()
if self.hitpoints != 0: if self.hitpoints != 0:
self.do_damage(msg) self.do_damage(msg)
# self.show_damage_msg(msg) # self.show_damage_msg(msg)
self._update() self._update()
elif isinstance(msg, ba.DieMessage): elif isinstance(msg, bs.DieMessage):
if self.node: if self.node:
self.hitpoints = 0 self.hitpoints = 0
self.frozen = True self.frozen = True
@ -629,46 +625,52 @@ class UFO(ba.Actor):
position=(p_x, p[1], p_z), position=(p_x, p[1], p_z),
blast_radius=2.0).autoretain() blast_radius=2.0).autoretain()
ba.timer(0 + i, ba.Call(ded_explode, i)) bs.timer(0 + i, bs.Call(ded_explode, i))
ba.timer(5, self.node.delete) bs.timer(5, self.node.delete)
ba.timer(0.1, self.suck.delete) bs.timer(0.1, self.suck.delete)
ba.timer(0.1, self.suck_anim.delete) bs.timer(0.1, self.suck_anim.delete)
elif isinstance(msg, ba.OutOfBoundsMessage): elif isinstance(msg, bs.OutOfBoundsMessage):
activity = _ba.get_foreground_host_activity() activity = bs.get_foreground_host_activity()
try: try:
point = activity.map.get_flag_position(None) point = activity.map.get_flag_position(None)
boss_spawn_pos = (point[0], point[1] + 1.5, point[2]) boss_spawn_pos = (point[0], point[1] + 1.5, point[2])
assert self.node assert self.node
self.node.position = boss_spawn_pos self.node.position = boss_spawn_pos
except: except:
self.handlemessage(ba.DieMessage()) self.handlemessage(bs.DieMessage())
elif isinstance(msg, ba.FreezeMessage): elif isinstance(msg, bs.FreezeMessage):
if not self.frozen: if not self.frozen:
self.frozen = True self.frozen = True
self.y_pos = -1.5 self.drop_bomb_timer = False
self.xz_pos = 0.01 self.drop_bots_timer = False
setattr(self.node, 'velocity',
(0, self.to_target.y, 0))
setattr(self.node, 'extra_acceleration',
(0, 0, 0))
self.node.reflection_scale = [2] self.node.reflection_scale = [2]
def unfrozen(): def unfrozen():
self.frozen = False self.frozen = False
if self.bot_dur_froze: self.drop_bomb_timer = bs.Timer(1.5,
ba.timer(0.1, ba.Call(self._drop_bots)) bs.Call(self._drop_bomb),
self.bot_dur_froze = False repeat=True)
self.y_pos = 3
self.xz_pos = 1 self.drop_bots_timer = bs.Timer(15.0,
bs.Call(self._drop_bots),
repeat=True)
self.node.reflection_scale = [0.25] self.node.reflection_scale = [0.25]
ba.timer(5.0, unfrozen) bs.timer(3.0, unfrozen)
else: else:
super().handlemessage(msg) super().handlemessage(msg)
class UFOSet: class UFOSet:
"""A container/controller for one or more ba.SpazBots. """A container/controller for one or more bs.SpazBots.
category: Bot Classes category: Bot Classes
""" """
@ -684,9 +686,9 @@ class UFOSet:
self._ufo_bot_lists: list[list[UFO]] = [ self._ufo_bot_lists: list[list[UFO]] = [
[] for _ in range(self._ufo_bot_list_count) [] for _ in range(self._ufo_bot_list_count)
] ]
self._ufo_spawn_sound = ba.getsound('spawn') self._ufo_spawn_sound = bs.getsound('spawn')
self._ufo_spawning_count = 0 self._ufo_spawning_count = 0
self._ufo_bot_update_timer: ba.Timer | None = None self._ufo_bot_update_timer: bs.Timer | None = None
self.start_moving() self.start_moving()
def _update(self) -> None: def _update(self) -> None:
@ -699,7 +701,7 @@ class UFOSet:
] ]
except Exception: except Exception:
bot_list = [] bot_list = []
ba.print_exception( bs.print_exception(
'Error updating bot list: ' 'Error updating bot list: '
+ str(self._ufo_bot_lists[self._ufo_bot_update_list]) + str(self._ufo_bot_lists[self._ufo_bot_update_list])
) )
@ -709,8 +711,8 @@ class UFOSet:
# Update our list of player points for the bots to use. # Update our list of player points for the bots to use.
player_pts = [] player_pts = []
for player in ba.getactivity().players: for player in bs.getactivity().players:
assert isinstance(player, ba.Player) assert isinstance(player, bs.Player)
try: try:
# TODO: could use abstracted player.position here so we # TODO: could use abstracted player.position here so we
# don't have to assume their actor type, but we have no # don't have to assume their actor type, but we have no
@ -720,12 +722,12 @@ class UFOSet:
assert player.actor.node assert player.actor.node
player_pts.append( player_pts.append(
( (
ba.Vec3(player.actor.node.position), bs.Vec3(player.actor.node.position),
ba.Vec3(player.actor.node.velocity), bs.Vec3(player.actor.node.velocity),
) )
) )
except Exception: except Exception:
ba.print_exception('Error on bot-set _update.') bs.print_exception('Error on bot-set _update.')
for bot in bot_list: for bot in bot_list:
bot.set_player_points(player_pts) bot.set_player_points(player_pts)
@ -733,8 +735,8 @@ class UFOSet:
def start_moving(self) -> None: def start_moving(self) -> None:
"""Start processing bot AI updates so they start doing their thing.""" """Start processing bot AI updates so they start doing their thing."""
self._ufo_bot_update_timer = ba.Timer( self._ufo_bot_update_timer = bs.Timer(
0.05, ba.WeakCall(self._update), repeat=True 0.05, bs.WeakCall(self._update), repeat=True
) )
def spawn_bot( def spawn_bot(
@ -745,13 +747,13 @@ class UFOSet:
on_spawn_call: Callable[[UFO], Any] | None = None, on_spawn_call: Callable[[UFO], Any] | None = None,
) -> None: ) -> None:
"""Spawn a bot from this set.""" """Spawn a bot from this set."""
from bastd.actor import spawner from bascenev1lib.actor import spawner
spawner.Spawner( spawner.Spawner(
pt=pos, pt=pos,
spawn_time=spawn_time, spawn_time=spawn_time,
send_spawn_message=False, send_spawn_message=False,
spawn_callback=ba.Call( spawn_callback=bs.Call(
self._spawn_bot, bot_type, pos, on_spawn_call self._spawn_bot, bot_type, pos, on_spawn_call
), ),
) )
@ -764,18 +766,18 @@ class UFOSet:
on_spawn_call: Callable[[UFO], Any] | None, on_spawn_call: Callable[[UFO], Any] | None,
) -> None: ) -> None:
spaz = bot_type() spaz = bot_type()
ba.playsound(self._ufo_spawn_sound, position=pos) self._ufo_spawn_sound.play(position=pos)
assert spaz.node assert spaz.node
spaz.node.handlemessage('flash') spaz.node.handlemessage('flash')
spaz.node.is_area_of_interest = False spaz.node.is_area_of_interest = False
spaz.handlemessage(ba.StandMessage(pos, random.uniform(0, 360))) spaz.handlemessage(bs.StandMessage(pos, random.uniform(0, 360)))
self.add_bot(spaz) self.add_bot(spaz)
self._ufo_spawning_count -= 1 self._ufo_spawning_count -= 1
if on_spawn_call is not None: if on_spawn_call is not None:
on_spawn_call(spaz) on_spawn_call(spaz)
def add_bot(self, bot: UFO) -> None: def add_bot(self, bot: UFO) -> None:
"""Add a ba.SpazBot instance to the set.""" """Add a bs.SpazBot instance to the set."""
self._ufo_bot_lists[self._ufo_bot_add_list].append(bot) self._ufo_bot_lists[self._ufo_bot_add_list].append(bot)
self._ufo_bot_add_list = ( self._ufo_bot_add_list = (
self._ufo_bot_add_list + 1) % self._ufo_bot_list_count self._ufo_bot_add_list + 1) % self._ufo_bot_list_count
@ -799,26 +801,26 @@ class UFOSet:
"""Immediately clear out any bots in the set.""" """Immediately clear out any bots in the set."""
# Don't do this if the activity is shutting down or dead. # Don't do this if the activity is shutting down or dead.
activity = ba.getactivity(doraise=False) activity = bs.getactivity(doraise=False)
if activity is None or activity.expired: if activity is None or activity.expired:
return return
for i, bot_list in enumerate(self._ufo_bot_lists): for i, bot_list in enumerate(self._ufo_bot_lists):
for bot in bot_list: for bot in bot_list:
bot.handlemessage(ba.DieMessage(immediate=True)) bot.handlemessage(bs.DieMessage(immediate=True))
self._ufo_bot_lists[i] = [] self._ufo_bot_lists[i] = []
class Player(ba.Player['Team']): class Player(bs.Player['Team']):
"""Our player type for this game.""" """Our player type for this game."""
class Team(ba.Team[Player]): class Team(bs.Team[Player]):
"""Our team type for this game.""" """Our team type for this game."""
# ba_meta export game # ba_meta export bascenev1.GameActivity
class UFOightGame(ba.TeamGameActivity[Player, Team]): class UFOightGame(bs.TeamGameActivity[Player, Team]):
""" """
A co-op game where you try to defeat UFO Boss A co-op game where you try to defeat UFO Boss
as fast as possible as fast as possible
@ -826,33 +828,33 @@ class UFOightGame(ba.TeamGameActivity[Player, Team]):
name = 'UFO Fight' name = 'UFO Fight'
description = 'REal Boss Fight?' description = 'REal Boss Fight?'
scoreconfig = ba.ScoreConfig( scoreconfig = bs.ScoreConfig(
label='Time', scoretype=ba.ScoreType.MILLISECONDS, lower_is_better=True label='Time', scoretype=bs.ScoreType.MILLISECONDS, lower_is_better=True
) )
default_music = ba.MusicType.TO_THE_DEATH default_music = bs.MusicType.TO_THE_DEATH
@classmethod @classmethod
def get_supported_maps(cls, sessiontype: type[ba.Session]) -> list[str]: def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]:
# For now we're hard-coding spawn positions and whatnot # For now we're hard-coding spawn positions and whatnot
# so we need to be sure to specify that we only support # so we need to be sure to specify that we only support
# a specific map. # a specific map.
return ['Football Stadium'] return ['Football Stadium']
@classmethod @classmethod
def supports_session_type(cls, sessiontype: type[ba.Session]) -> bool: def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool:
# We currently support Co-Op only. # We currently support Co-Op only.
return issubclass(sessiontype, ba.CoopSession) return issubclass(sessiontype, bs.CoopSession)
# In the constructor we should load any media we need/etc. # In the constructor we should load any media we need/etc.
# ...but not actually create anything yet. # ...but not actually create anything yet.
def __init__(self, settings: dict): def __init__(self, settings: dict):
super().__init__(settings) super().__init__(settings)
self._winsound = ba.getsound('score') self._winsound = bs.getsound('score')
self._won = False self._won = False
self._timer: OnScreenTimer | None = None self._timer: OnScreenTimer | None = None
self._bots = UFOSet() self._bots = UFOSet()
self._preset = str(settings['preset']) self._preset = str(settings['preset'])
self._credit = ba.newnode('text', self._credit = bs.newnode('text',
attrs={ attrs={
'v_attach': 'bottom', 'v_attach': 'bottom',
'h_align': 'center', 'h_align': 'center',
@ -864,9 +866,11 @@ class UFOightGame(ba.TeamGameActivity[Player, Team]):
'text': 'By Cross Joy' 'text': 'By Cross Joy'
}) })
def on_transition_in(self) -> None: def on_transition_in(self) -> None:
super().on_transition_in() super().on_transition_in()
gnode = ba.getactivity().globalsnode gnode = bs.getactivity().globalsnode
gnode.tint = (0.42, 0.55, 0.66) gnode.tint = (0.42, 0.55, 0.66)
# Called when our game actually begins. # Called when our game actually begins.
@ -874,24 +878,26 @@ class UFOightGame(ba.TeamGameActivity[Player, Team]):
super().on_begin() super().on_begin()
self.setup_standard_powerup_drops() self.setup_standard_powerup_drops()
# In pro mode there's no powerups. # In pro mode there's no powerups.
# Make our on-screen timer and start it roughly when our bots appear. # Make our on-screen timer and start it roughly when our bots appear.
self._timer = OnScreenTimer() self._timer = OnScreenTimer()
ba.timer(4.0, self._timer.start) bs.timer(4.0, self._timer.start)
def checker(): def checker():
if not self._won: if not self._won:
self.timer = ba.Timer(0.1, self._check_if_won, repeat=True) self.timer = bs.Timer(0.1, self._check_if_won, repeat=True)
ba.timer(10, checker) bs.timer(10, checker)
activity = _ba.get_foreground_host_activity() activity = bs.get_foreground_host_activity()
point = activity.map.get_flag_position(None) point = activity.map.get_flag_position(None)
boss_spawn_pos = (point[0], point[1] + 1.5, point[2]) boss_spawn_pos = (point[0], point[1] + 1.5, point[2])
# Spawn some baddies. # Spawn some baddies.
ba.timer( bs.timer(
1.0, 1.0,
lambda: self._bots.spawn_bot( lambda: self._bots.spawn_bot(
UFO, pos=boss_spawn_pos, spawn_time=3.0 UFO, pos=boss_spawn_pos, spawn_time=3.0
@ -915,10 +921,10 @@ class UFOightGame(ba.TeamGameActivity[Player, Team]):
def handlemessage(self, msg: Any) -> Any: def handlemessage(self, msg: Any) -> Any:
# A player has died. # A player has died.
if isinstance(msg, ba.PlayerDiedMessage): if isinstance(msg, bs.PlayerDiedMessage):
player = msg.getplayer(Player) player = msg.getplayer(Player)
self.stats.player_was_killed(player) self.stats.player_was_killed(player)
ba.timer(0.1, self._checkroundover) bs.timer(0.1, self._checkroundover)
# A spaz-bot has died. # A spaz-bot has died.
elif isinstance(msg, UFODiedMessage): elif isinstance(msg, UFODiedMessage):
@ -926,7 +932,7 @@ class UFOightGame(ba.TeamGameActivity[Player, Team]):
# bots if we ask here (the currently-dying bot isn't officially # bots if we ask here (the currently-dying bot isn't officially
# marked dead yet) ..so lets push a call into the event loop to # marked dead yet) ..so lets push a call into the event loop to
# check once this guy has finished dying. # check once this guy has finished dying.
ba.pushcall(self._check_if_won) bs.pushcall(self._check_if_won)
# Let the base class handle anything we don't. # Let the base class handle anything we don't.
else: else:
@ -948,20 +954,20 @@ class UFOightGame(ba.TeamGameActivity[Player, Team]):
assert self._timer is not None assert self._timer is not None
self._timer.stop() self._timer.stop()
results = ba.GameResults() results = bs.GameResults()
# If we won, set our score to the elapsed time in milliseconds. # If we won, set our score to the elapsed time in milliseconds.
# (there should just be 1 team here since this is co-op). # (there should just be 1 team here since this is co-op).
# ..if we didn't win, leave scores as default (None) which means # ..if we didn't win, leave scores as default (None) which means
# we lost. # we lost.
if self._won: if self._won:
elapsed_time_ms = int((ba.time() - self._timer.starttime) * 1000.0) elapsed_time_ms = int((bs.time() - self._timer.starttime) * 1000.0)
ba.cameraflash() bs.cameraflash()
ba.playsound(self._winsound) self._winsound.play()
for team in self.teams: for team in self.teams:
for player in team.players: for player in team.players:
if player.actor: if player.actor:
player.actor.handlemessage(ba.CelebrateMessage()) player.actor.handlemessage(bs.CelebrateMessage())
results.set_team_score(team, elapsed_time_ms) results.set_team_score(team, elapsed_time_ms)
# Ends the activity. # Ends the activity.
@ -969,11 +975,11 @@ class UFOightGame(ba.TeamGameActivity[Player, Team]):
# ba_meta export plugin # ba_meta export plugin
class MyUFOFightLevel(ba.Plugin): class MyUFOFightLevel(babase.Plugin):
def on_app_running(self) -> None: def on_app_running(self) -> None:
ba.app.add_coop_practice_level( babase.app.classic.add_coop_practice_level(
ba.Level( bs.Level(
name='The UFO Fight', name='The UFO Fight',
displayname='${GAME}', displayname='${GAME}',
gametype=UFOightGame, gametype=UFOightGame,
@ -981,3 +987,4 @@ class MyUFOFightLevel(ba.Plugin):
preview_texture_name='footballStadiumPreview', preview_texture_name='footballStadiumPreview',
) )
) )

View file

@ -1,3 +1,4 @@
# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport)
"""Ultimate Last Stand V2: """Ultimate Last Stand V2:
Made by Cross Joy""" Made by Cross Joy"""
@ -25,7 +26,7 @@ Made by Cross Joy"""
# ---------------------------------------------------------------------------- # ----------------------------------------------------------------------------
# ba_meta require api 7 # ba_meta require api 8
from __future__ import annotations from __future__ import annotations
@ -33,13 +34,15 @@ import random
from dataclasses import dataclass from dataclasses import dataclass
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
import ba import babase
from bastd.actor.playerspaz import PlayerSpaz import bauiv1 as bui
from bastd.actor.bomb import TNTSpawner import bascenev1 as bs
from bastd.actor.onscreentimer import OnScreenTimer from bascenev1lib.actor.playerspaz import PlayerSpaz
from bastd.actor.scoreboard import Scoreboard from bascenev1lib.actor.bomb import TNTSpawner
from bastd.actor.spazfactory import SpazFactory from bascenev1lib.actor.onscreentimer import OnScreenTimer
from bastd.actor.spazbot import (SpazBot, SpazBotSet, BomberBot, from bascenev1lib.actor.scoreboard import Scoreboard
from bascenev1lib.actor.spazfactory import SpazFactory
from bascenev1lib.actor.spazbot import (SpazBot, SpazBotSet, BomberBot,
BomberBotPro, BomberBotProShielded, BomberBotPro, BomberBotProShielded,
BrawlerBot, BrawlerBotPro, BrawlerBot, BrawlerBotPro,
BrawlerBotProShielded, TriggerBot, BrawlerBotProShielded, TriggerBot,
@ -48,7 +51,7 @@ from bastd.actor.spazbot import (SpazBot, SpazBotSet, BomberBot,
if TYPE_CHECKING: if TYPE_CHECKING:
from typing import Any, Sequence from typing import Any, Sequence
from bastd.actor.spazbot import SpazBot from bascenev1lib.actor.spazbot import SpazBot
class IceBot(SpazBot): class IceBot(SpazBot):
@ -71,7 +74,7 @@ class IceBot(SpazBot):
points_mult = 3 points_mult = 3
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,
@ -90,10 +93,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'],
@ -106,12 +109,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,
@ -122,7 +125,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',
@ -178,7 +181,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,
@ -195,10 +198,10 @@ 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)
@ -212,7 +215,7 @@ class SpawnInfo:
dincrease: float dincrease: float
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:
@ -222,7 +225,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:
@ -230,14 +233,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 UltimateLastStand(ba.TeamGameActivity[Player, Team]): class UltimateLastStand(bs.TeamGameActivity[Player, Team]):
"""Minigame involving dodging falling bombs.""" """Minigame involving dodging falling bombs."""
name = 'Ultimate Last Stand' name = 'Ultimate Last Stand'
description = 'Only the strongest will stand at the end.' description = 'Only the strongest will stand at the end.'
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)
# Print messages when players die (since its meaningful in this game). # Print messages when players die (since its meaningful in this game).
@ -250,16 +253,16 @@ class UltimateLastStand(ba.TeamGameActivity[Player, Team]):
@classmethod @classmethod
def get_available_settings( def get_available_settings(
cls, cls,
sessiontype: type[ba.Session]) -> list[ba.Setting]: 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.FloatChoiceSetting( bs.FloatChoiceSetting(
'Respawn Times', 'Respawn Times',
choices=[ choices=[
('Shorter', 0.25), ('Shorter', 0.25),
@ -270,31 +273,31 @@ class UltimateLastStand(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
# We're currently hard-coded for one map. # We're currently hard-coded for one map.
@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 ['Rampage'] return ['Rampage']
# We support teams, free-for-all, and co-op sessions. # We support teams, free-for-all, and co-op sessions.
@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)
or issubclass(sessiontype, ba.FreeForAllSession)) or issubclass(sessiontype, bs.FreeForAllSession))
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: float | None = None self._start_time: float | None = None
self._vs_text: ba.Actor | None = None self._vs_text: bs.Actor | None = None
self._round_end_timer: ba.Timer | None = None self._round_end_timer: bs.Timer | None = None
self._lives_per_player = int(settings['Lives Per Player']) self._lives_per_player = int(settings['Lives Per Player'])
self._balance_total_lives = bool( self._balance_total_lives = bool(
settings.get('Balance Total Lives', False)) settings.get('Balance Total Lives', False))
@ -302,17 +305,17 @@ class UltimateLastStand(ba.TeamGameActivity[Player, Team]):
self._last_player_death_time: float | None = None self._last_player_death_time: float | None = None
self._timer: OnScreenTimer | None = None self._timer: OnScreenTimer | None = None
self._tntspawner: TNTSpawner | None = None self._tntspawner: TNTSpawner | None = None
self._new_wave_sound = ba.getsound('scoreHit01') self._new_wave_sound = bs.getsound('scoreHit01')
self._bots = SpazBotSet() self._bots = SpazBotSet()
self._tntspawnpos = (0, 5.5, -6) self._tntspawnpos = (0, 5.5, -6)
self.spazList = [] self.spazList = []
# 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)
self.node = ba.newnode('text', self.node = bs.newnode('text',
attrs={ attrs={
'v_attach': 'bottom', 'v_attach': 'bottom',
'h_align': 'center', 'h_align': 'center',
@ -342,24 +345,24 @@ class UltimateLastStand(ba.TeamGameActivity[Player, Team]):
} # yapf: disable } # yapf: disable
# Some base class overrides: # Some base class overrides:
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)
if self._epic_mode: if self._epic_mode:
self.slow_motion = True self.slow_motion = True
def get_instance_description(self) -> str | Sequence: def get_instance_description(self) -> str | Sequence:
return 'Only the strongest team will stand at the end.' if isinstance( return 'Only the strongest team will stand at the end.' if isinstance(
self.session, self.session,
ba.DualTeamSession) else 'Only the strongest will stand at the end.' bs.DualTeamSession) else 'Only the strongest will stand at the end.'
def get_instance_description_short(self) -> str | Sequence: def get_instance_description_short(self) -> str | Sequence:
return 'Only the strongest team will stand at the end.' if isinstance( return 'Only the strongest team will stand at the end.' if isinstance(
self.session, self.session,
ba.DualTeamSession) else 'Only the strongest will stand at the end.' bs.DualTeamSession) else 'Only the strongest will stand at the end.'
def on_transition_in(self) -> None: def on_transition_in(self) -> None:
super().on_transition_in() super().on_transition_in()
ba.timer(1.3, ba.Call(ba.playsound, self._new_wave_sound)) bs.timer(1.3, babase.Call(babase.playsound, self._new_wave_sound))
def on_player_join(self, player: Player) -> None: def on_player_join(self, player: Player) -> None:
player.lives = self._lives_per_player player.lives = self._lives_per_player
@ -374,13 +377,13 @@ class UltimateLastStand(ba.TeamGameActivity[Player, Team]):
def on_begin(self) -> None: def on_begin(self) -> None:
super().on_begin() super().on_begin()
ba.animate_array(node=self.node, attr='color', size=3, keys={ bs.animate_array(node=self.node, attr='color', size=3, keys={
0.0: (0.5, 0.5, 0.5), 0.0: (0.5, 0.5, 0.5),
0.8: (0.83, 0.69, 0.21), 0.8: (0.83, 0.69, 0.21),
1.6: (0.5, 0.5, 0.5) 1.6: (0.5, 0.5, 0.5)
}, loop=True) }, loop=True)
ba.timer(0.001, ba.WeakCall(self._start_bot_updates)) bs.timer(0.001, bs.WeakCall(self._start_bot_updates))
self._tntspawner = TNTSpawner(position=self._tntspawnpos, self._tntspawner = TNTSpawner(position=self._tntspawnpos,
respawn_time=10.0) respawn_time=10.0)
@ -389,11 +392,11 @@ class UltimateLastStand(ba.TeamGameActivity[Player, Team]):
self.setup_standard_powerup_drops() self.setup_standard_powerup_drops()
# Check for immediate end (if we've only got 1 player, etc). # Check for immediate end (if we've only got 1 player, etc).
self._start_time = ba.time() self._start_time = bs.time()
# 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(
@ -409,7 +412,7 @@ class UltimateLastStand(ba.TeamGameActivity[Player, Team]):
lesser_team.players[add_index].lives += 1 lesser_team.players[add_index].lives += 1
add_index = (add_index + 1) % len(lesser_team.players) add_index = (add_index + 1) % len(lesser_team.players)
ba.timer(1.0, self._update, repeat=True) bs.timer(1.0, self._update, repeat=True)
self._update_icons() self._update_icons()
# We could check game-over conditions at explicit trigger points, # We could check game-over conditions at explicit trigger points,
@ -419,7 +422,7 @@ class UltimateLastStand(ba.TeamGameActivity[Player, Team]):
# pylint: disable=too-many-branches # pylint: disable=too-many-branches
# In free-for-all mode, everyone is just lined up along the bottom. # In free-for-all mode, everyone is just lined up along the bottom.
if isinstance(self.session, ba.FreeForAllSession): if isinstance(self.session, bs.FreeForAllSession):
count = len(self.teams) count = len(self.teams)
x_offs = 85 x_offs = 85
xval = x_offs * (count - 1) * -0.5 xval = x_offs * (count - 1) * -0.5
@ -453,21 +456,21 @@ class UltimateLastStand(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)
# A departing player may trigger game-over. # A departing player may trigger game-over.
# overriding the default character spawning.. # overriding the default character spawning..
def spawn_player(self, player: Player) -> ba.Actor: def spawn_player(self, player: Player) -> bs.Actor:
actor = self.spawn_player_spaz(player) actor = self.spawn_player_spaz(player)
ba.timer(0.3, ba.Call(self._print_lives, player)) bs.timer(0.3, babase.Call(self._print_lives, player))
# If we have any icons, update their state. # If we have any icons, update their state.
for icon in player.icons: for icon in player.icons:
@ -475,7 +478,7 @@ class UltimateLastStand(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:
@ -499,14 +502,14 @@ class UltimateLastStand(ba.TeamGameActivity[Player, Team]):
self._update_bots() self._update_bots()
if len(self.players) > 3: if len(self.players) > 3:
self._update_bots() self._update_bots()
self._bot_update_timer = ba.Timer(self._bot_update_interval, self._bot_update_timer = bs.Timer(self._bot_update_interval,
ba.WeakCall(self._update_bots)) bs.WeakCall(self._update_bots))
def _update_bots(self) -> None: def _update_bots(self) -> None:
assert self._bot_update_interval is not None assert self._bot_update_interval is not None
self._bot_update_interval = max(0.5, self._bot_update_interval * 0.98) self._bot_update_interval = max(0.5, self._bot_update_interval * 0.98)
self._bot_update_timer = ba.Timer(self._bot_update_interval, self._bot_update_timer = bs.Timer(self._bot_update_interval,
ba.WeakCall(self._update_bots)) bs.WeakCall(self._update_bots))
botspawnpts: list[Sequence[float]] = [[-5.0, 5.5, -4.14], botspawnpts: list[Sequence[float]] = [[-5.0, 5.5, -4.14],
[0.0, 5.5, -4.14], [0.0, 5.5, -4.14],
[5.0, 5.5, -4.14]] [5.0, 5.5, -4.14]]
@ -516,7 +519,7 @@ class UltimateLastStand(ba.TeamGameActivity[Player, Team]):
assert isinstance(player.actor, PlayerSpaz) assert isinstance(player.actor, PlayerSpaz)
assert player.actor.node assert player.actor.node
except Exception: except Exception:
ba.print_exception('Error updating bots.') babase.print_exception('Error updating bots.')
spawnpt = random.choice( spawnpt = random.choice(
[botspawnpts[0], botspawnpts[1], botspawnpts[2]]) [botspawnpts[0], botspawnpts[1], botspawnpts[2]])
@ -550,12 +553,12 @@ class UltimateLastStand(ba.TeamGameActivity[Player, Team]):
# Various high-level game events come through this method. # Various high-level game events come through this method.
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)
curtime = ba.time() curtime = bs.time()
# Record the player's moment of death. # Record the player's moment of death.
# assert isinstance(msg.spaz.player # assert isinstance(msg.spaz.player
@ -574,14 +577,14 @@ class UltimateLastStand(ba.TeamGameActivity[Player, Team]):
# Play big death sound on our last death # Play big death sound on our last death
# or for every one in solo mode. # or for every one in solo mode.
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)
else: else:
# Otherwise, in regular mode, respawn. # Otherwise, in regular mode, respawn.
@ -599,7 +602,7 @@ class UltimateLastStand(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 end_game(self) -> None: def end_game(self) -> None:
# Stop updating our time text, and set the final time to match # Stop updating our time text, and set the final time to match
@ -608,7 +611,7 @@ class UltimateLastStand(ba.TeamGameActivity[Player, Team]):
# Ok now calc game results: set a score for each team and then tell # Ok now calc game results: set a score for each team and then tell
# the game to end. # the game to end.
results = ba.GameResults() results = bs.GameResults()
# Remember that 'free-for-all' mode is simply a special form # Remember that 'free-for-all' mode is simply a special form
# of 'teams' mode where each player gets their own team, so we can # of 'teams' mode where each player gets their own team, so we can

View file

@ -1,23 +1,26 @@
# ba_meta require api 7 # Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport)
# 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
import _ba import bauiv1 as bui
import bascenev1 as bs
import _babase
import copy import copy
import random import random
from ba import _math from babase import _math
from ba._coopsession import CoopSession from bascenev1._coopsession import CoopSession
from ba._messages import PlayerDiedMessage, StandMessage from bascenev1._messages import PlayerDiedMessage, StandMessage
from bastd.actor.playerspaz import PlayerSpaz from bascenev1lib.actor.playerspaz import PlayerSpaz
from bastd.actor.scoreboard import Scoreboard from bascenev1lib.actor.scoreboard import Scoreboard
from bastd.game.elimination import Icon, Player from bascenev1lib.game.elimination import Icon, Player
from bastd.actor.spaz import PickupMessage from bascenev1lib.actor.spaz import PickupMessage
from bastd.actor.spazbot import SpazBotSet, BrawlerBot, SpazBotDiedMessage from bascenev1lib.actor.spazbot import SpazBotSet, BrawlerBot, SpazBotDiedMessage
from bastd.actor.spazfactory import SpazFactory from bascenev1lib.actor.spazfactory import SpazFactory
if TYPE_CHECKING: if TYPE_CHECKING:
@ -26,7 +29,7 @@ if TYPE_CHECKING:
class PlayerSpaz_Zom(PlayerSpaz): class PlayerSpaz_Zom(PlayerSpaz):
def handlemessage(self, m: Any) -> Any: def handlemessage(self, m: Any) -> Any:
if isinstance(m, ba.HitMessage): if isinstance(m, bs.HitMessage):
if not self.node: if not self.node:
return return
if not m._source_player is None: if not m._source_player is None:
@ -40,7 +43,7 @@ class PlayerSpaz_Zom(PlayerSpaz):
else: else:
super().handlemessage(m) super().handlemessage(m)
elif isinstance(m, ba.FreezeMessage): elif isinstance(m, bs.FreezeMessage):
pass pass
elif isinstance(m, PickupMessage): elif isinstance(m, PickupMessage):
@ -48,10 +51,10 @@ class PlayerSpaz_Zom(PlayerSpaz):
return None return None
try: try:
collision = ba.getcollision() collision = bs.getcollision()
opposingnode = collision.opposingnode opposingnode = collision.opposingnode
opposingbody = collision.opposingbody opposingbody = collision.opposingbody
except ba.NotFoundError: except bs.NotFoundError:
return True return True
try: try:
@ -85,7 +88,7 @@ class PlayerSpaz_Zom(PlayerSpaz):
class PlayerZombie(PlayerSpaz): class PlayerZombie(PlayerSpaz):
def handlemessage(self, m: Any) -> Any: def handlemessage(self, m: Any) -> Any:
if isinstance(m, ba.HitMessage): if isinstance(m, bs.HitMessage):
if not self.node: if not self.node:
return None return None
if not m._source_player is None: if not m._source_player is None:
@ -106,8 +109,8 @@ class PlayerZombie(PlayerSpaz):
class zBotSet(SpazBotSet): class zBotSet(SpazBotSet):
def start_moving(self) -> None: def start_moving(self) -> None:
"""Start processing bot AI updates so they start doing their thing.""" """Start processing bot AI updates so they start doing their thing."""
self._bot_update_timer = ba.Timer(0.05, self._bot_update_timer = bs.Timer(0.05,
ba.WeakCall(self.zUpdate), bs.WeakCall(self.zUpdate),
repeat=True) repeat=True)
def zUpdate(self) -> None: def zUpdate(self) -> None:
@ -118,31 +121,31 @@ class zBotSet(SpazBotSet):
]) ])
except Exception: except Exception:
bot_list = [] bot_list = []
ba.print_exception('Error updating bot list: ' + babase.print_exception('Error updating bot list: ' +
str(self._bot_lists[self._bot_update_list])) str(self._bot_lists[self._bot_update_list]))
self._bot_update_list = (self._bot_update_list + self._bot_update_list = (self._bot_update_list +
1) % self._bot_list_count 1) % self._bot_list_count
player_pts = [] player_pts = []
for player in ba.getactivity().players: for player in bs.getactivity().players:
assert isinstance(player, ba.Player) assert isinstance(player, bs.Player)
try: try:
if player.is_alive(): if player.is_alive():
assert isinstance(player.actor, Spaz) assert isinstance(player.actor, Spaz)
assert player.actor.node assert player.actor.node
if player.lives > 0: if player.lives > 0:
player_pts.append( player_pts.append(
(ba.Vec3(player.actor.node.position), (babase.Vec3(player.actor.node.position),
ba.Vec3(player.actor.node.velocity))) babase.Vec3(player.actor.node.velocity)))
except Exception: except Exception:
ba.print_exception('Error on bot-set _update.') babase.print_exception('Error on bot-set _update.')
for bot in bot_list: for bot in bot_list:
bot.set_player_points(player_pts) bot.set_player_points(player_pts)
bot.update_ai() bot.update_ai()
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:
@ -150,13 +153,13 @@ 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 ZombieHorde(ba.TeamGameActivity[Player, Team]): class ZombieHorde(bs.TeamGameActivity[Player, Team]):
name = 'Zombie Horde' name = 'Zombie Horde'
description = 'Kill walkers for points!' description = 'Kill walkers for points!'
scoreconfig = ba.ScoreConfig(label='Score', scoreconfig = bs.ScoreConfig(label='Score',
scoretype=ba.ScoreType.POINTS, scoretype=bs.ScoreType.POINTS,
none_is_winner=False, none_is_winner=False,
lower_is_better=False) lower_is_better=False)
# Show messages when players die since it's meaningful here. # Show messages when players die since it's meaningful here.
@ -164,23 +167,23 @@ class ZombieHorde(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(
'Max Zombies', 'Max Zombies',
default=10, default=10,
min_value=5, min_value=5,
max_value=50, max_value=50,
increment=5, increment=5,
), ),
ba.IntChoiceSetting( bs.IntChoiceSetting(
'Time Limit', 'Time Limit',
choices=[ choices=[
('None', 0), ('None', 0),
@ -192,7 +195,7 @@ class ZombieHorde(ba.TeamGameActivity[Player, Team]):
], ],
default=0, default=0,
), ),
ba.FloatChoiceSetting( bs.FloatChoiceSetting(
'Respawn Times', 'Respawn Times',
choices=[ choices=[
('Shorter', 0.25), ('Shorter', 0.25),
@ -203,29 +206,29 @@ class ZombieHorde(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(ba.BoolSetting('Solo Mode', default=False)) settings.append(bs.BoolSetting('Solo Mode', default=False))
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)
or issubclass(sessiontype, ba.FreeForAllSession)) or issubclass(sessiontype, bs.FreeForAllSession))
@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: float | None = None self._start_time: float | None = None
self._vs_text: ba.Actor | None = None self._vs_text: bs.Actor | None = None
self._round_end_timer: ba.Timer | None = None self._round_end_timer: bs.Timer | None = 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._max_zombies = int(settings['Max Zombies']) self._max_zombies = int(settings['Max Zombies'])
@ -236,53 +239,53 @@ class ZombieHorde(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)
self.spazList = [] self.spazList = []
self.zombieQ = 0 self.zombieQ = 0
activity = ba.getactivity() activity = bs.getactivity()
my_factory = SpazFactory.get() my_factory = SpazFactory.get()
appears = ['Kronk', 'Zoe', 'Pixel', 'Agent Johnson', appears = ['Kronk', 'Zoe', 'Pixel', 'Agent Johnson',
'Bones', 'Frosty', 'Kronk2'] 'Bones', 'Frosty', 'Kronk2']
myAppear = copy.copy(ba.app.spaz_appearances['Kronk']) myAppear = copy.copy(babase.app.classic.spaz_appearances['Kronk'])
myAppear.name = 'Kronk2' myAppear.name = 'Kronk2'
ba.app.spaz_appearances['Kronk2'] = myAppear babase.app.classic.spaz_appearances['Kronk2'] = myAppear
for appear in appears: for appear in appears:
my_factory.get_media(appear) my_factory.get_media(appear)
med = my_factory.spaz_media med = my_factory.spaz_media
med['Kronk2']['head_model'] = med['Zoe']['head_model'] med['Kronk2']['head_mesh'] = med['Zoe']['head_mesh']
med['Kronk2']['color_texture'] = med['Agent Johnson']['color_texture'] med['Kronk2']['color_texture'] = med['Agent Johnson']['color_texture']
med['Kronk2']['color_mask_texture'] = med['Pixel']['color_mask_texture'] med['Kronk2']['color_mask_texture'] = med['Pixel']['color_mask_texture']
med['Kronk2']['torso_model'] = med['Bones']['torso_model'] med['Kronk2']['torso_mesh'] = med['Bones']['torso_mesh']
med['Kronk2']['pelvis_model'] = med['Pixel']['pelvis_model'] med['Kronk2']['pelvis_mesh'] = med['Pixel']['pelvis_mesh']
med['Kronk2']['upper_arm_model'] = med['Frosty']['upper_arm_model'] med['Kronk2']['upper_arm_mesh'] = med['Frosty']['upper_arm_mesh']
med['Kronk2']['forearm_model'] = med['Frosty']['forearm_model'] med['Kronk2']['forearm_mesh'] = med['Frosty']['forearm_mesh']
med['Kronk2']['hand_model'] = med['Bones']['hand_model'] med['Kronk2']['hand_mesh'] = med['Bones']['hand_mesh']
med['Kronk2']['upper_leg_model'] = med['Bones']['upper_leg_model'] med['Kronk2']['upper_leg_mesh'] = med['Bones']['upper_leg_mesh']
med['Kronk2']['lower_leg_model'] = med['Pixel']['lower_leg_model'] med['Kronk2']['lower_leg_mesh'] = med['Pixel']['lower_leg_mesh']
med['Kronk2']['toes_model'] = med['Bones']['toes_model'] med['Kronk2']['toes_mesh'] = med['Bones']['toes_mesh']
def get_instance_description(self) -> str | Sequence: def get_instance_description(self) -> str | Sequence:
return ('Kill walkers for points! ', return ('Kill walkers for points! ',
'Dead player walker: 2 points!') if isinstance( 'Dead player walker: 2 points!') if isinstance(
self.session, ba.DualTeamSession) else ( self.session, bs.DualTeamSession) else (
'Kill walkers for points! Dead player walker: 2 points!') 'Kill walkers for points! Dead player walker: 2 points!')
def get_instance_description_short(self) -> str | Sequence: def get_instance_description_short(self) -> str | Sequence:
return ('Kill walkers for points! ', return ('Kill walkers for points! ',
'Dead player walker: 2 points!') if isinstance( 'Dead player walker: 2 points!') if isinstance(
self.session, ba.DualTeamSession) else ( self.session, bs.DualTeamSession) else (
'Kill walkers for points! Dead player walker: 2 points!') 'Kill walkers for points! Dead player walker: 2 points!')
def on_player_join(self, player: Player) -> None: def on_player_join(self, player: Player) -> None:
if self.has_begun(): if self.has_begun():
player.lives = 0 player.lives = 0
player.icons = [] player.icons = []
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),
) )
@ -314,13 +317,13 @@ class ZombieHorde(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.zombieQ = 1 self.zombieQ = 1
if self._solo_mode: if self._solo_mode:
self._vs_text = ba.NodeActor( self._vs_text = bs.NodeActor(
ba.newnode('text', bs.newnode('text',
attrs={ attrs={
'position': (0, 105), 'position': (0, 105),
'h_attach': 'center', 'h_attach': 'center',
@ -331,12 +334,12 @@ class ZombieHorde(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(
@ -365,13 +368,13 @@ class ZombieHorde(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_icons(self) -> None: def _update_icons(self) -> None:
# pylint: disable=too-many-branches # pylint: disable=too-many-branches
# In free-for-all mode, everyone is just lined up along the bottom. # In free-for-all mode, everyone is just lined up along the bottom.
if isinstance(self.session, ba.FreeForAllSession): if isinstance(self.session, bs.FreeForAllSession):
count = len(self.teams) count = len(self.teams)
x_offs = 85 x_offs = 85
xval = x_offs * (count - 1) * -0.5 xval = x_offs * (count - 1) * -0.5
@ -437,7 +440,7 @@ class ZombieHorde(ba.TeamGameActivity[Player, Team]):
icon.update_for_lives() icon.update_for_lives()
xval += x_offs xval += x_offs
def _get_spawn_point(self, player: Player) -> ba.Vec3 | None: def _get_spawn_point(self, player: Player) -> babase.Vec3 | None:
del player # Unused. del player # Unused.
# In solo-mode, if there's an existing live player on the map, spawn at # In solo-mode, if there's an existing live player on the map, spawn at
@ -455,10 +458,10 @@ class ZombieHorde(ba.TeamGameActivity[Player, Team]):
break break
if living_player: if living_player:
assert living_player_pos is not None assert living_player_pos is not None
player_pos = ba.Vec3(living_player_pos) player_pos = babase.Vec3(living_player_pos)
points: list[tuple[float, ba.Vec3]] = [] points: list[tuple[float, babase.Vec3]] = []
for team in self.teams: for team in self.teams:
start_pos = ba.Vec3(self.map.get_start_position(team.id)) start_pos = babase.Vec3(self.map.get_start_position(team.id))
points.append( points.append(
((start_pos - player_pos).length(), start_pos)) ((start_pos - player_pos).length(), start_pos))
# Hmm.. we need to sorting vectors too? # Hmm.. we need to sorting vectors too?
@ -466,13 +469,13 @@ class ZombieHorde(ba.TeamGameActivity[Player, Team]):
return points[-1][1] return points[-1][1]
return None return None
def spawn_player(self, player: Player) -> ba.Actor: def spawn_player(self, player: Player) -> bs.Actor:
position = self.map.get_ffa_start_position(self.players) position = self.map.get_ffa_start_position(self.players)
angle = 20 angle = 20
name = player.getname() name = player.getname()
light_color = _math.normalized_color(player.color) light_color = _math.normalized_color(player.color)
display_color = _ba.safecolor(player.color, target_intensity=0.75) display_color = _babase.safecolor(player.color, target_intensity=0.75)
spaz = PlayerSpaz_Zom(color=player.color, spaz = PlayerSpaz_Zom(color=player.color,
highlight=player.highlight, highlight=player.highlight,
character=player.character, character=player.character,
@ -500,14 +503,14 @@ class ZombieHorde(ba.TeamGameActivity[Player, Team]):
StandMessage( StandMessage(
position, position,
angle if angle is not None else random.uniform(0, 360))) angle if angle is not None else random.uniform(0, 360)))
_ba.playsound(self._spawn_sound, 1, position=spaz.node.position) bs.Sound.play(self._spawn_sound, 1, position=spaz.node.position)
light = _ba.newnode('light', attrs={'color': light_color}) light = bs.newnode('light', attrs={'color': light_color})
spaz.node.connectattr('position', light, 'position') spaz.node.connectattr('position', light, 'position')
ba.animate(light, 'intensity', {0: 0, 0.25: 1, 0.5: 0}) bs.animate(light, 'intensity', {0: 0, 0.25: 1, 0.5: 0})
_ba.timer(0.5, light.delete) bs.timer(0.5, light.delete)
if not self._solo_mode: if not self._solo_mode:
ba.timer(0.3, ba.Call(self._print_lives, player)) bs.timer(0.3, babase.Call(self._print_lives, player))
for icon in player.icons: for icon in player.icons:
icon.handle_player_spawned() icon.handle_player_spawned()
@ -539,30 +542,30 @@ class ZombieHorde(ba.TeamGameActivity[Player, Team]):
respawn_time = round(max(1.0, respawn_time), 0) respawn_time = round(max(1.0, respawn_time), 0)
if player.actor and not self.has_ended(): if player.actor and not self.has_ended():
from bastd.actor.respawnicon import RespawnIcon from bascenev1lib.actor.respawnicon import RespawnIcon
player.customdata['respawn_timer'] = _ba.Timer( player.customdata['respawn_timer'] = bs.Timer(
respawn_time, ba.WeakCall( respawn_time, bs.WeakCall(
self.spawn_player_if_exists_as_zombie, player)) self.spawn_player_if_exists_as_zombie, player))
player.customdata['respawn_icon'] = RespawnIcon( player.customdata['respawn_icon'] = RespawnIcon(
player, respawn_time) player, respawn_time)
def spawn_player_if_exists_as_zombie(self, player: PlayerType) -> None: def spawn_player_if_exists_as_zombie(self, player: PlayerT) -> None:
""" """
A utility method which calls self.spawn_player() *only* if the A utility method which calls self.spawn_player() *only* if the
ba.Player provided still exists; handy for use in timers and whatnot. bs.Player provided still exists; handy for use in timers and whatnot.
There is no need to override this; just override spawn_player(). There is no need to override this; just override spawn_player().
""" """
if player: if player:
self.spawn_player_zombie(player) self.spawn_player_zombie(player)
def spawn_player_zombie(self, player: PlayerType) -> ba.Actor: def spawn_player_zombie(self, player: PlayerT) -> bs.Actor:
position = self.map.get_ffa_start_position(self.players) position = self.map.get_ffa_start_position(self.players)
angle = 20 angle = 20
name = player.getname() name = player.getname()
light_color = _math.normalized_color(player.color) light_color = _math.normalized_color(player.color)
display_color = _ba.safecolor(player.color, target_intensity=0.75) display_color = _babase.safecolor(player.color, target_intensity=0.75)
spaz = PlayerSpaz_Zom(color=player.color, spaz = PlayerSpaz_Zom(color=player.color,
highlight=player.highlight, highlight=player.highlight,
character='Kronk2', character='Kronk2',
@ -591,21 +594,21 @@ class ZombieHorde(ba.TeamGameActivity[Player, Team]):
StandMessage( StandMessage(
position, position,
angle if angle is not None else random.uniform(0, 360))) angle if angle is not None else random.uniform(0, 360)))
_ba.playsound(self._spawn_sound, 1, position=spaz.node.position) bs.Sound.play(self._spawn_sound, 1, position=spaz.node.position)
light = _ba.newnode('light', attrs={'color': light_color}) light = bs.newnode('light', attrs={'color': light_color})
spaz.node.connectattr('position', light, 'position') spaz.node.connectattr('position', light, 'position')
ba.animate(light, 'intensity', {0: 0, 0.25: 1, 0.5: 0}) bs.animate(light, 'intensity', {0: 0, 0.25: 1, 0.5: 0})
_ba.timer(0.5, light.delete) bs.timer(0.5, light.delete)
if not self._solo_mode: if not self._solo_mode:
ba.timer(0.3, ba.Call(self._print_lives, player)) bs.timer(0.3, babase.Call(self._print_lives, player))
for icon in player.icons: for icon in player.icons:
icon.handle_player_spawned() icon.handle_player_spawned()
return spaz return spaz
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:
@ -642,13 +645,13 @@ class ZombieHorde(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)
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)
@ -665,7 +668,7 @@ class ZombieHorde(ba.TeamGameActivity[Player, Team]):
if msg._player in self.spazList: if msg._player in self.spazList:
self.spazList.remove(msg._player) self.spazList.remove(msg._player)
if player.lives < 0: if player.lives < 0:
ba.print_error( babase.print_error(
"Got lives < 0 in Elim; this shouldn't happen. solo:" + "Got lives < 0 in Elim; this shouldn't happen. solo:" +
str(self._solo_mode)) str(self._solo_mode))
player.lives = 0 player.lives = 0
@ -677,7 +680,7 @@ class ZombieHorde(ba.TeamGameActivity[Player, Team]):
# Play big death sound on our last death # Play big death sound on our last death
# or for every one in solo mode. # or for every one in solo mode.
if self._solo_mode or player.lives == 0: if self._solo_mode or 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:
@ -732,16 +735,16 @@ class ZombieHorde(ba.TeamGameActivity[Player, Team]):
theScores) and theScores.count(max(theScores)) > 1: theScores) and theScores.count(max(theScores)) > 1:
pass pass
else: else:
self._round_end_timer = ba.Timer(0.5, self.end_game) self._round_end_timer = bs.Timer(0.5, self.end_game)
else: else:
self._round_end_timer = ba.Timer(0.5, self.end_game) self._round_end_timer = bs.Timer(0.5, self.end_game)
def spawn_zombie(self) -> None: def spawn_zombie(self) -> None:
# We need a Z height... # We need a Z height...
thePt = list(self.get_random_point_in_play()) thePt = list(self.get_random_point_in_play())
thePt2 = self.map.get_ffa_start_position(self.players) thePt2 = self.map.get_ffa_start_position(self.players)
thePt[1] = thePt2[1] thePt[1] = thePt2[1]
ba.timer(0.1, ba.Call( bs.timer(0.1, babase.Call(
self._bots.spawn_bot, BrawlerBot, pos=thePt, spawn_time=1.0)) self._bots.spawn_bot, BrawlerBot, pos=thePt, spawn_time=1.0))
def _onSpazBotDied(self, DeathMsg) -> None: def _onSpazBotDied(self, DeathMsg) -> None:
@ -816,25 +819,25 @@ class ZombieHorde(ba.TeamGameActivity[Player, Team]):
setattr(BrawlerBot, 'color', (0.6, 0.6, 0.6)) setattr(BrawlerBot, 'color', (0.6, 0.6, 0.6))
setattr(BrawlerBot, 'highlight', (0.6, 0.6, 0.6)) setattr(BrawlerBot, 'highlight', (0.6, 0.6, 0.6))
setattr(BrawlerBot, 'character', 'Kronk') setattr(BrawlerBot, 'character', 'Kronk')
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.score) results.set_team_score(team, team.score)
self.end(results=results) self.end(results=results)
# ba_meta export game # ba_meta export bascenev1.GameActivity
class ZombieHordeCoop(ZombieHorde): class ZombieHordeCoop(ZombieHorde):
name = 'Zombie Horde' name = 'Zombie Horde'
@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 ['Football Stadium'] return ['Football Stadium']
@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.CoopSession)) return (issubclass(sessiontype, bs.CoopSession))
def _update(self) -> None: def _update(self) -> None:
if self.zombieQ > 0: if self.zombieQ > 0:
@ -855,12 +858,12 @@ class ZombieHordeCoop(ZombieHorde):
break break
if not any(player.is_alive() for player in self.teams[0].players): if not any(player.is_alive() for player in self.teams[0].players):
self._round_end_timer = ba.Timer(0.5, self.end_game) self._round_end_timer = bs.Timer(0.5, self.end_game)
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.
ba.TeamGameActivity.handlemessage(self, msg) bs.TeamGameActivity.handlemessage(self, msg)
player: Player = msg.getplayer(Player) player: Player = msg.getplayer(Player)
# If we have any icons, update their state. # If we have any icons, update their state.
for icon in player.icons: for icon in player.icons:
@ -870,10 +873,10 @@ class ZombieHordeCoop(ZombieHorde):
# ba_meta export plugin # ba_meta export plugin
class ZombieHordeLevel(ba.Plugin): class ZombieHordeLevel(babase.Plugin):
def on_app_running(self) -> None: def on_app_running(self) -> None:
ba.app.add_coop_practice_level( babase.app.classic.add_coop_practice_level(
ba.Level( bs._level.Level(
'Zombie Horde', 'Zombie Horde',
gametype=ZombieHordeCoop, gametype=ZombieHordeCoop,
settings={}, settings={},

View file

@ -27,7 +27,7 @@ import _babase
import bascenev1 as bs import bascenev1 as bs
import bascenev1lib import bascenev1lib
import bauiv1 as bui import bauiv1 as bui
from baenv import TARGET_BALLISTICA_BUILD from baenv import TARGET_BALLISTICA_BUILD as build_number
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
@ -37,8 +37,8 @@ if TYPE_CHECKING:
ANDROID = babase.app.classic.platform == "android" ANDROID = babase.app.classic.platform == "android"
DIRPATH = Path( DIRPATH = Path(
f"{_babase.app.python_directory_user if TARGET_BALLISTICA_BUILD < 21282 else _babase.app.env.python_directory_user}/image_id.json") f"{_babase.app.python_directory_user if build_number < 21282 else _babase.app.env.python_directory_user}/image_id.json")
APP_VERSION = _babase.app.version if TARGET_BALLISTICA_BUILD < 21282 else _babase.app.env.version APP_VERSION = _babase.app.version if build_number < 21282 else _babase.app.env.version
if ANDROID: # !can add ios in future if ANDROID: # !can add ios in future

View file

@ -98,7 +98,7 @@ class RagdollBGone(babase.Plugin):
# Pick a random death noise # Pick a random death noise
sound = death_sounds[random.randrange(len(death_sounds))] sound = death_sounds[random.randrange(len(death_sounds))]
# Play the sound where our Spaz is # Play the sound where our Spaz is
sound.play(position=args[0].node.position) bs.Sound.play(sound, position=args[0].node.position)
# Delete our Spaz node immediately. # Delete our Spaz node immediately.
# Removing stuff is weird and prone to errors, so we're gonna delay it. # Removing stuff is weird and prone to errors, so we're gonna delay it.
bs.timer(0.001, args[0].node.delete) bs.timer(0.001, args[0].node.delete)