Moved shared-objects to bastd

This commit is contained in:
Eric Froemling 2020-05-29 13:59:10 -07:00
parent a44821e03e
commit 4e15d72e4f
34 changed files with 724 additions and 548 deletions

View File

@ -4132,16 +4132,16 @@
"assets/build/windows/x64/python.exe": "https://files.ballistica.net/cache/ba1/25/a7/dc87c1be41605eb6fefd0145144c", "assets/build/windows/x64/python.exe": "https://files.ballistica.net/cache/ba1/25/a7/dc87c1be41605eb6fefd0145144c",
"assets/build/windows/x64/python37.dll": "https://files.ballistica.net/cache/ba1/b9/e4/d912f56e42e9991bcbb4c804cfcb", "assets/build/windows/x64/python37.dll": "https://files.ballistica.net/cache/ba1/b9/e4/d912f56e42e9991bcbb4c804cfcb",
"assets/build/windows/x64/pythonw.exe": "https://files.ballistica.net/cache/ba1/6c/bb/b6f52c306aa4e88061510e96cefe", "assets/build/windows/x64/pythonw.exe": "https://files.ballistica.net/cache/ba1/6c/bb/b6f52c306aa4e88061510e96cefe",
"build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/d9/29/c569224bc159225daed5cabdd517", "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/8d/c2/9fd3ab19a28b05160f818f787115",
"build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/b5/52/a015232b381b5a361e26cc4e33d6", "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/67/25/34c42457f20c9d87d538f4f69320",
"build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/b5/31/c229f5293e5ec5b3b8feb9308216", "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/d9/3d/39326060f1a1df1b18070d75ade8",
"build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/3e/8c/2b05b2168897862e0eefc0d5ddaa", "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/9f/b7/d63ab7e13f1b9d931b83ef652262",
"build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/a6/e5/923be95c40b9e7432f941bb98f79", "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/39/45/f4d0bbe6dfa0286b1faaad5d4c0e",
"build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/f5/3e/f929b7330662fc64f91e9613d6b3", "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/a8/2b/251dcadd37ae0d2c08a0f3bb683d",
"build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/e9/3a/25571131b13d74f19150e8fdf786", "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/3a/1a/b80f37d9802d40e625b2df3696b1",
"build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/4f/b3/9627d8ee06297e66f7238fbc4838", "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/46/fd/6400f9eba88a419487f5d3732e54",
"build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/fe/45/5646002baebd720592914c7f1c5b", "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/7d/6a/3dc3c77c340471c0a7b79bf077a4",
"build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/f3/ee/10a2c2eaf9783c9abd81141ee5e8", "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/97/5d/824c5c71f61d871c904c61fabc56",
"build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/8e/7b/e121ed5e35abf9cce71415fdecac", "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/91/92/1f309a3edf4b4aa595ea83472e7a",
"build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/16/d7/b53476ad786d0b1636fcf1906578" "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/d5/3c/fefdeed4e8048332724167fe1442"
} }

View File

@ -186,6 +186,7 @@
<w>bname</w> <w>bname</w>
<w>bndl</w> <w>bndl</w>
<w>boffs</w> <w>boffs</w>
<w>bombfactory</w>
<w>bombsquad</w> <w>bombsquad</w>
<w>bombsquadcb</w> <w>bombsquadcb</w>
<w>bombsquadgame</w> <w>bombsquadgame</w>
@ -1637,6 +1638,7 @@
<w>sessionclass</w> <w>sessionclass</w>
<w>sessiondata</w> <w>sessiondata</w>
<w>sessionglobals</w> <w>sessionglobals</w>
<w>sessionglobalsnode</w>
<w>sessionname</w> <w>sessionname</w>
<w>sessionplayer</w> <w>sessionplayer</w>
<w>sessionteam</w> <w>sessionteam</w>
@ -1655,6 +1657,7 @@
<w>sharedobjs</w> <w>sharedobjs</w>
<w>shiftdelay</w> <w>shiftdelay</w>
<w>shiftposition</w> <w>shiftposition</w>
<w>shobs</w>
<w>shortname</w> <w>shortname</w>
<w>shouldn</w> <w>shouldn</w>
<w>showpoints</w> <w>showpoints</w>

View File

@ -34,7 +34,7 @@ NOTE: This file was autogenerated by gendummymodule; do not edit by hand.
""" """
# (hash we can use to see if this file is out of date) # (hash we can use to see if this file is out of date)
# SOURCES_HASH=237466057120267570582079835997969754357 # SOURCES_HASH=214732868903831008614942145147141302125
# I'm sorry Pylint. I know this file saddens you. Be strong. # I'm sorry Pylint. I know this file saddens you. Be strong.
# pylint: disable=useless-suppression # pylint: disable=useless-suppression
@ -527,7 +527,7 @@ class Material:
# example 3: play some sounds when we're contacting the ground: # example 3: play some sounds when we're contacting the ground:
m = ba.Material() m = ba.Material()
m.add_actions(conditions=('they_have_material', m.add_actions(conditions=('they_have_material',
ba.sharedobj('footing_material')), shared.footing_material),
actions=(('impact_sound', ba.getsound('metalHit'), 2, 5), actions=(('impact_sound', ba.getsound('metalHit'), 2, 5),
('skid_sound', ba.getsound('metalSkid'), 2, 5))) ('skid_sound', ba.getsound('metalSkid'), 2, 5)))
@ -635,6 +635,10 @@ class Node:
move_left_right: float = 0.0 move_left_right: float = 0.0
curse_death_time: int = 0 curse_death_time: int = 0
boxing_gloves: bool = False boxing_gloves: bool = False
use_fixed_vr_overlay: bool = False
allow_kick_idle_players: bool = False
music_continuous: bool = False
music_count: int = 0
hurt: float = 0.0 hurt: float = 0.0
always_show_health_bar: bool = False always_show_health_bar: bool = False
mini_billboard_1_texture: Optional[ba.Texture] = None mini_billboard_1_texture: Optional[ba.Texture] = None
@ -648,7 +652,20 @@ class Node:
mini_billboard_3_end_time: int = 0 mini_billboard_3_end_time: int = 0
boxing_gloves_flashing: bool = False boxing_gloves_flashing: bool = False
dead: bool = False dead: bool = False
floor_reflection: bool = False
debris_friction: float = 0.0
debris_kill_height: float = 0.0
vr_near_clip: float = 0.0
shadow_ortho: bool = False
happy_thoughts_mode: bool = False
shadow_offset: Sequence[float] = (0.0, 0.0)
paused: bool = False
time: int = 0
ambient_color: Sequence[float] = (1.0, 1.0, 1.0)
camera_mode: str = 'rotate'
frozen: bool = False frozen: bool = False
area_of_interest_bounds: Sequence[float] = (-1, -1, -1, 1, 1, 1)
shadow_range: Sequence[float] = (0, 0, 0, 0)
counter_text: str = '' counter_text: str = ''
counter_texture: Optional[ba.Texture] = None counter_texture: Optional[ba.Texture] = None
shattered: int = 0 shattered: int = 0

View File

@ -39,7 +39,8 @@ from _ba import (CollideModel, Context, ContextCall, Data, InputDevice,
open_url, widget) open_url, widget)
from ba._activity import Activity from ba._activity import Activity
from ba._actor import Actor from ba._actor import Actor
from ba._player import PlayerInfo, Player, playercast, playercast_o from ba._player import (PlayerInfo, Player, playercast, playercast_o,
StandLocation)
from ba._nodeactor import NodeActor from ba._nodeactor import NodeActor
from ba._app import App from ba._app import App
from ba._coopgame import CoopGameActivity from ba._coopgame import CoopGameActivity
@ -71,7 +72,7 @@ from ba._appdelegate import AppDelegate
from ba._apputils import is_browser_likely_available from ba._apputils import is_browser_likely_available
from ba._campaign import Campaign from ba._campaign import Campaign
from ba._gameutils import (animate, animate_array, show_damage_count, from ba._gameutils import (animate, animate_array, show_damage_count,
sharedobj, timestring, cameraflash) timestring, cameraflash)
from ba._general import (WeakCall, Call, existing, Existable, from ba._general import (WeakCall, Call, existing, Existable,
verify_object_death) verify_object_death)
from ba._level import Level from ba._level import Level

View File

@ -26,7 +26,8 @@ from typing import TYPE_CHECKING, Generic, TypeVar
from ba._team import Team from ba._team import Team
from ba._player import Player from ba._player import Player
from ba._error import print_exception, print_error, SessionTeamNotFoundError from ba._error import (print_exception, SessionTeamNotFoundError,
NodeNotFoundError)
from ba._dependency import DependencyComponent from ba._dependency import DependencyComponent
from ba._general import Call, verify_object_death from ba._general import Call, verify_object_death
from ba._messages import UNHANDLED from ba._messages import UNHANDLED
@ -155,6 +156,11 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]):
# Create our internal engine data. # Create our internal engine data.
self._activity_data = _ba.register_activity(self) self._activity_data = _ba.register_activity(self)
assert isinstance(settings, dict)
assert _ba.getactivity() is self
self._globalsnode: Optional[ba.Node] = None
# Player/Team types should have been specified as type args; # Player/Team types should have been specified as type args;
# grab those. # grab those.
self._playertype: Type[PlayerType] self._playertype: Type[PlayerType]
@ -174,11 +180,6 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]):
# Preloaded data for actors, maps, etc; indexed by type. # Preloaded data for actors, maps, etc; indexed by type.
self.preloads: Dict[Type, Any] = {} self.preloads: Dict[Type, Any] = {}
if not isinstance(settings, dict):
raise TypeError('expected dict for settings')
if _ba.getactivity(doraise=False) is not self:
raise Exception('invalid context state')
# Hopefully can eventually kill this; activities should # Hopefully can eventually kill this; activities should
# validate/store whatever settings they need at init time # validate/store whatever settings they need at init time
# (in a more type-safe way). # (in a more type-safe way).
@ -191,9 +192,6 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]):
self._should_end_immediately_results: ( self._should_end_immediately_results: (
Optional[ba.TeamGameResults]) = None Optional[ba.TeamGameResults]) = None
self._should_end_immediately_delay = 0.0 self._should_end_immediately_delay = 0.0
self._called_activity_on_transition_in = False
self._called_activity_on_begin = False
self._activity_death_check_timer: Optional[ba.Timer] = None self._activity_death_check_timer: Optional[ba.Timer] = None
self._expired = False self._expired = False
@ -234,6 +232,16 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]):
Call(session.transitioning_out_activity_was_freed, Call(session.transitioning_out_activity_was_freed,
self.can_show_ad_on_death)) self.can_show_ad_on_death))
@property
def globalsnode(self) -> ba.Node:
"""The 'globals' ba.Node for the activity. This contains various
global controls and values.
"""
node = self._globalsnode
if not node:
raise NodeNotFoundError()
return node
@property @property
def stats(self) -> ba.Stats: def stats(self) -> ba.Stats:
"""The stats instance accessible while the activity is running. """The stats instance accessible while the activity is running.
@ -334,12 +342,11 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]):
from ba import _actor as bsactor from ba import _actor as bsactor
if not isinstance(actor, bsactor.Actor): if not isinstance(actor, bsactor.Actor):
raise TypeError('non-actor passed to retain_actor') raise TypeError('non-actor passed to retain_actor')
if (self.has_transitioned_in()
and _ba.time() - self._last_prune_dead_actors_time > 10.0): # Make sure our pruning is happening...
print_error('It looks like nodes/actors are not' assert (not self.has_transitioned_in()
' being pruned in your activity;' or _ba.time() - self._last_prune_dead_actors_time < 10.0)
' did you call Activity.on_transition_in()'
' from your subclass?; ' + str(self) + ' (loc. a)')
self._actor_refs.append(actor) self._actor_refs.append(actor)
def add_actor_weak_ref(self, actor: ba.Actor) -> None: def add_actor_weak_ref(self, actor: ba.Actor) -> None:
@ -350,12 +357,11 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]):
from ba import _actor as bsactor from ba import _actor as bsactor
if not isinstance(actor, bsactor.Actor): if not isinstance(actor, bsactor.Actor):
raise TypeError('non-actor passed to add_actor_weak_ref') raise TypeError('non-actor passed to add_actor_weak_ref')
if (self.has_transitioned_in()
and _ba.time() - self._last_prune_dead_actors_time > 10.0): # Make sure our pruning is happening...
print_error('It looks like nodes/actors are ' assert (not self.has_transitioned_in()
'not being pruned in your activity;' or _ba.time() - self._last_prune_dead_actors_time < 10.0)
' did you call Activity.on_transition_in()'
' from your subclass?; ' + str(self) + ' (loc. b)')
self._actor_weak_refs.append(weakref.ref(actor)) self._actor_weak_refs.append(weakref.ref(actor))
@property @property
@ -396,7 +402,6 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]):
or teams, however. They remain owned by the previous Activity or teams, however. They remain owned by the previous Activity
up until ba.Activity.on_begin() is called. up until ba.Activity.on_begin() is called.
""" """
self._called_activity_on_transition_in = True
def on_transition_out(self) -> None: def on_transition_out(self) -> None:
"""Called when your activity begins transitioning out. """Called when your activity begins transitioning out.
@ -411,28 +416,12 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]):
At this point the activity's initial players and teams are filled in At this point the activity's initial players and teams are filled in
and it should begin its actual game logic. and it should begin its actual game logic.
""" """
self._called_activity_on_begin = True
def handlemessage(self, msg: Any) -> Any: def handlemessage(self, msg: Any) -> Any:
"""General message handling; can be passed any message object.""" """General message handling; can be passed any message object."""
del msg # Unused arg. del msg # Unused arg.
return UNHANDLED return UNHANDLED
def end(self,
results: Any = None,
delay: float = 0.0,
force: bool = False) -> None:
"""Commences Activity shutdown and delivers results to the ba.Session.
'delay' is the time delay before the Activity actually ends
(in seconds). Further calls to end() will be ignored up until
this time, unless 'force' is True, in which case the new results
will replace the old.
"""
# Ask the session to end us.
self.session.end_activity(self, results, delay, force)
def has_transitioned_in(self) -> bool: def has_transitioned_in(self) -> bool:
"""Return whether on_transition_in() has been called.""" """Return whether on_transition_in() has been called."""
return self._has_transitioned_in return self._has_transitioned_in
@ -455,15 +444,15 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]):
(internal) (internal)
""" """
from ba._general import WeakCall from ba._general import WeakCall
from ba._gameutils import sharedobj
assert not self._has_transitioned_in assert not self._has_transitioned_in
self._has_transitioned_in = True self._has_transitioned_in = True
# Set up the globals node based on our settings. # Set up the globals node based on our settings.
with _ba.Context(self): with _ba.Context(self):
glb = self._globalsnode = _ba.newnode('globals')
# Now that it's going to be front and center, # Now that it's going to be front and center,
# set some global values based on what the activity wants. # set some global values based on what the activity wants.
glb = sharedobj('globals')
glb.use_fixed_vr_overlay = self.use_fixed_vr_overlay glb.use_fixed_vr_overlay = self.use_fixed_vr_overlay
glb.allow_kick_idle_players = self.allow_kick_idle_players glb.allow_kick_idle_players = self.allow_kick_idle_players
if self.inherits_slow_motion and prev_globals is not None: if self.inherits_slow_motion and prev_globals is not None:
@ -498,7 +487,7 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]):
try: try:
self.on_transition_in() self.on_transition_in()
except Exception: except Exception:
print_exception('Error in on_transition_in for', self) print_exception(f'Error in on_transition_in for {self}')
# Tell the C++ layer that this activity is the main one, so it uses # Tell the C++ layer that this activity is the main one, so it uses
# settings from our globals, directs various events to us, etc. # settings from our globals, directs various events to us, etc.
@ -538,8 +527,6 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]):
self._has_begun = True self._has_begun = True
self.on_begin() self.on_begin()
self._sanity_check_begin_call()
# If the whole session wants to die and was waiting on us, # If the whole session wants to die and was waiting on us,
# can kick off that process now. # can kick off that process now.
if session.wants_to_end: if session.wants_to_end:
@ -550,6 +537,21 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]):
self.end(self._should_end_immediately_results, self.end(self._should_end_immediately_results,
self._should_end_immediately_delay) self._should_end_immediately_delay)
def end(self,
results: Any = None,
delay: float = 0.0,
force: bool = False) -> None:
"""Commences Activity shutdown and delivers results to the ba.Session.
'delay' is the time delay before the Activity actually ends
(in seconds). Further calls to end() will be ignored up until
this time, unless 'force' is True, in which case the new results
will replace the old.
"""
# Ask the session to end us.
self.session.end_activity(self, results, delay, force)
def create_player(self, sessionplayer: ba.SessionPlayer) -> PlayerType: def create_player(self, sessionplayer: ba.SessionPlayer) -> PlayerType:
"""Create the Player instance for this Activity. """Create the Player instance for this Activity.
@ -559,7 +561,7 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]):
point as it is not yet fully wired up; wait for on_player_join() point as it is not yet fully wired up; wait for on_player_join()
for that. for that.
""" """
del sessionplayer # Unused del sessionplayer # Unused.
player = self._playertype() player = self._playertype()
return player return player
@ -686,19 +688,6 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]):
sessionteam.gameteam = None sessionteam.gameteam = None
def _sanity_check_begin_call(self) -> None:
# Make sure ba.Activity.on_transition_in() got called at some point.
if not self._called_activity_on_transition_in:
print_error(
'ba.Activity.on_transition_in() never got called for ' +
str(self) + '; did you forget to call it'
' in your on_transition_in override?')
# Make sure that ba.Activity.on_begin() got called at some point.
if not self._called_activity_on_begin:
print_error(
'ba.Activity.on_begin() never got called for ' + str(self) +
'; did you forget to call it in your on_begin override?')
def _setup_player_and_team_types(self) -> None: def _setup_player_and_team_types(self) -> None:
"""Pull player and team types from our typing.Generic params.""" """Pull player and team types from our typing.Generic params."""
@ -819,7 +808,7 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]):
# It is expected that Team objects may last longer than # It is expected that Team objects may last longer than
# the SessionTeam they came from (game objects may hold # the SessionTeam they came from (game objects may hold
# team references past the point at which the underlying # team references past the point at which the underlying
# player/team leaves) # player/team has left the game)
pass pass
except Exception: except Exception:
print_exception(f'Error resetting Team {team}') print_exception(f'Error resetting Team {team}')

View File

@ -623,7 +623,7 @@ class App:
# FIXME: Shouldn't be touching scene stuff here; # FIXME: Shouldn't be touching scene stuff here;
# should just pass the request on to the host-session. # should just pass the request on to the host-session.
with _ba.Context(activity): with _ba.Context(activity):
globs = _gameutils.sharedobj('globals') globs = activity.globalsnode
if not globs.paused: if not globs.paused:
_ba.playsound(_ba.getsound('refWhistle')) _ba.playsound(_ba.getsound('refWhistle'))
globs.paused = True globs.paused = True
@ -645,14 +645,13 @@ class App:
If there's a foreground host-activity that's currently paused, tell it If there's a foreground host-activity that's currently paused, tell it
to resume. to resume.
""" """
from ba._gameutils import sharedobj
# FIXME: Shouldn't be touching scene stuff here; # FIXME: Shouldn't be touching scene stuff here;
# should just pass the request on to the host-session. # should just pass the request on to the host-session.
activity = _ba.get_foreground_host_activity() activity = _ba.get_foreground_host_activity()
if activity is not None: if activity is not None:
with _ba.Context(activity): with _ba.Context(activity):
globs = sharedobj('globals') globs = activity.globalsnode
if globs.paused: if globs.paused:
_ba.playsound(_ba.getsound('refWhistle')) _ba.playsound(_ba.getsound('refWhistle'))
globs.paused = False globs.paused = False

View File

@ -249,7 +249,7 @@ class CoopGameActivity(GameActivity[PlayerType, TeamType]):
def fade_to_red(self) -> None: def fade_to_red(self) -> None:
"""Fade the screen to red; (such as when the good guys have lost).""" """Fade the screen to red; (such as when the good guys have lost)."""
from ba import _gameutils from ba import _gameutils
c_existing = _gameutils.sharedobj('globals').tint c_existing = self.globalsnode.tint
cnode = _ba.newnode('combine', cnode = _ba.newnode('combine',
attrs={ attrs={
'input0': c_existing[0], 'input0': c_existing[0],
@ -259,7 +259,7 @@ class CoopGameActivity(GameActivity[PlayerType, TeamType]):
}) })
_gameutils.animate(cnode, 'input1', {0: c_existing[1], 2.0: 0}) _gameutils.animate(cnode, 'input1', {0: c_existing[1], 2.0: 0})
_gameutils.animate(cnode, 'input2', {0: c_existing[2], 2.0: 0}) _gameutils.animate(cnode, 'input2', {0: c_existing[2], 2.0: 0})
cnode.connectattr('output', _gameutils.sharedobj('globals'), 'tint') cnode.connectattr('output', self.globalsnode, 'tint')
def setup_low_life_warning_sound(self) -> None: def setup_low_life_warning_sound(self) -> None:
"""Set up a beeping noise to play when any players are near death.""" """Set up a beeping noise to play when any players are near death."""

View File

@ -403,6 +403,7 @@ class GameActivity(Activity[PlayerType, TeamType]):
return '' return ''
def on_transition_in(self) -> None: def on_transition_in(self) -> None:
super().on_transition_in() super().on_transition_in()
# Make our map. # Make our map.
@ -455,7 +456,6 @@ class GameActivity(Activity[PlayerType, TeamType]):
# pylint: disable=too-many-nested-blocks # pylint: disable=too-many-nested-blocks
# pylint: disable=cyclic-import # pylint: disable=cyclic-import
from bastd.ui.continues import ContinuesWindow from bastd.ui.continues import ContinuesWindow
from ba._gameutils import sharedobj
from ba._coopsession import CoopSession from ba._coopsession import CoopSession
from ba._enums import TimeType from ba._enums import TimeType
@ -472,7 +472,7 @@ class GameActivity(Activity[PlayerType, TeamType]):
if isinstance(session, CoopSession): if isinstance(session, CoopSession):
assert session.campaign is not None assert session.campaign is not None
if session.campaign.sequential: if session.campaign.sequential:
gnode = sharedobj('globals') gnode = self.globalsnode
# Only attempt this if we're not currently paused # Only attempt this if we're not currently paused
# and there appears to be no UI. # and there appears to be no UI.
@ -1024,7 +1024,6 @@ class GameActivity(Activity[PlayerType, TeamType]):
This will be displayed at the top of the screen. This will be displayed at the top of the screen.
If the time-limit expires, end_game() will be called. If the time-limit expires, end_game() will be called.
""" """
from ba._gameutils import sharedobj
from ba._nodeactor import NodeActor from ba._nodeactor import NodeActor
if duration <= 0.0: if duration <= 0.0:
return return
@ -1048,8 +1047,9 @@ class GameActivity(Activity[PlayerType, TeamType]):
'time2': duration * 1000, 'time2': duration * 1000,
'timemin': 0 'timemin': 0
})) }))
sharedobj('globals').connectattr( self.globalsnode.connectattr('time',
'time', self._standard_time_limit_text_input.node, 'time1') self._standard_time_limit_text_input.node,
'time1')
assert self._standard_time_limit_text_input.node assert self._standard_time_limit_text_input.node
assert self._standard_time_limit_text.node assert self._standard_time_limit_text.node
self._standard_time_limit_text_input.node.connectattr( self._standard_time_limit_text_input.node.connectattr(

View File

@ -23,10 +23,10 @@
from __future__ import annotations from __future__ import annotations
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
# from typing_extensions import Protocol
import _ba import _ba
from ba._enums import TimeType, TimeFormat, SpecialChar from ba._enums import TimeType, TimeFormat, SpecialChar
from ba._error import ActivityNotFoundError
if TYPE_CHECKING: if TYPE_CHECKING:
from typing import Any, Dict, Sequence, Optional from typing import Any, Dict, Sequence, Optional
@ -41,15 +41,6 @@ TROPHY_CHARS = {
'4': SpecialChar.TROPHY4 '4': SpecialChar.TROPHY4
} }
# class Respawnable(Protocol):
# """A Protocol for objects able to be respawned.
# Category: Protocols
# """
# respawn_timer: Optional[ba.Timer]
# respawn_icon: Optional[RespawnIcon]
def get_trophy_string(trophy_id: str) -> str: def get_trophy_string(trophy_id: str) -> str:
"""Given a trophy id, returns a string to visualize it.""" """Given a trophy id, returns a string to visualize it."""
@ -58,125 +49,6 @@ def get_trophy_string(trophy_id: str) -> str:
return '?' return '?'
def sharedobj(name: str) -> Any:
"""Return a predefined object for the current Activity, creating if needed.
Category: Gameplay Functions
Available values for 'name':
'globals': returns the 'globals' ba.Node, containing various global
controls & values.
'object_material': a ba.Material that should be applied to any small,
normal, physical objects such as bombs, boxes, players, etc. Other
materials often check for the presence of this material as a
prerequisite for performing certain actions (such as disabling collisions
between initially-overlapping objects)
'player_material': a ba.Material to be applied to player parts. Generally,
materials related to the process of scoring when reaching a goal, etc
will look for the presence of this material on things that hit them.
'pickup_material': a ba.Material; collision shapes used for picking things
up will have this material applied. To prevent an object from being
picked up, you can add a material that disables collisions against things
containing this material.
'footing_material': anything that can be 'walked on' should have this
ba.Material applied; generally just terrain and whatnot. A character will
snap upright whenever touching something with this material so it should
not be applied to props, etc.
'attack_material': a ba.Material applied to explosion shapes, punch
shapes, etc. An object not wanting to receive impulse/etc messages can
disable collisions against this material.
'death_material': a ba.Material that sends a ba.DieMessage() to anything
that touches it; handy for terrain below a cliff, etc.
'region_material': a ba.Material used for non-physical collision shapes
(regions); collisions can generally be allowed with this material even
when initially overlapping since it is not physical.
'railing_material': a ba.Material with a very low friction/stiffness/etc
that can be applied to invisible 'railings' useful for gently keeping
characters from falling off of cliffs.
"""
# pylint: disable=too-many-branches
from ba._messages import DieMessage
# We store these on the current context; whether its an activity or
# session.
activity = _ba.getactivity(doraise=False)
if activity is not None:
# Grab shared-objs dict.
sharedobjs = getattr(activity, 'sharedobjs', None)
# Grab item out of it.
try:
return sharedobjs[name] # (pylint bug?) pylint: disable=E1136
except KeyError:
pass
obj: Any
# Hmm looks like it doesn't yet exist; create it if its a valid value.
if name == 'globals':
node_obj = _ba.newnode('globals')
obj = node_obj
elif name in [
'object_material', 'player_material', 'pickup_material',
'footing_material', 'attack_material'
]:
obj = _ba.Material()
elif name == 'death_material':
mat = obj = _ba.Material()
mat.add_actions(
('message', 'their_node', 'at_connect', DieMessage()))
elif name == 'region_material':
obj = _ba.Material()
elif name == 'railing_material':
mat = obj = _ba.Material()
mat.add_actions(('modify_part_collision', 'collide', False))
mat.add_actions(('modify_part_collision', 'stiffness', 0.003))
mat.add_actions(('modify_part_collision', 'damping', 0.00001))
mat.add_actions(conditions=('they_have_material',
sharedobj('player_material')),
actions=(('modify_part_collision', 'collide',
True), ('modify_part_collision',
'friction', 0.0)))
else:
raise ValueError(
"unrecognized shared object (activity context): '" + name +
"'")
else:
session = _ba.getsession(doraise=False)
if session is not None:
# Grab shared-objs dict (creating if necessary).
sharedobjs = session.sharedobjs
# Grab item out of it.
obj = sharedobjs.get(name)
if obj is not None:
return obj
# Hmm looks like it doesn't yet exist; create if its a valid value.
if name == 'globals':
obj = _ba.newnode('sessionglobals')
else:
raise ValueError('unrecognized shared object '
"(session context): '" + name + "'")
else:
raise RuntimeError('no current activity or session context')
# Ok, got a shiny new shared obj; store it for quick access next time.
sharedobjs[name] = obj
return obj
def animate(node: ba.Node, def animate(node: ba.Node,
attr: str, attr: str,
keys: Dict[float, float], keys: Dict[float, float],
@ -238,7 +110,14 @@ def animate(node: ba.Node,
# Do the connects last so all our attrs are in place when we push initial # Do the connects last so all our attrs are in place when we push initial
# values through. # values through.
sharedobj('globals').connectattr(driver, curve, 'in')
# We operate in either activities or sessions..
try:
globalsnode = _ba.getactivity().globalsnode
except ActivityNotFoundError:
globalsnode = _ba.getsession().sessionglobalsnode
globalsnode.connectattr(driver, curve, 'in')
curve.connectattr('out', node, attr) curve.connectattr('out', node, attr)
return curve return curve
@ -282,12 +161,18 @@ def animate_array(node: ba.Node,
else: else:
raise ValueError('invalid timeformat value: "' + str(timeformat) + '"') raise ValueError('invalid timeformat value: "' + str(timeformat) + '"')
# We operate in either activities or sessions..
try:
globalsnode = _ba.getactivity().globalsnode
except ActivityNotFoundError:
globalsnode = _ba.getsession().sessionglobalsnode
for i in range(size): for i in range(size):
curve = _ba.newnode('animcurve', curve = _ba.newnode('animcurve',
owner=node, owner=node,
name=('Driving ' + str(node) + ' \'' + attr + name=('Driving ' + str(node) + ' \'' + attr +
'\' member ' + str(i))) '\' member ' + str(i)))
sharedobj('globals').connectattr(driver, curve, 'in') globalsnode.connectattr(driver, curve, 'in')
curve.times = [int(mult * time) for time, val in items] curve.times = [int(mult * time) for time, val in items]
curve.values = [val[i] for time, val in items] curve.values = [val[i] for time, val in items]
curve.offset = _ba.time(timeformat=TimeFormat.MILLISECONDS) + int( curve.offset = _ba.time(timeformat=TimeFormat.MILLISECONDS) + int(

View File

@ -226,7 +226,7 @@ class Map(Actor):
' staticmethod in the activity constructor') ' staticmethod in the activity constructor')
# Set various globals. # Set various globals.
gnode = _gameutils.sharedobj('globals') gnode = _ba.getactivity().globalsnode
# Set area-of-interest bounds. # Set area-of-interest bounds.
aoi_bounds = self.get_def_bound_box('area_of_interest_bounds') aoi_bounds = self.get_def_bound_box('area_of_interest_bounds')

View File

@ -506,7 +506,7 @@ def setmusic(musictype: Optional[MusicType], continuous: bool = False) -> None:
# the do_play_music call in our music controller. This way we can # the do_play_music call in our music controller. This way we can
# seamlessly support custom soundtracks in replays/etc since we're being # seamlessly support custom soundtracks in replays/etc since we're being
# driven purely by node data. # driven purely by node data.
gnode = _gameutils.sharedobj('globals') gnode = _ba.getactivity().globalsnode
gnode.music_continuous = continuous gnode.music_continuous = continuous
gnode.music = '' if musictype is None else musictype.value gnode.music = '' if musictype is None else musictype.value
gnode.music_count += 1 gnode.music_count += 1

View File

@ -46,6 +46,16 @@ class PlayerInfo:
character: str character: str
@dataclass
class StandLocation:
"""Describes a point in space and an angle to face.
Category: Gameplay Classes
"""
position: _ba.Vec3
angle: Optional[float] = None
class Player(Generic[TeamType]): class Player(Generic[TeamType]):
"""A player in a specific ba.Activity. """A player in a specific ba.Activity.

View File

@ -25,7 +25,7 @@ import weakref
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
import _ba import _ba
from ba._error import print_error, print_exception from ba._error import print_error, print_exception, NodeNotFoundError
from ba._lang import Lstr from ba._lang import Lstr
from ba._player import Player from ba._player import Player
@ -113,7 +113,6 @@ class Session:
# pylint: disable=cyclic-import # pylint: disable=cyclic-import
from ba._lobby import Lobby from ba._lobby import Lobby
from ba._stats import Stats from ba._stats import Stats
from ba._gameutils import sharedobj
from ba._gameactivity import GameActivity from ba._gameactivity import GameActivity
from ba._activity import Activity from ba._activity import Activity
from ba._team import SessionTeam from ba._team import SessionTeam
@ -201,7 +200,15 @@ class Session:
self.stats = Stats() self.stats = Stats()
# Instantiate our session globals node which will apply its settings. # Instantiate our session globals node which will apply its settings.
sharedobj('globals') self._sessionglobalsnode = _ba.newnode('sessionglobals')
@property
def sessionglobalsnode(self) -> ba.Node:
"""The sessionglobals ba.Node for the session."""
node = self._sessionglobalsnode
if not node:
raise NodeNotFoundError()
return node
def on_player_request(self, player: ba.SessionPlayer) -> bool: def on_player_request(self, player: ba.SessionPlayer) -> bool:
"""Called when a new ba.Player wants to join the Session. """Called when a new ba.Player wants to join the Session.
@ -347,16 +354,6 @@ class Session:
def on_team_leave(self, team: ba.SessionTeam) -> None: def on_team_leave(self, team: ba.SessionTeam) -> None:
"""Called when a ba.Team is leaving the session.""" """Called when a ba.Team is leaving the session."""
def _complete_end_activity(self, activity: ba.Activity,
results: Any) -> None:
# Run the subclass callback in the session context.
try:
with _ba.Context(self):
self.on_activity_end(activity, results)
except Exception:
print_exception('exception in on_activity_end() for session', self,
'activity', activity, 'with results', results)
def end_activity(self, activity: ba.Activity, results: Any, delay: float, def end_activity(self, activity: ba.Activity, results: Any, delay: float,
force: bool) -> None: force: bool) -> None:
"""Commence shutdown of a ba.Activity (if not already occurring). """Commence shutdown of a ba.Activity (if not already occurring).
@ -414,7 +411,6 @@ class Session:
(on_transition_in, etc) to get it. (so you can't do (on_transition_in, etc) to get it. (so you can't do
session.set_activity(foo) and then ba.newnode() to add a node to foo) session.set_activity(foo) and then ba.newnode() to add a node to foo)
""" """
from ba._gameutils import sharedobj
from ba._enums import TimeType from ba._enums import TimeType
# Sanity test: make sure this doesn't get called recursively. # Sanity test: make sure this doesn't get called recursively.
@ -439,11 +435,8 @@ class Session:
str(self._next_activity) + ')') str(self._next_activity) + ')')
prev_activity = self._activity_retained prev_activity = self._activity_retained
if prev_activity is not None: prev_globals = (prev_activity.globalsnode
with _ba.Context(prev_activity): if prev_activity is not None else None)
prev_globals = sharedobj('globals')
else:
prev_globals = None
# Let the activity do its thing. # Let the activity do its thing.
activity.transition_in(prev_globals) activity.transition_in(prev_globals)
@ -491,6 +484,16 @@ class Session:
""" """
return [] return []
def _complete_end_activity(self, activity: ba.Activity,
results: Any) -> None:
# Run the subclass callback in the session context.
try:
with _ba.Context(self):
self.on_activity_end(activity, results)
except Exception:
print_exception('exception in on_activity_end() for session', self,
'activity', activity, 'with results', results)
def _request_player(self, sessionplayer: ba.SessionPlayer) -> bool: def _request_player(self, sessionplayer: ba.SessionPlayer) -> bool:
"""Called by the C++ layer when players want to join.""" """Called by the C++ layer when players want to join."""

View File

@ -26,12 +26,19 @@
from __future__ import annotations from __future__ import annotations
import random import random
from typing import TYPE_CHECKING from typing import TYPE_CHECKING, TypeVar
import ba import ba
from bastd.gameutils import SharedObjects
if TYPE_CHECKING: if TYPE_CHECKING:
from typing import Any, Sequence, Optional, Callable, List, Tuple from typing import Any, Sequence, Optional, Callable, List, Tuple, Type
# Attr we store these objects as on the current activity.
# (based on our module so hopefully avoids conflicts)
STORAGE_ATTR_NAME = '_' + __name__.replace('.', '_') + '_bombfactory'
PlayerType = TypeVar('PlayerType', bound='ba.Player')
class BombFactory: class BombFactory:
@ -153,6 +160,7 @@ class BombFactory:
You shouldn't need to do this; call bastd.actor.bomb.get_factory() You shouldn't need to do this; call bastd.actor.bomb.get_factory()
to get a shared instance. to get a shared instance.
""" """
shared = SharedObjects.get()
self.bomb_model = ba.getmodel('bomb') self.bomb_model = ba.getmodel('bomb')
self.sticky_bomb_model = ba.getmodel('bombSticky') self.sticky_bomb_model = ba.getmodel('bombSticky')
@ -191,17 +199,24 @@ class BombFactory:
self.sticky_material = ba.Material() self.sticky_material = ba.Material()
self.bomb_material.add_actions( self.bomb_material.add_actions(
conditions=((('we_are_younger_than', 100), 'or', conditions=(
('they_are_younger_than', 100)), (
'and', ('they_have_material', ('we_are_younger_than', 100),
ba.sharedobj('object_material'))), 'or',
actions=('modify_node_collision', 'collide', False)) ('they_are_younger_than', 100),
),
'and',
('they_have_material', shared.object_material),
),
actions=('modify_node_collision', 'collide', False),
)
# we want pickup materials to always hit us even if we're currently not # we want pickup materials to always hit us even if we're currently not
# colliding with their node (generally due to the above rule) # colliding with their node (generally due to the above rule)
self.bomb_material.add_actions( self.bomb_material.add_actions(conditions=('they_have_material',
conditions=('they_have_material', ba.sharedobj('pickup_material')), shared.pickup_material),
actions=('modify_part_collision', 'use_node_collide', False)) actions=('modify_part_collision',
'use_node_collide', False))
self.bomb_material.add_actions(actions=('modify_part_collision', self.bomb_material.add_actions(actions=('modify_part_collision',
'friction', 0.3)) 'friction', 0.3))
@ -209,36 +224,54 @@ class BombFactory:
self.land_mine_no_explode_material = ba.Material() self.land_mine_no_explode_material = ba.Material()
self.land_mine_blast_material = ba.Material() self.land_mine_blast_material = ba.Material()
self.land_mine_blast_material.add_actions( self.land_mine_blast_material.add_actions(
conditions=(('we_are_older_than', conditions=(
200), 'and', ('they_are_older_than', ('we_are_older_than', 200),
200), 'and', ('eval_colliding', ), 'and',
'and', (('they_dont_have_material', ('they_are_older_than', 200),
self.land_mine_no_explode_material), 'and', 'and',
(('they_have_material', ('eval_colliding', ),
ba.sharedobj('object_material')), 'or', 'and',
('they_have_material', (
ba.sharedobj('player_material'))))), ('they_dont_have_material',
actions=('message', 'our_node', 'at_connect', ImpactMessage())) self.land_mine_no_explode_material),
'and',
(
('they_have_material', shared.object_material),
'or',
('they_have_material', shared.player_material),
),
),
),
actions=('message', 'our_node', 'at_connect', ImpactMessage()),
)
self.impact_blast_material = ba.Material() self.impact_blast_material = ba.Material()
self.impact_blast_material.add_actions( self.impact_blast_material.add_actions(
conditions=(('we_are_older_than', conditions=(
200), 'and', ('they_are_older_than', ('we_are_older_than', 200),
200), 'and', ('eval_colliding', ), 'and',
'and', (('they_have_material', ('they_are_older_than', 200),
ba.sharedobj('footing_material')), 'or', 'and',
('they_have_material', ('eval_colliding', ),
ba.sharedobj('object_material')))), 'and',
actions=('message', 'our_node', 'at_connect', ImpactMessage())) (
('they_have_material', shared.footing_material),
'or',
('they_have_material', shared.object_material),
),
),
actions=('message', 'our_node', 'at_connect', ImpactMessage()),
)
self.blast_material = ba.Material() self.blast_material = ba.Material()
self.blast_material.add_actions( self.blast_material.add_actions(
conditions=(('they_have_material', conditions=(('they_have_material', shared.object_material), ),
ba.sharedobj('object_material'))), actions=(
actions=(('modify_part_collision', 'collide', True), ('modify_part_collision', 'collide', True),
('modify_part_collision', 'physical', ('modify_part_collision', 'physical', False),
False), ('message', 'our_node', 'at_connect', ('message', 'our_node', 'at_connect', ExplodeHitMessage()),
ExplodeHitMessage()))) ),
)
self.dink_sounds = (ba.getsound('bombDrop01'), self.dink_sounds = (ba.getsound('bombDrop01'),
ba.getsound('bombDrop02')) ba.getsound('bombDrop02'))
@ -247,10 +280,11 @@ class BombFactory:
# collision sounds # collision sounds
self.normal_sound_material.add_actions( self.normal_sound_material.add_actions(
conditions=('they_have_material', conditions=('they_have_material', shared.footing_material),
ba.sharedobj('footing_material')), actions=(
actions=(('impact_sound', self.dink_sounds, 2, 0.8), ('impact_sound', self.dink_sounds, 2, 0.8),
('roll_sound', self.roll_sound, 3, 6))) ('roll_sound', self.roll_sound, 3, 6),
))
self.sticky_material.add_actions(actions=(('modify_part_collision', self.sticky_material.add_actions(actions=(('modify_part_collision',
'stiffness', 0.1), 'stiffness', 0.1),
@ -258,24 +292,22 @@ class BombFactory:
'damping', 1.0))) 'damping', 1.0)))
self.sticky_material.add_actions( self.sticky_material.add_actions(
conditions=(('they_have_material', conditions=(
ba.sharedobj('player_material')), ('they_have_material', shared.player_material),
'or', ('they_have_material', 'or',
ba.sharedobj('footing_material'))), ('they_have_material', shared.footing_material),
actions=('message', 'our_node', 'at_connect', SplatMessage())) ),
actions=('message', 'our_node', 'at_connect', SplatMessage()),
)
def get_factory() -> BombFactory: def get_factory() -> BombFactory:
"""Get/create a shared bastd.actor.bomb.BombFactory object.""" """Get/create a shared bastd.actor.bomb.BombFactory object."""
activity = ba.getactivity() activity = ba.getactivity()
factory = getattr(activity, STORAGE_ATTR_NAME, None)
# FIXME: Need to figure out an elegant way to store if factory is None:
# shared actor data with an activity. factory = BombFactory()
factory: BombFactory setattr(activity, STORAGE_ATTR_NAME, factory)
try:
factory = activity.shared_bomb_factory # type: ignore
except Exception:
factory = activity.shared_bomb_factory = BombFactory() # type: ignore
assert isinstance(factory, BombFactory) assert isinstance(factory, BombFactory)
return factory return factory
@ -329,26 +361,27 @@ class Blast(ba.Actor):
super().__init__() super().__init__()
shared = SharedObjects.get()
factory = get_factory() factory = get_factory()
self.blast_type = blast_type self.blast_type = blast_type
self.source_player = source_player self._source_player = source_player
self.hit_type = hit_type self.hit_type = hit_type
self.hit_subtype = hit_subtype self.hit_subtype = hit_subtype
self.radius = blast_radius self.radius = blast_radius
# set our position a bit lower so we throw more things upward # set our position a bit lower so we throw more things upward
rmats = (factory.blast_material, ba.sharedobj('attack_material')) rmats = (factory.blast_material, shared.attack_material)
self.node = ba.newnode('region', self.node = ba.newnode(
delegate=self, 'region',
attrs={ delegate=self,
'position': (position[0], position[1] - 0.1, attrs={
position[2]), 'position': (position[0], position[1] - 0.1, position[2]),
'scale': 'scale': (self.radius, self.radius, self.radius),
(self.radius, self.radius, self.radius), 'type': 'sphere',
'type': 'sphere', 'materials': rmats
'materials': rmats },
}) )
ba.timer(0.05, self.node.delete) ba.timer(0.05, self.node.delete)
@ -619,7 +652,7 @@ class Blast(ba.Actor):
hit_type=self.hit_type, hit_type=self.hit_type,
hit_subtype=self.hit_subtype, hit_subtype=self.hit_subtype,
radius=self.radius, radius=self.radius,
source_player=ba.existing(self.source_player))) source_player=ba.existing(self._source_player)))
if self.blast_type == 'ice': if self.blast_type == 'ice':
ba.playsound(get_factory().freeze_sound, 10, position=nodepos) ba.playsound(get_factory().freeze_sound, 10, position=nodepos)
node.handlemessage(ba.FreezeMessage()) node.handlemessage(ba.FreezeMessage())
@ -654,6 +687,7 @@ class Bomb(ba.Actor):
""" """
super().__init__() super().__init__()
shared = SharedObjects.get()
factory = get_factory() factory = get_factory()
if bomb_type not in ('ice', 'impact', 'land_mine', 'normal', 'sticky', if bomb_type not in ('ice', 'impact', 'land_mine', 'normal', 'sticky',
@ -681,7 +715,7 @@ class Bomb(ba.Actor):
self._explode_callbacks: List[Callable[[Bomb, Blast], Any]] = [] self._explode_callbacks: List[Callable[[Bomb, Blast], Any]] = []
# the player this came from # the player this came from
self.source_player = source_player self._source_player = source_player
# by default our hit type/subtype is our own, but we pick up types of # by default our hit type/subtype is our own, but we pick up types of
# whoever sets us off so we know what caused a chain reaction # whoever sets us off so we know what caused a chain reaction
@ -702,12 +736,10 @@ class Bomb(ba.Actor):
# ground.. perhaps we don't wanna add this even in the tnt case?.. # ground.. perhaps we don't wanna add this even in the tnt case?..
materials: Tuple[ba.Material, ...] materials: Tuple[ba.Material, ...]
if self.bomb_type == 'tnt': if self.bomb_type == 'tnt':
materials = (factory.bomb_material, materials = (factory.bomb_material, shared.footing_material,
ba.sharedobj('footing_material'), shared.object_material)
ba.sharedobj('object_material'))
else: else:
materials = (factory.bomb_material, materials = (factory.bomb_material, shared.object_material)
ba.sharedobj('object_material'))
if self.bomb_type == 'impact': if self.bomb_type == 'impact':
materials = materials + (factory.impact_blast_material, ) materials = materials + (factory.impact_blast_material, )
@ -824,11 +856,20 @@ class Bomb(ba.Actor):
ba.animate(self.node, 'model_scale', {0: 0, 0.2: 1.3, 0.26: 1}) ba.animate(self.node, 'model_scale', {0: 0, 0.2: 1.3, 0.26: 1})
def get_source_player(self) -> Optional[ba.Player]: def get_source_player(
"""Returns a ba.Player representing the source of this bomb. self, playertype: Type[PlayerType]) -> Optional[PlayerType]:
"""Return the source-player if there is one and they still exist.
Be prepared for values of None or invalid Player refs.""" The type of player for the current activity should be passed so that
return self.source_player the type-checker properly identifies the returned value as one.
"""
player: Any = self._source_player
assert isinstance(player, (playertype, type(None)))
# We should not be delivering invalid refs.
# (technically if someone holds on to this message this can happen)
assert player is None or player.exists()
return player
def on_expire(self) -> None: def on_expire(self) -> None:
super().on_expire() super().on_expire()
@ -899,7 +940,7 @@ class Bomb(ba.Actor):
velocity=self.node.velocity, velocity=self.node.velocity,
blast_radius=self.blast_radius, blast_radius=self.blast_radius,
blast_type=self.bomb_type, blast_type=self.bomb_type,
source_player=self.source_player, source_player=ba.existing(self._source_player),
hit_type=self.hit_type, hit_type=self.hit_type,
hit_subtype=self.hit_subtype).autoretain() hit_subtype=self.hit_subtype).autoretain()
for callback in self._explode_callbacks: for callback in self._explode_callbacks:
@ -979,7 +1020,7 @@ class Bomb(ba.Actor):
# person causing them). # person causing them).
source_player = msg.get_source_player(ba.Player) source_player = msg.get_source_player(ba.Player)
if source_player is not None: if source_player is not None:
self.source_player = source_player self._source_player = source_player
# Also inherit the hit type (if a landmine sets off by a bomb, # Also inherit the hit type (if a landmine sets off by a bomb,
# the credit should go to the mine) # the credit should go to the mine)
@ -1007,12 +1048,14 @@ class Bomb(ba.Actor):
self.explode() self.explode()
elif isinstance(msg, ImpactMessage): elif isinstance(msg, ImpactMessage):
self._handle_impact() self._handle_impact()
elif isinstance(msg, ba.PickedUpMessage): # Ok the logic below looks like it was backwards to me. Disabling
# change our source to whoever just picked us up *only* if its None # until further notice.
# this way we can get points for killing bots with their own bombs # elif isinstance(msg, ba.PickedUpMessage):
# hmm would there be a downside to this?... # # Change our source to whoever just picked us up *only* if it
if self.source_player is not None: # # is None. This way we can get points for killing bots with their
self.source_player = msg.node.source_player # # own bombs. Hmm would there be a downside to this?
# if self._source_player is not None:
# self._source_player = msg.node.source_player
elif isinstance(msg, SplatMessage): elif isinstance(msg, SplatMessage):
self._handle_splat() self._handle_splat()
elif isinstance(msg, ba.DroppedMessage): elif isinstance(msg, ba.DroppedMessage):

View File

@ -26,6 +26,7 @@ from dataclasses import dataclass
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
import ba import ba
from bastd.gameutils import SharedObjects
if TYPE_CHECKING: if TYPE_CHECKING:
from typing import Any, Sequence, Optional from typing import Any, Sequence, Optional
@ -64,13 +65,13 @@ class FlagFactory:
You shouldn't need to do this; call bastd.actor.flag.get_factory() to You shouldn't need to do this; call bastd.actor.flag.get_factory() to
get a shared instance. get a shared instance.
""" """
shared = SharedObjects.get()
self.flagmaterial = ba.Material() self.flagmaterial = ba.Material()
self.flagmaterial.add_actions( self.flagmaterial.add_actions(
conditions=( conditions=(
('we_are_younger_than', 100), ('we_are_younger_than', 100),
'and', 'and',
('they_have_material', ba.sharedobj('object_material')), ('they_have_material', shared.object_material),
), ),
actions=('modify_node_collision', 'collide', False), actions=('modify_node_collision', 'collide', False),
) )
@ -78,7 +79,7 @@ class FlagFactory:
self.flagmaterial.add_actions( self.flagmaterial.add_actions(
conditions=( conditions=(
'they_have_material', 'they_have_material',
ba.sharedobj('footing_material'), shared.footing_material,
), ),
actions=( actions=(
('message', 'our_node', 'at_connect', 'footing', 1), ('message', 'our_node', 'at_connect', 'footing', 1),
@ -91,7 +92,7 @@ class FlagFactory:
self.flagmaterial.add_actions( self.flagmaterial.add_actions(
conditions=( conditions=(
'they_have_material', 'they_have_material',
ba.sharedobj('footing_material'), shared.footing_material,
), ),
actions=( actions=(
('impact_sound', self.impact_sound, 2, 5), ('impact_sound', self.impact_sound, 2, 5),
@ -102,9 +103,9 @@ class FlagFactory:
self.no_hit_material = ba.Material() self.no_hit_material = ba.Material()
self.no_hit_material.add_actions( self.no_hit_material.add_actions(
conditions=( conditions=(
('they_have_material', ba.sharedobj('pickup_material')), ('they_have_material', shared.pickup_material),
'or', 'or',
('they_have_material', ba.sharedobj('attack_material')), ('they_have_material', shared.attack_material),
), ),
actions=('modify_part_collision', 'collide', False), actions=('modify_part_collision', 'collide', False),
) )
@ -112,9 +113,9 @@ class FlagFactory:
# We also don't want anything moving it. # We also don't want anything moving it.
self.no_hit_material.add_actions( self.no_hit_material.add_actions(
conditions=( conditions=(
('they_have_material', ba.sharedobj('object_material')), ('they_have_material', shared.object_material),
'or', 'or',
('they_dont_have_material', ba.sharedobj('footing_material')), ('they_dont_have_material', shared.footing_material),
), ),
actions=(('modify_part_collision', 'collide', False), actions=(('modify_part_collision', 'collide', False),
('modify_part_collision', 'physical', False)), ('modify_part_collision', 'physical', False)),
@ -215,6 +216,7 @@ class Flag(ba.Actor):
self._initial_position: Optional[Sequence[float]] = None self._initial_position: Optional[Sequence[float]] = None
self._has_moved = False self._has_moved = False
shared = SharedObjects.get()
factory = FlagFactory.get() factory = FlagFactory.get()
if materials is None: if materials is None:
@ -225,9 +227,8 @@ class Flag(ba.Actor):
if not touchable: if not touchable:
materials = [factory.no_hit_material] + materials materials = [factory.no_hit_material] + materials
finalmaterials = ( finalmaterials = ([shared.object_material, factory.flagmaterial] +
[ba.sharedobj('object_material'), factory.flagmaterial] + materials)
materials)
self.node = ba.newnode('flag', self.node = ba.newnode('flag',
attrs={ attrs={
'position': 'position':

View File

@ -79,7 +79,7 @@ class OnScreenCountdown(ba.Actor):
def start(self) -> None: def start(self) -> None:
"""Start the timer.""" """Start the timer."""
globalsnode = ba.sharedobj('globals') globalsnode = ba.getactivity().globalsnode
globalsnode.connectattr('time', self.inputnode, 'time1') globalsnode.connectattr('time', self.inputnode, 'time1')
self.inputnode.time2 = (globalsnode.time + self.inputnode.time2 = (globalsnode.time +
(self._timeremaining + 1) * 1000) (self._timeremaining + 1) * 1000)
@ -87,7 +87,8 @@ class OnScreenCountdown(ba.Actor):
def on_expire(self) -> None: def on_expire(self) -> None:
super().on_expire() super().on_expire()
# release callbacks/refs
# Release callbacks/refs.
self._endcall = None self._endcall = None
def _update(self, forcevalue: int = None) -> None: def _update(self, forcevalue: int = None) -> None:

View File

@ -66,7 +66,8 @@ class OnScreenTimer(ba.Actor):
assert isinstance(tval, int) assert isinstance(tval, int)
self._starttime_ms = tval self._starttime_ms = tval
self.inputnode.time1 = self._starttime_ms self.inputnode.time1 = self._starttime_ms
ba.sharedobj('globals').connectattr('time', self.inputnode, 'time2') ba.getactivity().globalsnode.connectattr('time', self.inputnode,
'time2')
def has_started(self) -> bool: def has_started(self) -> bool:
"""Return whether this timer has started yet.""" """Return whether this timer has started yet."""

View File

@ -26,6 +26,7 @@ import random
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
import ba import ba
from bastd.gameutils import SharedObjects
if TYPE_CHECKING: if TYPE_CHECKING:
from typing import List, Any, Optional, Sequence from typing import List, Any, Optional, Sequence
@ -104,6 +105,7 @@ class PowerupBoxFactory:
to get a shared instance. to get a shared instance.
""" """
from ba.internal import get_default_powerup_distribution from ba.internal import get_default_powerup_distribution
shared = SharedObjects.get()
self._lastpoweruptype: Optional[str] = None self._lastpoweruptype: Optional[str] = None
self.model = ba.getmodel('powerup') self.model = ba.getmodel('powerup')
self.model_simple = ba.getmodel('powerupSimple') self.model_simple = ba.getmodel('powerupSimple')
@ -130,19 +132,22 @@ class PowerupBoxFactory:
# Pass a powerup-touched message to applicable stuff. # Pass a powerup-touched message to applicable stuff.
self.powerup_material.add_actions( self.powerup_material.add_actions(
conditions=('they_have_material', self.powerup_accept_material), conditions=('they_have_material', self.powerup_accept_material),
actions=(('modify_part_collision', 'collide', actions=(
True), ('modify_part_collision', 'physical', False), ('modify_part_collision', 'collide', True),
('message', 'our_node', 'at_connect', _TouchedMessage()))) ('modify_part_collision', 'physical', False),
('message', 'our_node', 'at_connect', _TouchedMessage()),
))
# We don't wanna be picked up. # We don't wanna be picked up.
self.powerup_material.add_actions( self.powerup_material.add_actions(
conditions=('they_have_material', ba.sharedobj('pickup_material')), conditions=('they_have_material', shared.pickup_material),
actions=('modify_part_collision', 'collide', False)) actions=('modify_part_collision', 'collide', False),
)
self.powerup_material.add_actions( self.powerup_material.add_actions(
conditions=('they_have_material', conditions=('they_have_material', shared.footing_material),
ba.sharedobj('footing_material')), actions=('impact_sound', self.drop_sound, 0.5, 0.1),
actions=('impact_sound', self.drop_sound, 0.5, 0.1)) )
self._powerupdist: List[str] = [] self._powerupdist: List[str] = []
for powerup, freq in get_default_powerup_distribution(): for powerup, freq in get_default_powerup_distribution():
@ -228,7 +233,7 @@ class PowerupBox(ba.Actor):
""" """
super().__init__() super().__init__()
shared = SharedObjects.get()
factory = PowerupBoxFactory.get() factory = PowerupBoxFactory.get()
self.poweruptype = poweruptype self.poweruptype = poweruptype
self._powersgiven = False self._powersgiven = False
@ -270,7 +275,7 @@ class PowerupBox(ba.Actor):
'reflection': 'powerup', 'reflection': 'powerup',
'reflection_scale': [1.0], 'reflection_scale': [1.0],
'materials': (factory.powerup_material, 'materials': (factory.powerup_material,
ba.sharedobj('object_material')) shared.object_material)
}) # yapf: disable }) # yapf: disable
# Animate in. # Animate in.

View File

@ -29,6 +29,7 @@ from typing import TYPE_CHECKING
import ba import ba
from bastd.actor import bomb as stdbomb from bastd.actor import bomb as stdbomb
from bastd.actor.powerupbox import PowerupBoxFactory from bastd.actor.powerupbox import PowerupBoxFactory
from bastd.gameutils import SharedObjects
if TYPE_CHECKING: if TYPE_CHECKING:
from typing import (Any, Sequence, Optional, Dict, List, Union, Callable, from typing import (Any, Sequence, Optional, Dict, List, Union, Callable,
@ -108,6 +109,7 @@ class Spaz(ba.Actor):
# pylint: disable=too-many-statements # pylint: disable=too-many-statements
super().__init__() super().__init__()
shared = SharedObjects.get()
activity = self.activity activity = self.activity
factory = get_factory() factory = get_factory()
@ -126,7 +128,7 @@ class Spaz(ba.Actor):
self._punch_power_scale = 1.2 self._punch_power_scale = 1.2
else: else:
self._punch_power_scale = factory.punch_power_scale self._punch_power_scale = factory.punch_power_scale
self.fly = ba.sharedobj('globals').happy_thoughts_mode self.fly = ba.getactivity().globalsnode.happy_thoughts_mode
if isinstance(activity, ba.GameActivity): if isinstance(activity, ba.GameActivity):
self._hockey = activity.map.is_hockey self._hockey = activity.map.is_hockey
else: else:
@ -135,14 +137,10 @@ class Spaz(ba.Actor):
self._cursed = False self._cursed = False
self._connected_to_player: Optional[ba.Player] = None self._connected_to_player: Optional[ba.Player] = None
materials = [ materials = [
factory.spaz_material, factory.spaz_material, shared.object_material,
ba.sharedobj('object_material'), shared.player_material
ba.sharedobj('player_material')
]
roller_materials = [
factory.roller_material,
ba.sharedobj('player_material')
] ]
roller_materials = [factory.roller_material, shared.player_material]
extras_material = [] extras_material = []
if can_accept_powerups: if can_accept_powerups:
@ -152,8 +150,8 @@ class Spaz(ba.Actor):
extras_material.append(pam) extras_material.append(pam)
media = factory.get_media(character) media = factory.get_media(character)
punchmats = (factory.punch_material, ba.sharedobj('attack_material')) punchmats = (factory.punch_material, shared.attack_material)
pickupmats = (factory.pickup_material, ba.sharedobj('pickup_material')) pickupmats = (factory.pickup_material, shared.pickup_material)
self.node: ba.Node = ba.newnode( self.node: ba.Node = ba.newnode(
type='spaz', type='spaz',
delegate=self, delegate=self,

View File

@ -24,9 +24,11 @@ from __future__ import annotations
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
import _ba
import ba import ba
from bastd.actor import spaz as basespaz from bastd.gameutils import SharedObjects
from bastd.actor.spaz import (PickupMessage, PunchHitMessage,
CurseExplodeMessage)
import _ba
if TYPE_CHECKING: if TYPE_CHECKING:
from typing import Any, Dict from typing import Any, Dict
@ -101,6 +103,7 @@ class SpazFactory:
def __init__(self) -> None: def __init__(self) -> None:
"""Instantiate a factory object.""" """Instantiate a factory object."""
shared = SharedObjects.get()
self.impact_sounds_medium = (ba.getsound('impactMedium'), self.impact_sounds_medium = (ba.getsound('impactMedium'),
ba.getsound('impactMedium2')) ba.getsound('impactMedium2'))
self.impact_sounds_hard = (ba.getsound('impactHard'), self.impact_sounds_hard = (ba.getsound('impactHard'),
@ -123,14 +126,14 @@ class SpazFactory:
self.pickup_material = ba.Material() self.pickup_material = ba.Material()
self.curse_material = ba.Material() self.curse_material = ba.Material()
footing_material = ba.sharedobj('footing_material') footing_material = shared.footing_material
object_material = ba.sharedobj('object_material') object_material = shared.object_material
player_material = ba.sharedobj('player_material') player_material = shared.player_material
region_material = ba.sharedobj('region_material') region_material = shared.region_material
# send footing messages to spazzes so they know when they're on solid # Send footing messages to spazzes so they know when they're on
# ground. # solid ground.
# eww this should really just be built into the spaz node # Eww; this probably should just be built into the spaz node.
self.roller_material.add_actions( self.roller_material.add_actions(
conditions=('they_have_material', footing_material), conditions=('they_have_material', footing_material),
actions=(('message', 'our_node', 'at_connect', 'footing', 1), actions=(('message', 'our_node', 'at_connect', 'footing', 1),
@ -140,27 +143,36 @@ class SpazFactory:
conditions=('they_have_material', footing_material), conditions=('they_have_material', footing_material),
actions=(('message', 'our_node', 'at_connect', 'footing', 1), actions=(('message', 'our_node', 'at_connect', 'footing', 1),
('message', 'our_node', 'at_disconnect', 'footing', -1))) ('message', 'our_node', 'at_disconnect', 'footing', -1)))
# punches
# Punches.
self.punch_material.add_actions( self.punch_material.add_actions(
conditions=('they_are_different_node_than_us', ), conditions=('they_are_different_node_than_us', ),
actions=(('modify_part_collision', 'collide', actions=(
True), ('modify_part_collision', 'physical', False), ('modify_part_collision', 'collide', True),
('message', 'our_node', 'at_connect', ('modify_part_collision', 'physical', False),
basespaz.PunchHitMessage()))) ('message', 'our_node', 'at_connect', PunchHitMessage()),
# pickups ))
# Pickups.
self.pickup_material.add_actions( self.pickup_material.add_actions(
conditions=(('they_are_different_node_than_us', ), 'and', conditions=(('they_are_different_node_than_us', ), 'and',
('they_have_material', object_material)), ('they_have_material', object_material)),
actions=(('modify_part_collision', 'collide', actions=(
True), ('modify_part_collision', 'physical', False), ('modify_part_collision', 'collide', True),
('message', 'our_node', 'at_connect', ('modify_part_collision', 'physical', False),
basespaz.PickupMessage()))) ('message', 'our_node', 'at_connect', PickupMessage()),
# curse ))
# Curse.
self.curse_material.add_actions( self.curse_material.add_actions(
conditions=(('they_are_different_node_than_us', ), 'and', conditions=(
('they_have_material', player_material)), ('they_are_different_node_than_us', ),
'and',
('they_have_material', player_material),
),
actions=('message', 'our_node', 'at_connect', actions=('message', 'our_node', 'at_connect',
basespaz.CurseExplodeMessage())) CurseExplodeMessage()),
)
self.foot_impact_sounds = (ba.getsound('footImpact01'), self.foot_impact_sounds = (ba.getsound('footImpact01'),
ba.getsound('footImpact02'), ba.getsound('footImpact02'),
@ -171,34 +183,45 @@ class SpazFactory:
self.roller_material.add_actions( self.roller_material.add_actions(
conditions=('they_have_material', footing_material), conditions=('they_have_material', footing_material),
actions=(('impact_sound', self.foot_impact_sounds, 1, actions=(
0.2), ('skid_sound', self.foot_skid_sound, 20, 0.3), ('impact_sound', self.foot_impact_sounds, 1, 0.2),
('roll_sound', self.foot_roll_sound, 20, 3.0))) ('skid_sound', self.foot_skid_sound, 20, 0.3),
('roll_sound', self.foot_roll_sound, 20, 3.0),
))
self.skid_sound = ba.getsound('gravelSkid') self.skid_sound = ba.getsound('gravelSkid')
self.spaz_material.add_actions( self.spaz_material.add_actions(
conditions=('they_have_material', footing_material), conditions=('they_have_material', footing_material),
actions=(('impact_sound', self.foot_impact_sounds, 20, actions=(
6), ('skid_sound', self.skid_sound, 2.0, 1), ('impact_sound', self.foot_impact_sounds, 20, 6),
('roll_sound', self.skid_sound, 2.0, 1))) ('skid_sound', self.skid_sound, 2.0, 1),
('roll_sound', self.skid_sound, 2.0, 1),
))
self.shield_up_sound = ba.getsound('shieldUp') self.shield_up_sound = ba.getsound('shieldUp')
self.shield_down_sound = ba.getsound('shieldDown') self.shield_down_sound = ba.getsound('shieldDown')
self.shield_hit_sound = ba.getsound('shieldHit') self.shield_hit_sound = ba.getsound('shieldHit')
# we don't want to collide with stuff we're initially overlapping # We don't want to collide with stuff we're initially overlapping
# (unless its marked with a special region material) # (unless its marked with a special region material).
self.spaz_material.add_actions( self.spaz_material.add_actions(
conditions=((('we_are_younger_than', 51), 'and', conditions=(
('they_are_different_node_than_us', )), 'and', (
('they_dont_have_material', region_material)), ('we_are_younger_than', 51),
actions=('modify_node_collision', 'collide', False)) 'and',
('they_are_different_node_than_us', ),
),
'and',
('they_dont_have_material', region_material),
),
actions=('modify_node_collision', 'collide', False),
)
self.spaz_media: Dict[str, Any] = {} self.spaz_media: Dict[str, Any] = {}
# lets load some basic rules (allows them to be tweaked from the # Lets load some basic rules.
# master server) # (allows them to be tweaked from the master server)
self.shield_decay_rate = _ba.get_account_misc_read_val('rsdr', 10.0) self.shield_decay_rate = _ba.get_account_misc_read_val('rsdr', 10.0)
self.punch_cooldown = _ba.get_account_misc_read_val('rpc', 400) self.punch_cooldown = _ba.get_account_misc_read_val('rpc', 400)
self.punch_cooldown_gloves = (_ba.get_account_misc_read_val( self.punch_cooldown_gloves = (_ba.get_account_misc_read_val(

View File

@ -32,6 +32,7 @@ import ba
from bastd.actor.playerspaz import PlayerSpaz from bastd.actor.playerspaz import PlayerSpaz
from bastd.actor.flag import Flag from bastd.actor.flag import Flag
from bastd.actor.scoreboard import Scoreboard from bastd.actor.scoreboard import Scoreboard
from bastd.gameutils import SharedObjects
if TYPE_CHECKING: if TYPE_CHECKING:
from typing import Any, Type, List, Dict, Sequence, Union from typing import Any, Type, List, Dict, Sequence, Union
@ -111,6 +112,7 @@ class AssaultGame(ba.TeamGameActivity[Player, Team]):
return 'touch ${ARG1} flags', self._score_to_win return 'touch ${ARG1} flags', self._score_to_win
def create_team(self, sessionteam: ba.SessionTeam) -> Team: def create_team(self, sessionteam: ba.SessionTeam) -> Team:
shared = SharedObjects.get()
base_pos = self.map.get_flag_position(sessionteam.id) base_pos = self.map.get_flag_position(sessionteam.id)
ba.newnode('light', ba.newnode('light',
attrs={ attrs={
@ -129,7 +131,7 @@ class AssaultGame(ba.TeamGameActivity[Player, Team]):
mat = self._base_region_materials[sessionteam.id] = ba.Material() mat = self._base_region_materials[sessionteam.id] = ba.Material()
mat.add_actions( mat.add_actions(
conditions=('they_have_material', ba.sharedobj('player_material')), conditions=('they_have_material', shared.player_material),
actions=( actions=(
('modify_part_collision', 'collide', True), ('modify_part_collision', 'collide', True),
('modify_part_collision', 'physical', False), ('modify_part_collision', 'physical', False),

View File

@ -31,6 +31,7 @@ import ba
from bastd.actor.flag import Flag from bastd.actor.flag import Flag
from bastd.actor.playerspaz import PlayerSpaz from bastd.actor.playerspaz import PlayerSpaz
from bastd.actor.scoreboard import Scoreboard from bastd.actor.scoreboard import Scoreboard
from bastd.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
@ -142,6 +143,7 @@ class ChosenOneGame(ba.TeamGameActivity[Player, Team]):
def on_begin(self) -> None: def on_begin(self) -> None:
super().on_begin() super().on_begin()
shared = SharedObjects.get()
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._flag_spawn_pos = self.map.get_flag_position(None) self._flag_spawn_pos = self.map.get_flag_position(None)
@ -155,7 +157,7 @@ class ChosenOneGame(ba.TeamGameActivity[Player, Team]):
mat.add_actions( mat.add_actions(
conditions=( conditions=(
'they_have_material', 'they_have_material',
ba.sharedobj('player_material'), shared.player_material,
), ),
actions=( actions=(
('modify_part_collision', 'collide', True), ('modify_part_collision', 'collide', True),
@ -329,8 +331,7 @@ class ChosenOneGame(ba.TeamGameActivity[Player, Team]):
super().handlemessage(msg) super().handlemessage(msg)
player = msg.getplayer(Player) player = msg.getplayer(Player)
if player is self._get_chosen_one_player(): if player is self._get_chosen_one_player():
killerplayer = ba.playercast_o(Player, killerplayer = msg.getkillerplayer(Player)
msg.getkillerplayer(Player))
self._set_chosen_one_player(None if ( self._set_chosen_one_player(None if (
killerplayer is None or killerplayer is player killerplayer is None or killerplayer is player
or not killerplayer.is_alive()) else killerplayer) or not killerplayer.is_alive()) else killerplayer)

View File

@ -32,6 +32,7 @@ import ba
from bastd.actor.flag import Flag from bastd.actor.flag import Flag
from bastd.actor.scoreboard import Scoreboard from bastd.actor.scoreboard import Scoreboard
from bastd.actor.playerspaz import PlayerSpaz from bastd.actor.playerspaz import PlayerSpaz
from bastd.gameutils import SharedObjects
if TYPE_CHECKING: if TYPE_CHECKING:
from typing import Any, Optional, Type, List, Dict, Sequence, Union from typing import Any, Optional, Type, List, Dict, Sequence, Union
@ -119,6 +120,7 @@ class ConquestGame(ba.TeamGameActivity[Player, Team]):
def __init__(self, settings: Dict[str, Any]): def __init__(self, settings: Dict[str, Any]):
super().__init__(settings) super().__init__(settings)
shared = SharedObjects.get()
self._scoreboard = Scoreboard() self._scoreboard = Scoreboard()
self._score_sound = ba.getsound('score') self._score_sound = ba.getsound('score')
self._swipsound = ba.getsound('swip') self._swipsound = ba.getsound('swip')
@ -134,7 +136,7 @@ class ConquestGame(ba.TeamGameActivity[Player, Team]):
# We want flags to tell us they've been hit but not react physically. # We want flags to tell us they've been hit but not react physically.
self._extraflagmat.add_actions( self._extraflagmat.add_actions(
conditions=('they_have_material', ba.sharedobj('player_material')), conditions=('they_have_material', shared.player_material),
actions=(('modify_part_collision', 'collide', True), actions=(('modify_part_collision', 'collide', True),
('call', 'at_connect', self._handle_flag_player_collide))) ('call', 'at_connect', self._handle_flag_player_collide)))

View File

@ -35,6 +35,7 @@ from bastd.actor.spazbot import SpazBotSet, BouncyBot, SpazBotDiedMessage
from bastd.actor.onscreencountdown import OnScreenCountdown from bastd.actor.onscreencountdown import OnScreenCountdown
from bastd.actor.scoreboard import Scoreboard from bastd.actor.scoreboard import Scoreboard
from bastd.actor.respawnicon import RespawnIcon from bastd.actor.respawnicon import RespawnIcon
from bastd.gameutils import SharedObjects
if TYPE_CHECKING: if TYPE_CHECKING:
from typing import Any, Type, Dict, List, Tuple, Optional from typing import Any, Type, Dict, List, Tuple, Optional
@ -78,6 +79,7 @@ class EasterEggHuntGame(ba.TeamGameActivity[Player, Team]):
def __init__(self, settings: Dict[str, Any]): def __init__(self, settings: Dict[str, Any]):
super().__init__(settings) super().__init__(settings)
shared = SharedObjects.get()
self._last_player_death_time = None self._last_player_death_time = None
self._scoreboard = Scoreboard() self._scoreboard = Scoreboard()
self.egg_model = ba.getmodel('egg') self.egg_model = ba.getmodel('egg')
@ -89,7 +91,7 @@ class EasterEggHuntGame(ba.TeamGameActivity[Player, Team]):
self._max_eggs = 1.0 self._max_eggs = 1.0
self.egg_material = ba.Material() self.egg_material = ba.Material()
self.egg_material.add_actions( self.egg_material.add_actions(
conditions=('they_have_material', ba.sharedobj('player_material')), conditions=('they_have_material', shared.player_material),
actions=(('call', 'at_connect', self._on_egg_player_collide), )) actions=(('call', 'at_connect', self._on_egg_player_collide), ))
self._eggs: List[Egg] = [] self._eggs: List[Egg] = []
self._update_timer: Optional[ba.Timer] = None self._update_timer: Optional[ba.Timer] = None
@ -243,12 +245,13 @@ class Egg(ba.Actor):
super().__init__() super().__init__()
activity = self.activity activity = self.activity
assert isinstance(activity, EasterEggHuntGame) assert isinstance(activity, EasterEggHuntGame)
shared = SharedObjects.get()
# Spawn just above the provided point. # Spawn just above the provided point.
self._spawn_pos = (position[0], position[1] + 1.0, position[2]) self._spawn_pos = (position[0], position[1] + 1.0, position[2])
ctex = (activity.egg_tex_1, activity.egg_tex_2, ctex = (activity.egg_tex_1, activity.egg_tex_2,
activity.egg_tex_3)[random.randrange(3)] activity.egg_tex_3)[random.randrange(3)]
mats = [ba.sharedobj('object_material'), activity.egg_material] mats = [shared.object_material, activity.egg_material]
self.node = ba.newnode('prop', self.node = ba.newnode('prop',
delegate=self, delegate=self,
attrs={ attrs={

View File

@ -530,8 +530,8 @@ class FootballCoopGame(ba.CoopGameActivity[Player, Team]):
})) }))
self._time_text_input = ba.NodeActor( self._time_text_input = ba.NodeActor(
ba.newnode('timedisplay', attrs={'showsubseconds': True})) ba.newnode('timedisplay', attrs={'showsubseconds': True}))
ba.sharedobj('globals').connectattr('time', self._time_text_input.node, self.globalsnode.connectattr('time', self._time_text_input.node,
'time2') 'time2')
assert self._time_text_input.node assert self._time_text_input.node
assert self._time_text.node assert self._time_text.node
self._time_text_input.node.connectattr('output', self._time_text.node, self._time_text_input.node.connectattr('output', self._time_text.node,

View File

@ -31,6 +31,7 @@ import ba
from bastd.actor.playerspaz import PlayerSpaz from bastd.actor.playerspaz import PlayerSpaz
from bastd.actor.scoreboard import Scoreboard from bastd.actor.scoreboard import Scoreboard
from bastd.actor.powerupbox import PowerupBoxFactory from bastd.actor.powerupbox import PowerupBoxFactory
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
@ -48,6 +49,7 @@ class Puck(ba.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()
activity = self.getactivity() activity = self.getactivity()
# Spawn just above the provided point. # Spawn just above the provided point.
@ -56,7 +58,7 @@ class Puck(ba.Actor):
self.scored = False self.scored = False
assert activity is not None assert activity is not None
assert isinstance(activity, HockeyGame) assert isinstance(activity, HockeyGame)
pmats = [ba.sharedobj('object_material'), activity.puck_material] pmats = [shared.object_material, activity.puck_material]
self.node = ba.newnode('prop', self.node = ba.newnode('prop',
delegate=self, delegate=self,
attrs={ attrs={
@ -153,6 +155,7 @@ class HockeyGame(ba.TeamGameActivity[Player, Team]):
def __init__(self, settings: Dict[str, Any]): def __init__(self, settings: Dict[str, Any]):
super().__init__(settings) super().__init__(settings)
shared = SharedObjects.get()
self._scoreboard = Scoreboard() self._scoreboard = Scoreboard()
self._cheer_sound = ba.getsound('cheer') self._cheer_sound = ba.getsound('cheer')
self._chant_sound = ba.getsound('crowdChant') self._chant_sound = ba.getsound('crowdChant')
@ -165,22 +168,26 @@ class HockeyGame(ba.TeamGameActivity[Player, Team]):
self.puck_material = ba.Material() self.puck_material = ba.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',
shared.pickup_material),
actions=('modify_part_collision',
'collide', False))
self.puck_material.add_actions( self.puck_material.add_actions(
conditions=('they_have_material', ba.sharedobj('pickup_material')), conditions=(
actions=('modify_part_collision', 'collide', False)) ('we_are_younger_than', 100),
self.puck_material.add_actions( 'and',
conditions=(('we_are_younger_than', 100), ('they_have_material', shared.object_material),
'and', ('they_have_material', ),
ba.sharedobj('object_material'))), actions=('modify_node_collision', 'collide', False),
actions=('modify_node_collision', 'collide', False)) )
self.puck_material.add_actions( self.puck_material.add_actions(conditions=('they_have_material',
conditions=('they_have_material', shared.footing_material),
ba.sharedobj('footing_material')), actions=('impact_sound',
actions=('impact_sound', self._puck_sound, 0.2, 5)) self._puck_sound, 0.2, 5))
# Keep track of which player last touched the puck # Keep track of which player last touched the puck
self.puck_material.add_actions( self.puck_material.add_actions(
conditions=('they_have_material', ba.sharedobj('player_material')), conditions=('they_have_material', shared.player_material),
actions=(('call', 'at_connect', actions=(('call', 'at_connect',
self._handle_puck_player_collide), )) self._handle_puck_player_collide), ))

View File

@ -33,6 +33,7 @@ import ba
from bastd.actor.flag import Flag from bastd.actor.flag import Flag
from bastd.actor.playerspaz import PlayerSpaz from bastd.actor.playerspaz import PlayerSpaz
from bastd.actor.scoreboard import Scoreboard from bastd.actor.scoreboard import Scoreboard
from bastd.gameutils import SharedObjects
if TYPE_CHECKING: if TYPE_CHECKING:
from weakref import ReferenceType from weakref import ReferenceType
@ -97,6 +98,7 @@ class KingOfTheHillGame(ba.TeamGameActivity[Player, Team]):
def __init__(self, settings: Dict[str, Any]): def __init__(self, settings: Dict[str, Any]):
super().__init__(settings) super().__init__(settings)
shared = SharedObjects.get()
self._scoreboard = Scoreboard() self._scoreboard = Scoreboard()
self._swipsound = ba.getsound('swip') self._swipsound = ba.getsound('swip')
self._tick_sound = ba.getsound('tick') self._tick_sound = ba.getsound('tick')
@ -121,7 +123,7 @@ class KingOfTheHillGame(ba.TeamGameActivity[Player, Team]):
self._time_limit = float(settings['Time Limit']) self._time_limit = float(settings['Time Limit'])
self._flag_region_material = ba.Material() self._flag_region_material = ba.Material()
self._flag_region_material.add_actions( self._flag_region_material.add_actions(
conditions=('they_have_material', ba.sharedobj('player_material')), conditions=('they_have_material', shared.player_material),
actions=( actions=(
('modify_part_collision', 'collide', True), ('modify_part_collision', 'collide', True),
('modify_part_collision', 'physical', False), ('modify_part_collision', 'physical', False),
@ -145,6 +147,7 @@ class KingOfTheHillGame(ba.TeamGameActivity[Player, Team]):
def on_begin(self) -> None: def on_begin(self) -> None:
super().on_begin() super().on_begin()
shared = SharedObjects.get()
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._flag_pos = self.map.get_flag_position(None) self._flag_pos = self.map.get_flag_position(None)
@ -164,10 +167,7 @@ class KingOfTheHillGame(ba.TeamGameActivity[Player, Team]):
'color': (0.2, 0.2, 0.2) 'color': (0.2, 0.2, 0.2)
}) })
# Flag region. # Flag region.
flagmats = [ flagmats = [self._flag_region_material, shared.region_material]
self._flag_region_material,
ba.sharedobj('region_material')
]
ba.newnode('region', ba.newnode('region',
attrs={ attrs={
'position': self._flag_pos, 'position': self._flag_pos,

View File

@ -33,6 +33,7 @@ import ba
from bastd.actor.bomb import Bomb from bastd.actor.bomb import Bomb
from bastd.actor.playerspaz import PlayerSpaz from bastd.actor.playerspaz import PlayerSpaz
from bastd.actor.scoreboard import Scoreboard from bastd.actor.scoreboard import Scoreboard
from bastd.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,
@ -196,14 +197,17 @@ class RaceGame(ba.TeamGameActivity[Player, Team]):
def on_transition_in(self) -> None: def on_transition_in(self) -> None:
super().on_transition_in() super().on_transition_in()
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 = ba.Material()
mat.add_actions(conditions=('they_have_material', mat.add_actions(conditions=('they_have_material',
ba.sharedobj('player_material')), shared.player_material),
actions=(('modify_part_collision', 'collide', True), actions=(
('modify_part_collision', 'physical', ('modify_part_collision', 'collide', True),
False), ('call', 'at_connect', ('modify_part_collision', 'physical', False),
self._handle_race_point_collide))) ('call', 'at_connect',
self._handle_race_point_collide),
))
for rpt in pts: for rpt in pts:
self._regions.append(RaceRegion(rpt, len(self._regions))) self._regions.append(RaceRegion(rpt, len(self._regions)))

View File

@ -34,6 +34,7 @@ from bastd.actor.bomb import TNTSpawner
from bastd.actor.scoreboard import Scoreboard from bastd.actor.scoreboard import Scoreboard
from bastd.actor.respawnicon import RespawnIcon from bastd.actor.respawnicon import RespawnIcon
from bastd.actor.powerupbox import PowerupBox, PowerupBoxFactory from bastd.actor.powerupbox import PowerupBox, PowerupBoxFactory
from bastd.gameutils import SharedObjects
from bastd.actor.spazbot import ( from bastd.actor.spazbot import (
SpazBotSet, SpazBot, SpazBotDiedMessage, BomberBot, BrawlerBot, TriggerBot, SpazBotSet, SpazBot, SpazBotDiedMessage, BomberBot, BrawlerBot, TriggerBot,
TriggerBotPro, BomberBotProShielded, TriggerBotProShielded, ChargerBot, TriggerBotPro, BomberBotProShielded, TriggerBotProShielded, ChargerBot,
@ -88,6 +89,7 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]):
def __init__(self, settings: Dict[str, Any]): def __init__(self, settings: Dict[str, Any]):
settings['map'] = 'Tower D' settings['map'] = 'Tower D'
super().__init__(settings) super().__init__(settings)
shared = SharedObjects.get()
self._preset = self.settings_raw.get('preset', 'pro') self._preset = self.settings_raw.get('preset', 'pro')
self._player_death_sound = ba.getsound('playerDeath') self._player_death_sound = ba.getsound('playerDeath')
@ -109,7 +111,7 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]):
self._score_region_material = ba.Material() self._score_region_material = ba.Material()
self._score_region_material.add_actions( self._score_region_material.add_actions(
conditions=('they_have_material', ba.sharedobj('player_material')), conditions=('they_have_material', shared.player_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_reached_end))) ('call', 'at_connect', self._handle_reached_end)))

View File

@ -171,9 +171,9 @@ class TargetPracticeGame(ba.TeamGameActivity[Player, Team]):
# Feed the explosion point to all our targets and get points in return. # Feed the explosion point to all our targets and get points in return.
# Note: we operate on a copy of self._targets since the list may change # Note: we operate on a copy of self._targets since the list may change
# under us if we hit stuff (don't wanna get points for new targets). # under us if we hit stuff (don't wanna get points for new targets).
player = ba.playercast_o(Player, bomb.get_source_player()) player = bomb.get_source_player(Player)
if not player: if not player:
return # could happen if they leave after throwing a bomb.. return # Could happen if they leave after throwing a bomb.
bullseye = any( bullseye = any(
target.do_hit_at_position(pos, player) target.do_hit_at_position(pos, player)

View File

@ -24,5 +24,142 @@ from __future__ import annotations
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
import ba
if TYPE_CHECKING: if TYPE_CHECKING:
from typing import Sequence from typing import Sequence, Optional
# Attr we store these objects as on the current activity.
# (based on our module so hopefully avoids conflicts)
STORAGE_ATTR_NAME = '_' + __name__.replace('.', '_') + '_sharedobjs'
class SharedObjects:
"""Various common components for use in games.
Category: Gameplay Classes
Objects contained here are created on-demand as accessed and shared
by everything in the current activity. This includes things such as
standard materials.
"""
def __init__(self) -> None:
activity = ba.getactivity()
if hasattr(activity, STORAGE_ATTR_NAME):
raise RuntimeError('Use SharedObjects.get() to fetch the'
' shared instance for this activity.')
self._object_material: Optional[ba.Material] = None
self._player_material: Optional[ba.Material] = None
self._pickup_material: Optional[ba.Material] = None
self._footing_material: Optional[ba.Material] = None
self._attack_material: Optional[ba.Material] = None
self._death_material: Optional[ba.Material] = None
self._region_material: Optional[ba.Material] = None
self._railing_material: Optional[ba.Material] = None
@staticmethod
def get() -> SharedObjects:
"""Fetch/create the instance of this class for the current activity."""
activity = ba.getactivity()
shobs = getattr(activity, STORAGE_ATTR_NAME, None)
if shobs is None:
shobs = SharedObjects()
setattr(activity, STORAGE_ATTR_NAME, shobs)
assert isinstance(shobs, SharedObjects)
return shobs
@property
def player_material(self) -> ba.Material:
"""a ba.Material to be applied to player parts. Generally,
materials related to the process of scoring when reaching a goal, etc
will look for the presence of this material on things that hit them.
"""
if self._player_material is None:
self._player_material = ba.Material()
return self._player_material
@property
def object_material(self) -> ba.Material:
"""A ba.Material that should be applied to any small,
normal, physical objects such as bombs, boxes, players, etc. Other
materials often check for the presence of this material as a
prerequisite for performing certain actions (such as disabling
collisions between initially-overlapping objects)
"""
if self._object_material is None:
self._object_material = ba.Material()
return self._object_material
@property
def pickup_material(self) -> ba.Material:
"""A ba.Material; collision shapes used for picking things
up will have this material applied. To prevent an object from being
picked up, you can add a material that disables collisions against
things containing this material.
"""
if self._pickup_material is None:
self._pickup_material = ba.Material()
return self._pickup_material
@property
def footing_material(self) -> ba.Material:
"""Anything that can be 'walked on' should have this
ba.Material applied; generally just terrain and whatnot. A character
will snap upright whenever touching something with this material so it
should not be applied to props, etc.
"""
if self._footing_material is None:
self._footing_material = ba.Material()
return self._footing_material
@property
def attack_material(self) -> ba.Material:
"""A ba.Material applied to explosion shapes, punch
shapes, etc. An object not wanting to receive impulse/etc messages can
disable collisions against this material.
"""
if self._attack_material is None:
self._attack_material = ba.Material()
return self._attack_material
@property
def death_material(self) -> ba.Material:
"""A ba.Material that sends a ba.DieMessage() to anything
that touches it; handy for terrain below a cliff, etc.
"""
if self._death_material is None:
mat = self._death_material = ba.Material()
mat.add_actions(
('message', 'their_node', 'at_connect', ba.DieMessage()))
return self._death_material
@property
def region_material(self) -> ba.Material:
"""A ba.Material used for non-physical collision shapes
(regions); collisions can generally be allowed with this material even
when initially overlapping since it is not physical.
"""
if self._region_material is None:
self._region_material = ba.Material()
return self._region_material
@property
def railing_material(self) -> ba.Material:
"""A ba.Material with a very low friction/stiffness/etc
that can be applied to invisible 'railings' useful for gently keeping
characters from falling off of cliffs.
"""
if self._railing_material is None:
mat = self._railing_material = ba.Material()
mat.add_actions(('modify_part_collision', 'collide', False))
mat.add_actions(('modify_part_collision', 'stiffness', 0.003))
mat.add_actions(('modify_part_collision', 'damping', 0.00001))
mat.add_actions(
conditions=('they_have_material', self.player_material),
actions=(
('modify_part_collision', 'collide', True),
('modify_part_collision', 'friction', 0.0),
),
)
return self._railing_material

View File

@ -182,7 +182,7 @@ class MainMenuActivity(ba.Activity[ba.Player, ba.Team]):
vr_bottom_fill_model = ba.getmodel('thePadVRFillBottom') vr_bottom_fill_model = ba.getmodel('thePadVRFillBottom')
vr_top_fill_model = ba.getmodel('thePadVRFillTop') vr_top_fill_model = ba.getmodel('thePadVRFillTop')
gnode = ba.sharedobj('globals') gnode = self.globalsnode
gnode.camera_mode = 'rotate' gnode.camera_mode = 'rotate'
tint = (1.14, 1.1, 1.0) tint = (1.14, 1.1, 1.0)

View File

@ -26,7 +26,7 @@ from __future__ import annotations
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
import ba import ba
# from bastd import stdmap from bastd.gameutils import SharedObjects
if TYPE_CHECKING: if TYPE_CHECKING:
from typing import Any, List, Dict from typing import Any, List, Dict
@ -65,6 +65,7 @@ class HockeyStadium(ba.Map):
def __init__(self) -> None: def __init__(self) -> None:
super().__init__() super().__init__()
shared = SharedObjects.get()
self.node = ba.newnode('terrain', self.node = ba.newnode('terrain',
delegate=self, delegate=self,
attrs={ attrs={
@ -75,7 +76,7 @@ class HockeyStadium(ba.Map):
'color_texture': 'color_texture':
self.preloaddata['tex'], self.preloaddata['tex'],
'materials': [ 'materials': [
ba.sharedobj('footing_material'), shared.footing_material,
self.preloaddata['ice_material'] self.preloaddata['ice_material']
] ]
}) })
@ -87,9 +88,7 @@ class HockeyStadium(ba.Map):
'background': True, 'background': True,
'color_texture': self.preloaddata['stands_tex'] 'color_texture': self.preloaddata['stands_tex']
}) })
mats = [ mats = [shared.footing_material, self.preloaddata['ice_material']]
ba.sharedobj('footing_material'), self.preloaddata['ice_material']
]
self.floor = ba.newnode('terrain', self.floor = ba.newnode('terrain',
attrs={ attrs={
'model': self.preloaddata['models'][1], 'model': self.preloaddata['models'][1],
@ -105,7 +104,7 @@ class HockeyStadium(ba.Map):
'visible_in_reflections': False, 'visible_in_reflections': False,
'color_texture': self.preloaddata['stands_tex'] 'color_texture': self.preloaddata['stands_tex']
}) })
gnode = ba.sharedobj('globals') gnode = ba.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
@ -145,6 +144,7 @@ class FootballStadium(ba.Map):
def __init__(self) -> None: def __init__(self) -> None:
super().__init__() super().__init__()
shared = SharedObjects.get()
self.node = ba.newnode( self.node = ba.newnode(
'terrain', 'terrain',
delegate=self, delegate=self,
@ -152,7 +152,7 @@ class FootballStadium(ba.Map):
'model': self.preloaddata['model'], 'model': self.preloaddata['model'],
'collide_model': self.preloaddata['collide_model'], 'collide_model': self.preloaddata['collide_model'],
'color_texture': self.preloaddata['tex'], 'color_texture': self.preloaddata['tex'],
'materials': [ba.sharedobj('footing_material')] 'materials': [shared.footing_material]
}) })
ba.newnode('terrain', ba.newnode('terrain',
attrs={ attrs={
@ -162,7 +162,7 @@ class FootballStadium(ba.Map):
'background': True, 'background': True,
'color_texture': self.preloaddata['tex'] 'color_texture': self.preloaddata['tex']
}) })
gnode = ba.sharedobj('globals') gnode = ba.getactivity().globalsnode
gnode.tint = (1.3, 1.2, 1.0) gnode.tint = (1.3, 1.2, 1.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)
@ -218,6 +218,7 @@ class Bridgit(ba.Map):
def __init__(self) -> None: def __init__(self) -> None:
super().__init__() super().__init__()
shared = SharedObjects.get()
self.node = ba.newnode( self.node = ba.newnode(
'terrain', 'terrain',
delegate=self, delegate=self,
@ -225,7 +226,7 @@ class Bridgit(ba.Map):
'collide_model': self.preloaddata['collide_model'], 'collide_model': self.preloaddata['collide_model'],
'model': self.preloaddata['model_top'], 'model': self.preloaddata['model_top'],
'color_texture': self.preloaddata['tex'], 'color_texture': self.preloaddata['tex'],
'materials': [ba.sharedobj('footing_material')] 'materials': [shared.footing_material]
}) })
self.bottom = ba.newnode('terrain', self.bottom = ba.newnode('terrain',
attrs={ attrs={
@ -253,7 +254,7 @@ class Bridgit(ba.Map):
'terrain', 'terrain',
attrs={ attrs={
'collide_model': self.preloaddata['railing_collide_model'], 'collide_model': self.preloaddata['railing_collide_model'],
'materials': [ba.sharedobj('railing_material')], 'materials': [shared.railing_material],
'bumper': True 'bumper': True
}) })
self.bg_collide = ba.newnode('terrain', self.bg_collide = ba.newnode('terrain',
@ -261,12 +262,12 @@ class Bridgit(ba.Map):
'collide_model': 'collide_model':
self.preloaddata['collide_bg'], self.preloaddata['collide_bg'],
'materials': [ 'materials': [
ba.sharedobj('footing_material'), shared.footing_material,
self.preloaddata['bg_material'], self.preloaddata['bg_material'],
ba.sharedobj('death_material') shared.death_material
] ]
}) })
gnode = ba.sharedobj('globals') gnode = ba.getactivity().globalsnode
gnode.tint = (1.1, 1.2, 1.3) gnode.tint = (1.1, 1.2, 1.3)
gnode.ambient_color = (1.1, 1.2, 1.3) gnode.ambient_color = (1.1, 1.2, 1.3)
gnode.vignette_outer = (0.65, 0.6, 0.55) gnode.vignette_outer = (0.65, 0.6, 0.55)
@ -312,6 +313,7 @@ class BigG(ba.Map):
def __init__(self) -> None: def __init__(self) -> None:
super().__init__() super().__init__()
shared = SharedObjects.get()
self.node = ba.newnode( self.node = ba.newnode(
'terrain', 'terrain',
delegate=self, delegate=self,
@ -320,7 +322,7 @@ class BigG(ba.Map):
'color': (0.7, 0.7, 0.7), 'color': (0.7, 0.7, 0.7),
'model': self.preloaddata['model_top'], 'model': self.preloaddata['model_top'],
'color_texture': self.preloaddata['tex'], 'color_texture': self.preloaddata['tex'],
'materials': [ba.sharedobj('footing_material')] 'materials': [shared.footing_material]
}) })
self.bottom = ba.newnode('terrain', self.bottom = ba.newnode('terrain',
attrs={ attrs={
@ -349,7 +351,7 @@ class BigG(ba.Map):
'terrain', 'terrain',
attrs={ attrs={
'collide_model': self.preloaddata['bumper_collide_model'], 'collide_model': self.preloaddata['bumper_collide_model'],
'materials': [ba.sharedobj('railing_material')], 'materials': [shared.railing_material],
'bumper': True 'bumper': True
}) })
self.bg_collide = ba.newnode('terrain', self.bg_collide = ba.newnode('terrain',
@ -357,12 +359,12 @@ class BigG(ba.Map):
'collide_model': 'collide_model':
self.preloaddata['collide_bg'], self.preloaddata['collide_bg'],
'materials': [ 'materials': [
ba.sharedobj('footing_material'), shared.footing_material,
self.preloaddata['bg_material'], self.preloaddata['bg_material'],
ba.sharedobj('death_material') shared.death_material
] ]
}) })
gnode = ba.sharedobj('globals') gnode = ba.getactivity().globalsnode
gnode.tint = (1.1, 1.2, 1.3) gnode.tint = (1.1, 1.2, 1.3)
gnode.ambient_color = (1.1, 1.2, 1.3) gnode.ambient_color = (1.1, 1.2, 1.3)
gnode.vignette_outer = (0.65, 0.6, 0.55) gnode.vignette_outer = (0.65, 0.6, 0.55)
@ -406,6 +408,7 @@ class Roundabout(ba.Map):
def __init__(self) -> None: def __init__(self) -> None:
super().__init__(vr_overlay_offset=(0, -1, 1)) super().__init__(vr_overlay_offset=(0, -1, 1))
shared = SharedObjects.get()
self.node = ba.newnode( self.node = ba.newnode(
'terrain', 'terrain',
delegate=self, delegate=self,
@ -413,7 +416,7 @@ class Roundabout(ba.Map):
'collide_model': self.preloaddata['collide_model'], 'collide_model': self.preloaddata['collide_model'],
'model': self.preloaddata['model'], 'model': self.preloaddata['model'],
'color_texture': self.preloaddata['tex'], 'color_texture': self.preloaddata['tex'],
'materials': [ba.sharedobj('footing_material')] 'materials': [shared.footing_material]
}) })
self.bottom = ba.newnode('terrain', self.bottom = ba.newnode('terrain',
attrs={ attrs={
@ -442,19 +445,19 @@ class Roundabout(ba.Map):
'collide_model': 'collide_model':
self.preloaddata['collide_bg'], self.preloaddata['collide_bg'],
'materials': [ 'materials': [
ba.sharedobj('footing_material'), shared.footing_material,
self.preloaddata['bg_material'], self.preloaddata['bg_material'],
ba.sharedobj('death_material') shared.death_material
] ]
}) })
self.railing = ba.newnode( self.railing = ba.newnode(
'terrain', 'terrain',
attrs={ attrs={
'collide_model': self.preloaddata['railing_collide_model'], 'collide_model': self.preloaddata['railing_collide_model'],
'materials': [ba.sharedobj('railing_material')], 'materials': [shared.railing_material],
'bumper': True 'bumper': True
}) })
gnode = ba.sharedobj('globals') gnode = ba.getactivity().globalsnode
gnode.tint = (1.0, 1.05, 1.1) gnode.tint = (1.0, 1.05, 1.1)
gnode.ambient_color = (1.0, 1.05, 1.1) gnode.ambient_color = (1.0, 1.05, 1.1)
gnode.shadow_ortho = True gnode.shadow_ortho = True
@ -499,6 +502,7 @@ class MonkeyFace(ba.Map):
def __init__(self) -> None: def __init__(self) -> None:
super().__init__() super().__init__()
shared = SharedObjects.get()
self.node = ba.newnode( self.node = ba.newnode(
'terrain', 'terrain',
delegate=self, delegate=self,
@ -506,7 +510,7 @@ class MonkeyFace(ba.Map):
'collide_model': self.preloaddata['collide_model'], 'collide_model': self.preloaddata['collide_model'],
'model': self.preloaddata['model'], 'model': self.preloaddata['model'],
'color_texture': self.preloaddata['tex'], 'color_texture': self.preloaddata['tex'],
'materials': [ba.sharedobj('footing_material')] 'materials': [shared.footing_material]
}) })
self.bottom = ba.newnode('terrain', self.bottom = ba.newnode('terrain',
attrs={ attrs={
@ -535,19 +539,19 @@ class MonkeyFace(ba.Map):
'collide_model': 'collide_model':
self.preloaddata['collide_bg'], self.preloaddata['collide_bg'],
'materials': [ 'materials': [
ba.sharedobj('footing_material'), shared.footing_material,
self.preloaddata['bg_material'], self.preloaddata['bg_material'],
ba.sharedobj('death_material') shared.death_material
] ]
}) })
self.railing = ba.newnode( self.railing = ba.newnode(
'terrain', 'terrain',
attrs={ attrs={
'collide_model': self.preloaddata['railing_collide_model'], 'collide_model': self.preloaddata['railing_collide_model'],
'materials': [ba.sharedobj('railing_material')], 'materials': [shared.railing_material],
'bumper': True 'bumper': True
}) })
gnode = ba.sharedobj('globals') gnode = ba.getactivity().globalsnode
gnode.tint = (1.1, 1.2, 1.2) gnode.tint = (1.1, 1.2, 1.2)
gnode.ambient_color = (1.2, 1.3, 1.3) gnode.ambient_color = (1.2, 1.3, 1.3)
gnode.vignette_outer = (0.60, 0.62, 0.66) gnode.vignette_outer = (0.60, 0.62, 0.66)
@ -593,6 +597,7 @@ class ZigZag(ba.Map):
def __init__(self) -> None: def __init__(self) -> None:
super().__init__() super().__init__()
shared = SharedObjects.get()
self.node = ba.newnode( self.node = ba.newnode(
'terrain', 'terrain',
delegate=self, delegate=self,
@ -600,7 +605,7 @@ class ZigZag(ba.Map):
'collide_model': self.preloaddata['collide_model'], 'collide_model': self.preloaddata['collide_model'],
'model': self.preloaddata['model'], 'model': self.preloaddata['model'],
'color_texture': self.preloaddata['tex'], 'color_texture': self.preloaddata['tex'],
'materials': [ba.sharedobj('footing_material')] 'materials': [shared.footing_material]
}) })
self.background = ba.newnode( self.background = ba.newnode(
'terrain', 'terrain',
@ -628,19 +633,19 @@ class ZigZag(ba.Map):
'collide_model': 'collide_model':
self.preloaddata['collide_bg'], self.preloaddata['collide_bg'],
'materials': [ 'materials': [
ba.sharedobj('footing_material'), shared.footing_material,
self.preloaddata['bg_material'], self.preloaddata['bg_material'],
ba.sharedobj('death_material') shared.death_material
] ]
}) })
self.railing = ba.newnode( self.railing = ba.newnode(
'terrain', 'terrain',
attrs={ attrs={
'collide_model': self.preloaddata['railing_collide_model'], 'collide_model': self.preloaddata['railing_collide_model'],
'materials': [ba.sharedobj('railing_material')], 'materials': [shared.railing_material],
'bumper': True 'bumper': True
}) })
gnode = ba.sharedobj('globals') gnode = ba.getactivity().globalsnode
gnode.tint = (1.0, 1.15, 1.15) gnode.tint = (1.0, 1.15, 1.15)
gnode.ambient_color = (1.0, 1.15, 1.15) gnode.ambient_color = (1.0, 1.15, 1.15)
gnode.vignette_outer = (0.57, 0.59, 0.63) gnode.vignette_outer = (0.57, 0.59, 0.63)
@ -682,6 +687,7 @@ class ThePad(ba.Map):
def __init__(self) -> None: def __init__(self) -> None:
super().__init__() super().__init__()
shared = SharedObjects.get()
self.node = ba.newnode( self.node = ba.newnode(
'terrain', 'terrain',
delegate=self, delegate=self,
@ -689,7 +695,7 @@ class ThePad(ba.Map):
'collide_model': self.preloaddata['collide_model'], 'collide_model': self.preloaddata['collide_model'],
'model': self.preloaddata['model'], 'model': self.preloaddata['model'],
'color_texture': self.preloaddata['tex'], 'color_texture': self.preloaddata['tex'],
'materials': [ba.sharedobj('footing_material')] 'materials': [shared.footing_material]
}) })
self.bottom = ba.newnode('terrain', self.bottom = ba.newnode('terrain',
attrs={ attrs={
@ -709,7 +715,7 @@ class ThePad(ba.Map):
'terrain', 'terrain',
attrs={ attrs={
'collide_model': self.preloaddata['railing_collide_model'], 'collide_model': self.preloaddata['railing_collide_model'],
'materials': [ba.sharedobj('railing_material')], 'materials': [shared.railing_material],
'bumper': True 'bumper': True
}) })
ba.newnode('terrain', ba.newnode('terrain',
@ -721,7 +727,7 @@ class ThePad(ba.Map):
'background': True, 'background': True,
'color_texture': self.preloaddata['vr_fill_mound_tex'] 'color_texture': self.preloaddata['vr_fill_mound_tex']
}) })
gnode = ba.sharedobj('globals') gnode = ba.getactivity().globalsnode
gnode.tint = (1.1, 1.1, 1.0) gnode.tint = (1.1, 1.1, 1.0)
gnode.ambient_color = (1.1, 1.1, 1.0) gnode.ambient_color = (1.1, 1.1, 1.0)
gnode.vignette_outer = (0.7, 0.65, 0.75) gnode.vignette_outer = (0.7, 0.65, 0.75)
@ -760,6 +766,7 @@ class DoomShroom(ba.Map):
def __init__(self) -> None: def __init__(self) -> None:
super().__init__() super().__init__()
shared = SharedObjects.get()
self.node = ba.newnode( self.node = ba.newnode(
'terrain', 'terrain',
delegate=self, delegate=self,
@ -767,7 +774,7 @@ class DoomShroom(ba.Map):
'collide_model': self.preloaddata['collide_model'], 'collide_model': self.preloaddata['collide_model'],
'model': self.preloaddata['model'], 'model': self.preloaddata['model'],
'color_texture': self.preloaddata['tex'], 'color_texture': self.preloaddata['tex'],
'materials': [ba.sharedobj('footing_material')] 'materials': [shared.footing_material]
}) })
self.background = ba.newnode( self.background = ba.newnode(
'terrain', 'terrain',
@ -791,16 +798,13 @@ class DoomShroom(ba.Map):
'lighting': False, 'lighting': False,
'color_texture': self.preloaddata['tex'] 'color_texture': self.preloaddata['tex']
}) })
self.bg_collide = ba.newnode('terrain', self.bg_collide = ba.newnode(
attrs={ 'terrain',
'collide_model': attrs={
self.preloaddata['collide_bg'], 'collide_model': self.preloaddata['collide_bg'],
'materials': [ 'materials': [shared.footing_material, shared.death_material]
ba.sharedobj('footing_material'), })
ba.sharedobj('death_material') gnode = ba.getactivity().globalsnode
]
})
gnode = ba.sharedobj('globals')
gnode.tint = (0.82, 1.10, 1.15) gnode.tint = (0.82, 1.10, 1.15)
gnode.ambient_color = (0.9, 1.3, 1.1) gnode.ambient_color = (0.9, 1.3, 1.1)
gnode.shadow_ortho = False gnode.shadow_ortho = False
@ -854,6 +858,7 @@ class LakeFrigid(ba.Map):
def __init__(self) -> None: def __init__(self) -> None:
super().__init__() super().__init__()
shared = SharedObjects.get()
self.node = ba.newnode('terrain', self.node = ba.newnode('terrain',
delegate=self, delegate=self,
attrs={ attrs={
@ -864,7 +869,7 @@ class LakeFrigid(ba.Map):
'color_texture': 'color_texture':
self.preloaddata['tex'], self.preloaddata['tex'],
'materials': [ 'materials': [
ba.sharedobj('footing_material'), shared.footing_material,
self.preloaddata['ice_material'] self.preloaddata['ice_material']
] ]
}) })
@ -890,7 +895,7 @@ class LakeFrigid(ba.Map):
'background': True, 'background': True,
'color_texture': self.preloaddata['tex'] 'color_texture': self.preloaddata['tex']
}) })
gnode = ba.sharedobj('globals') gnode = ba.getactivity().globalsnode
gnode.tint = (1, 1, 1) gnode.tint = (1, 1, 1)
gnode.ambient_color = (1, 1, 1) gnode.ambient_color = (1, 1, 1)
gnode.shadow_ortho = True gnode.shadow_ortho = True
@ -931,6 +936,7 @@ class TipTop(ba.Map):
def __init__(self) -> None: def __init__(self) -> None:
super().__init__(vr_overlay_offset=(0, -0.2, 2.5)) super().__init__(vr_overlay_offset=(0, -0.2, 2.5))
shared = SharedObjects.get()
self.node = ba.newnode( self.node = ba.newnode(
'terrain', 'terrain',
delegate=self, delegate=self,
@ -939,7 +945,7 @@ class TipTop(ba.Map):
'model': self.preloaddata['model'], 'model': self.preloaddata['model'],
'color_texture': self.preloaddata['tex'], 'color_texture': self.preloaddata['tex'],
'color': (0.7, 0.7, 0.7), 'color': (0.7, 0.7, 0.7),
'materials': [ba.sharedobj('footing_material')] 'materials': [shared.footing_material]
}) })
self.bottom = ba.newnode('terrain', self.bottom = ba.newnode('terrain',
attrs={ attrs={
@ -961,10 +967,10 @@ class TipTop(ba.Map):
'terrain', 'terrain',
attrs={ attrs={
'collide_model': self.preloaddata['railing_collide_model'], 'collide_model': self.preloaddata['railing_collide_model'],
'materials': [ba.sharedobj('railing_material')], 'materials': [shared.railing_material],
'bumper': True 'bumper': True
}) })
gnode = ba.sharedobj('globals') gnode = ba.getactivity().globalsnode
gnode.tint = (0.8, 0.9, 1.3) gnode.tint = (0.8, 0.9, 1.3)
gnode.ambient_color = (0.8, 0.9, 1.3) gnode.ambient_color = (0.8, 0.9, 1.3)
gnode.vignette_outer = (0.79, 0.79, 0.69) gnode.vignette_outer = (0.79, 0.79, 0.69)
@ -1006,6 +1012,7 @@ class CragCastle(ba.Map):
def __init__(self) -> None: def __init__(self) -> None:
super().__init__() super().__init__()
shared = SharedObjects.get()
self.node = ba.newnode( self.node = ba.newnode(
'terrain', 'terrain',
delegate=self, delegate=self,
@ -1013,7 +1020,7 @@ class CragCastle(ba.Map):
'collide_model': self.preloaddata['collide_model'], 'collide_model': self.preloaddata['collide_model'],
'model': self.preloaddata['model'], 'model': self.preloaddata['model'],
'color_texture': self.preloaddata['tex'], 'color_texture': self.preloaddata['tex'],
'materials': [ba.sharedobj('footing_material')] 'materials': [shared.footing_material]
}) })
self.bottom = ba.newnode('terrain', self.bottom = ba.newnode('terrain',
attrs={ attrs={
@ -1033,7 +1040,7 @@ class CragCastle(ba.Map):
'terrain', 'terrain',
attrs={ attrs={
'collide_model': self.preloaddata['railing_collide_model'], 'collide_model': self.preloaddata['railing_collide_model'],
'materials': [ba.sharedobj('railing_material')], 'materials': [shared.railing_material],
'bumper': True 'bumper': True
}) })
ba.newnode('terrain', ba.newnode('terrain',
@ -1045,7 +1052,7 @@ class CragCastle(ba.Map):
'background': True, 'background': True,
'color_texture': self.preloaddata['vr_fill_mound_tex'] 'color_texture': self.preloaddata['vr_fill_mound_tex']
}) })
gnode = ba.sharedobj('globals') gnode = ba.getactivity().globalsnode
gnode.shadow_ortho = True gnode.shadow_ortho = True
gnode.shadow_offset = (0, 0, -5.0) gnode.shadow_offset = (0, 0, -5.0)
gnode.tint = (1.15, 1.05, 0.75) gnode.tint = (1.15, 1.05, 0.75)
@ -1106,6 +1113,7 @@ class TowerD(ba.Map):
def __init__(self) -> None: def __init__(self) -> None:
super().__init__(vr_overlay_offset=(0, 1, 1)) super().__init__(vr_overlay_offset=(0, 1, 1))
shared = SharedObjects.get()
self.node = ba.newnode( self.node = ba.newnode(
'terrain', 'terrain',
delegate=self, delegate=self,
@ -1113,7 +1121,7 @@ class TowerD(ba.Map):
'collide_model': self.preloaddata['collide_model'], 'collide_model': self.preloaddata['collide_model'],
'model': self.preloaddata['model'], 'model': self.preloaddata['model'],
'color_texture': self.preloaddata['tex'], 'color_texture': self.preloaddata['tex'],
'materials': [ba.sharedobj('footing_material')] 'materials': [shared.footing_material]
}) })
self.node_bottom = ba.newnode( self.node_bottom = ba.newnode(
'terrain', 'terrain',
@ -1147,7 +1155,7 @@ class TowerD(ba.Map):
'affect_bg_dynamics': False, 'affect_bg_dynamics': False,
'materials': [self.preloaddata['player_wall_material']] 'materials': [self.preloaddata['player_wall_material']]
}) })
gnode = ba.sharedobj('globals') gnode = ba.getactivity().globalsnode
gnode.tint = (1.15, 1.11, 1.03) gnode.tint = (1.15, 1.11, 1.03)
gnode.ambient_color = (1.2, 1.1, 1.0) gnode.ambient_color = (1.2, 1.1, 1.0)
gnode.vignette_outer = (0.7, 0.73, 0.7) gnode.vignette_outer = (0.7, 0.73, 0.7)
@ -1209,6 +1217,7 @@ class HappyThoughts(ba.Map):
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()
self.node = ba.newnode( self.node = ba.newnode(
'terrain', 'terrain',
delegate=self, delegate=self,
@ -1216,7 +1225,7 @@ class HappyThoughts(ba.Map):
'collide_model': self.preloaddata['collide_model'], 'collide_model': self.preloaddata['collide_model'],
'model': self.preloaddata['model'], 'model': self.preloaddata['model'],
'color_texture': self.preloaddata['tex'], 'color_texture': self.preloaddata['tex'],
'materials': [ba.sharedobj('footing_material')] 'materials': [shared.footing_material]
}) })
self.bottom = ba.newnode('terrain', self.bottom = ba.newnode('terrain',
attrs={ attrs={
@ -1241,7 +1250,7 @@ class HappyThoughts(ba.Map):
'background': True, 'background': True,
'color_texture': self.preloaddata['vr_fill_mound_tex'] 'color_texture': self.preloaddata['vr_fill_mound_tex']
}) })
gnode = ba.sharedobj('globals') gnode = ba.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)
@ -1309,6 +1318,7 @@ class StepRightUp(ba.Map):
def __init__(self) -> None: def __init__(self) -> None:
super().__init__(vr_overlay_offset=(0, -1, 2)) super().__init__(vr_overlay_offset=(0, -1, 2))
shared = SharedObjects.get()
self.node = ba.newnode( self.node = ba.newnode(
'terrain', 'terrain',
delegate=self, delegate=self,
@ -1316,7 +1326,7 @@ class StepRightUp(ba.Map):
'collide_model': self.preloaddata['collide_model'], 'collide_model': self.preloaddata['collide_model'],
'model': self.preloaddata['model'], 'model': self.preloaddata['model'],
'color_texture': self.preloaddata['tex'], 'color_texture': self.preloaddata['tex'],
'materials': [ba.sharedobj('footing_material')] 'materials': [shared.footing_material]
}) })
self.node_bottom = ba.newnode( self.node_bottom = ba.newnode(
'terrain', 'terrain',
@ -1343,7 +1353,7 @@ class StepRightUp(ba.Map):
'background': True, 'background': True,
'color_texture': self.preloaddata['bgtex'] 'color_texture': self.preloaddata['bgtex']
}) })
gnode = ba.sharedobj('globals') gnode = ba.getactivity().globalsnode
gnode.tint = (1.2, 1.1, 1.0) gnode.tint = (1.2, 1.1, 1.0)
gnode.ambient_color = (1.2, 1.1, 1.0) gnode.ambient_color = (1.2, 1.1, 1.0)
gnode.vignette_outer = (0.7, 0.65, 0.75) gnode.vignette_outer = (0.7, 0.65, 0.75)
@ -1394,6 +1404,7 @@ class Courtyard(ba.Map):
def __init__(self) -> None: def __init__(self) -> None:
super().__init__() super().__init__()
shared = SharedObjects.get()
self.node = ba.newnode( self.node = ba.newnode(
'terrain', 'terrain',
delegate=self, delegate=self,
@ -1401,7 +1412,7 @@ class Courtyard(ba.Map):
'collide_model': self.preloaddata['collide_model'], 'collide_model': self.preloaddata['collide_model'],
'model': self.preloaddata['model'], 'model': self.preloaddata['model'],
'color_texture': self.preloaddata['tex'], 'color_texture': self.preloaddata['tex'],
'materials': [ba.sharedobj('footing_material')] 'materials': [shared.footing_material]
}) })
self.background = ba.newnode( self.background = ba.newnode(
'terrain', 'terrain',
@ -1437,7 +1448,7 @@ class Courtyard(ba.Map):
'affect_bg_dynamics': False, 'affect_bg_dynamics': False,
'materials': [self.preloaddata['player_wall_material']] 'materials': [self.preloaddata['player_wall_material']]
}) })
gnode = ba.sharedobj('globals') gnode = ba.getactivity().globalsnode
gnode.tint = (1.2, 1.17, 1.1) gnode.tint = (1.2, 1.17, 1.1)
gnode.ambient_color = (1.2, 1.17, 1.1) gnode.ambient_color = (1.2, 1.17, 1.1)
gnode.vignette_outer = (0.6, 0.6, 0.64) gnode.vignette_outer = (0.6, 0.6, 0.64)
@ -1489,6 +1500,7 @@ class Rampage(ba.Map):
def __init__(self) -> None: def __init__(self) -> None:
super().__init__(vr_overlay_offset=(0, 0, 2)) super().__init__(vr_overlay_offset=(0, 0, 2))
shared = SharedObjects.get()
self.node = ba.newnode( self.node = ba.newnode(
'terrain', 'terrain',
delegate=self, delegate=self,
@ -1496,7 +1508,7 @@ class Rampage(ba.Map):
'collide_model': self.preloaddata['collide_model'], 'collide_model': self.preloaddata['collide_model'],
'model': self.preloaddata['model'], 'model': self.preloaddata['model'],
'color_texture': self.preloaddata['tex'], 'color_texture': self.preloaddata['tex'],
'materials': [ba.sharedobj('footing_material')] 'materials': [shared.footing_material]
}) })
self.background = ba.newnode( self.background = ba.newnode(
'terrain', 'terrain',
@ -1531,10 +1543,10 @@ class Rampage(ba.Map):
'terrain', 'terrain',
attrs={ attrs={
'collide_model': self.preloaddata['railing_collide_model'], 'collide_model': self.preloaddata['railing_collide_model'],
'materials': [ba.sharedobj('railing_material')], 'materials': [shared.railing_material],
'bumper': True 'bumper': True
}) })
gnode = ba.sharedobj('globals') gnode = ba.getactivity().globalsnode
gnode.tint = (1.2, 1.1, 0.97) gnode.tint = (1.2, 1.1, 0.97)
gnode.ambient_color = (1.3, 1.2, 1.03) gnode.ambient_color = (1.3, 1.2, 1.03)
gnode.vignette_outer = (0.62, 0.64, 0.69) gnode.vignette_outer = (0.62, 0.64, 0.69)

View File

@ -1,5 +1,5 @@
<!-- THIS FILE IS AUTO GENERATED; DO NOT EDIT BY HAND --> <!-- THIS FILE IS AUTO GENERATED; DO NOT EDIT BY HAND -->
<h4><em>last updated on 2020-05-28 for Ballistica version 1.5.0 build 20033</em></h4> <h4><em>last updated on 2020-05-29 for Ballistica version 1.5.0 build 20033</em></h4>
<p>This page documents the Python classes and functions in the 'ba' module, <p>This page documents the Python classes and functions in the 'ba' module,
which are the ones most relevant to modding in Ballistica. If you come across something you feel should be included here or could be better explained, please <a href="mailto:support@froemling.net">let me know</a>. Happy modding!</p> which are the ones most relevant to modding in Ballistica. If you come across something you feel should be included here or could be better explained, please <a href="mailto:support@froemling.net">let me know</a>. Happy modding!</p>
<hr> <hr>
@ -40,6 +40,7 @@
</ul> </ul>
<li><a href="#class_ba_SessionPlayer">ba.SessionPlayer</a></li> <li><a href="#class_ba_SessionPlayer">ba.SessionPlayer</a></li>
<li><a href="#class_ba_SessionTeam">ba.SessionTeam</a></li> <li><a href="#class_ba_SessionTeam">ba.SessionTeam</a></li>
<li><a href="#class_ba_StandLocation">ba.StandLocation</a></li>
<li><a href="#class_ba_Stats">ba.Stats</a></li> <li><a href="#class_ba_Stats">ba.Stats</a></li>
<li><a href="#class_ba_Team">ba.Team</a></li> <li><a href="#class_ba_Team">ba.Team</a></li>
<li><a href="#class_ba_TeamGameResults">ba.TeamGameResults</a></li> <li><a href="#class_ba_TeamGameResults">ba.TeamGameResults</a></li>
@ -61,7 +62,6 @@
<li><a href="#function_ba_playsound">ba.playsound()</a></li> <li><a href="#function_ba_playsound">ba.playsound()</a></li>
<li><a href="#function_ba_printnodes">ba.printnodes()</a></li> <li><a href="#function_ba_printnodes">ba.printnodes()</a></li>
<li><a href="#function_ba_setmusic">ba.setmusic()</a></li> <li><a href="#function_ba_setmusic">ba.setmusic()</a></li>
<li><a href="#function_ba_sharedobj">ba.sharedobj()</a></li>
<li><a href="#function_ba_show_damage_count">ba.show_damage_count()</a></li> <li><a href="#function_ba_show_damage_count">ba.show_damage_count()</a></li>
</ul> </ul>
<h4><a name="class_category_General_Utility_Classes">General Utility Classes</a></h4> <h4><a name="class_category_General_Utility_Classes">General Utility Classes</a></h4>
@ -345,7 +345,7 @@ actually award achievements.</p>
can overlap during transitions.</p> can overlap during transitions.</p>
<h3>Attributes:</h3> <h3>Attributes:</h3>
<h5><a href="#attr_ba_Activity__expired">expired</a>, <a href="#attr_ba_Activity__players">players</a>, <a href="#attr_ba_Activity__playertype">playertype</a>, <a href="#attr_ba_Activity__session">session</a>, <a href="#attr_ba_Activity__settings_raw">settings_raw</a>, <a href="#attr_ba_Activity__stats">stats</a>, <a href="#attr_ba_Activity__teams">teams</a>, <a href="#attr_ba_Activity__teamtype">teamtype</a></h5> <h5><a href="#attr_ba_Activity__expired">expired</a>, <a href="#attr_ba_Activity__globalsnode">globalsnode</a>, <a href="#attr_ba_Activity__players">players</a>, <a href="#attr_ba_Activity__playertype">playertype</a>, <a href="#attr_ba_Activity__session">session</a>, <a href="#attr_ba_Activity__settings_raw">settings_raw</a>, <a href="#attr_ba_Activity__stats">stats</a>, <a href="#attr_ba_Activity__teams">teams</a>, <a href="#attr_ba_Activity__teamtype">teamtype</a></h5>
<dl> <dl>
<dt><h4><a name="attr_ba_Activity__expired">expired</a></h4></dt><dd> <dt><h4><a name="attr_ba_Activity__expired">expired</a></h4></dt><dd>
<p><span>bool</span></p> <p><span>bool</span></p>
@ -355,6 +355,12 @@ actually award achievements.</p>
At this point no new nodes, timers, etc should be made, At this point no new nodes, timers, etc should be made,
run, etc, and the activity should be considered a 'zombie'.</p> run, etc, and the activity should be considered a 'zombie'.</p>
</dd>
<dt><h4><a name="attr_ba_Activity__globalsnode">globalsnode</a></h4></dt><dd>
<p><span><a href="#class_ba_Node">ba.Node</a></span></p>
<p>The 'globals' <a href="#class_ba_Node">ba.Node</a> for the activity. This contains various
global controls and values.</p>
</dd> </dd>
<dt><h4><a name="attr_ba_Activity__players">players</a></h4></dt><dd> <dt><h4><a name="attr_ba_Activity__players">players</a></h4></dt><dd>
<p><span>List[PlayerType]</span></p> <p><span>List[PlayerType]</span></p>
@ -1541,7 +1547,7 @@ start_long_action(callback_when_done=<a href="#class_ba_ContextCall">ba.ContextC
<h3>Attributes Inherited:</h3> <h3>Attributes Inherited:</h3>
<h5><a href="#attr_ba_Activity__players">players</a>, <a href="#attr_ba_Activity__settings_raw">settings_raw</a>, <a href="#attr_ba_Activity__teams">teams</a></h5> <h5><a href="#attr_ba_Activity__players">players</a>, <a href="#attr_ba_Activity__settings_raw">settings_raw</a>, <a href="#attr_ba_Activity__teams">teams</a></h5>
<h3>Attributes Defined Here:</h3> <h3>Attributes Defined Here:</h3>
<h5><a href="#attr_ba_CoopGameActivity__expired">expired</a>, <a href="#attr_ba_CoopGameActivity__map">map</a>, <a href="#attr_ba_CoopGameActivity__playertype">playertype</a>, <a href="#attr_ba_CoopGameActivity__session">session</a>, <a href="#attr_ba_CoopGameActivity__stats">stats</a>, <a href="#attr_ba_CoopGameActivity__teamtype">teamtype</a></h5> <h5><a href="#attr_ba_CoopGameActivity__expired">expired</a>, <a href="#attr_ba_CoopGameActivity__globalsnode">globalsnode</a>, <a href="#attr_ba_CoopGameActivity__map">map</a>, <a href="#attr_ba_CoopGameActivity__playertype">playertype</a>, <a href="#attr_ba_CoopGameActivity__session">session</a>, <a href="#attr_ba_CoopGameActivity__stats">stats</a>, <a href="#attr_ba_CoopGameActivity__teamtype">teamtype</a></h5>
<dl> <dl>
<dt><h4><a name="attr_ba_CoopGameActivity__expired">expired</a></h4></dt><dd> <dt><h4><a name="attr_ba_CoopGameActivity__expired">expired</a></h4></dt><dd>
<p><span>bool</span></p> <p><span>bool</span></p>
@ -1551,6 +1557,12 @@ start_long_action(callback_when_done=<a href="#class_ba_ContextCall">ba.ContextC
At this point no new nodes, timers, etc should be made, At this point no new nodes, timers, etc should be made,
run, etc, and the activity should be considered a 'zombie'.</p> run, etc, and the activity should be considered a 'zombie'.</p>
</dd>
<dt><h4><a name="attr_ba_CoopGameActivity__globalsnode">globalsnode</a></h4></dt><dd>
<p><span><a href="#class_ba_Node">ba.Node</a></span></p>
<p>The 'globals' <a href="#class_ba_Node">ba.Node</a> for the activity. This contains various
global controls and values.</p>
</dd> </dd>
<dt><h4><a name="attr_ba_CoopGameActivity__map">map</a></h4></dt><dd> <dt><h4><a name="attr_ba_CoopGameActivity__map">map</a></h4></dt><dd>
<p><span><a href="#class_ba_Map">ba.Map</a></span></p> <p><span><a href="#class_ba_Map">ba.Map</a></span></p>
@ -1660,12 +1672,18 @@ and it should begin its actual game logic.</p>
<h3>Attributes Inherited:</h3> <h3>Attributes Inherited:</h3>
<h5><a href="#attr_ba_Session__allow_mid_activity_joins">allow_mid_activity_joins</a>, <a href="#attr_ba_Session__lobby">lobby</a>, <a href="#attr_ba_Session__max_players">max_players</a>, <a href="#attr_ba_Session__min_players">min_players</a>, <a href="#attr_ba_Session__players">players</a>, <a href="#attr_ba_Session__teams">teams</a>, <a href="#attr_ba_Session__use_team_colors">use_team_colors</a>, <a href="#attr_ba_Session__use_teams">use_teams</a></h5> <h5><a href="#attr_ba_Session__allow_mid_activity_joins">allow_mid_activity_joins</a>, <a href="#attr_ba_Session__lobby">lobby</a>, <a href="#attr_ba_Session__max_players">max_players</a>, <a href="#attr_ba_Session__min_players">min_players</a>, <a href="#attr_ba_Session__players">players</a>, <a href="#attr_ba_Session__teams">teams</a>, <a href="#attr_ba_Session__use_team_colors">use_team_colors</a>, <a href="#attr_ba_Session__use_teams">use_teams</a></h5>
<h3>Attributes Defined Here:</h3> <h3>Attributes Defined Here:</h3>
<h5><a href="#attr_ba_CoopSession__campaign">campaign</a>, <a href="#attr_ba_CoopSession__sessionglobalsnode">sessionglobalsnode</a></h5>
<dl> <dl>
<dt><h4><a name="attr_ba_CoopSession__campaign">campaign</a></h4></dt><dd> <dt><h4><a name="attr_ba_CoopSession__campaign">campaign</a></h4></dt><dd>
<p><span>Optional[<a href="#class_ba_Campaign">ba.Campaign</a>]</span></p> <p><span>Optional[<a href="#class_ba_Campaign">ba.Campaign</a>]</span></p>
<p>The <a href="#class_ba_Campaign">ba.Campaign</a> instance this Session represents, or None if <p>The <a href="#class_ba_Campaign">ba.Campaign</a> instance this Session represents, or None if
there is no associated Campaign.</p> there is no associated Campaign.</p>
</dd>
<dt><h4><a name="attr_ba_CoopSession__sessionglobalsnode">sessionglobalsnode</a></h4></dt><dd>
<p><span><a href="#class_ba_Node">ba.Node</a></span></p>
<p>The sessionglobals <a href="#class_ba_Node">ba.Node</a> for the session.</p>
</dd> </dd>
</dl> </dl>
<h3>Methods Inherited:</h3> <h3>Methods Inherited:</h3>
@ -2011,6 +2029,14 @@ its time with lingering corpses, sound effects, etc.</p>
<h3>Attributes Inherited:</h3> <h3>Attributes Inherited:</h3>
<h5><a href="#attr_ba_Session__allow_mid_activity_joins">allow_mid_activity_joins</a>, <a href="#attr_ba_Session__lobby">lobby</a>, <a href="#attr_ba_Session__max_players">max_players</a>, <a href="#attr_ba_Session__min_players">min_players</a>, <a href="#attr_ba_Session__players">players</a>, <a href="#attr_ba_Session__teams">teams</a>, <a href="#attr_ba_Session__use_team_colors">use_team_colors</a>, <a href="#attr_ba_Session__use_teams">use_teams</a></h5> <h5><a href="#attr_ba_Session__allow_mid_activity_joins">allow_mid_activity_joins</a>, <a href="#attr_ba_Session__lobby">lobby</a>, <a href="#attr_ba_Session__max_players">max_players</a>, <a href="#attr_ba_Session__min_players">min_players</a>, <a href="#attr_ba_Session__players">players</a>, <a href="#attr_ba_Session__teams">teams</a>, <a href="#attr_ba_Session__use_team_colors">use_team_colors</a>, <a href="#attr_ba_Session__use_teams">use_teams</a></h5>
<h3>Attributes Defined Here:</h3>
<dl>
<dt><h4><a name="attr_ba_DualTeamSession__sessionglobalsnode">sessionglobalsnode</a></h4></dt><dd>
<p><span><a href="#class_ba_Node">ba.Node</a></span></p>
<p>The sessionglobals <a href="#class_ba_Node">ba.Node</a> for the session.</p>
</dd>
</dl>
<h3>Methods Inherited:</h3> <h3>Methods Inherited:</h3>
<h5><a href="#method_ba_MultiTeamSession__announce_game_results">announce_game_results()</a>, <a href="#method_ba_MultiTeamSession__begin_next_activity">begin_next_activity()</a>, <a href="#method_ba_MultiTeamSession__end">end()</a>, <a href="#method_ba_MultiTeamSession__end_activity">end_activity()</a>, <a href="#method_ba_MultiTeamSession__get_custom_menu_entries">get_custom_menu_entries()</a>, <a href="#method_ba_MultiTeamSession__get_ffa_series_length">get_ffa_series_length()</a>, <a href="#method_ba_MultiTeamSession__get_game_number">get_game_number()</a>, <a href="#method_ba_MultiTeamSession__get_max_players">get_max_players()</a>, <a href="#method_ba_MultiTeamSession__get_next_game_description">get_next_game_description()</a>, <a href="#method_ba_MultiTeamSession__get_series_length">get_series_length()</a>, <a href="#method_ba_MultiTeamSession__getactivity">getactivity()</a>, <a href="#method_ba_MultiTeamSession__handlemessage">handlemessage()</a>, <a href="#method_ba_MultiTeamSession__launch_end_session_activity">launch_end_session_activity()</a>, <a href="#method_ba_MultiTeamSession__on_activity_end">on_activity_end()</a>, <a href="#method_ba_MultiTeamSession__on_player_leave">on_player_leave()</a>, <a href="#method_ba_MultiTeamSession__on_player_request">on_player_request()</a>, <a href="#method_ba_MultiTeamSession__on_team_join">on_team_join()</a>, <a href="#method_ba_MultiTeamSession__on_team_leave">on_team_leave()</a>, <a href="#method_ba_MultiTeamSession__set_activity">set_activity()</a>, <a href="#method_ba_MultiTeamSession__transitioning_out_activity_was_freed">transitioning_out_activity_was_freed()</a></h5> <h5><a href="#method_ba_MultiTeamSession__announce_game_results">announce_game_results()</a>, <a href="#method_ba_MultiTeamSession__begin_next_activity">begin_next_activity()</a>, <a href="#method_ba_MultiTeamSession__end">end()</a>, <a href="#method_ba_MultiTeamSession__end_activity">end_activity()</a>, <a href="#method_ba_MultiTeamSession__get_custom_menu_entries">get_custom_menu_entries()</a>, <a href="#method_ba_MultiTeamSession__get_ffa_series_length">get_ffa_series_length()</a>, <a href="#method_ba_MultiTeamSession__get_game_number">get_game_number()</a>, <a href="#method_ba_MultiTeamSession__get_max_players">get_max_players()</a>, <a href="#method_ba_MultiTeamSession__get_next_game_description">get_next_game_description()</a>, <a href="#method_ba_MultiTeamSession__get_series_length">get_series_length()</a>, <a href="#method_ba_MultiTeamSession__getactivity">getactivity()</a>, <a href="#method_ba_MultiTeamSession__handlemessage">handlemessage()</a>, <a href="#method_ba_MultiTeamSession__launch_end_session_activity">launch_end_session_activity()</a>, <a href="#method_ba_MultiTeamSession__on_activity_end">on_activity_end()</a>, <a href="#method_ba_MultiTeamSession__on_player_leave">on_player_leave()</a>, <a href="#method_ba_MultiTeamSession__on_player_request">on_player_request()</a>, <a href="#method_ba_MultiTeamSession__on_team_join">on_team_join()</a>, <a href="#method_ba_MultiTeamSession__on_team_leave">on_team_leave()</a>, <a href="#method_ba_MultiTeamSession__set_activity">set_activity()</a>, <a href="#method_ba_MultiTeamSession__transitioning_out_activity_was_freed">transitioning_out_activity_was_freed()</a></h5>
<h3>Methods Defined or Overridden:</h3> <h3>Methods Defined or Overridden:</h3>
@ -2049,6 +2075,14 @@ its time with lingering corpses, sound effects, etc.</p>
<h3>Attributes Inherited:</h3> <h3>Attributes Inherited:</h3>
<h5><a href="#attr_ba_Session__allow_mid_activity_joins">allow_mid_activity_joins</a>, <a href="#attr_ba_Session__lobby">lobby</a>, <a href="#attr_ba_Session__max_players">max_players</a>, <a href="#attr_ba_Session__min_players">min_players</a>, <a href="#attr_ba_Session__players">players</a>, <a href="#attr_ba_Session__teams">teams</a>, <a href="#attr_ba_Session__use_team_colors">use_team_colors</a>, <a href="#attr_ba_Session__use_teams">use_teams</a></h5> <h5><a href="#attr_ba_Session__allow_mid_activity_joins">allow_mid_activity_joins</a>, <a href="#attr_ba_Session__lobby">lobby</a>, <a href="#attr_ba_Session__max_players">max_players</a>, <a href="#attr_ba_Session__min_players">min_players</a>, <a href="#attr_ba_Session__players">players</a>, <a href="#attr_ba_Session__teams">teams</a>, <a href="#attr_ba_Session__use_team_colors">use_team_colors</a>, <a href="#attr_ba_Session__use_teams">use_teams</a></h5>
<h3>Attributes Defined Here:</h3>
<dl>
<dt><h4><a name="attr_ba_FreeForAllSession__sessionglobalsnode">sessionglobalsnode</a></h4></dt><dd>
<p><span><a href="#class_ba_Node">ba.Node</a></span></p>
<p>The sessionglobals <a href="#class_ba_Node">ba.Node</a> for the session.</p>
</dd>
</dl>
<h3>Methods Inherited:</h3> <h3>Methods Inherited:</h3>
<h5><a href="#method_ba_MultiTeamSession__announce_game_results">announce_game_results()</a>, <a href="#method_ba_MultiTeamSession__begin_next_activity">begin_next_activity()</a>, <a href="#method_ba_MultiTeamSession__end">end()</a>, <a href="#method_ba_MultiTeamSession__end_activity">end_activity()</a>, <a href="#method_ba_MultiTeamSession__get_custom_menu_entries">get_custom_menu_entries()</a>, <a href="#method_ba_MultiTeamSession__get_ffa_series_length">get_ffa_series_length()</a>, <a href="#method_ba_MultiTeamSession__get_game_number">get_game_number()</a>, <a href="#method_ba_MultiTeamSession__get_max_players">get_max_players()</a>, <a href="#method_ba_MultiTeamSession__get_next_game_description">get_next_game_description()</a>, <a href="#method_ba_MultiTeamSession__get_series_length">get_series_length()</a>, <a href="#method_ba_MultiTeamSession__getactivity">getactivity()</a>, <a href="#method_ba_MultiTeamSession__handlemessage">handlemessage()</a>, <a href="#method_ba_MultiTeamSession__launch_end_session_activity">launch_end_session_activity()</a>, <a href="#method_ba_MultiTeamSession__on_activity_end">on_activity_end()</a>, <a href="#method_ba_MultiTeamSession__on_player_leave">on_player_leave()</a>, <a href="#method_ba_MultiTeamSession__on_player_request">on_player_request()</a>, <a href="#method_ba_MultiTeamSession__on_team_join">on_team_join()</a>, <a href="#method_ba_MultiTeamSession__on_team_leave">on_team_leave()</a>, <a href="#method_ba_MultiTeamSession__set_activity">set_activity()</a>, <a href="#method_ba_MultiTeamSession__transitioning_out_activity_was_freed">transitioning_out_activity_was_freed()</a></h5> <h5><a href="#method_ba_MultiTeamSession__announce_game_results">announce_game_results()</a>, <a href="#method_ba_MultiTeamSession__begin_next_activity">begin_next_activity()</a>, <a href="#method_ba_MultiTeamSession__end">end()</a>, <a href="#method_ba_MultiTeamSession__end_activity">end_activity()</a>, <a href="#method_ba_MultiTeamSession__get_custom_menu_entries">get_custom_menu_entries()</a>, <a href="#method_ba_MultiTeamSession__get_ffa_series_length">get_ffa_series_length()</a>, <a href="#method_ba_MultiTeamSession__get_game_number">get_game_number()</a>, <a href="#method_ba_MultiTeamSession__get_max_players">get_max_players()</a>, <a href="#method_ba_MultiTeamSession__get_next_game_description">get_next_game_description()</a>, <a href="#method_ba_MultiTeamSession__get_series_length">get_series_length()</a>, <a href="#method_ba_MultiTeamSession__getactivity">getactivity()</a>, <a href="#method_ba_MultiTeamSession__handlemessage">handlemessage()</a>, <a href="#method_ba_MultiTeamSession__launch_end_session_activity">launch_end_session_activity()</a>, <a href="#method_ba_MultiTeamSession__on_activity_end">on_activity_end()</a>, <a href="#method_ba_MultiTeamSession__on_player_leave">on_player_leave()</a>, <a href="#method_ba_MultiTeamSession__on_player_request">on_player_request()</a>, <a href="#method_ba_MultiTeamSession__on_team_join">on_team_join()</a>, <a href="#method_ba_MultiTeamSession__on_team_leave">on_team_leave()</a>, <a href="#method_ba_MultiTeamSession__set_activity">set_activity()</a>, <a href="#method_ba_MultiTeamSession__transitioning_out_activity_was_freed">transitioning_out_activity_was_freed()</a></h5>
<h3>Methods Defined or Overridden:</h3> <h3>Methods Defined or Overridden:</h3>
@ -2098,7 +2132,7 @@ its time with lingering corpses, sound effects, etc.</p>
<h3>Attributes Inherited:</h3> <h3>Attributes Inherited:</h3>
<h5><a href="#attr_ba_Activity__players">players</a>, <a href="#attr_ba_Activity__settings_raw">settings_raw</a>, <a href="#attr_ba_Activity__teams">teams</a></h5> <h5><a href="#attr_ba_Activity__players">players</a>, <a href="#attr_ba_Activity__settings_raw">settings_raw</a>, <a href="#attr_ba_Activity__teams">teams</a></h5>
<h3>Attributes Defined Here:</h3> <h3>Attributes Defined Here:</h3>
<h5><a href="#attr_ba_GameActivity__expired">expired</a>, <a href="#attr_ba_GameActivity__map">map</a>, <a href="#attr_ba_GameActivity__playertype">playertype</a>, <a href="#attr_ba_GameActivity__session">session</a>, <a href="#attr_ba_GameActivity__stats">stats</a>, <a href="#attr_ba_GameActivity__teamtype">teamtype</a></h5> <h5><a href="#attr_ba_GameActivity__expired">expired</a>, <a href="#attr_ba_GameActivity__globalsnode">globalsnode</a>, <a href="#attr_ba_GameActivity__map">map</a>, <a href="#attr_ba_GameActivity__playertype">playertype</a>, <a href="#attr_ba_GameActivity__session">session</a>, <a href="#attr_ba_GameActivity__stats">stats</a>, <a href="#attr_ba_GameActivity__teamtype">teamtype</a></h5>
<dl> <dl>
<dt><h4><a name="attr_ba_GameActivity__expired">expired</a></h4></dt><dd> <dt><h4><a name="attr_ba_GameActivity__expired">expired</a></h4></dt><dd>
<p><span>bool</span></p> <p><span>bool</span></p>
@ -2108,6 +2142,12 @@ its time with lingering corpses, sound effects, etc.</p>
At this point no new nodes, timers, etc should be made, At this point no new nodes, timers, etc should be made,
run, etc, and the activity should be considered a 'zombie'.</p> run, etc, and the activity should be considered a 'zombie'.</p>
</dd>
<dt><h4><a name="attr_ba_GameActivity__globalsnode">globalsnode</a></h4></dt><dd>
<p><span><a href="#class_ba_Node">ba.Node</a></span></p>
<p>The 'globals' <a href="#class_ba_Node">ba.Node</a> for the activity. This contains various
global controls and values.</p>
</dd> </dd>
<dt><h4><a name="attr_ba_GameActivity__map">map</a></h4></dt><dd> <dt><h4><a name="attr_ba_GameActivity__map">map</a></h4></dt><dd>
<p><span><a href="#class_ba_Map">ba.Map</a></span></p> <p><span><a href="#class_ba_Map">ba.Map</a></span></p>
@ -3299,7 +3339,7 @@ m.add_actions(actions=(('modify_part_collision', 'physical', False),
<pre><span><em><small># example 3: play some sounds when we're contacting the ground:</small></em></span> <pre><span><em><small># example 3: play some sounds when we're contacting the ground:</small></em></span>
m = <a href="#class_ba_Material">ba.Material</a>() m = <a href="#class_ba_Material">ba.Material</a>()
m.add_actions(conditions=('they_have_material', m.add_actions(conditions=('they_have_material',
<a href="#function_ba_sharedobj">ba.sharedobj</a>('footing_material')), shared.footing_material),
actions=(('impact_sound', <a href="#function_ba_getsound">ba.getsound</a>('metalHit'), 2, 5), actions=(('impact_sound', <a href="#function_ba_getsound">ba.getsound</a>('metalHit'), 2, 5),
('skid_sound', <a href="#function_ba_getsound">ba.getsound</a>('metalSkid'), 2, 5)))</pre> ('skid_sound', <a href="#function_ba_getsound">ba.getsound</a>('metalSkid'), 2, 5)))</pre>
@ -3329,6 +3369,14 @@ Use <a href="#function_ba_getmodel">ba.getmodel</a>() to instantiate one.</p>
<h3>Attributes Inherited:</h3> <h3>Attributes Inherited:</h3>
<h5><a href="#attr_ba_Session__allow_mid_activity_joins">allow_mid_activity_joins</a>, <a href="#attr_ba_Session__lobby">lobby</a>, <a href="#attr_ba_Session__max_players">max_players</a>, <a href="#attr_ba_Session__min_players">min_players</a>, <a href="#attr_ba_Session__players">players</a>, <a href="#attr_ba_Session__teams">teams</a>, <a href="#attr_ba_Session__use_team_colors">use_team_colors</a>, <a href="#attr_ba_Session__use_teams">use_teams</a></h5> <h5><a href="#attr_ba_Session__allow_mid_activity_joins">allow_mid_activity_joins</a>, <a href="#attr_ba_Session__lobby">lobby</a>, <a href="#attr_ba_Session__max_players">max_players</a>, <a href="#attr_ba_Session__min_players">min_players</a>, <a href="#attr_ba_Session__players">players</a>, <a href="#attr_ba_Session__teams">teams</a>, <a href="#attr_ba_Session__use_team_colors">use_team_colors</a>, <a href="#attr_ba_Session__use_teams">use_teams</a></h5>
<h3>Attributes Defined Here:</h3>
<dl>
<dt><h4><a name="attr_ba_MultiTeamSession__sessionglobalsnode">sessionglobalsnode</a></h4></dt><dd>
<p><span><a href="#class_ba_Node">ba.Node</a></span></p>
<p>The sessionglobals <a href="#class_ba_Node">ba.Node</a> for the session.</p>
</dd>
</dl>
<h3>Methods Inherited:</h3> <h3>Methods Inherited:</h3>
<h5><a href="#method_ba_Session__begin_next_activity">begin_next_activity()</a>, <a href="#method_ba_Session__end">end()</a>, <a href="#method_ba_Session__end_activity">end_activity()</a>, <a href="#method_ba_Session__get_custom_menu_entries">get_custom_menu_entries()</a>, <a href="#method_ba_Session__getactivity">getactivity()</a>, <a href="#method_ba_Session__handlemessage">handlemessage()</a>, <a href="#method_ba_Session__launch_end_session_activity">launch_end_session_activity()</a>, <a href="#method_ba_Session__on_player_leave">on_player_leave()</a>, <a href="#method_ba_Session__on_player_request">on_player_request()</a>, <a href="#method_ba_Session__on_team_leave">on_team_leave()</a>, <a href="#method_ba_Session__set_activity">set_activity()</a>, <a href="#method_ba_Session__transitioning_out_activity_was_freed">transitioning_out_activity_was_freed()</a></h5> <h5><a href="#method_ba_Session__begin_next_activity">begin_next_activity()</a>, <a href="#method_ba_Session__end">end()</a>, <a href="#method_ba_Session__end_activity">end_activity()</a>, <a href="#method_ba_Session__get_custom_menu_entries">get_custom_menu_entries()</a>, <a href="#method_ba_Session__getactivity">getactivity()</a>, <a href="#method_ba_Session__handlemessage">handlemessage()</a>, <a href="#method_ba_Session__launch_end_session_activity">launch_end_session_activity()</a>, <a href="#method_ba_Session__on_player_leave">on_player_leave()</a>, <a href="#method_ba_Session__on_player_request">on_player_request()</a>, <a href="#method_ba_Session__on_team_leave">on_team_leave()</a>, <a href="#method_ba_Session__set_activity">set_activity()</a>, <a href="#method_ba_Session__transitioning_out_activity_was_freed">transitioning_out_activity_was_freed()</a></h5>
<h3>Methods Defined or Overridden:</h3> <h3>Methods Defined or Overridden:</h3>
@ -4272,7 +4320,7 @@ Pass 0 or a negative number for no ban time.</p>
maintaining state between them (players, teams, score tallies, etc).</p> maintaining state between them (players, teams, score tallies, etc).</p>
<h3>Attributes:</h3> <h3>Attributes:</h3>
<h5><a href="#attr_ba_Session__allow_mid_activity_joins">allow_mid_activity_joins</a>, <a href="#attr_ba_Session__lobby">lobby</a>, <a href="#attr_ba_Session__max_players">max_players</a>, <a href="#attr_ba_Session__min_players">min_players</a>, <a href="#attr_ba_Session__players">players</a>, <a href="#attr_ba_Session__teams">teams</a>, <a href="#attr_ba_Session__use_team_colors">use_team_colors</a>, <a href="#attr_ba_Session__use_teams">use_teams</a></h5> <h5><a href="#attr_ba_Session__allow_mid_activity_joins">allow_mid_activity_joins</a>, <a href="#attr_ba_Session__lobby">lobby</a>, <a href="#attr_ba_Session__max_players">max_players</a>, <a href="#attr_ba_Session__min_players">min_players</a>, <a href="#attr_ba_Session__players">players</a>, <a href="#attr_ba_Session__sessionglobalsnode">sessionglobalsnode</a>, <a href="#attr_ba_Session__teams">teams</a>, <a href="#attr_ba_Session__use_team_colors">use_team_colors</a>, <a href="#attr_ba_Session__use_teams">use_teams</a></h5>
<dl> <dl>
<dt><h4><a name="attr_ba_Session__allow_mid_activity_joins">allow_mid_activity_joins</a></h4></dt><dd> <dt><h4><a name="attr_ba_Session__allow_mid_activity_joins">allow_mid_activity_joins</a></h4></dt><dd>
<p><span>bool</span></p> <p><span>bool</span></p>
@ -4305,6 +4353,11 @@ to proceed past the initial joining screen.</p>
list in <a href="#class_ba_Activity">ba.Activity</a>; not this. Some players, such as those who have list in <a href="#class_ba_Activity">ba.Activity</a>; not this. Some players, such as those who have
not yet selected a character, will only appear on this list.</p> not yet selected a character, will only appear on this list.</p>
</dd>
<dt><h4><a name="attr_ba_Session__sessionglobalsnode">sessionglobalsnode</a></h4></dt><dd>
<p><span><a href="#class_ba_Node">ba.Node</a></span></p>
<p>The sessionglobals <a href="#class_ba_Node">ba.Node</a> for the session.</p>
</dd> </dd>
<dt><h4><a name="attr_ba_Session__teams">teams</a></h4></dt><dd> <dt><h4><a name="attr_ba_Session__teams">teams</a></h4></dt><dd>
<p><span>List[<a href="#class_ba_SessionTeam">ba.SessionTeam</a>]</span></p> <p><span>List[<a href="#class_ba_SessionTeam">ba.SessionTeam</a>]</span></p>
@ -4812,6 +4865,22 @@ of the session.</p>
<li>MIKIROG</li> <li>MIKIROG</li>
</ul> </ul>
<hr> <hr>
<h2><strong><a name="class_ba_StandLocation">ba.StandLocation</a></strong></h3>
<p><em>&lt;top level class&gt;</em>
</p>
<p>Describes a point in space and an angle to face.</p>
<p>Category: <a href="#class_category_Gameplay_Classes">Gameplay Classes</a>
</p>
<h3>Methods:</h3>
<dl>
<dt><h4><a name="method_ba_StandLocation____init__">&lt;constructor&gt;</a></dt></h4><dd>
<p><span>ba.StandLocation(position: _<a href="#class_ba_Vec3">ba.Vec3</a>, angle: Optional[float] = None)</span></p>
</dd>
</dl>
<hr>
<h2><strong><a name="class_ba_StandMessage">ba.StandMessage</a></strong></h3> <h2><strong><a name="class_ba_StandMessage">ba.StandMessage</a></strong></h3>
<p><em>&lt;top level class&gt;</em> <p><em>&lt;top level class&gt;</em>
</p> </p>
@ -4961,7 +5030,7 @@ of the session.</p>
<h3>Attributes Inherited:</h3> <h3>Attributes Inherited:</h3>
<h5><a href="#attr_ba_Activity__players">players</a>, <a href="#attr_ba_Activity__settings_raw">settings_raw</a>, <a href="#attr_ba_Activity__teams">teams</a></h5> <h5><a href="#attr_ba_Activity__players">players</a>, <a href="#attr_ba_Activity__settings_raw">settings_raw</a>, <a href="#attr_ba_Activity__teams">teams</a></h5>
<h3>Attributes Defined Here:</h3> <h3>Attributes Defined Here:</h3>
<h5><a href="#attr_ba_TeamGameActivity__expired">expired</a>, <a href="#attr_ba_TeamGameActivity__map">map</a>, <a href="#attr_ba_TeamGameActivity__playertype">playertype</a>, <a href="#attr_ba_TeamGameActivity__session">session</a>, <a href="#attr_ba_TeamGameActivity__stats">stats</a>, <a href="#attr_ba_TeamGameActivity__teamtype">teamtype</a></h5> <h5><a href="#attr_ba_TeamGameActivity__expired">expired</a>, <a href="#attr_ba_TeamGameActivity__globalsnode">globalsnode</a>, <a href="#attr_ba_TeamGameActivity__map">map</a>, <a href="#attr_ba_TeamGameActivity__playertype">playertype</a>, <a href="#attr_ba_TeamGameActivity__session">session</a>, <a href="#attr_ba_TeamGameActivity__stats">stats</a>, <a href="#attr_ba_TeamGameActivity__teamtype">teamtype</a></h5>
<dl> <dl>
<dt><h4><a name="attr_ba_TeamGameActivity__expired">expired</a></h4></dt><dd> <dt><h4><a name="attr_ba_TeamGameActivity__expired">expired</a></h4></dt><dd>
<p><span>bool</span></p> <p><span>bool</span></p>
@ -4971,6 +5040,12 @@ of the session.</p>
At this point no new nodes, timers, etc should be made, At this point no new nodes, timers, etc should be made,
run, etc, and the activity should be considered a 'zombie'.</p> run, etc, and the activity should be considered a 'zombie'.</p>
</dd>
<dt><h4><a name="attr_ba_TeamGameActivity__globalsnode">globalsnode</a></h4></dt><dd>
<p><span><a href="#class_ba_Node">ba.Node</a></span></p>
<p>The 'globals' <a href="#class_ba_Node">ba.Node</a> for the activity. This contains various
global controls and values.</p>
</dd> </dd>
<dt><h4><a name="attr_ba_TeamGameActivity__map">map</a></h4></dt><dd> <dt><h4><a name="attr_ba_TeamGameActivity__map">map</a></h4></dt><dd>
<p><span><a href="#class_ba_Map">ba.Map</a></span></p> <p><span><a href="#class_ba_Map">ba.Map</a></span></p>
@ -6303,54 +6378,6 @@ user can override particular game music with their own.</p>
<p>if 'continuous' is True and musictype is the same as what is already <p>if 'continuous' is True and musictype is the same as what is already
playing, the playing track will not be restarted.</p> playing, the playing track will not be restarted.</p>
<hr>
<h2><strong><a name="function_ba_sharedobj">ba.sharedobj()</a></strong></h3>
<p><span>sharedobj(name: str) -&gt; Any</span></p>
<p>Return a predefined object for the current Activity, creating if needed.</p>
<p>Category: <a href="#function_category_Gameplay_Functions">Gameplay Functions</a></p>
<p>Available values for 'name':</p>
<p>'globals': returns the 'globals' <a href="#class_ba_Node">ba.Node</a>, containing various global
controls & values.</p>
<p>'object_material': a <a href="#class_ba_Material">ba.Material</a> that should be applied to any small,
normal, physical objects such as bombs, boxes, players, etc. Other
materials often check for the presence of this material as a
prerequisite for performing certain actions (such as disabling collisions
between initially-overlapping objects)</p>
<p>'player_material': a <a href="#class_ba_Material">ba.Material</a> to be applied to player parts. Generally,
materials related to the process of scoring when reaching a goal, etc
will look for the presence of this material on things that hit them.</p>
<p>'pickup_material': a <a href="#class_ba_Material">ba.Material</a>; collision shapes used for picking things
up will have this material applied. To prevent an object from being
picked up, you can add a material that disables collisions against things
containing this material.</p>
<p>'footing_material': anything that can be 'walked on' should have this
<a href="#class_ba_Material">ba.Material</a> applied; generally just terrain and whatnot. A character will
snap upright whenever touching something with this material so it should
not be applied to props, etc.</p>
<p>'attack_material': a <a href="#class_ba_Material">ba.Material</a> applied to explosion shapes, punch
shapes, etc. An object not wanting to receive impulse/etc messages can
disable collisions against this material.</p>
<p>'death_material': a <a href="#class_ba_Material">ba.Material</a> that sends a <a href="#class_ba_DieMessage">ba.DieMessage</a>() to anything
that touches it; handy for terrain below a cliff, etc.</p>
<p>'region_material': a <a href="#class_ba_Material">ba.Material</a> used for non-physical collision shapes
(regions); collisions can generally be allowed with this material even
when initially overlapping since it is not physical.</p>
<p>'railing_material': a <a href="#class_ba_Material">ba.Material</a> with a very low friction/stiffness/etc
that can be applied to invisible 'railings' useful for gently keeping
characters from falling off of cliffs.</p>
<hr> <hr>
<h2><strong><a name="function_ba_show_damage_count">ba.show_damage_count()</a></strong></h3> <h2><strong><a name="function_ba_show_damage_count">ba.show_damage_count()</a></strong></h3>
<p><span>show_damage_count(damage: str, position: Sequence[float], direction: Sequence[float]) -&gt; None</span></p> <p><span>show_damage_count(damage: str, position: Sequence[float], direction: Sequence[float]) -&gt; None</span></p>