Merge pull request #365 from Dliwk/docs-generation

Docs generation with pdoc
This commit is contained in:
Eric Froemling 2022-03-19 18:33:13 -05:00 committed by GitHub
commit d9d71f3b8d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
81 changed files with 1827 additions and 3900 deletions

View File

@ -3,7 +3,11 @@
<words> <words>
<w>gamename</w> <w>gamename</w>
<w>maxlen</w> <w>maxlen</w>
<w>outdirname</w>
<w>pagename</w> <w>pagename</w>
<w>pythondir</w>
<w>templatesdir</w>
<w>unhashable</w>
</words> </words>
</dictionary> </dictionary>
</component> </component>

View File

@ -69,8 +69,8 @@
<inspection_tool class="PyTypeCheckerInspection" enabled="false" level="WARNING" enabled_by_default="false" /> <inspection_tool class="PyTypeCheckerInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="PyTypeHintsInspection" enabled="false" level="WARNING" enabled_by_default="false" /> <inspection_tool class="PyTypeHintsInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="PyUnreachableCodeInspection" enabled="false" level="WARNING" enabled_by_default="false" /> <inspection_tool class="PyUnreachableCodeInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="PyUnresolvedReferencesInspection" enabled="true" level="WARNING" enabled_by_default="false"> <inspection_tool class="PyUnresolvedReferencesInspection" enabled="true" level="WARNING" enabled_by_default="true">
<scope name="PyIgnoreUnresolved" level="WARNING" enabled="false"> <scope name="PyIgnoreUnresolved" level="WARNING" enabled="true">
<option name="ignoredIdentifiers"> <option name="ignoredIdentifiers">
<list> <list>
<option value="astroid.node_classes.NodeNG.*" /> <option value="astroid.node_classes.NodeNG.*" />
@ -84,7 +84,7 @@
</list> </list>
</option> </option>
</scope> </scope>
<scope name="UncheckedPython" level="WARNING" enabled="false"> <scope name="UncheckedPython" level="WARNING" enabled="true">
<option name="ignoredIdentifiers"> <option name="ignoredIdentifiers">
<list> <list>
<option value="astroid.node_classes.NodeNG.*" /> <option value="astroid.node_classes.NodeNG.*" />

View File

@ -1 +1 @@
128050019134230065776415771561414927503 263249044076897294312459199917994463006

File diff suppressed because it is too large Load Diff

View File

@ -18,7 +18,7 @@ from _ba import (
newnode, playsound, printnodes, printobjects, pushcall, quit, rowwidget, newnode, playsound, printnodes, printobjects, pushcall, quit, rowwidget,
safecolor, screenmessage, scrollwidget, set_analytics_screen, charstr, safecolor, screenmessage, scrollwidget, set_analytics_screen, charstr,
textwidget, time, timer, open_url, widget, clipboard_is_supported, textwidget, time, timer, open_url, widget, clipboard_is_supported,
clipboard_has_text, clipboard_get_text, clipboard_set_text) clipboard_has_text, clipboard_get_text, clipboard_set_text, getdata)
from ba._activity import Activity from ba._activity import Activity
from ba._plugin import PotentialPlugin, Plugin, PluginSubsystem from ba._plugin import PotentialPlugin, Plugin, PluginSubsystem
from ba._actor import Actor from ba._actor import Actor
@ -81,15 +81,26 @@ from ba._collision import Collision, getcollision
app: App app: App
__all__: list[str] = []
# Have these things present themselves cleanly as 'ba.Foo' # Have these things present themselves cleanly as 'ba.Foo'
# instead of 'ba._submodule.Foo' # instead of 'ba._submodule.Foo'
def _simplify_module_names() -> None: def _simplify_module_names() -> None:
from efro.util import set_canonical_module import os
globs = globals()
set_canonical_module( for attr, _obj in globals().items():
module_globals=globs, if not attr.startswith('_'):
names=[n for n in globs.keys() if not n.startswith('_')]) __all__.append(attr)
# Though pdoc gets confused when we override __module__,
# so let's make an exception for it.
if os.environ.get('BA_DOCS_GENERATION', '0') != '1':
from efro.util import set_canonical_module
globs = globals()
set_canonical_module(
module_globals=globs,
names=[n for n in globs.keys() if not n.startswith('_')])
_simplify_module_names() _simplify_module_names()

View File

@ -18,7 +18,7 @@ if TYPE_CHECKING:
class AccountSubsystem: class AccountSubsystem:
"""Subsystem for account handling in the app. """Subsystem for account handling in the app.
Category: App Classes Category: **App Classes**
Access the single shared instance of this class at 'ba.app.plugins'. Access the single shared instance of this class at 'ba.app.plugins'.
""" """

View File

@ -65,7 +65,7 @@ ACH_LEVEL_NAMES = {
class AchievementSubsystem: class AchievementSubsystem:
"""Subsystem for achievement handling. """Subsystem for achievement handling.
Category: App Classes Category: **App Classes**
Access the single shared instance of this class at 'ba.app.ach'. Access the single shared instance of this class at 'ba.app.ach'.
""" """
@ -436,7 +436,7 @@ def _display_next_achievement() -> None:
class Achievement: class Achievement:
"""Represents attributes and state for an individual achievement. """Represents attributes and state for an individual achievement.
Category: App Classes Category: **App Classes**
""" """
def __init__(self, def __init__(self,

View File

@ -32,104 +32,97 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]):
Examples of Activities include games, score-screens, cutscenes, etc. Examples of Activities include games, score-screens, cutscenes, etc.
A ba.Session has one 'current' Activity at any time, though their existence A ba.Session has one 'current' Activity at any time, though their existence
can overlap during transitions. can overlap during transitions.
Attributes:
settings_raw
The settings dict passed in when the activity was made.
This attribute is deprecated and should be avoided when possible;
activities should pull all values they need from the 'settings' arg
passed to the Activity __init__ call.
teams
The list of ba.Teams in the Activity. This gets populated just before
before on_begin() is called and is updated automatically as players
join or leave the game. (at least in free-for-all mode where every
player gets their own team; in teams mode there are always 2 teams
regardless of the player count).
players
The list of ba.Players in the Activity. This gets populated just
before on_begin() is called and is updated automatically as players
join or leave the game.
""" """
# pylint: disable=too-many-public-methods # pylint: disable=too-many-public-methods
# Annotating attr types at the class level lets us introspect at runtime.
settings_raw: dict[str, Any] settings_raw: dict[str, Any]
"""The settings dict passed in when the activity was made.
This attribute is deprecated and should be avoided when possible;
activities should pull all values they need from the 'settings' arg
passed to the Activity __init__ call."""
teams: list[TeamType] teams: list[TeamType]
"""The list of ba.Team-s in the Activity. This gets populated just
before on_begin() is called and is updated automatically as players
join or leave the game. (at least in free-for-all mode where every
player gets their own team; in teams mode there are always 2 teams
regardless of the player count)."""
players: list[PlayerType] players: list[PlayerType]
"""The list of ba.Player-s in the Activity. This gets populated just
before on_begin() is called and is updated automatically as players
join or leave the game."""
# Whether to print every time a player dies. This can be pertinent
# in games such as Death-Match but can be annoying in games where it
# doesn't matter.
announce_player_deaths = False announce_player_deaths = False
"""Whether to print every time a player dies. This can be pertinent
in games such as Death-Match but can be annoying in games where it
doesn't matter."""
# Joining activities are for waiting for initial player joins.
# They are treated slightly differently than regular activities,
# mainly in that all players are passed to the activity at once
# instead of as each joins.
is_joining_activity = False is_joining_activity = False
"""Joining activities are for waiting for initial player joins.
They are treated slightly differently than regular activities,
mainly in that all players are passed to the activity at once
instead of as each joins."""
# Whether game-time should still progress when in menus/etc.
allow_pausing = False allow_pausing = False
"""Whether game-time should still progress when in menus/etc."""
# Whether idle players can potentially be kicked (should not happen in
# menus/etc).
allow_kick_idle_players = True allow_kick_idle_players = True
"""Whether idle players can potentially be kicked (should not happen in
menus/etc)."""
# In vr mode, this determines whether overlay nodes (text, images, etc)
# are created at a fixed position in space or one that moves based on
# the current map. Generally this should be on for games and off for
# transitions/score-screens/etc. that persist between maps.
use_fixed_vr_overlay = False use_fixed_vr_overlay = False
"""In vr mode, this determines whether overlay nodes (text, images, etc)
are created at a fixed position in space or one that moves based on
the current map. Generally this should be on for games and off for
transitions/score-screens/etc. that persist between maps."""
# If True, runs in slow motion and turns down sound pitch.
slow_motion = False slow_motion = False
"""If True, runs in slow motion and turns down sound pitch."""
# Set this to True to inherit slow motion setting from previous
# activity (useful for transitions to avoid hitches).
inherits_slow_motion = False inherits_slow_motion = False
"""Set this to True to inherit slow motion setting from previous
activity (useful for transitions to avoid hitches)."""
# Set this to True to keep playing the music from the previous activity
# (without even restarting it).
inherits_music = False inherits_music = False
"""Set this to True to keep playing the music from the previous activity
(without even restarting it)."""
# Set this to true to inherit VR camera offsets from the previous
# activity (useful for preventing sporadic camera movement
# during transitions).
inherits_vr_camera_offset = False inherits_vr_camera_offset = False
"""Set this to true to inherit VR camera offsets from the previous
activity (useful for preventing sporadic camera movement
during transitions)."""
# Set this to true to inherit (non-fixed) VR overlay positioning from
# the previous activity (useful for prevent sporadic overlay jostling
# during transitions).
inherits_vr_overlay_center = False inherits_vr_overlay_center = False
"""Set this to true to inherit (non-fixed) VR overlay positioning from
the previous activity (useful for prevent sporadic overlay jostling
during transitions)."""
# Set this to true to inherit screen tint/vignette colors from the
# previous activity (useful to prevent sudden color changes during
# transitions).
inherits_tint = False inherits_tint = False
"""Set this to true to inherit screen tint/vignette colors from the
previous activity (useful to prevent sudden color changes during
transitions)."""
# Whether players should be allowed to join in the middle of this
# activity. Note that Sessions may not allow mid-activity-joins even
# if the activity says its ok.
allow_mid_activity_joins: bool = True allow_mid_activity_joins: bool = True
"""Whether players should be allowed to join in the middle of this
activity. Note that Sessions may not allow mid-activity-joins even
if the activity says its ok."""
# If the activity fades or transitions in, it should set the length of
# time here so that previous activities will be kept alive for that
# long (avoiding 'holes' in the screen)
# This value is given in real-time seconds.
transition_time = 0.0 transition_time = 0.0
"""If the activity fades or transitions in, it should set the length of
time here so that previous activities will be kept alive for that
long (avoiding 'holes' in the screen)
This value is given in real-time seconds."""
# Is it ok to show an ad after this activity ends before showing
# the next activity?
can_show_ad_on_death = False can_show_ad_on_death = False
"""Is it ok to show an ad after this activity ends before showing
the next activity?"""
def __init__(self, settings: dict): def __init__(self, settings: dict):
"""Creates an Activity in the current ba.Session. """Creates an Activity in the current ba.Session.
The activity will not be actually run until ba.Session.setactivity() The activity will not be actually run until ba.Session.setactivity
is called. 'settings' should be a dict of key/value pairs specific is called. 'settings' should be a dict of key/value pairs specific
to the activity. to the activity.
@ -369,8 +362,8 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]):
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.
Note that this may happen at any time even if end() has not been Note that this may happen at any time even if ba.Activity.end() has
called. not been called.
""" """
def on_begin(self) -> None: def on_begin(self) -> None:
@ -386,11 +379,12 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]):
return UNHANDLED return UNHANDLED
def has_transitioned_in(self) -> bool: def has_transitioned_in(self) -> bool:
"""Return whether on_transition_in() has been called.""" """Return whether ba.Activity.on_transition_in()
has been called."""
return self._has_transitioned_in return self._has_transitioned_in
def has_begun(self) -> bool: def has_begun(self) -> bool:
"""Return whether on_begin() has been called.""" """Return whether ba.Activity.on_begin() has been called."""
return self._has_begun return self._has_begun
def has_ended(self) -> bool: def has_ended(self) -> bool:
@ -398,7 +392,7 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]):
return self._has_ended return self._has_ended
def is_transitioning_out(self) -> bool: def is_transitioning_out(self) -> bool:
"""Return whether on_transition_out() has been called.""" """Return whether ba.Activity.on_transition_out() has been called."""
return self._transitioning_out return self._transitioning_out
def transition_in(self, prev_globals: Optional[ba.Node]) -> None: def transition_in(self, prev_globals: Optional[ba.Node]) -> None:
@ -517,8 +511,8 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]):
Subclasses can override this if the activity's player class Subclasses can override this if the activity's player class
requires a custom constructor; otherwise it will be called with requires a custom constructor; otherwise it will be called with
no args. Note that the player object should not be used at this no args. Note that the player object should not be used at this
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
for that. ba.Activity.on_player_join() for that.
""" """
del sessionplayer # Unused. del sessionplayer # Unused.
player = self._playertype() player = self._playertype()

View File

@ -21,7 +21,7 @@ TA = TypeVar('TA', bound='Actor')
class Actor: class Actor:
"""High level logical entities in a ba.Activity. """High level logical entities in a ba.Activity.
Category: Gameplay Classes Category: **Gameplay Classes**
Actors act as controllers, combining some number of ba.Nodes, Actors act as controllers, combining some number of ba.Nodes,
ba.Textures, ba.Sounds, etc. into a high-level cohesive unit. ba.Textures, ba.Sounds, etc. into a high-level cohesive unit.
@ -33,15 +33,16 @@ class Actor:
(killing off or transitioning out their nodes) when the last Python (killing off or transitioning out their nodes) when the last Python
reference to them disappears, so you can use logic such as: reference to them disappears, so you can use logic such as:
# Create a flag Actor in our game activity: ##### Example
from bastd.actor.flag import Flag >>> # Create a flag Actor in our game activity:
self.flag = Flag(position=(0, 10, 0)) ... from bastd.actor.flag import Flag
... self.flag = Flag(position=(0, 10, 0))
# Later, destroy the flag. ...
# (provided nothing else is holding a reference to it) ... # Later, destroy the flag.
# We could also just assign a new flag to this value. ... # (provided nothing else is holding a reference to it)
# Either way, the old flag disappears. ... # We could also just assign a new flag to this value.
self.flag = None ... # Either way, the old flag disappears.
... self.flag = None
This is in contrast to the behavior of the more low level ba.Nodes, This is in contrast to the behavior of the more low level ba.Nodes,
which are always explicitly created and destroyed and don't care which are always explicitly created and destroyed and don't care
@ -51,18 +52,18 @@ class Actor:
if you want an Actor to stick around until explicitly killed if you want an Actor to stick around until explicitly killed
regardless of references. regardless of references.
Another key feature of ba.Actor is its handlemessage() method, which Another key feature of ba.Actor is its ba.Actor.handlemessage() method,
takes a single arbitrary object as an argument. This provides a safe way which takes a single arbitrary object as an argument. This provides a safe
to communicate between ba.Actor, ba.Activity, ba.Session, and any other way to communicate between ba.Actor, ba.Activity, ba.Session, and any other
class providing a handlemessage() method. The most universally handled class providing a handlemessage() method. The most universally handled
message type for Actors is the ba.DieMessage. message type for Actors is the ba.DieMessage.
# Another way to kill the flag from the example above: Another way to kill the flag from the example above:
# We can safely call this on any type with a 'handlemessage' method We can safely call this on any type with a 'handlemessage' method
# (though its not guaranteed to always have a meaningful effect). (though its not guaranteed to always have a meaningful effect).
# In this case the Actor instance will still be around, but its exists() In this case the Actor instance will still be around, but its
# and is_alive() methods will both return False. ba.Actor.exists() and ba.Actor.is_alive() methods will both return False.
self.flag.handlemessage(ba.DieMessage()) >>> self.flag.handlemessage(ba.DieMessage())
""" """
def __init__(self) -> None: def __init__(self) -> None:
@ -112,7 +113,7 @@ class Actor:
return self return self
def on_expire(self) -> None: def on_expire(self) -> None:
"""Called for remaining ba.Actors when their ba.Activity shuts down. """Called for remaining `ba.Actor`s when their ba.Activity shuts down.
Actors can use this opportunity to clear callbacks or other Actors can use this opportunity to clear callbacks or other
references which have the potential of keeping the ba.Activity references which have the potential of keeping the ba.Activity

View File

@ -15,7 +15,7 @@ if TYPE_CHECKING:
class AdsSubsystem: class AdsSubsystem:
"""Subsystem for ads functionality in the app. """Subsystem for ads functionality in the app.
Category: App Classes Category: **App Classes**
Access the single shared instance of this class at 'ba.app.ads'. Access the single shared instance of this class at 'ba.app.ads'.
""" """

View File

@ -28,7 +28,7 @@ if TYPE_CHECKING:
class App: class App:
"""A class for high level app functionality and state. """A class for high level app functionality and state.
Category: App Classes Category: **App Classes**
Use ba.app to access the single shared instance of this class. Use ba.app to access the single shared instance of this class.

View File

@ -14,7 +14,7 @@ if TYPE_CHECKING:
class AppConfig(dict): class AppConfig(dict):
"""A special dict that holds the game's persistent configuration values. """A special dict that holds the game's persistent configuration values.
Category: App Classes Category: **App Classes**
It also provides methods for fetching values with app-defined fallback It also provides methods for fetching values with app-defined fallback
defaults, applying contained values to the game, and committing the defaults, applying contained values to the game, and committing the
@ -155,7 +155,7 @@ def read_config() -> tuple[AppConfig, bool]:
def commit_app_config(force: bool = False) -> None: def commit_app_config(force: bool = False) -> None:
"""Commit the config to persistent storage. """Commit the config to persistent storage.
Category: General Utility Functions Category: **General Utility Functions**
(internal) (internal)
""" """

View File

@ -23,9 +23,9 @@ def getcampaign(name: str) -> ba.Campaign:
class Campaign: class Campaign:
"""Represents a unique set or series of ba.Levels. """Represents a unique set or series of ba.Level-s.
Category: App Classes Category: **App Classes**
""" """
def __init__(self, name: str, sequential: bool = True): def __init__(self, name: str, sequential: bool = True):
@ -52,7 +52,7 @@ class Campaign:
@property @property
def levels(self) -> list[ba.Level]: def levels(self) -> list[ba.Level]:
"""The list of ba.Levels in the Campaign.""" """The list of ba.Level-s in the Campaign."""
return self._levels return self._levels
def getlevel(self, name: str) -> ba.Level: def getlevel(self, name: str) -> ba.Level:

View File

@ -16,7 +16,7 @@ if TYPE_CHECKING:
class Collision: class Collision:
"""A class providing info about occurring collisions. """A class providing info about occurring collisions.
Category: Gameplay Classes Category: **Gameplay Classes**
""" """
@property @property
@ -67,6 +67,6 @@ _collision = Collision()
def getcollision() -> Collision: def getcollision() -> Collision:
"""Return the in-progress collision. """Return the in-progress collision.
Category: Gameplay Functions Category: **Gameplay Functions**
""" """
return _collision return _collision

View File

@ -21,7 +21,7 @@ TeamType = TypeVar('TeamType', bound='ba.Team')
class CoopGameActivity(GameActivity[PlayerType, TeamType]): class CoopGameActivity(GameActivity[PlayerType, TeamType]):
"""Base class for cooperative-mode games. """Base class for cooperative-mode games.
Category: Gameplay Classes Category: **Gameplay Classes**
""" """
# We can assume our session is a CoopSession. # We can assume our session is a CoopSession.

View File

@ -19,25 +19,23 @@ TEAM_NAMES = ['Good Guys']
class CoopSession(Session): class CoopSession(Session):
"""A ba.Session which runs cooperative-mode games. """A ba.Session which runs cooperative-mode games.
Category: Gameplay Classes Category: **Gameplay Classes**
These generally consist of 1-4 players against These generally consist of 1-4 players against
the computer and include functionality such as the computer and include functionality such as
high score lists. high score lists.
Attributes:
campaign
The ba.Campaign instance this Session represents, or None if
there is no associated Campaign.
""" """
use_teams = True use_teams = True
use_team_colors = False use_team_colors = False
allow_mid_activity_joins = False allow_mid_activity_joins = False
# Note: even though these are instance vars, we annotate them at the # Note: even though these are instance vars, we annotate them at the
# class level so that docs generation can access their types. # class level so that docs generation can access their types.
campaign: Optional[ba.Campaign] campaign: Optional[ba.Campaign]
"""The ba.Campaign instance this Session represents, or None if
there is no associated Campaign."""
def __init__(self) -> None: def __init__(self) -> None:
"""Instantiate a co-op mode session.""" """Instantiate a co-op mode session."""

View File

@ -19,7 +19,7 @@ T = TypeVar('T', bound='DependencyComponent')
class Dependency(Generic[T]): class Dependency(Generic[T]):
"""A dependency on a DependencyComponent (with an optional config). """A dependency on a DependencyComponent (with an optional config).
Category: Dependency Classes Category: **Dependency Classes**
This class is used to request and access functionality provided This class is used to request and access functionality provided
by other DependencyComponent classes from a DependencyComponent class. by other DependencyComponent classes from a DependencyComponent class.
@ -87,7 +87,7 @@ class Dependency(Generic[T]):
class DependencyComponent: class DependencyComponent:
"""Base class for all classes that can act as or use dependencies. """Base class for all classes that can act as or use dependencies.
category: Dependency Classes Category: **Dependency Classes**
""" """
_dep_entry: weakref.ref[DependencyEntry] _dep_entry: weakref.ref[DependencyEntry]
@ -165,7 +165,7 @@ class DependencyEntry:
class DependencySet(Generic[T]): class DependencySet(Generic[T]):
"""Set of resolved dependencies and their associated data. """Set of resolved dependencies and their associated data.
Category: Dependency Classes Category: **Dependency Classes**
To use DependencyComponents, a set must be created, resolved, and then To use DependencyComponents, a set must be created, resolved, and then
loaded. The DependencyComponents are only valid while the set remains loaded. The DependencyComponents are only valid while the set remains
@ -291,7 +291,7 @@ class DependencySet(Generic[T]):
class AssetPackage(DependencyComponent): class AssetPackage(DependencyComponent):
"""ba.DependencyComponent representing a bundled package of game assets. """ba.DependencyComponent representing a bundled package of game assets.
Category: Asset Classes Category: **Asset Classes**
""" """
def __init__(self) -> None: def __init__(self) -> None:

View File

@ -15,7 +15,7 @@ if TYPE_CHECKING:
class DualTeamSession(MultiTeamSession): class DualTeamSession(MultiTeamSession):
"""ba.Session type for teams mode games. """ba.Session type for teams mode games.
Category: Gameplay Classes Category: **Gameplay Classes**
""" """
# Base class overrides: # Base class overrides:

View File

@ -16,7 +16,7 @@ if TYPE_CHECKING:
class DependencyError(Exception): class DependencyError(Exception):
"""Exception raised when one or more ba.Dependency items are missing. """Exception raised when one or more ba.Dependency items are missing.
category: Exception Classes Category: **Exception Classes**
(this will generally be missing assets). (this will generally be missing assets).
""" """
@ -34,7 +34,7 @@ class DependencyError(Exception):
class ContextError(Exception): class ContextError(Exception):
"""Exception raised when a call is made in an invalid context. """Exception raised when a call is made in an invalid context.
category: Exception Classes Category: **Exception Classes**
Examples of this include calling UI functions within an Activity context Examples of this include calling UI functions within an Activity context
or calling scene manipulation functions outside of a game context. or calling scene manipulation functions outside of a game context.
@ -44,91 +44,91 @@ class ContextError(Exception):
class NotFoundError(Exception): class NotFoundError(Exception):
"""Exception raised when a referenced object does not exist. """Exception raised when a referenced object does not exist.
category: Exception Classes Category: **Exception Classes**
""" """
class PlayerNotFoundError(NotFoundError): class PlayerNotFoundError(NotFoundError):
"""Exception raised when an expected ba.Player does not exist. """Exception raised when an expected ba.Player does not exist.
category: Exception Classes Category: **Exception Classes**
""" """
class SessionPlayerNotFoundError(NotFoundError): class SessionPlayerNotFoundError(NotFoundError):
"""Exception raised when an expected ba.SessionPlayer does not exist. """Exception raised when an expected ba.SessionPlayer does not exist.
category: Exception Classes Category: **Exception Classes**
""" """
class TeamNotFoundError(NotFoundError): class TeamNotFoundError(NotFoundError):
"""Exception raised when an expected ba.Team does not exist. """Exception raised when an expected ba.Team does not exist.
category: Exception Classes Category: **Exception Classes**
""" """
class DelegateNotFoundError(NotFoundError): class DelegateNotFoundError(NotFoundError):
"""Exception raised when an expected delegate object does not exist. """Exception raised when an expected delegate object does not exist.
category: Exception Classes Category: **Exception Classes**
""" """
class SessionTeamNotFoundError(NotFoundError): class SessionTeamNotFoundError(NotFoundError):
"""Exception raised when an expected ba.SessionTeam does not exist. """Exception raised when an expected ba.SessionTeam does not exist.
category: Exception Classes Category: **Exception Classes**
""" """
class NodeNotFoundError(NotFoundError): class NodeNotFoundError(NotFoundError):
"""Exception raised when an expected ba.Node does not exist. """Exception raised when an expected ba.Node does not exist.
category: Exception Classes Category: **Exception Classes**
""" """
class ActorNotFoundError(NotFoundError): class ActorNotFoundError(NotFoundError):
"""Exception raised when an expected ba.Actor does not exist. """Exception raised when an expected ba.Actor does not exist.
category: Exception Classes Category: **Exception Classes**
""" """
class ActivityNotFoundError(NotFoundError): class ActivityNotFoundError(NotFoundError):
"""Exception raised when an expected ba.Activity does not exist. """Exception raised when an expected ba.Activity does not exist.
category: Exception Classes Category: **Exception Classes**
""" """
class SessionNotFoundError(NotFoundError): class SessionNotFoundError(NotFoundError):
"""Exception raised when an expected ba.Session does not exist. """Exception raised when an expected ba.Session does not exist.
category: Exception Classes Category: **Exception Classes**
""" """
class InputDeviceNotFoundError(NotFoundError): class InputDeviceNotFoundError(NotFoundError):
"""Exception raised when an expected ba.InputDevice does not exist. """Exception raised when an expected ba.InputDevice does not exist.
category: Exception Classes Category: **Exception Classes**
""" """
class WidgetNotFoundError(NotFoundError): class WidgetNotFoundError(NotFoundError):
"""Exception raised when an expected ba.Widget does not exist. """Exception raised when an expected ba.Widget does not exist.
category: Exception Classes Category: **Exception Classes**
""" """
def print_exception(*args: Any, **keywds: Any) -> None: def print_exception(*args: Any, **keywds: Any) -> None:
"""Print info about an exception along with pertinent context state. """Print info about an exception along with pertinent context state.
category: General Utility Functions Category: **General Utility Functions**
Prints all arguments provided along with various info about the Prints all arguments provided along with various info about the
current context and the outstanding exception. current context and the outstanding exception.
@ -168,7 +168,7 @@ def print_exception(*args: Any, **keywds: Any) -> None:
def print_error(err_str: str, once: bool = False) -> None: def print_error(err_str: str, once: bool = False) -> None:
"""Print info about an error along with pertinent context state. """Print info about an error along with pertinent context state.
category: General Utility Functions Category: **General Utility Functions**
Prints all positional arguments provided along with various info about the Prints all positional arguments provided along with various info about the
current context. current context.

View File

@ -16,7 +16,7 @@ if TYPE_CHECKING:
class FreeForAllSession(MultiTeamSession): class FreeForAllSession(MultiTeamSession):
"""ba.Session type for free-for-all mode games. """ba.Session type for free-for-all mode games.
Category: Gameplay Classes Category: **Gameplay Classes**
""" """
use_teams = False use_teams = False
use_team_colors = False use_team_colors = False

View File

@ -31,7 +31,7 @@ TeamType = TypeVar('TeamType', bound='ba.Team')
class GameActivity(Activity[PlayerType, TeamType]): class GameActivity(Activity[PlayerType, TeamType]):
"""Common base class for all game ba.Activities. """Common base class for all game ba.Activities.
category: Gameplay Classes Category: **Gameplay Classes**
""" """
# pylint: disable=too-many-public-methods # pylint: disable=too-many-public-methods

View File

@ -27,10 +27,10 @@ class GameResults:
""" """
Results for a completed game. Results for a completed game.
Category: Gameplay Classes Category: **Gameplay Classes**
Upon completion, a game should fill one of these out and pass it to its Upon completion, a game should fill one of these out and pass it to its
ba.Activity.end() call. ba.Activity.end call.
""" """
def __init__(self) -> None: def __init__(self) -> None:

View File

@ -29,7 +29,7 @@ TROPHY_CHARS = {
class GameTip: class GameTip:
"""Defines a tip presentable to the user at the start of a game. """Defines a tip presentable to the user at the start of a game.
Category: Gameplay Classes Category: **Gameplay Classes**
""" """
text: str text: str
icon: Optional[ba.Texture] = None icon: Optional[ba.Texture] = None
@ -53,7 +53,7 @@ def animate(node: ba.Node,
suppress_format_warning: bool = False) -> ba.Node: suppress_format_warning: bool = False) -> ba.Node:
"""Animate values on a target ba.Node. """Animate values on a target ba.Node.
Category: Gameplay Functions Category: **Gameplay Functions**
Creates an 'animcurve' node with the provided values and time as an input, Creates an 'animcurve' node with the provided values and time as an input,
connect it to the provided attribute, and set it to die with the target. connect it to the provided attribute, and set it to die with the target.
@ -127,9 +127,9 @@ def animate_array(node: ba.Node,
suppress_format_warning: bool = False) -> None: suppress_format_warning: bool = False) -> None:
"""Animate an array of values on a target ba.Node. """Animate an array of values on a target ba.Node.
Category: Gameplay Functions Category: **Gameplay Functions**
Like ba.animate(), but operates on array attributes. Like ba.animate, but operates on array attributes.
""" """
# pylint: disable=too-many-locals # pylint: disable=too-many-locals
combine = _ba.newnode('combine', owner=node, attrs={'size': size}) combine = _ba.newnode('combine', owner=node, attrs={'size': size})
@ -198,7 +198,7 @@ def show_damage_count(damage: str, position: Sequence[float],
direction: Sequence[float]) -> None: direction: Sequence[float]) -> None:
"""Pop up a damage count at a position in space. """Pop up a damage count at a position in space.
Category: Gameplay Functions Category: **Gameplay Functions**
""" """
lifespan = 1.0 lifespan = 1.0
app = _ba.app app = _ba.app
@ -253,7 +253,7 @@ def timestring(timeval: float,
suppress_format_warning: bool = False) -> ba.Lstr: suppress_format_warning: bool = False) -> ba.Lstr:
"""Generate a ba.Lstr for displaying a time value. """Generate a ba.Lstr for displaying a time value.
Category: General Utility Functions Category: **General Utility Functions**
Given a time value, returns a ba.Lstr with: Given a time value, returns a ba.Lstr with:
(hours if > 0 ) : minutes : seconds : (centiseconds if centi=True). (hours if > 0 ) : minutes : seconds : (centiseconds if centi=True).
@ -321,7 +321,7 @@ def timestring(timeval: float,
def cameraflash(duration: float = 999.0) -> None: def cameraflash(duration: float = 999.0) -> None:
"""Create a strobing camera flash effect. """Create a strobing camera flash effect.
Category: Gameplay Functions Category: **Gameplay Functions**
(as seen when a team wins a game) (as seen when a team wins a game)
Duration is in seconds. Duration is in seconds.

View File

@ -24,7 +24,7 @@ if TYPE_CHECKING:
class Existable(Protocol): class Existable(Protocol):
"""A Protocol for objects supporting an exists() method. """A Protocol for objects supporting an exists() method.
Category: Protocols Category: **Protocols**
""" """
def exists(self) -> bool: def exists(self) -> bool:
@ -39,7 +39,7 @@ T = TypeVar('T')
def existing(obj: Optional[ExistableType]) -> Optional[ExistableType]: def existing(obj: Optional[ExistableType]) -> Optional[ExistableType]:
"""Convert invalid references to None for any ba.Existable object. """Convert invalid references to None for any ba.Existable object.
Category: Gameplay Functions Category: **Gameplay Functions**
To best support type checking, it is important that invalid references To best support type checking, it is important that invalid references
not be passed around and instead get converted to values of None. not be passed around and instead get converted to values of None.
@ -59,7 +59,7 @@ def existing(obj: Optional[ExistableType]) -> Optional[ExistableType]:
def getclass(name: str, subclassof: type[T]) -> type[T]: def getclass(name: str, subclassof: type[T]) -> type[T]:
"""Given a full class name such as foo.bar.MyClass, return the class. """Given a full class name such as foo.bar.MyClass, return the class.
Category: General Utility Functions Category: **General Utility Functions**
The class will be checked to make sure it is a subclass of the provided The class will be checked to make sure it is a subclass of the provided
'subclassof' class, and a TypeError will be raised if not. 'subclassof' class, and a TypeError will be raised if not.
@ -140,7 +140,7 @@ def get_type_name(cls: type) -> str:
class _WeakCall: class _WeakCall:
"""Wrap a callable and arguments into a single callable object. """Wrap a callable and arguments into a single callable object.
Category: General Utility Classes Category: **General Utility Classes**
When passed a bound method as the callable, the instance portion When passed a bound method as the callable, the instance portion
of it is weak-referenced, meaning the underlying instance is of it is weak-referenced, meaning the underlying instance is
@ -150,20 +150,30 @@ class _WeakCall:
Think of this as a handy way to tell an object to do something Think of this as a handy way to tell an object to do something
at some point in the future if it happens to still exist. at some point in the future if it happens to still exist.
# EXAMPLE A: this code will create a FooClass instance and call its ##### Examples
# bar() method 5 seconds later; it will be kept alive even though **EXAMPLE A:** this code will create a FooClass instance and call its
# we overwrite its variable with None because the bound method bar() method 5 seconds later; it will be kept alive even though
# we pass as a timer callback (foo.bar) strong-references it we overwrite its variable with None because the bound method
foo = FooClass() we pass as a timer callback (foo.bar) strong-references it
ba.timer(5.0, foo.bar) >>> foo = FooClass()
foo = None ... ba.timer(5.0, foo.bar)
... foo = None
# EXAMPLE B: this code will *not* keep our object alive; it will die **EXAMPLE B:** This code will *not* keep our object alive; it will die
# when we overwrite it with None and the timer will be a no-op when it when we overwrite it with None and the timer will be a no-op when it
# fires fires
foo = FooClass() >>> foo = FooClass()
ba.timer(5.0, ba.WeakCall(foo.bar)) ... ba.timer(5.0, ba.WeakCall(foo.bar))
foo = None ... foo = None
**EXAMPLE C:** Wrap a method call with some positional and keyword args:
>>> myweakcall = ba.WeakCall(self.dostuff, argval1,
... namedarg=argval2)
... # Now we have a single callable to run that whole mess.
... # The same as calling myobj.dostuff(argval1, namedarg=argval2)
... # (provided my_obj still exists; this will do nothing
... # otherwise).
... myweakcall()
Note: additional args and keywords you provide to the WeakCall() Note: additional args and keywords you provide to the WeakCall()
constructor are stored as regular strong-references; you'll need constructor are stored as regular strong-references; you'll need
@ -175,15 +185,6 @@ class _WeakCall:
Pass a callable as the first arg, followed by any number of Pass a callable as the first arg, followed by any number of
arguments or keywords. arguments or keywords.
# Example: wrap a method call with some positional and
# keyword args:
myweakcall = ba.WeakCall(myobj.dostuff, argval1, namedarg=argval2)
# Now we have a single callable to run that whole mess.
# The same as calling myobj.dostuff(argval1, namedarg=argval2)
# (provided my_obj still exists; this will do nothing otherwise)
myweakcall()
""" """
if hasattr(args[0], '__func__'): if hasattr(args[0], '__func__'):
self._call = WeakMethod(args[0]) self._call = WeakMethod(args[0])
@ -212,13 +213,13 @@ class _WeakCall:
class _Call: class _Call:
"""Wraps a callable and arguments into a single callable object. """Wraps a callable and arguments into a single callable object.
Category: General Utility Classes Category: **General Utility Classes**
The callable is strong-referenced so it won't die until this The callable is strong-referenced so it won't die until this
object does. object does.
Note that a bound method (ex: myobj.dosomething) contains a reference Note that a bound method (ex: ``myobj.dosomething``) contains a reference
to 'self' (myobj in that case), so you will be keeping that object to ``self`` (``myobj`` in that case), so you will be keeping that object
alive too. Use ba.WeakCall if you want to pass a method to callback alive too. Use ba.WeakCall if you want to pass a method to callback
without keeping its object alive. without keeping its object alive.
""" """
@ -229,12 +230,12 @@ class _Call:
Pass a callable as the first arg, followed by any number of Pass a callable as the first arg, followed by any number of
arguments or keywords. arguments or keywords.
# Example: wrap a method call with 1 positional and 1 keyword arg: ##### Example
mycall = ba.Call(myobj.dostuff, argval1, namedarg=argval2) Wrap a method call with 1 positional and 1 keyword arg:
>>> mycall = ba.Call(myobj.dostuff, argval, namedarg=argval2)
# Now we have a single callable to run that whole mess. ... # Now we have a single callable to run that whole mess.
# ..the same as calling myobj.dostuff(argval1, namedarg=argval2) ... # ..the same as calling myobj.dostuff(argval, namedarg=argval2)
mycall() ... mycall()
""" """
self._call = args[0] self._call = args[0]
self._args = args[1:] self._args = args[1:]
@ -283,7 +284,7 @@ class WeakMethod:
def verify_object_death(obj: object) -> None: def verify_object_death(obj: object) -> None:
"""Warn if an object does not get freed within a short period. """Warn if an object does not get freed within a short period.
Category: General Utility Functions Category: **General Utility Functions**
This can be handy to detect and prevent memory/resource leaks. This can be handy to detect and prevent memory/resource leaks.
""" """
@ -304,7 +305,7 @@ def verify_object_death(obj: object) -> None:
def print_active_refs(obj: Any) -> None: def print_active_refs(obj: Any) -> None:
"""Print info about things referencing a given object. """Print info about things referencing a given object.
Category: General Utility Functions Category: **General Utility Functions**
Useful for tracking down cyclical references and causes for zombie objects. Useful for tracking down cyclical references and causes for zombie objects.
""" """
@ -361,7 +362,7 @@ def _verify_object_death(wref: weakref.ref) -> None:
def storagename(suffix: str = None) -> str: def storagename(suffix: str = None) -> str:
"""Generate a unique name for storing class data in shared places. """Generate a unique name for storing class data in shared places.
Category: General Utility Functions Category: **General Utility Functions**
This consists of a leading underscore, the module path at the This consists of a leading underscore, the module path at the
call site with dots replaced by underscores, the containing class's call site with dots replaced by underscores, the containing class's
@ -371,15 +372,17 @@ def storagename(suffix: str = None) -> str:
Note that this will function even if called in the class definition. Note that this will function even if called in the class definition.
# Example: generate a unique name for storage purposes: ##### Examples
class MyThingie: Generate a unique name for storage purposes:
>>> class MyThingie:
# This will give something like '_mymodule_submodule_mythingie_data'. ... # This will give something like
_STORENAME = ba.storagename('data') ... # '_mymodule_submodule_mythingie_data'.
... _STORENAME = ba.storagename('data')
# Use that name to store some data in the Activity we were passed. ...
def __init__(self, activity): ... # Use that name to store some data in the Activity we were
activity.customdata[self._STORENAME] = {} ... # passed.
... def __init__(self, activity):
... activity.customdata[self._STORENAME] = {}
""" """
frame = inspect.currentframe() frame = inspect.currentframe()
if frame is None: if frame is None:

View File

@ -13,23 +13,21 @@ if TYPE_CHECKING:
class Keyboard: class Keyboard:
"""Chars definitions for on-screen keyboard. """Chars definitions for on-screen keyboard.
Category: App Classes Category: **App Classes**
Keyboards are discoverable by the meta-tag system Keyboards are discoverable by the meta-tag system
and the user can select which one they want to use. and the user can select which one they want to use.
On-screen keyboard uses chars from active ba.Keyboard. On-screen keyboard uses chars from active ba.Keyboard.
Attributes:
name
Displays when user selecting this keyboard.
chars
Used for row/column lengths.
pages
Extra chars like emojis.
nums
The 'num' page.
""" """
name: str name: str
"""Displays when user selecting this keyboard."""
chars: list[tuple[str, ...]] chars: list[tuple[str, ...]]
"""Used for row/column lengths."""
pages: dict[str, tuple[str, ...]] pages: dict[str, tuple[str, ...]]
"""Extra chars like emojis."""
nums: tuple[str, ...] nums: tuple[str, ...]
"""The 'num' page."""

View File

@ -17,7 +17,7 @@ if TYPE_CHECKING:
class LanguageSubsystem: class LanguageSubsystem:
"""Wraps up language related app functionality. """Wraps up language related app functionality.
Category: App Classes Category: **App Classes**
To use this class, access the single instance of it at 'ba.app.lang'. To use this class, access the single instance of it at 'ba.app.lang'.
""" """
@ -367,7 +367,7 @@ class LanguageSubsystem:
class Lstr: class Lstr:
"""Used to define strings in a language-independent way. """Used to define strings in a language-independent way.
category: General Utility Classes Category: **General Utility Classes**
These should be used whenever possible in place of hard-coded strings These should be used whenever possible in place of hard-coded strings
so that in-game or UI elements show up correctly on all clients in their so that in-game or UI elements show up correctly on all clients in their
@ -376,24 +376,28 @@ class Lstr:
To see available resource keys, look at any of the bs_language_*.py files To see available resource keys, look at any of the bs_language_*.py files
in the game or the translations pages at legacy.ballistica.net/translate. in the game or the translations pages at legacy.ballistica.net/translate.
# EXAMPLE 1: specify a string from a resource path ##### Examples
mynode.text = ba.Lstr(resource='audioSettingsWindow.titleText') EXAMPLE 1: specify a string from a resource path
>>> mynode.text = ba.Lstr(resource='audioSettingsWindow.titleText')
# EXAMPLE 2: specify a translated string via a category and english value; EXAMPLE 2: specify a translated string via a category and english
# if a translated value is available, it will be used; otherwise the value; if a translated value is available, it will be used; otherwise
# english value will be. To see available translation categories, look the english value will be. To see available translation categories,
# under the 'translations' resource section. look under the 'translations' resource section.
mynode.text = ba.Lstr(translate=('gameDescriptions', 'Defeat all enemies')) >>> mynode.text = ba.Lstr(translate=('gameDescriptions',
... 'Defeat all enemies'))
# EXAMPLE 3: specify a raw value and some substitutions. Substitutions can EXAMPLE 3: specify a raw value and some substitutions. Substitutions
# be used with resource and translate modes as well. can be used with resource and translate modes as well.
mynode.text = ba.Lstr(value='${A} / ${B}', >>> mynode.text = ba.Lstr(value='${A} / ${B}',
subs=[('${A}', str(score)), ('${B}', str(total))]) ... subs=[('${A}', str(score)), ('${B}', str(total))])
# EXAMPLE 4: Lstrs can be nested. This example would display the resource EXAMPLE 4: ba.Lstr's can be nested. This example would display the
# at res_a but replace ${NAME} with the value of the resource at res_b resource at res_a but replace ${NAME} with the value of the
mytextnode.text = ba.Lstr(resource='res_a', resource at res_b
subs=[('${NAME}', ba.Lstr(resource='res_b'))]) >>> mytextnode.text = ba.Lstr(
... resource='res_a',
... subs=[('${NAME}', ba.Lstr(resource='res_b'))])
""" """
# pylint: disable=dangerous-default-value # pylint: disable=dangerous-default-value

View File

@ -17,7 +17,7 @@ if TYPE_CHECKING:
class Level: class Level:
"""An entry in a ba.Campaign consisting of a name, game type, and settings. """An entry in a ba.Campaign consisting of a name, game type, and settings.
category: Gameplay Classes Category: **Gameplay Classes**
""" """
def __init__(self, def __init__(self,

View File

@ -18,7 +18,7 @@ if TYPE_CHECKING:
def preload_map_preview_media() -> None: def preload_map_preview_media() -> None:
"""Preload media needed for map preview UIs. """Preload media needed for map preview UIs.
Category: Asset Functions Category: **Asset Functions**
""" """
_ba.getmodel('level_select_button_opaque') _ba.getmodel('level_select_button_opaque')
_ba.getmodel('level_select_button_transparent') _ba.getmodel('level_select_button_transparent')
@ -31,7 +31,7 @@ def preload_map_preview_media() -> None:
def get_filtered_map_name(name: str) -> str: def get_filtered_map_name(name: str) -> str:
"""Filter a map name to account for name changes, etc. """Filter a map name to account for name changes, etc.
Category: Asset Functions Category: **Asset Functions**
This can be used to support old playlists, etc. This can be used to support old playlists, etc.
""" """
@ -46,7 +46,7 @@ def get_filtered_map_name(name: str) -> str:
def get_map_display_string(name: str) -> ba.Lstr: def get_map_display_string(name: str) -> ba.Lstr:
"""Return a ba.Lstr for displaying a given map\'s name. """Return a ba.Lstr for displaying a given map\'s name.
Category: Asset Functions Category: **Asset Functions**
""" """
from ba import _language from ba import _language
return _language.Lstr(translate=('mapsNames', name)) return _language.Lstr(translate=('mapsNames', name))
@ -55,7 +55,7 @@ def get_map_display_string(name: str) -> ba.Lstr:
def getmaps(playtype: str) -> list[str]: def getmaps(playtype: str) -> list[str]:
"""Return a list of ba.Map types supporting a playtype str. """Return a list of ba.Map types supporting a playtype str.
Category: Asset Functions Category: **Asset Functions**
Maps supporting a given playtype must provide a particular set of Maps supporting a given playtype must provide a particular set of
features and lend themselves to a certain style of play. features and lend themselves to a certain style of play.
@ -104,7 +104,7 @@ def getmaps(playtype: str) -> list[str]:
def get_unowned_maps() -> list[str]: def get_unowned_maps() -> list[str]:
"""Return the list of local maps not owned by the current account. """Return the list of local maps not owned by the current account.
Category: Asset Functions Category: **Asset Functions**
""" """
from ba import _store from ba import _store
unowned_maps: set[str] = set() unowned_maps: set[str] = set()
@ -120,7 +120,7 @@ def get_unowned_maps() -> list[str]:
def get_map_class(name: str) -> type[ba.Map]: def get_map_class(name: str) -> type[ba.Map]:
"""Return a map type given a name. """Return a map type given a name.
Category: Asset Functions Category: **Asset Functions**
""" """
name = get_filtered_map_name(name) name = get_filtered_map_name(name)
try: try:
@ -133,7 +133,7 @@ def get_map_class(name: str) -> type[ba.Map]:
class Map(Actor): class Map(Actor):
"""A game map. """A game map.
Category: Gameplay Classes Category: **Gameplay Classes**
Consists of a collection of terrain nodes, metadata, and other Consists of a collection of terrain nodes, metadata, and other
functionality comprising a game map. functionality comprising a game map.
@ -345,7 +345,7 @@ class Map(Actor):
self, players: Sequence[ba.Player]) -> Sequence[float]: self, players: Sequence[ba.Player]) -> Sequence[float]:
"""Return a random starting position in one of the FFA spawn areas. """Return a random starting position in one of the FFA spawn areas.
If a list of ba.Players is provided; the returned points will be If a list of ba.Player-s is provided; the returned points will be
as far from these players as possible. as far from these players as possible.
""" """

View File

@ -50,24 +50,19 @@ class DeathType(Enum):
class DieMessage: class DieMessage:
"""A message telling an object to die. """A message telling an object to die.
Category: Message Classes Category: **Message Classes**
Most ba.Actors respond to this.
Attributes:
immediate
If this is set to True, the actor should disappear immediately.
This is for 'removing' stuff from the game more so than 'killing'
it. If False, the actor should die a 'normal' death and can take
its time with lingering corpses, sound effects, etc.
how
The particular reason for death.
Most ba.Actor-s respond to this.
""" """
immediate: bool = False immediate: bool = False
"""If this is set to True, the actor should disappear immediately.
This is for 'removing' stuff from the game more so than 'killing'
it. If False, the actor should die a 'normal' death and can take
its time with lingering corpses, sound effects, etc."""
how: DeathType = DeathType.GENERIC how: DeathType = DeathType.GENERIC
"""The particular reason for death."""
PlayerType = TypeVar('PlayerType', bound='ba.Player') PlayerType = TypeVar('PlayerType', bound='ba.Player')
@ -76,19 +71,15 @@ PlayerType = TypeVar('PlayerType', bound='ba.Player')
class PlayerDiedMessage: class PlayerDiedMessage:
"""A message saying a ba.Player has died. """A message saying a ba.Player has died.
category: Message Classes Category: **Message Classes**
Attributes:
killed
If True, the player was killed;
If False, they left the game or the round ended.
how
The particular type of death.
""" """
killed: bool killed: bool
"""If True, the player was killed;
If False, they left the game or the round ended."""
how: ba.DeathType how: ba.DeathType
"""The particular type of death."""
def __init__(self, player: ba.Player, was_killed: bool, def __init__(self, player: ba.Player, was_killed: bool,
killerplayer: Optional[ba.Player], how: ba.DeathType): killerplayer: Optional[ba.Player], how: ba.DeathType):
@ -132,41 +123,34 @@ class PlayerDiedMessage:
class StandMessage: class StandMessage:
"""A message telling an object to move to a position in space. """A message telling an object to move to a position in space.
Category: Message Classes Category: **Message Classes**
Used when teleporting players to home base, etc. Used when teleporting players to home base, etc.
Attributes:
position
Where to move to.
angle
The angle to face (in degrees)
""" """
position: Sequence[float] = (0.0, 0.0, 0.0) position: Sequence[float] = (0.0, 0.0, 0.0)
"""Where to move to."""
angle: float = 0.0 angle: float = 0.0
"""The angle to face (in degrees)"""
@dataclass @dataclass
class PickUpMessage: class PickUpMessage:
"""Tells an object that it has picked something up. """Tells an object that it has picked something up.
Category: Message Classes Category: **Message Classes**
Attributes:
node
The ba.Node that is getting picked up.
""" """
node: ba.Node node: ba.Node
"""The ba.Node that is getting picked up."""
@dataclass @dataclass
class DropMessage: class DropMessage:
"""Tells an object that it has dropped what it was holding. """Tells an object that it has dropped what it was holding.
Category: Message Classes Category: **Message Classes**
""" """
@ -174,35 +158,29 @@ class DropMessage:
class PickedUpMessage: class PickedUpMessage:
"""Tells an object that it has been picked up by something. """Tells an object that it has been picked up by something.
Category: Message Classes Category: **Message Classes**
Attributes:
node
The ba.Node doing the picking up.
""" """
node: ba.Node node: ba.Node
"""The ba.Node doing the picking up."""
@dataclass @dataclass
class DroppedMessage: class DroppedMessage:
"""Tells an object that it has been dropped. """Tells an object that it has been dropped.
Category: Message Classes Category: **Message Classes**
Attributes:
node
The ba.Node doing the dropping.
""" """
node: ba.Node node: ba.Node
"""The ba.Node doing the dropping."""
@dataclass @dataclass
class ShouldShatterMessage: class ShouldShatterMessage:
"""Tells an object that it should shatter. """Tells an object that it should shatter.
Category: Message Classes Category: **Message Classes**
""" """
@ -210,21 +188,18 @@ class ShouldShatterMessage:
class ImpactDamageMessage: class ImpactDamageMessage:
"""Tells an object that it has been jarred violently. """Tells an object that it has been jarred violently.
Category: Message Classes Category: **Message Classes**
Attributes:
intensity
The intensity of the impact.
""" """
intensity: float intensity: float
"""The intensity of the impact."""
@dataclass @dataclass
class FreezeMessage: class FreezeMessage:
"""Tells an object to become frozen. """Tells an object to become frozen.
Category: Message Classes Category: **Message Classes**
As seen in the effects of an ice ba.Bomb. As seen in the effects of an ice ba.Bomb.
""" """
@ -234,7 +209,7 @@ class FreezeMessage:
class ThawMessage: class ThawMessage:
"""Tells an object to stop being frozen. """Tells an object to stop being frozen.
Category: Message Classes Category: **Message Classes**
""" """
@ -242,20 +217,17 @@ class ThawMessage:
class CelebrateMessage: class CelebrateMessage:
"""Tells an object to celebrate. """Tells an object to celebrate.
Category: Message Classes Category: **Message Classes**
Attributes:
duration
Amount of time to celebrate in seconds.
""" """
duration: float = 10.0 duration: float = 10.0
"""Amount of time to celebrate in seconds."""
class HitMessage: class HitMessage:
"""Tells an object it has been hit in some way. """Tells an object it has been hit in some way.
Category: Message Classes Category: **Message Classes**
This is used by punches, explosions, etc to convey This is used by punches, explosions, etc to convey
their effect to a target. their effect to a target.

View File

@ -37,7 +37,7 @@ class ScanResults:
class MetadataSubsystem: class MetadataSubsystem:
"""Subsystem for working with script metadata in the app. """Subsystem for working with script metadata in the app.
Category: App Classes Category: **App Classes**
Access the single shared instance of this class at 'ba.app.meta'. Access the single shared instance of this class at 'ba.app.meta'.
""" """

View File

@ -22,7 +22,7 @@ DEFAULT_TEAM_NAMES = ('Blue', 'Red')
class MultiTeamSession(Session): class MultiTeamSession(Session):
"""Common base class for ba.DualTeamSession and ba.FreeForAllSession. """Common base class for ba.DualTeamSession and ba.FreeForAllSession.
Category: Gameplay Classes Category: **Gameplay Classes**
Free-for-all-mode is essentially just teams-mode with each ba.Player having Free-for-all-mode is essentially just teams-mode with each ba.Player having
their own ba.Team, so there is much overlap in functionality. their own ba.Team, so there is much overlap in functionality.
@ -141,7 +141,7 @@ class MultiTeamSession(Session):
team.customdata['previous_score'] = team.customdata['score'] = 0 team.customdata['previous_score'] = team.customdata['score'] = 0
def get_max_players(self) -> int: def get_max_players(self) -> int:
"""Return max number of ba.Players allowed to join the game at once.""" """Return max number of ba.Player-s allowed to join the game at once"""
if self.use_teams: if self.use_teams:
return _ba.app.config.get('Team Game Max Players', 8) return _ba.app.config.get('Team Game Max Players', 8)
return _ba.app.config.get('Free-for-All Max Players', 8) return _ba.app.config.get('Free-for-All Max Players', 8)

View File

@ -18,7 +18,7 @@ if TYPE_CHECKING:
class MusicType(Enum): class MusicType(Enum):
"""Types of music available to play in-game. """Types of music available to play in-game.
Category: Enums Category: **Enums**
These do not correspond to specific pieces of music, but rather to These do not correspond to specific pieces of music, but rather to
'situations'. The actual music played for each type can be overridden 'situations'. The actual music played for each type can be overridden
@ -51,7 +51,7 @@ class MusicType(Enum):
class MusicPlayMode(Enum): class MusicPlayMode(Enum):
"""Influences behavior when playing music. """Influences behavior when playing music.
Category: Enums Category: **Enums**
""" """
REGULAR = 'regular' REGULAR = 'regular'
TEST = 'test' TEST = 'test'
@ -61,7 +61,7 @@ class MusicPlayMode(Enum):
class AssetSoundtrackEntry: class AssetSoundtrackEntry:
"""A music entry using an internal asset. """A music entry using an internal asset.
Category: App Classes Category: **App Classes**
""" """
assetname: str assetname: str
volume: float = 1.0 volume: float = 1.0
@ -120,7 +120,7 @@ ASSET_SOUNDTRACK_ENTRIES: dict[MusicType, AssetSoundtrackEntry] = {
class MusicSubsystem: class MusicSubsystem:
"""Subsystem for music playback in the app. """Subsystem for music playback in the app.
Category: App Classes Category: **App Classes**
Access the single shared instance of this class at 'ba.app.music'. Access the single shared instance of this class at 'ba.app.music'.
""" """
@ -385,7 +385,7 @@ class MusicSubsystem:
class MusicPlayer: class MusicPlayer:
"""Wrangles soundtrack music playback. """Wrangles soundtrack music playback.
Category: App Classes Category: **App Classes**
Music can be played either through the game itself Music can be played either through the game itself
or via a platform-specific external player. or via a platform-specific external player.
@ -474,7 +474,7 @@ def setmusic(musictype: Optional[ba.MusicType],
continuous: bool = False) -> None: continuous: bool = False) -> None:
"""Set the app to play (or stop playing) a certain type of music. """Set the app to play (or stop playing) a certain type of music.
category: Gameplay Functions category: **Gameplay Functions**
This function will handle loading and playing sound assets as necessary, This function will handle loading and playing sound assets as necessary,
and also supports custom user soundtracks on specific platforms so the and also supports custom user soundtracks on specific platforms so the

View File

@ -17,7 +17,7 @@ if TYPE_CHECKING:
class NodeActor(Actor): class NodeActor(Actor):
"""A simple ba.Actor type that wraps a single ba.Node. """A simple ba.Actor type that wraps a single ba.Node.
Category: Gameplay Classes Category: **Gameplay Classes**
This Actor will delete its Node when told to die, and it's This Actor will delete its Node when told to die, and it's
exists() call will return whether the Node still exists or not. exists() call will return whether the Node still exists or not.

View File

@ -48,18 +48,15 @@ class Player(Generic[TeamType]):
These correspond to ba.SessionPlayer objects, but are associated with a These correspond to ba.SessionPlayer objects, but are associated with a
single ba.Activity instance. This allows activities to specify their single ba.Activity instance. This allows activities to specify their
own custom ba.Player types. own custom ba.Player types.
Attributes:
actor
The ba.Actor associated with the player.
""" """
# These are instance attrs but we define them at the type level so # These are instance attrs but we define them at the type level so
# their type annotations are introspectable (for docs generation). # their type annotations are introspectable (for docs generation).
character: str character: str
actor: Optional[ba.Actor] actor: Optional[ba.Actor]
"""The ba.Actor associated with the player."""
color: Sequence[float] color: Sequence[float]
highlight: Sequence[float] highlight: Sequence[float]
@ -225,8 +222,7 @@ class Player(Generic[TeamType]):
return self._sessionplayer.exists() and not self._expired return self._sessionplayer.exists() and not self._expired
def getname(self, full: bool = False, icon: bool = True) -> str: def getname(self, full: bool = False, icon: bool = True) -> str:
"""getname(full: bool = False, icon: bool = True) -> str """
Returns the player's name. If icon is True, the long version of the Returns the player's name. If icon is True, the long version of the
name may include an icon. name may include an icon.
""" """
@ -235,8 +231,7 @@ class Player(Generic[TeamType]):
return self._sessionplayer.getname(full=full, icon=icon) return self._sessionplayer.getname(full=full, icon=icon)
def is_alive(self) -> bool: def is_alive(self) -> bool:
"""is_alive() -> bool """
Returns True if the player has a ba.Actor assigned and its Returns True if the player has a ba.Actor assigned and its
is_alive() method return True. False is returned otherwise. is_alive() method return True. False is returned otherwise.
""" """
@ -245,8 +240,7 @@ class Player(Generic[TeamType]):
return self.actor is not None and self.actor.is_alive() return self.actor is not None and self.actor.is_alive()
def get_icon(self) -> dict[str, Any]: def get_icon(self) -> dict[str, Any]:
"""get_icon() -> dict[str, Any] """
Returns the character's icon (images, colors, etc contained in a dict) Returns the character's icon (images, colors, etc contained in a dict)
""" """
assert self._postinited assert self._postinited
@ -256,9 +250,7 @@ class Player(Generic[TeamType]):
def assigninput(self, inputtype: Union[ba.InputType, tuple[ba.InputType, def assigninput(self, inputtype: Union[ba.InputType, tuple[ba.InputType,
...]], ...]],
call: Callable) -> None: call: Callable) -> None:
"""assigninput(type: Union[ba.InputType, Tuple[ba.InputType, ...]], """
call: Callable) -> None
Set the python callable to be run for one or more types of input. Set the python callable to be run for one or more types of input.
""" """
assert self._postinited assert self._postinited
@ -266,8 +258,7 @@ class Player(Generic[TeamType]):
return self._sessionplayer.assigninput(type=inputtype, call=call) return self._sessionplayer.assigninput(type=inputtype, call=call)
def resetinput(self) -> None: def resetinput(self) -> None:
"""resetinput() -> None """
Clears out the player's assigned input actions. Clears out the player's assigned input actions.
""" """
assert self._postinited assert self._postinited

View File

@ -16,9 +16,9 @@ if TYPE_CHECKING:
class PluginSubsystem: class PluginSubsystem:
"""Subsystem for plugin handling in the app. """Subsystem for plugin handling in the app.
Category: App Classes Category: **App Classes**
Access the single shared instance of this class at 'ba.app.plugins'. Access the single shared instance of this class at `ba.app.plugins`.
""" """
def __init__(self) -> None: def __init__(self) -> None:
@ -96,7 +96,7 @@ class PluginSubsystem:
class PotentialPlugin: class PotentialPlugin:
"""Represents a ba.Plugin which can potentially be loaded. """Represents a ba.Plugin which can potentially be loaded.
Category: App Classes Category: **App Classes**
These generally represent plugins which were detected by the These generally represent plugins which were detected by the
meta-tag scan. However they may also represent plugins which meta-tag scan. However they may also represent plugins which
@ -111,7 +111,7 @@ class PotentialPlugin:
class Plugin: class Plugin:
"""A plugin to alter app behavior in some way. """A plugin to alter app behavior in some way.
Category: App Classes Category: **App Classes**
Plugins are discoverable by the meta-tag system Plugins are discoverable by the meta-tag system
and the user can select which ones they want to activate. and the user can select which ones they want to activate.

View File

@ -16,31 +16,27 @@ if TYPE_CHECKING:
class PowerupMessage: class PowerupMessage:
"""A message telling an object to accept a powerup. """A message telling an object to accept a powerup.
Category: Message Classes Category: **Message Classes**
This message is normally received by touching a ba.PowerupBox. This message is normally received by touching a ba.PowerupBox.
Attributes:
poweruptype
The type of powerup to be granted (a string).
See ba.Powerup.poweruptype for available type values.
sourcenode
The node the powerup game from, or None otherwise.
If a powerup is accepted, a ba.PowerupAcceptMessage should be sent
back to the sourcenode to inform it of the fact. This will generally
cause the powerup box to make a sound and disappear or whatnot.
""" """
poweruptype: str poweruptype: str
"""The type of powerup to be granted (a string).
See ba.Powerup.poweruptype for available type values."""
sourcenode: Optional[ba.Node] = None sourcenode: Optional[ba.Node] = None
"""The node the powerup game from, or None otherwise.
If a powerup is accepted, a ba.PowerupAcceptMessage should be sent
back to the sourcenode to inform it of the fact. This will generally
cause the powerup box to make a sound and disappear or whatnot."""
@dataclass @dataclass
class PowerupAcceptMessage: class PowerupAcceptMessage:
"""A message informing a ba.Powerup that it was accepted. """A message informing a ba.Powerup that it was accepted.
Category: Message Classes Category: **Message Classes**
This is generally sent in response to a ba.PowerupMessage This is generally sent in response to a ba.PowerupMessage
to inform the box (or whoever granted it) that it can go away. to inform the box (or whoever granted it) that it can go away.

View File

@ -16,7 +16,7 @@ if TYPE_CHECKING:
class ScoreType(Enum): class ScoreType(Enum):
"""Type of scores. """Type of scores.
Category: Enums Category: **Enums**
""" """
SECONDS = 's' SECONDS = 's'
MILLISECONDS = 'ms' MILLISECONDS = 'ms'
@ -27,30 +27,22 @@ class ScoreType(Enum):
class ScoreConfig: class ScoreConfig:
"""Settings for how a game handles scores. """Settings for how a game handles scores.
Category: Gameplay Classes Category: **Gameplay Classes**
Attributes:
label
A label show to the user for scores; 'Score', 'Time Survived', etc.
scoretype
How the score value should be displayed.
lower_is_better
Whether lower scores are preferable. Higher scores are by default.
none_is_winner
Whether a value of None is considered better than other scores.
By default it is not.
version
To change high-score lists used by a game without renaming the game,
change this. Defaults to an empty string.
""" """
label: str = 'Score' label: str = 'Score'
"""A label show to the user for scores; 'Score', 'Time Survived', etc."""
scoretype: ba.ScoreType = ScoreType.POINTS scoretype: ba.ScoreType = ScoreType.POINTS
"""How the score value should be displayed."""
lower_is_better: bool = False lower_is_better: bool = False
"""Whether lower scores are preferable. Higher scores are by default."""
none_is_winner: bool = False none_is_winner: bool = False
"""Whether a value of None is considered better than other scores.
By default it is not."""
version: str = '' version: str = ''
"""To change high-score lists used by a game without renaming the game,
change this. Defaults to an empty string."""

View File

@ -77,7 +77,7 @@ def _cmd(command_data: bytes) -> None:
class ServerController: class ServerController:
"""Overall controller for the app in server mode. """Overall controller for the app in server mode.
Category: App Classes Category: **App Classes**
""" """
def __init__(self, config: ServerConfig) -> None: def __init__(self, config: ServerConfig) -> None:

View File

@ -17,9 +17,9 @@ if TYPE_CHECKING:
class Session: class Session:
"""Defines a high level series of ba.Activities with a common purpose. """Defines a high level series of ba.Activity-es with a common purpose.
category: Gameplay Classes Category: **Gameplay Classes**
Examples of sessions are ba.FreeForAllSession, ba.DualTeamSession, and Examples of sessions are ba.FreeForAllSession, ba.DualTeamSession, and
ba.CoopSession. ba.CoopSession.
@ -27,58 +27,48 @@ class Session:
A Session is responsible for wrangling and transitioning between various A Session is responsible for wrangling and transitioning between various
ba.Activity instances such as mini-games and score-screens, and for ba.Activity instances such as mini-games and score-screens, and for
maintaining state between them (players, teams, score tallies, etc). maintaining state between them (players, teams, score tallies, etc).
Attributes:
sessionteams
All the ba.SessionTeams in the Session. Most things should use the
list of ba.Teams in ba.Activity; not this.
sessionplayers
All ba.SessionPlayers in the Session. Most things should use the
list of ba.Players in ba.Activity; not this. Some players, such as
those who have not yet selected a character, will only be
found on this list.
min_players
The minimum number of players who must be present for the Session
to proceed past the initial joining screen.
max_players
The maximum number of players allowed in the Session.
lobby
The ba.Lobby instance where new ba.Players go to select a
Profile/Team/etc. before being added to games.
Be aware this value may be None if a Session does not allow
any such selection.
use_teams
Whether this session groups players into an explicit set of
teams. If this is off, a unique team is generated for each
player that joins.
use_team_colors
Whether players on a team should all adopt the colors of that
team instead of their own profile colors. This only applies if
use_teams is enabled.
customdata
A shared dictionary for objects to use as storage on this session.
Ensure that keys here are unique to avoid collisions.
""" """
use_teams: bool = False
use_team_colors: bool = True
# Note: even though these are instance vars, we annotate them at the use_teams: bool = False
# class level so that docs generation can access their types. """Whether this session groups players into an explicit set of
teams. If this is off, a unique team is generated for each
player that joins."""
use_team_colors: bool = True
"""Whether players on a team should all adopt the colors of that
team instead of their own profile colors. This only applies if
use_teams is enabled."""
# Note: even though these are instance vars, we annotate and document them
# at the class level so that looks better and nobody get lost while
# reading large __init__
lobby: ba.Lobby lobby: ba.Lobby
"""The ba.Lobby instance where new ba.Player-s go to select a
Profile/Team/etc. before being added to games.
Be aware this value may be None if a Session does not allow
any such selection."""
max_players: int max_players: int
"""The maximum number of players allowed in the Session."""
min_players: int min_players: int
"""The minimum number of players who must be present for the Session
to proceed past the initial joining screen"""
sessionplayers: list[ba.SessionPlayer] sessionplayers: list[ba.SessionPlayer]
"""All ba.SessionPlayers in the Session. Most things should use the
list of ba.Player-s in ba.Activity; not this. Some players, such as
those who have not yet selected a character, will only be
found on this list."""
customdata: dict customdata: dict
"""A shared dictionary for objects to use as storage on this session.
Ensure that keys here are unique to avoid collisions."""
sessionteams: list[ba.SessionTeam] sessionteams: list[ba.SessionTeam]
"""All the ba.SessionTeams in the Session. Most things should use the
list of ba.Team-s in ba.Activity; not this."""
def __init__(self, def __init__(self,
depsets: Sequence[ba.DependencySet], depsets: Sequence[ba.DependencySet],

View File

@ -21,20 +21,17 @@ if TYPE_CHECKING:
class PlayerScoredMessage: class PlayerScoredMessage:
"""Informs something that a ba.Player scored. """Informs something that a ba.Player scored.
Category: Message Classes Category: **Message Classes**
Attributes:
score
The score value.
""" """
score: int score: int
"""The score value."""
class PlayerRecord: class PlayerRecord:
"""Stats for an individual player in a ba.Stats object. """Stats for an individual player in a ba.Stats object.
Category: Gameplay Classes Category: **Gameplay Classes**
This does not necessarily correspond to a ba.Player that is This does not necessarily correspond to a ba.Player that is
still present (stats may be retained for players that leave still present (stats may be retained for players that leave
@ -232,7 +229,7 @@ class PlayerRecord:
class Stats: class Stats:
"""Manages scores and statistics for a ba.Session. """Manages scores and statistics for a ba.Session.
category: Gameplay Classes Category: **Gameplay Classes**
""" """
def __init__(self) -> None: def __init__(self) -> None:

View File

@ -17,39 +17,32 @@ if TYPE_CHECKING:
class SessionTeam: class SessionTeam:
"""A team of one or more ba.SessionPlayers. """A team of one or more ba.SessionPlayers.
Category: Gameplay Classes Category: **Gameplay Classes**
Note that a SessionPlayer *always* has a SessionTeam; Note that a SessionPlayer *always* has a SessionTeam;
in some cases, such as free-for-all ba.Sessions, in some cases, such as free-for-all ba.Sessions,
each SessionTeam consists of just one SessionPlayer. each SessionTeam consists of just one SessionPlayer.
Attributes:
name
The team's name.
id
The unique numeric id of the team.
color
The team's color.
players
The list of ba.SessionPlayers on the team.
customdata
A dict for use by the current ba.Session for
storing data associated with this team.
Unlike customdata, this persists for the duration
of the session.
""" """
# Annotate our attr types at the class level so they're introspectable. # Annotate our attr types at the class level so they're introspectable.
name: Union[ba.Lstr, str] name: Union[ba.Lstr, str]
"""The team's name."""
color: tuple[float, ...] # FIXME: can't we make this fixed len? color: tuple[float, ...] # FIXME: can't we make this fixed len?
"""The team's color."""
players: list[ba.SessionPlayer] players: list[ba.SessionPlayer]
"""The list of ba.SessionPlayer-s on the team."""
customdata: dict customdata: dict
"""A dict for use by the current ba.Session for
storing data associated with this team.
Unlike customdata, this persists for the duration
of the session."""
id: int id: int
"""The unique numeric id of the team."""
def __init__(self, def __init__(self,
team_id: int = 0, team_id: int = 0,
@ -79,7 +72,7 @@ PlayerType = TypeVar('PlayerType', bound='ba.Player')
class Team(Generic[PlayerType]): class Team(Generic[PlayerType]):
"""A team in a specific ba.Activity. """A team in a specific ba.Activity.
Category: Gameplay Classes Category: **Gameplay Classes**
These correspond to ba.SessionTeam objects, but are created per activity These correspond to ba.SessionTeam objects, but are created per activity
so that the activity can use its own custom team subclass. so that the activity can use its own custom team subclass.
@ -197,7 +190,7 @@ class Team(Generic[PlayerType]):
class EmptyTeam(Team['ba.EmptyPlayer']): class EmptyTeam(Team['ba.EmptyPlayer']):
"""An empty player for use by Activities that don't need to define one. """An empty player for use by Activities that don't need to define one.
Category: Gameplay Classes Category: **Gameplay Classes**
ba.Player and ba.Team are 'Generic' types, and so passing those top level ba.Player and ba.Team are 'Generic' types, and so passing those top level
classes as type arguments when defining a ba.Activity reduces type safety. classes as type arguments when defining a ba.Activity reduces type safety.

View File

@ -24,7 +24,7 @@ TeamType = TypeVar('TeamType', bound='ba.Team')
class TeamGameActivity(GameActivity[PlayerType, TeamType]): class TeamGameActivity(GameActivity[PlayerType, TeamType]):
"""Base class for teams and free-for-all mode games. """Base class for teams and free-for-all mode games.
Category: Gameplay Classes Category: **Gameplay Classes**
(Free-for-all is essentially just a special case where every (Free-for-all is essentially just a special case where every
ba.Player has their own ba.Team) ba.Player has their own ba.Team)

View File

@ -18,7 +18,7 @@ if TYPE_CHECKING:
class UISubsystem: class UISubsystem:
"""Consolidated UI functionality for the app. """Consolidated UI functionality for the app.
Category: App Classes Category: **App Classes**
To use this class, access the single instance of it at 'ba.app.ui'. To use this class, access the single instance of it at 'ba.app.ui'.
""" """

View File

@ -22,112 +22,110 @@ PlayerType = TypeVar('PlayerType', bound='ba.Player')
class BombFactory: class BombFactory:
"""Wraps up media and other resources used by ba.Bombs. """Wraps up media and other resources used by ba.Bombs.
category: Gameplay Classes Category: **Gameplay Classes**
A single instance of this is shared between all bombs A single instance of this is shared between all bombs
and can be retrieved via bastd.actor.bomb.get_factory(). and can be retrieved via bastd.actor.bomb.get_factory().
Attributes:
bomb_model
The ba.Model of a standard or ice bomb.
sticky_bomb_model
The ba.Model of a sticky-bomb.
impact_bomb_model
The ba.Model of an impact-bomb.
land_mine_model
The ba.Model of a land-mine.
tnt_model
The ba.Model of a tnt box.
regular_tex
The ba.Texture for regular bombs.
ice_tex
The ba.Texture for ice bombs.
sticky_tex
The ba.Texture for sticky bombs.
impact_tex
The ba.Texture for impact bombs.
impact_lit_tex
The ba.Texture for impact bombs with lights lit.
land_mine_tex
The ba.Texture for land-mines.
land_mine_lit_tex
The ba.Texture for land-mines with the light lit.
tnt_tex
The ba.Texture for tnt boxes.
hiss_sound
The ba.Sound for the hiss sound an ice bomb makes.
debris_fall_sound
The ba.Sound for random falling debris after an explosion.
wood_debris_fall_sound
A ba.Sound for random wood debris falling after an explosion.
explode_sounds
A tuple of ba.Sounds for explosions.
freeze_sound
A ba.Sound of an ice bomb freezing something.
fuse_sound
A ba.Sound of a burning fuse.
activate_sound
A ba.Sound for an activating impact bomb.
warn_sound
A ba.Sound for an impact bomb about to explode due to time-out.
bomb_material
A ba.Material applied to all bombs.
normal_sound_material
A ba.Material that generates standard bomb noises on impacts, etc.
sticky_material
A ba.Material that makes 'splat' sounds and makes collisions softer.
land_mine_no_explode_material
A ba.Material that keeps land-mines from blowing up.
Applied to land-mines when they are created to allow land-mines to
touch without exploding.
land_mine_blast_material
A ba.Material applied to activated land-mines that causes them to
explode on impact.
impact_blast_material
A ba.Material applied to activated impact-bombs that causes them to
explode on impact.
blast_material
A ba.Material applied to bomb blast geometry which triggers impact
events with what it touches.
dink_sounds
A tuple of ba.Sounds for when bombs hit the ground.
sticky_impact_sound
The ba.Sound for a squish made by a sticky bomb hitting something.
roll_sound
ba.Sound for a rolling bomb.
""" """
bomb_model: ba.Model
"""The ba.Model of a standard or ice bomb."""
sticky_bomb_model: ba.Model
"""The ba.Model of a sticky-bomb."""
impact_bomb_model: ba.Model
"""The ba.Model of an impact-bomb."""
land_mine_model: ba.Model
"""The ba.Model of a land-mine."""
tnt_model: ba.Model
"""The ba.Model of a tnt box."""
regular_tex: ba.Texture
"""The ba.Texture for regular bombs."""
ice_tex: ba.Texture
"""The ba.Texture for ice bombs."""
sticky_tex: ba.Texture
"""The ba.Texture for sticky bombs."""
impact_tex: ba.Texture
"""The ba.Texture for impact bombs."""
impact_lit_tex: ba.Texture
"""The ba.Texture for impact bombs with lights lit."""
land_mine_tex: ba.Texture
"""The ba.Texture for land-mines."""
land_mine_lit_tex: ba.Texture
"""The ba.Texture for land-mines with the light lit."""
tnt_tex: ba.Texture
"""The ba.Texture for tnt boxes."""
hiss_sound: ba.Sound
"""The ba.Sound for the hiss sound an ice bomb makes."""
debris_fall_sound: ba.Sound
"""The ba.Sound for random falling debris after an explosion."""
wood_debris_fall_sound: ba.Sound
"""A ba.Sound for random wood debris falling after an explosion."""
explode_sounds: Sequence[ba.Sound]
"""A tuple of ba.Sound-s for explosions."""
freeze_sound: ba.Sound
"""A ba.Sound of an ice bomb freezing something."""
fuse_sound: ba.Sound
"""A ba.Sound of a burning fuse."""
activate_sound: ba.Sound
"""A ba.Sound for an activating impact bomb."""
warn_sound: ba.Sound
"""A ba.Sound for an impact bomb about to explode due to time-out."""
bomb_material: ba.Material
"""A ba.Material applied to all bombs."""
normal_sound_material: ba.Material
"""A ba.Material that generates standard bomb noises on impacts, etc."""
sticky_material: ba.Material
"""A ba.Material that makes 'splat' sounds and makes collisions softer."""
land_mine_no_explode_material: ba.Material
"""A ba.Material that keeps land-mines from blowing up.
Applied to land-mines when they are created to allow land-mines to
touch without exploding."""
land_mine_blast_material: ba.Material
"""A ba.Material applied to activated land-mines that causes them to
explode on impact."""
impact_blast_material: ba.Material
"""A ba.Material applied to activated impact-bombs that causes them to
explode on impact."""
blast_material: ba.Material
"""A ba.Material applied to bomb blast geometry which triggers impact
events with what it touches."""
dink_sounds: Sequence[ba.Sound]
"""A tuple of ba.Sound-s for when bombs hit the ground."""
sticky_impact_sound: ba.Sound
"""The ba.Sound for a squish made by a sticky bomb hitting something."""
roll_sound: ba.Sound
"""ba.Sound for a rolling bomb."""
_STORENAME = ba.storagename() _STORENAME = ba.storagename()
@classmethod @classmethod

View File

@ -15,38 +15,36 @@ if TYPE_CHECKING:
class FlagFactory: class FlagFactory:
"""Wraps up media and other resources used by ba.Flags. """Wraps up media and other resources used by `Flag`s.
category: Gameplay Classes Category: **Gameplay Classes**
A single instance of this is shared between all flags A single instance of this is shared between all flags
and can be retrieved via bastd.actor.flag.get_factory(). and can be retrieved via FlagFactory.get().
Attributes:
flagmaterial
The ba.Material applied to all ba.Flags.
impact_sound
The ba.Sound used when a ba.Flag hits the ground.
skid_sound
The ba.Sound used when a ba.Flag skids along the ground.
no_hit_material
A ba.Material that prevents contact with most objects;
applied to 'non-touchable' flags.
flag_texture
The ba.Texture for flags.
""" """
flagmaterial: ba.Material
"""The ba.Material applied to all `Flag`s."""
impact_sound: ba.Sound
"""The ba.Sound used when a `Flag` hits the ground."""
skid_sound: ba.Sound
"""The ba.Sound used when a `Flag` skids along the ground."""
no_hit_material: ba.Material
"""A ba.Material that prevents contact with most objects;
applied to 'non-touchable' flags."""
flag_texture: ba.Texture
"""The ba.Texture for flags."""
_STORENAME = ba.storagename() _STORENAME = ba.storagename()
def __init__(self) -> None: def __init__(self) -> None:
"""Instantiate a FlagFactory. """Instantiate a `FlagFactory`.
You shouldn't need to do this; call bastd.actor.flag.get_factory() to You shouldn't need to do this; call FlagFactory.get() to
get a shared instance. get a shared instance.
""" """
shared = SharedObjects.get() shared = SharedObjects.get()
@ -109,7 +107,7 @@ class FlagFactory:
@classmethod @classmethod
def get(cls) -> FlagFactory: def get(cls) -> FlagFactory:
"""Get/create a shared FlagFactory instance.""" """Get/create a shared `FlagFactory` instance."""
activity = ba.getactivity() activity = ba.getactivity()
factory = activity.customdata.get(cls._STORENAME) factory = activity.customdata.get(cls._STORENAME)
if factory is None: if factory is None:
@ -121,58 +119,47 @@ class FlagFactory:
@dataclass @dataclass
class FlagPickedUpMessage: class FlagPickedUpMessage:
"""A message saying a ba.Flag has been picked up. """A message saying a `Flag` has been picked up.
category: Message Classes Category: **Message Classes**
"""
Attributes:
flag
The ba.Flag that has been picked up.
node
The ba.Node doing the picking up.
"""
flag: Flag flag: Flag
"""The `Flag` that has been picked up."""
node: ba.Node node: ba.Node
"""The ba.Node doing the picking up."""
@dataclass @dataclass
class FlagDiedMessage: class FlagDiedMessage:
"""A message saying a ba.Flag has died. """A message saying a `Flag` has died.
category: Message Classes Category: **Message Classes**
Attributes:
flag
The ba.Flag that died.
""" """
flag: Flag flag: Flag
"""The `Flag` that died."""
@dataclass @dataclass
class FlagDroppedMessage: class FlagDroppedMessage:
"""A message saying a ba.Flag has been dropped. """A message saying a `Flag` has been dropped.
category: Message Classes Category: **Message Classes**
Attributes:
flag
The ba.Flag that was dropped.
node
The ba.Node that was holding it.
""" """
flag: Flag flag: Flag
"""The `Flag` that was dropped."""
node: ba.Node node: ba.Node
"""The ba.Node that was holding it."""
class Flag(ba.Actor): class Flag(ba.Actor):
"""A flag; used in games such as capture-the-flag or king-of-the-hill. """A flag; used in games such as capture-the-flag or king-of-the-hill.
category: Gameplay Classes Category: **Gameplay Classes**
Can be stationary or carry-able by players. Can be stationary or carry-able by players.
""" """
@ -189,7 +176,7 @@ class Flag(ba.Actor):
useful for things like king-of-the-hill where players should useful for things like king-of-the-hill where players should
not be moving the flag around. not be moving the flag around.
'materials can be a list of extra ba.Materials to apply to the flag. 'materials can be a list of extra `ba.Material`s to apply to the flag.
If 'dropped_timeout' is provided (in seconds), the flag will die If 'dropped_timeout' is provided (in seconds), the flag will die
after remaining untouched for that long once it has been moved after remaining untouched for that long once it has been moved

View File

@ -17,31 +17,29 @@ TeamType = TypeVar('TeamType', bound=ba.Team)
class PlayerSpazHurtMessage: class PlayerSpazHurtMessage:
"""A message saying a ba.PlayerSpaz was hurt. """A message saying a PlayerSpaz was hurt.
category: Message Classes Category: **Message Classes**
Attributes:
spaz
The ba.PlayerSpaz that was hurt
""" """
spaz: PlayerSpaz
"""The PlayerSpaz that was hurt"""
def __init__(self, spaz: PlayerSpaz): def __init__(self, spaz: PlayerSpaz):
"""Instantiate with the given ba.Spaz value.""" """Instantiate with the given ba.Spaz value."""
self.spaz = spaz self.spaz = spaz
class PlayerSpaz(Spaz): class PlayerSpaz(Spaz):
"""A ba.Spaz subclass meant to be controlled by a ba.Player. """A Spaz subclass meant to be controlled by a ba.Player.
category: Gameplay Classes Category: **Gameplay Classes**
When a PlayerSpaz dies, it delivers a ba.PlayerDiedMessage When a PlayerSpaz dies, it delivers a ba.PlayerDiedMessage
to the current ba.Activity. (unless the death was the result of the to the current ba.Activity. (unless the death was the result of the
player leaving the game, in which case no message is sent) player leaving the game, in which case no message is sent)
When a PlayerSpaz is hurt, it delivers a ba.PlayerSpazHurtMessage When a PlayerSpaz is hurt, it delivers a PlayerSpazHurtMessage
to the current ba.Activity. to the current ba.Activity.
""" """

View File

@ -23,69 +23,67 @@ class _TouchedMessage:
class PowerupBoxFactory: class PowerupBoxFactory:
"""A collection of media and other resources used by ba.Powerups. """A collection of media and other resources used by ba.Powerups.
category: Gameplay Classes Category: **Gameplay Classes**
A single instance of this is shared between all powerups A single instance of this is shared between all powerups
and can be retrieved via ba.Powerup.get_factory(). and can be retrieved via ba.Powerup.get_factory().
Attributes:
model
The ba.Model of the powerup box.
model_simple
A simpler ba.Model of the powerup box, for use in shadows, etc.
tex_bomb
Triple-bomb powerup ba.Texture.
tex_punch
Punch powerup ba.Texture.
tex_ice_bombs
Ice bomb powerup ba.Texture.
tex_sticky_bombs
Sticky bomb powerup ba.Texture.
tex_shield
Shield powerup ba.Texture.
tex_impact_bombs
Impact-bomb powerup ba.Texture.
tex_health
Health powerup ba.Texture.
tex_land_mines
Land-mine powerup ba.Texture.
tex_curse
Curse powerup ba.Texture.
health_powerup_sound
ba.Sound played when a health powerup is accepted.
powerup_sound
ba.Sound played when a powerup is accepted.
powerdown_sound
ba.Sound that can be used when powerups wear off.
powerup_material
ba.Material applied to powerup boxes.
powerup_accept_material
Powerups will send a ba.PowerupMessage to anything they touch
that has this ba.Material applied.
""" """
model: ba.Model
"""The ba.Model of the powerup box."""
model_simple: ba.Model
"""A simpler ba.Model of the powerup box, for use in shadows, etc."""
tex_bomb: ba.Texture
"""Triple-bomb powerup ba.Texture."""
tex_punch: ba.Texture
"""Punch powerup ba.Texture."""
tex_ice_bombs: ba.Texture
"""Ice bomb powerup ba.Texture."""
tex_sticky_bombs: ba.Texture
"""Sticky bomb powerup ba.Texture."""
tex_shield: ba.Texture
"""Shield powerup ba.Texture."""
tex_impact_bombs: ba.Texture
"""Impact-bomb powerup ba.Texture."""
tex_health: ba.Texture
"""Health powerup ba.Texture."""
tex_land_mines: ba.Texture
"""Land-mine powerup ba.Texture."""
tex_curse: ba.Texture
"""Curse powerup ba.Texture."""
health_powerup_sound: ba.Sound
"""ba.Sound played when a health powerup is accepted."""
powerup_sound: ba.Sound
"""ba.Sound played when a powerup is accepted."""
powerdown_sound: ba.Sound
"""ba.Sound that can be used when powerups wear off."""
powerup_material: ba.Material
"""ba.Material applied to powerup boxes."""
powerup_accept_material: ba.Material
"""Powerups will send a ba.PowerupMessage to anything they touch
that has this ba.Material applied."""
_STORENAME = ba.storagename() _STORENAME = ba.storagename()
def __init__(self) -> None: def __init__(self) -> None:
"""Instantiate a PowerupBoxFactory. """Instantiate a PowerupBoxFactory.
You shouldn't need to do this; call ba.Powerup.get_factory() You shouldn't need to do this; call Powerup.get_factory()
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
@ -191,18 +189,16 @@ class PowerupBox(ba.Actor):
This will deliver a ba.PowerupMessage to anything that touches it This will deliver a ba.PowerupMessage to anything that touches it
which has the ba.PowerupBoxFactory.powerup_accept_material applied. which has the ba.PowerupBoxFactory.powerup_accept_material applied.
Attributes:
poweruptype
The string powerup type. This can be 'triple_bombs', 'punch',
'ice_bombs', 'impact_bombs', 'land_mines', 'sticky_bombs', 'shield',
'health', or 'curse'.
node
The 'prop' ba.Node representing this box.
""" """
poweruptype: str
"""The string powerup type. This can be 'triple_bombs', 'punch',
'ice_bombs', 'impact_bombs', 'land_mines', 'sticky_bombs', 'shield',
'health', or 'curse'."""
node: ba.Node
"""The 'prop' ba.Node representing this box."""
def __init__(self, def __init__(self,
position: Sequence[float] = (0.0, 1.0, 0.0), position: Sequence[float] = (0.0, 1.0, 0.0),
poweruptype: str = 'triple_bombs', poweruptype: str = 'triple_bombs',

View File

@ -16,29 +16,27 @@ if TYPE_CHECKING:
class Spawner: class Spawner:
"""Utility for delayed spawning of objects. """Utility for delayed spawning of objects.
category: Gameplay Classes Category: **Gameplay Classes**
Creates a light flash and sends a ba.Spawner.SpawnMessage Creates a light flash and sends a Spawner.SpawnMessage
to the current activity after a delay. to the current activity after a delay.
""" """
class SpawnMessage: class SpawnMessage:
"""Spawn message sent by a ba.Spawner after its delay has passed. """Spawn message sent by a Spawner after its delay has passed.
category: Message Classes Category: **Message Classes**
Attributes:
spawner
The ba.Spawner we came from.
data
The data object passed by the user.
pt
The spawn position.
""" """
spawner: Spawner
"""The ba.Spawner we came from."""
data: Any
"""The data object passed by the user."""
pt: Sequence[float]
"""The spawn position."""
def __init__( def __init__(
self, self,
spawner: Spawner, spawner: Spawner,

View File

@ -42,23 +42,21 @@ class Spaz(ba.Actor):
""" """
Base class for various Spazzes. Base class for various Spazzes.
category: Gameplay Classes Category: **Gameplay Classes**
A Spaz is the standard little humanoid character in the game. A Spaz is the standard little humanoid character in the game.
It can be controlled by a player or by AI, and can have It can be controlled by a player or by AI, and can have
various different appearances. The name 'Spaz' is not to be various different appearances. The name 'Spaz' is not to be
confused with the 'Spaz' character in the game, which is just confused with the 'Spaz' character in the game, which is just
one of the skins available for instances of this class. one of the skins available for instances of this class.
Attributes:
node
The 'spaz' ba.Node.
""" """
# pylint: disable=too-many-public-methods # pylint: disable=too-many-public-methods
# pylint: disable=too-many-locals # pylint: disable=too-many-locals
node: ba.Node
"""The 'spaz' ba.Node."""
points_mult = 1 points_mult = 1
curse_time: Optional[float] = 5.0 curse_time: Optional[float] = 5.0
default_bomb_count = 1 default_bomb_count = 1

View File

@ -27,17 +27,15 @@ PRO_BOT_HIGHLIGHT = (0.6, 0.1, 0.05)
class SpazBotPunchedMessage: class SpazBotPunchedMessage:
"""A message saying a ba.SpazBot got punched. """A message saying a ba.SpazBot got punched.
category: Message Classes Category: **Message Classes**
Attributes:
spazbot
The ba.SpazBot that got punched.
damage
How much damage was done to the ba.SpazBot.
""" """
spazbot: SpazBot
"""The ba.SpazBot that got punched."""
damage: int
"""How much damage was done to the SpazBot."""
def __init__(self, spazbot: SpazBot, damage: int): def __init__(self, spazbot: SpazBot, damage: int):
"""Instantiate a message with the given values.""" """Instantiate a message with the given values."""
self.spazbot = spazbot self.spazbot = spazbot
@ -47,20 +45,18 @@ class SpazBotPunchedMessage:
class SpazBotDiedMessage: class SpazBotDiedMessage:
"""A message saying a ba.SpazBot has died. """A message saying a ba.SpazBot has died.
category: Message Classes Category: **Message Classes**
Attributes:
spazbot
The ba.SpazBot that was killed.
killerplayer
The ba.Player that killed it (or None).
how
The particular type of death.
""" """
spazbot: SpazBot
"""The SpazBot that was killed."""
killerplayer: Optional[ba.Player]
"""The ba.Player that killed it (or None)."""
how: ba.DeathType
"""The particular type of death."""
def __init__(self, spazbot: SpazBot, killerplayer: Optional[ba.Player], def __init__(self, spazbot: SpazBot, killerplayer: Optional[ba.Player],
how: ba.DeathType): how: ba.DeathType):
"""Instantiate with given values.""" """Instantiate with given values."""
@ -72,7 +68,7 @@ class SpazBotDiedMessage:
class SpazBot(Spaz): class SpazBot(Spaz):
"""A really dumb AI version of ba.Spaz. """A really dumb AI version of ba.Spaz.
category: Bot Classes Category: **Bot Classes**
Add these to a ba.BotSet to use them. Add these to a ba.BotSet to use them.

View File

@ -11,72 +11,70 @@ from bastd.gameutils import SharedObjects
import _ba import _ba
if TYPE_CHECKING: if TYPE_CHECKING:
from typing import Any from typing import Any, Sequence
class SpazFactory: class SpazFactory:
"""Wraps up media and other resources used by ba.Spaz instances. """Wraps up media and other resources used by ba.Spaz instances.
Category: Gameplay Classes Category: **Gameplay Classes**
Generally one of these is created per ba.Activity and shared Generally one of these is created per ba.Activity and shared
between all spaz instances. Use ba.Spaz.get_factory() to return between all spaz instances. Use ba.Spaz.get_factory() to return
the shared factory for the current activity. the shared factory for the current activity.
Attributes:
impact_sounds_medium
A tuple of ba.Sounds for when a ba.Spaz hits something kinda hard.
impact_sounds_hard
A tuple of ba.Sounds for when a ba.Spaz hits something really hard.
impact_sounds_harder
A tuple of ba.Sounds for when a ba.Spaz hits something really
really hard.
single_player_death_sound
The sound that plays for an 'important' spaz death such as in
co-op games.
punch_sound
A standard punch ba.Sound.
punch_sound_strong
A tuple of stronger sounding punch ba.Sounds.
punch_sound_stronger
A really really strong sounding punch ba.Sound.
swish_sound
A punch swish ba.Sound.
block_sound
A ba.Sound for when an attack is blocked by invincibility.
shatter_sound
A ba.Sound for when a frozen ba.Spaz shatters.
splatter_sound
A ba.Sound for when a ba.Spaz blows up via curse.
spaz_material
A ba.Material applied to all of parts of a ba.Spaz.
roller_material
A ba.Material applied to the invisible roller ball body that
a ba.Spaz uses for locomotion.
punch_material
A ba.Material applied to the 'fist' of a ba.Spaz.
pickup_material
A ba.Material applied to the 'grabber' body of a ba.Spaz.
curse_material
A ba.Material applied to a cursed ba.Spaz that triggers an explosion.
""" """
impact_sounds_medium: Sequence[ba.Sound]
"""A tuple of ba.Sound-s for when a ba.Spaz hits something kinda hard."""
impact_sounds_hard: Sequence[ba.Sound]
"""A tuple of ba.Sound-s for when a ba.Spaz hits something really hard."""
impact_sounds_harder: Sequence[ba.Sound]
"""A tuple of ba.Sound-s for when a ba.Spaz hits something really
really hard."""
single_player_death_sound: ba.Sound
"""The sound that plays for an 'important' spaz death such as in
co-op games."""
punch_sound: ba.Sound
"""A standard punch ba.Sound."""
punch_sound_strong: Sequence[ba.Sound]
"""A tuple of stronger sounding punch ba.Sounds."""
punch_sound_stronger: ba.Sound
"""A really really strong sounding punch ba.Sound."""
swish_sound: ba.Sound
"""A punch swish ba.Sound."""
block_sound: ba.Sound
"""A ba.Sound for when an attack is blocked by invincibility."""
shatter_sound: ba.Sound
"""A ba.Sound for when a frozen ba.Spaz shatters."""
splatter_sound: ba.Sound
"""A ba.Sound for when a ba.Spaz blows up via curse."""
spaz_material: ba.Material
"""A ba.Material applied to all of parts of a ba.Spaz."""
roller_material: ba.Material
"""A ba.Material applied to the invisible roller ball body that
a ba.Spaz uses for locomotion."""
punch_material: ba.Material
"""A ba.Material applied to the 'fist' of a ba.Spaz."""
pickup_material: ba.Material
"""A ba.Material applied to the 'grabber' body of a ba.Spaz."""
curse_material: ba.Material
"""A ba.Material applied to a cursed ba.Spaz that triggers an explosion."""
_STORENAME = ba.storagename() _STORENAME = ba.storagename()
def _preload(self, character: str) -> None: def _preload(self, character: str) -> None:

View File

@ -17,13 +17,11 @@ class ConfigCheckBox:
It will automatically save and apply the config when its It will automatically save and apply the config when its
value changes. value changes.
Attributes:
widget
The underlying ba.Widget instance.
""" """
widget: ba.Widget
"""The underlying ba.Widget instance."""
def __init__(self, def __init__(self,
parent: ba.Widget, parent: ba.Widget,
configkey: str, configkey: str,
@ -65,22 +63,20 @@ class ConfigNumberEdit:
It will automatically save and apply the config when its It will automatically save and apply the config when its
value changes. value changes.
Attributes:
nametext
The text widget displaying the name.
valuetext
The text widget displaying the current value.
minusbutton
The button widget used to reduce the value.
plusbutton
The button widget used to increase the value.
""" """
nametext: ba.Widget
"""The text widget displaying the name."""
valuetext: ba.Widget
"""The text widget displaying the current value."""
minusbutton: ba.Widget
"""The button widget used to reduce the value."""
plusbutton: ba.Widget
"""The button widget used to increase the value."""
def __init__(self, def __init__(self,
parent: ba.Widget, parent: ba.Widget,
configkey: str, configkey: str,

View File

@ -15,7 +15,9 @@ if TYPE_CHECKING:
class PopupWindow: class PopupWindow:
"""A transient window that positions and scales itself for visibility.""" """A transient window that positions and scales itself for visibility.
Category: UI Classes"""
def __init__(self, def __init__(self,
position: tuple[float, float], position: tuple[float, float],

View File

@ -0,0 +1,3 @@
.pdoc .docstring {
margin-left: 2rem;
}

View File

@ -0,0 +1,39 @@
{% extends "default/index.html.jinja2" %}
{% block content %}
<header class="pdoc">
{% block logo %}
<a href="https://ballistica.net">
<img src="https://files.ballistica.net/ballistica_media/ballistica_logo_half.png"
alt="project logo"/>
</a>
{% endblock %}
{% if search %}
<input type="search"
placeholder="Search Python API Documentation..."
aria-label="search box">
{% endif %}
</header>
<main class="pdoc">
<h1>Welcome to Ballistica Documentations!</h1>
<i>Last updated for Ballistica {{ ba_version }}
(build {{ ba_build }})</i>
<hr/>
<p>
Here you can find information about Python classes/functions
used by Ballistica.
Fell free to create an
<a href="https://github.com/efroemling/ballistica/issues/">
issue</a>
or send a
<a href="https://github.com/efroemling/ballistica/pulls/">PR</a>
if something in this docs feels incorrect or can be improved.
Note that <code>bastd</code>'s docs may look a little terrible
right
now, hope that's temporary. :)
</p>
</main>
{% if search %}
{% include "search.html.jinja2" %}
{% endif %}
{% endblock %}

View File

@ -0,0 +1,9 @@
{% extends "default/module.html.jinja2" %}
{% macro is_public(doc) %}
{% if "(internal)" in doc.docstring %}
{# Returning no text is interpreted as false #}
{% else %}
{{ default_is_public(doc) }}
{% endif %}
{% endmacro %}

View File

@ -34,6 +34,7 @@
"ansiwrap", "ansiwrap",
"filelock", "filelock",
"Cocoa", "Cocoa",
"pdoc",
"certifi" "certifi"
], ],
"python_paths": [ "python_paths": [

View File

@ -37,4 +37,5 @@ ignore_missing_imports = True
[mypy-efrotools.pylintplugins] [mypy-efrotools.pylintplugins]
disallow_any_unimported = False disallow_any_unimported = False
[mypy-pdoc]
ignore_missing_imports = True

View File

@ -25,7 +25,7 @@ void PythonClassCollideModel::SetupType(PyTypeObject* obj) {
obj->tp_doc = obj->tp_doc =
"A reference to a collide-model.\n" "A reference to a collide-model.\n"
"\n" "\n"
"Category: Asset Classes\n" "Category: **Asset Classes**\n"
"\n" "\n"
"Use ba.getcollidemodel() to instantiate one."; "Use ba.getcollidemodel() to instantiate one.";
obj->tp_repr = (reprfunc)tp_repr; obj->tp_repr = (reprfunc)tp_repr;

View File

@ -19,7 +19,7 @@ void PythonClassContext::SetupType(PyTypeObject* obj) {
"\n" "\n"
"A game context state.\n" "A game context state.\n"
"\n" "\n"
"Category: General Utility Classes\n" "Category: **General Utility Classes**\n"
"\n" "\n"
"Many operations such as ba.newnode() or ba.gettexture() operate\n" "Many operations such as ba.newnode() or ba.gettexture() operate\n"
"implicitly on the current context. Each ba.Activity has its own\n" "implicitly on the current context. Each ba.Activity has its own\n"
@ -30,42 +30,43 @@ void PythonClassContext::SetupType(PyTypeObject* obj) {
"since timers and other callbacks will take care of saving and\n" "since timers and other callbacks will take care of saving and\n"
"restoring the context automatically, but there may be rare cases where\n" "restoring the context automatically, but there may be rare cases where\n"
"you need to deal with them, such as when loading media in for use in\n" "you need to deal with them, such as when loading media in for use in\n"
"the UI (there is a special 'ui' context for all user-interface-related\n" "the UI (there is a special `'ui'` context for all\n"
"functionality)\n" "user-interface-related functionality).\n"
"\n" "\n"
"When instantiating a ba.Context instance, a single 'source' argument\n" "When instantiating a ba.Context instance, a single `'source'` "
"argument\n"
"is passed, which can be one of the following strings/objects:\n\n" "is passed, which can be one of the following strings/objects:\n\n"
"'empty':\n" "###### `'empty'`\n"
" Gives an empty context; it can be handy to run code here to ensure\n" "> Gives an empty context; it can be handy to run code here to ensure\n"
" it does no loading of media, creation of nodes, etc.\n" "it does no loading of media, creation of nodes, etc.\n"
"\n" "\n"
"'current':\n" "###### `'current'`\n"
" Sets the context object to the current context.\n" "> Sets the context object to the current context.\n"
"\n" "\n"
"'ui':\n" "###### `'ui'`\n"
" Sets to the UI context. UI functions as well as loading of media to\n" "> Sets to the UI context. UI functions as well as loading of media to\n"
" be used in said functions must happen in the UI context.\n" "be used in said functions must happen in the UI context.\n"
"\n" "\n"
"A ba.Activity instance:\n" "###### A ba.Activity instance\n"
" Gives the context for the provided ba.Activity.\n" "> Gives the context for the provided ba.Activity.\n"
" Most all code run during a game happens in an Activity's Context.\n" " Most all code run during a game happens in an Activity's Context.\n"
"\n" "\n"
"A ba.Session instance:\n" "###### A ba.Session instance\n"
" Gives the context for the provided ba.Session.\n" "> Gives the context for the provided ba.Session.\n"
" Generally a user should not need to run anything here.\n" "Generally a user should not need to run anything here.\n"
"\n" "\n"
"\n" "\n"
"Usage:\n" "##### Usage\n"
"\n"
"Contexts are generally used with the python 'with' statement, which\n" "Contexts are generally used with the python 'with' statement, which\n"
"sets the context as current on entry and resets it to the previous\n" "sets the context as current on entry and resets it to the previous\n"
"value on exit.\n" "value on exit.\n"
"\n" "\n"
"# Example: load a few textures into the UI context\n" "##### Example\n"
"# (for use in widgets, etc):\n" "Load a few textures into the UI context\n"
"with ba.Context('ui'):\n" "(for use in widgets, etc):\n"
" tex1 = ba.gettexture('foo_tex_1')\n" ">>> with ba.Context('ui'):\n"
" tex2 = ba.gettexture('foo_tex_2')\n"; "... tex1 = ba.gettexture('foo_tex_1')\n"
"... tex2 = ba.gettexture('foo_tex_2')\n";
obj->tp_new = tp_new; obj->tp_new = tp_new;
obj->tp_dealloc = (destructor)tp_dealloc; obj->tp_dealloc = (destructor)tp_dealloc;

View File

@ -16,7 +16,7 @@ void PythonClassContextCall::SetupType(PyTypeObject* obj) {
"\n" "\n"
"A context-preserving callable.\n" "A context-preserving callable.\n"
"\n" "\n"
"Category: General Utility Classes\n" "Category: **General Utility Classes**\n"
"\n" "\n"
"A ContextCall wraps a callable object along with a reference\n" "A ContextCall wraps a callable object along with a reference\n"
"to the current context (see ba.Context); it handles restoring the\n" "to the current context (see ba.Context); it handles restoring the\n"
@ -38,17 +38,20 @@ void PythonClassContextCall::SetupType(PyTypeObject* obj) {
"shutdown, whereas ba.WeakCall simply looks at whether the target\n" "shutdown, whereas ba.WeakCall simply looks at whether the target\n"
"object still exists.\n" "object still exists.\n"
"\n" "\n"
"# Example A: code like this can inadvertently prevent our activity\n" "##### Examples\n"
"# (self) from ending until the operation completes, since the bound\n" "**Example A:** code like this can inadvertently prevent our activity\n"
"# method we're passing (self.dosomething) contains a strong-reference\n" "(self) from ending until the operation completes, since the bound\n"
"# to self).\n" "method we're passing (self.dosomething) contains a strong-reference\n"
"start_some_long_action(callback_when_done=self.dosomething)\n" "to self).\n"
">>> start_some_long_action(callback_when_done=self.dosomething)\n"
"\n" "\n"
"# Example B: in this case our activity (self) can still die\n" "**Example B:** in this case our activity (self) can still die\n"
"# properly; the callback will clear itself when the activity starts\n" "properly; the callback will clear itself when the activity starts\n"
"# shutting down, becoming a harmless no-op and releasing the reference\n" "shutting down, becoming a harmless no-op and releasing the reference\n"
"# to our activity.\n" "to our activity.\n"
"start_long_action(callback_when_done=ba.ContextCall(self.mycallback))\n"; "\n"
">>> start_long_action(\n"
"... callback_when_done=ba.ContextCall(self.mycallback))\n";
obj->tp_new = tp_new; obj->tp_new = tp_new;
obj->tp_dealloc = (destructor)tp_dealloc; obj->tp_dealloc = (destructor)tp_dealloc;

View File

@ -24,7 +24,7 @@ void PythonClassData::SetupType(PyTypeObject* obj) {
obj->tp_doc = obj->tp_doc =
"A reference to a data object.\n" "A reference to a data object.\n"
"\n" "\n"
"Category: Asset Classes\n" "Category: **Asset Classes**\n"
"\n" "\n"
"Use ba.getdata() to instantiate one."; "Use ba.getdata() to instantiate one.";
obj->tp_repr = (reprfunc)tp_repr; obj->tp_repr = (reprfunc)tp_repr;

View File

@ -19,45 +19,45 @@ void PythonClassInputDevice::SetupType(PyTypeObject* obj) {
obj->tp_doc = obj->tp_doc =
"An input-device such as a gamepad, touchscreen, or keyboard.\n" "An input-device such as a gamepad, touchscreen, or keyboard.\n"
"\n" "\n"
"Category: Gameplay Classes\n" "Category: **Gameplay Classes**\n"
"\n" "\n"
"Attributes:\n" "Attributes:\n"
"\n" "\n"
" allows_configuring: bool\n" " allows_configuring (bool):\n"
" Whether the input-device can be configured.\n" " Whether the input-device can be configured.\n"
"\n" "\n"
" has_meaningful_button_names: bool\n" " has_meaningful_button_names (bool):\n"
" Whether button names returned by this instance match labels\n" " Whether button names returned by this instance match labels\n"
" on the actual device. (Can be used to determine whether to show\n" " on the actual device. (Can be used to determine whether to show\n"
" them in controls-overlays, etc.)\n" " them in controls-overlays, etc.).\n"
"\n" "\n"
" player: Optional[ba.SessionPlayer]\n" " player (Optional[ba.SessionPlayer]):\n"
" The player associated with this input device.\n" " The player associated with this input device.\n"
"\n" "\n"
" client_id: int\n" " client_id (int):\n"
" The numeric client-id this device is associated with.\n" " The numeric client-id this device is associated with.\n"
" This is only meaningful for remote client inputs; for\n" " This is only meaningful for remote client inputs; for\n"
" all local devices this will be -1.\n" " all local devices this will be -1.\n"
"\n" "\n"
" name: str\n" " name (str):\n"
" The name of the device.\n" " The name of the device.\n"
"\n" "\n"
" unique_identifier: str\n" " unique_identifier (str):\n"
" A string that can be used to persistently identify the device,\n" " A string that can be used to persistently identify the device,\n"
" even among other devices of the same type. Used for saving\n" " even among other devices of the same type. Used for saving\n"
" prefs, etc.\n" " prefs, etc.\n"
"\n" "\n"
" id: int\n" " id (int):\n"
" The unique numeric id of this device.\n" " The unique numeric id of this device.\n"
"\n" "\n"
" instance_number: int\n" " instance_number (int):\n"
" The number of this device among devices of the same type.\n" " The number of this device among devices of the same type.\n"
"\n" "\n"
" is_controller_app: bool\n" " is_controller_app (bool):\n"
" Whether this input-device represents a locally-connected\n" " Whether this input-device represents a locally-connected\n"
" controller-app.\n" " controller-app.\n"
"\n" "\n"
" is_remote_client: bool\n" " is_remote_client (bool):\n"
" Whether this input-device represents a remotely-connected\n" " Whether this input-device represents a remotely-connected\n"
" client.\n" " client.\n"
"\n"; "\n";
@ -417,7 +417,8 @@ PyMethodDef PythonClassInputDevice::tp_methods[] = {
{"exists", (PyCFunction)Exists, METH_NOARGS, {"exists", (PyCFunction)Exists, METH_NOARGS,
"exists() -> bool\n" "exists() -> bool\n"
"\n" "\n"
"Return whether the underlying device for this object is still present."}, "Return whether the underlying device for this object is\n"
"still present.\n"},
{"get_button_name", (PyCFunction)GetButtonName, {"get_button_name", (PyCFunction)GetButtonName,
METH_VARARGS | METH_KEYWORDS, // NOLINT (signed bitwise ops) METH_VARARGS | METH_KEYWORDS, // NOLINT (signed bitwise ops)
"get_button_name(button_id: int) -> ba.Lstr\n" "get_button_name(button_id: int) -> ba.Lstr\n"

View File

@ -51,25 +51,25 @@ void PythonClassMaterial::SetupType(PyTypeObject* obj) {
"\n" "\n"
"An entity applied to game objects to modify collision behavior.\n" "An entity applied to game objects to modify collision behavior.\n"
"\n" "\n"
"Category: Gameplay Classes\n" "Category: **Gameplay Classes**\n"
"\n" "\n"
"A material can affect physical characteristics, generate sounds,\n" "A material can affect physical characteristics, generate sounds,\n"
"or trigger callback functions when collisions occur.\n" "or trigger callback functions when collisions occur.\n"
"\n" "\n"
"Materials are applied to 'parts', which are groups of one or more\n" "Materials are applied to 'parts', which are groups of one or more\n"
"rigid bodies created as part of a ba.Node. Nodes can have any number\n" "rigid bodies created as part of a ba.Node. Nodes can have any number\n"
"of parts, each with its own set of materials. Generally materials are\n" "of parts, each with its own set of materials. Generally materials are\n"
"specified as array attributes on the Node. The 'spaz' node, for\n" "specified as array attributes on the Node. The `spaz` node, for\n"
"example, has various attributes such as 'materials',\n" "example, has various attributes such as `materials`,\n"
"'roller_materials', and 'punch_materials', which correspond to the\n" "`roller_materials`, and `punch_materials`, which correspond\n"
"various parts it creates.\n" "to the various parts it creates.\n"
"\n" "\n"
"Use ba.Material() to instantiate a blank material, and then use its\n" "Use ba.Material to instantiate a blank material, and then use its\n"
"add_actions() method to define what the material does.\n" "ba.Material.add_actions() method to define what the material does.\n"
"\n" "\n"
"Attributes:\n" "Attributes:\n"
"\n" "\n"
" " ATTR_LABEL ": str\n" " " ATTR_LABEL " (str):\n"
" A label for the material; only used for debugging.\n"; " A label for the material; only used for debugging.\n";
// clang-format on // clang-format on
@ -280,135 +280,149 @@ PyMethodDef PythonClassMaterial::tp_methods[] = {
"\n" "\n"
"Add one or more actions to the material, optionally with conditions.\n" "Add one or more actions to the material, optionally with conditions.\n"
"\n" "\n"
"Conditions:\n" "##### Conditions\n"
"Conditions are provided as tuples which can be combined\n"
"to form boolean logic. A single condition might look like\n"
"`('condition_name', cond_arg)`, or a more complex nested one\n"
"might look like `(('some_condition', cond_arg), 'or',\n"
"('another_condition', cond2_arg))`.\n"
"\n" "\n"
"Conditions are provided as tuples which can be combined to form boolean\n" "`'and'`, `'or'`, and `'xor'` are available to chain\n"
"logic. A single condition might look like ('condition_name', cond_arg),\n" "together 2 conditions, as seen above.\n"
"or a more complex nested one might look like (('some_condition',\n"
"cond_arg), 'or', ('another_condition', cond2_arg)).\n"
"\n" "\n"
"'and', 'or', and 'xor' are available to chain together 2 conditions, as\n" "##### Available Conditions\n"
" seen above.\n" "###### `('they_have_material', material)`\n"
"> Does the part we\'re hitting have a given ba.Material?\n"
"\n" "\n"
"Available Conditions:\n" "###### `('they_dont_have_material', material)`\n"
"> Does the part we\'re hitting not have a given ba.Material?\n"
"\n" "\n"
"('they_have_material', material) - does the part we\'re hitting have a\n" "###### `('eval_colliding')`\n"
" given ba.Material?\n" "> Is `'collide'` true at this point\n"
"in material evaluation? (see the `modify_part_collision` action)\n"
"\n" "\n"
"('they_dont_have_material', material) - does the part we\'re hitting\n" "###### `('eval_not_colliding')`\n"
" not have a given ba.Material?\n" "> Is 'collide' false at this point\n"
"in material evaluation? (see the `modify_part_collision` action)\n"
"\n" "\n"
"('eval_colliding') - is 'collide' true at this point in material\n" "###### `('we_are_younger_than', age)`\n"
" evaluation? (see the modify_part_collision action)\n" "> Is our part younger than `age` (in milliseconds)?\n"
"\n" "\n"
"('eval_not_colliding') - is 'collide' false at this point in material\n" "###### `('we_are_older_than', age)`\n"
" evaluation? (see the modify_part_collision action)\n" "> Is our part older than `age` (in milliseconds)?\n"
"\n" "\n"
"('we_are_younger_than', age) - is our part younger than 'age'\n" "###### `('they_are_younger_than', age)`\n"
" (in milliseconds)?\n" "> Is the part we're hitting younger than `age` (in milliseconds)?\n"
"\n" "\n"
"('we_are_older_than', age) - is our part older than 'age'\n" "###### `('they_are_older_than', age)`\n"
" (in milliseconds)?\n" "> Is the part we're hitting older than `age` (in milliseconds)?\n"
"\n" "\n"
"('they_are_younger_than', age) - is the part we're hitting younger than\n" "###### `('they_are_same_node_as_us')`\n"
" 'age' (in milliseconds)?\n" "> Does the part we're hitting belong to the same ba.Node as us?\n"
"\n" "\n"
"('they_are_older_than', age) - is the part we're hitting older than\n" "###### `('they_are_different_node_than_us')`\n"
" 'age' (in milliseconds)?\n" "> Does the part we're hitting belong to a different ba.Node than us?\n"
"\n" "\n"
"('they_are_same_node_as_us') - does the part we're hitting belong to\n" "##### Actions\n"
" the same ba.Node as us?\n" "In a similar manner, actions are specified as tuples.\n"
"Multiple actions can be specified by providing a tuple\n"
"of tuples.\n"
"\n" "\n"
"('they_are_different_node_than_us') - does the part we're hitting\n" "##### Available Actions\n"
" belong to a different ba.Node than us?\n" "###### `('call', when, callable)`\n"
"> Calls the provided callable;\n"
"`when` can be either `'at_connect'` or `'at_disconnect'`.\n"
"`'at_connect'` means to fire\n"
"when the two parts first come in contact; `'at_disconnect'`\n"
"means to fire once they cease being in contact.\n"
"\n" "\n"
"Actions:\n" "###### `('message', who, when, message_obj)`\n"
"> Sends a message object;\n"
"`who` can be either `'our_node'` or `'their_node'`, `when` can be\n"
"`'at_connect'` or `'at_disconnect'`, and `message_obj` is the message\n"
"object to send.\n"
"This has the same effect as calling the node's\n"
"ba.Node.handlemessage() method.\n"
"\n" "\n"
"In a similar manner, actions are specified as tuples. Multiple actions\n" "###### `('modify_part_collision', attr, value)`\n"
"can be specified by providing a tuple of tuples.\n" "> Changes some\n"
"characteristic of the physical collision that will occur between\n"
"our part and their part. This change will remain in effect as\n"
"long as the two parts remain overlapping. This means if you have a\n"
"part with a material that turns `'collide'` off against parts\n"
"younger than 100ms, and it touches another part that is 50ms old,\n"
"it will continue to not collide with that part until they separate,\n"
"even if the 100ms threshold is passed. Options for attr/value are:\n"
"`'physical'` (boolean value; whether a *physical* response will\n"
"occur at all), `'friction'` (float value; how friction-y the\n"
"physical response will be), `'collide'` (boolean value;\n"
"whether *any* collision will occur at all, including non-physical\n"
"stuff like callbacks), `'use_node_collide'`\n"
"(boolean value; whether to honor modify_node_collision\n"
"overrides for this collision), `'stiffness'` (float value,\n"
"how springy the physical response is), `'damping'` (float\n"
"value, how damped the physical response is), `'bounce'` (float\n"
"value; how bouncy the physical response is).\n"
"\n" "\n"
"Available Actions:\n" "###### `('modify_node_collision', attr, value)`\n"
"> Similar to\n"
"`modify_part_collision`, but operates at a node-level.\n"
"collision attributes set here will remain in effect as long as\n"
"*anything* from our part's node and their part's node overlap.\n"
"A key use of this functionality is to prevent new nodes from\n"
"colliding with each other if they appear overlapped;\n"
"if `modify_part_collision` is used, only the individual\n"
"parts that were overlapping would avoid contact, but other parts\n"
"could still contact leaving the two nodes 'tangled up'. Using\n"
"`modify_node_collision` ensures that the nodes must completely\n"
"separate before they can start colliding. Currently the only attr\n"
"available here is `'collide'` (a boolean value).\n"
"\n" "\n"
"('call', when, callable) - calls the provided callable; 'when' can be\n" "###### `('sound', sound, volume)`\n"
" either 'at_connect' or 'at_disconnect'. 'at_connect' means to fire\n" "> Plays a ba.Sound when a collision\n"
" when the two parts first come in contact; 'at_disconnect' means to\n" "occurs, at a given volume, regardless of the collision speed/etc.\n"
" fire once they cease being in contact.\n"
"\n" "\n"
"('message', who, when, message_obj) - sends a message object; 'who' can\n" "###### `('impact_sound', sound, targetImpulse, volume)`\n"
" be either 'our_node' or 'their_node', 'when' can be 'at_connect' or\n" "> Plays a sound\n"
" 'at_disconnect', and message_obj is the message object to send.\n" "when a collision occurs, based on the speed of impact.\n"
" This has the same effect as calling the node's handlemessage()\n" "Provide a ba.Sound, a target-impulse, and a volume.\n"
" method.\n"
"\n" "\n"
"('modify_part_collision', attr, value) - changes some characteristic\n" "###### `('skid_sound', sound, targetImpulse, volume)`\n"
" of the physical collision that will occur between our part and their\n" "> Plays a sound\n"
" part. This change will remain in effect as long as the two parts\n" "during a collision when parts are 'scraping' against each other.\n"
" remain overlapping. This means if you have a part with a material\n" "Provide a ba.Sound, a target-impulse, and a volume.\n"
" that turns 'collide' off against parts younger than 100ms, and it\n"
" touches another part that is 50ms old, it will continue to not\n"
" collide with that part until they separate, even if the 100ms\n"
" threshold is passed. Options for attr/value are: 'physical' (boolean\n"
" value; whether a *physical* response will occur at all), 'friction'\n"
" (float value; how friction-y the physical response will be),\n"
" 'collide' (boolean value; whether *any* collision will occur at all,\n"
" including non-physical stuff like callbacks), 'use_node_collide'\n"
" (boolean value; whether to honor modify_node_collision overrides for\n"
" this collision), 'stiffness' (float value, how springy the physical\n"
" response is), 'damping' (float value, how damped the physical\n"
" response is), 'bounce' (float value; how bouncy the physical response\n"
" is).\n"
"\n" "\n"
"('modify_node_collision', attr, value) - similar to\n" "###### `('roll_sound', sound, targetImpulse, volume)`\n"
" modify_part_collision, but operates at a node-level.\n" "> Plays a sound\n"
" collision attributes set here will remain in effect as long as\n" "during a collision when parts are 'rolling' against each other.\n"
" *anything* from our part's node and their part's node overlap.\n" "Provide a ba.Sound, a target-impulse, and a volume.\n"
" A key use of this functionality is to prevent new nodes from\n"
" colliding with each other if they appear overlapped;\n"
" if modify_part_collision is used, only the individual parts that\n"
" were overlapping would avoid contact, but other parts could still\n"
" contact leaving the two nodes 'tangled up'. Using\n"
" modify_node_collision ensures that the nodes must completely\n"
" separate before they can start colliding. Currently the only attr\n"
" available here is 'collide' (a boolean value).\n"
"\n" "\n"
"('sound', sound, volume) - plays a ba.Sound when a collision occurs, at\n" "##### Examples\n"
" a given volume, regardless of the collision speed/etc.\n" "**Example 1:** create a material that lets us ignore\n"
"collisions against any nodes we touch in the first\n"
"100 ms of our existence; handy for preventing us from\n"
"exploding outward if we spawn on top of another object:\n"
">>> m = ba.Material()\n"
"... m.add_actions(\n"
"... conditions=(('we_are_younger_than', 100),\n"
"... 'or', ('they_are_younger_than', 100)),\n"
"... actions=('modify_node_collision', 'collide', False))\n"
"\n" "\n"
"('impact_sound', sound, targetImpulse, volume) - plays a sound when a\n" "**Example 2:** send a ba.DieMessage to anything we touch, but cause\n"
" collision occurs, based on the speed of impact. Provide a ba.Sound, a\n" "no physical response. This should cause any ba.Actor to drop dead:\n"
" target-impulse, and a volume.\n" ">>> m = ba.Material()\n"
"... m.add_actions(\n"
"... actions=(('modify_part_collision', 'physical', False),\n"
"... ('message', 'their_node', 'at_connect',\n"
"... ba.DieMessage())))\n"
"\n" "\n"
"('skid_sound', sound, targetImpulse, volume) - plays a sound during a\n" "**Example 3:** play some sounds when we're contacting the ground:\n"
" collision when parts are 'scraping' against each other. Provide a\n" ">>> m = ba.Material()\n"
" ba.Sound, a target-impulse, and a volume.\n" "... m.add_actions(\n"
"\n" "... conditions=('they_have_material',\n"
"('roll_sound', sound, targetImpulse, volume) - plays a sound during a\n" "... shared.footing_material),\n"
" collision when parts are 'rolling' against each other. Provide a\n" "... actions=(('impact_sound', ba.getsound('metalHit'), 2, 5),\n"
" ba.Sound, a target-impulse, and a volume.\n" "... ('skid_sound', ba.getsound('metalSkid'), 2, 5)))\n"},
"\n"
"# example 1: create a material that lets us ignore\n"
"# collisions against any nodes we touch in the first\n"
"# 100 ms of our existence; handy for preventing us from\n"
"# exploding outward if we spawn on top of another object:\n"
"m = ba.Material()\n"
"m.add_actions(conditions=(('we_are_younger_than', 100),\n"
" 'or',('they_are_younger_than', 100)),\n"
" actions=('modify_node_collision', 'collide', False))\n"
"\n"
"# example 2: send a DieMessage to anything we touch, but cause\n"
"# no physical response. This should cause any ba.Actor to drop dead:\n"
"m = ba.Material()\n"
"m.add_actions(actions=(('modify_part_collision', 'physical', False),\n"
" ('message', 'their_node', 'at_connect',\n"
" ba.DieMessage())))\n"
"\n"
"# example 3: play some sounds when we're contacting the ground:\n"
"m = ba.Material()\n"
"m.add_actions(conditions=('they_have_material',\n"
" shared.footing_material),\n"
" actions=(('impact_sound', ba.getsound('metalHit'), 2, 5),\n"
" ('skid_sound', ba.getsound('metalSkid'), 2, 5)))\n"
"\n"},
{"__dir__", (PyCFunction)Dir, METH_NOARGS, {"__dir__", (PyCFunction)Dir, METH_NOARGS,
"allows inclusion of our custom attrs in standard python dir()"}, "allows inclusion of our custom attrs in standard python dir()"},

View File

@ -24,7 +24,7 @@ void PythonClassModel::SetupType(PyTypeObject* obj) {
obj->tp_doc = obj->tp_doc =
"A reference to a model.\n" "A reference to a model.\n"
"\n" "\n"
"Category: Asset Classes\n" "Category: **Asset Classes**\n"
"\n" "\n"
"Models are used for drawing.\n" "Models are used for drawing.\n"
"Use ba.getmodel() to instantiate one."; "Use ba.getmodel() to instantiate one.";

View File

@ -25,7 +25,7 @@ void PythonClassNode::SetupType(PyTypeObject* obj) {
obj->tp_doc = obj->tp_doc =
"Reference to a Node; the low level building block of the game.\n" "Reference to a Node; the low level building block of the game.\n"
"\n" "\n"
"Category: Gameplay Classes\n" "Category: **Gameplay Classes**\n"
"\n" "\n"
"At its core, a game is nothing more than a scene of Nodes\n" "At its core, a game is nothing more than a scene of Nodes\n"
"with attributes getting interconnected or set over time.\n" "with attributes getting interconnected or set over time.\n"
@ -38,7 +38,7 @@ void PythonClassNode::SetupType(PyTypeObject* obj) {
"ba.Node.exists() can be used to determine if a Node still points to\n" "ba.Node.exists() can be used to determine if a Node still points to\n"
"a live node in the game.\n" "a live node in the game.\n"
"\n" "\n"
"You can use ba.Node(None) to instantiate an invalid\n" "You can use `ba.Node(None)` to instantiate an invalid\n"
"Node reference (sometimes used as attr values/etc)."; "Node reference (sometimes used as attr values/etc).";
obj->tp_new = tp_new; obj->tp_new = tp_new;
obj->tp_dealloc = (destructor)tp_dealloc; obj->tp_dealloc = (destructor)tp_dealloc;
@ -404,7 +404,8 @@ PyMethodDef PythonClassNode::tp_methods[] = {
{"getdelegate", (PyCFunction)GetDelegate, METH_VARARGS | METH_KEYWORDS, {"getdelegate", (PyCFunction)GetDelegate, METH_VARARGS | METH_KEYWORDS,
"getdelegate(type: type, doraise: bool = False) -> <varies>\n" "getdelegate(type: type, doraise: bool = False) -> <varies>\n"
"\n" "\n"
"Return the node's current delegate object if it matches a certain type.\n" "Return the node's current delegate object if it matches\n"
"a certain type.\n"
"\n" "\n"
"If the node has no delegate or it is not an instance of the passed\n" "If the node has no delegate or it is not an instance of the passed\n"
"type, then None will be returned. If 'doraise' is True, then an\n" "type, then None will be returned. If 'doraise' is True, then an\n"
@ -412,7 +413,7 @@ PyMethodDef PythonClassNode::tp_methods[] = {
{"delete", (PyCFunction)Delete, METH_VARARGS | METH_KEYWORDS, {"delete", (PyCFunction)Delete, METH_VARARGS | METH_KEYWORDS,
"delete(ignore_missing: bool = True) -> None\n" "delete(ignore_missing: bool = True) -> None\n"
"\n" "\n"
"Delete the node. Ignores already-deleted nodes if ignore_missing\n" "Delete the node. Ignores already-deleted nodes if `ignore_missing`\n"
"is True; otherwise a ba.NodeNotFoundError is thrown."}, "is True; otherwise a ba.NodeNotFoundError is thrown."},
{"handlemessage", (PyCFunction)HandleMessage, METH_VARARGS, {"handlemessage", (PyCFunction)HandleMessage, METH_VARARGS,
"handlemessage(*args: Any) -> None\n" "handlemessage(*args: Any) -> None\n"
@ -422,7 +423,7 @@ PyMethodDef PythonClassNode::tp_methods[] = {
"All standard message objects are forwarded along to the ba.Node's\n" "All standard message objects are forwarded along to the ba.Node's\n"
"delegate for handling (generally the ba.Actor that made the node).\n" "delegate for handling (generally the ba.Actor that made the node).\n"
"\n" "\n"
"ba.Nodes are unique, however, in that they can be passed a second\n" "ba.Node-s are unique, however, in that they can be passed a second\n"
"form of message; 'node-messages'. These consist of a string type-name\n" "form of message; 'node-messages'. These consist of a string type-name\n"
"as a first argument along with the args specific to that type name\n" "as a first argument along with the args specific to that type name\n"
"as additional arguments.\n" "as additional arguments.\n"
@ -437,17 +438,18 @@ PyMethodDef PythonClassNode::tp_methods[] = {
{"connectattr", (PyCFunction)ConnectAttr, METH_VARARGS, {"connectattr", (PyCFunction)ConnectAttr, METH_VARARGS,
"connectattr(srcattr: str, dstnode: Node, dstattr: str) -> None\n" "connectattr(srcattr: str, dstnode: Node, dstattr: str) -> None\n"
"\n" "\n"
"Connect one of this node's attributes to an attribute on another node.\n" "Connect one of this node's attributes to an attribute on another\n"
"This will immediately set the target attribute's value to that of the\n" "node. This will immediately set the target attribute's value to that\n"
"source attribute, and will continue to do so once per step as long as\n" "of the source attribute, and will continue to do so once per step\n"
"the two nodes exist. The connection can be severed by setting the\n" "as long as the two nodes exist. The connection can be severed by\n"
"target attribute to any value or connecting another node attribute\n" "setting the target attribute to any value or connecting another\n"
"to it.\n" "node attribute to it.\n"
"\n" "\n"
"# Example: create a locator and attach a light to it:\n" "##### Example\n"
"light = ba.newnode('light')\n" "Create a locator and attach a light to it:\n"
"loc = ba.newnode('locator', attrs={'position': (0,10,0)})\n" ">>> light = ba.newnode('light')\n"
"loc.connectattr('position', light, 'position')"}, "... loc = ba.newnode('locator', attrs={'position': (0, 10, 0)})\n"
"... loc.connectattr('position', light, 'position')\n"},
{"__dir__", (PyCFunction)Dir, METH_NOARGS, {"__dir__", (PyCFunction)Dir, METH_NOARGS,
"allows inclusion of our custom attrs in standard python dir()"}, "allows inclusion of our custom attrs in standard python dir()"},
{nullptr}}; {nullptr}};

View File

@ -46,11 +46,11 @@ void PythonClassSessionPlayer::SetupType(PyTypeObject* obj) {
obj->tp_doc = obj->tp_doc =
"A reference to a player in the ba.Session.\n" "A reference to a player in the ba.Session.\n"
"\n" "\n"
"Category: Gameplay Classes\n" "Category: **Gameplay Classes**\n"
"\n" "\n"
"These are created and managed internally and\n" "These are created and managed internally and\n"
"provided to your Session/Activity instances.\n" "provided to your ba.Session/ba.Activity instances.\n"
"Be aware that, like ba.Nodes, ba.SessionPlayer objects are 'weak'\n" "Be aware that, like `ba.Node`s, ba.SessionPlayer objects are 'weak'\n"
"references under-the-hood; a player can leave the game at\n" "references under-the-hood; a player can leave the game at\n"
" any point. For this reason, you should make judicious use of the\n" " any point. For this reason, you should make judicious use of the\n"
"ba.SessionPlayer.exists() method (or boolean operator) to ensure\n" "ba.SessionPlayer.exists() method (or boolean operator) to ensure\n"
@ -58,40 +58,39 @@ void PythonClassSessionPlayer::SetupType(PyTypeObject* obj) {
"for any length of time.\n" "for any length of time.\n"
"\n" "\n"
"Attributes:\n" "Attributes:\n"
"\n" " " ATTR_ID " (int):\n"
" " ATTR_ID ": int\n"
" The unique numeric ID of the Player.\n" " The unique numeric ID of the Player.\n"
"\n" "\n"
" Note that you can also use the boolean operator for this same\n" " Note that you can also use the boolean operator for this same\n"
" functionality, so a statement such as \"if player\" will do\n" " functionality, so a statement such as \"if player\" will do\n"
" the right thing both for Player objects and values of None.\n" " the right thing both for Player objects and values of None.\n"
"\n" "\n"
" " ATTR_IN_GAME ": bool\n" " " ATTR_IN_GAME " (bool):\n"
" This bool value will be True once the Player has completed\n" " This bool value will be True once the Player has completed\n"
" any lobby character/team selection.\n" " any lobby character/team selection.\n"
"\n" "\n"
" " ATTR_SESSIONTEAM ": ba.SessionTeam\n" " " ATTR_SESSIONTEAM " (ba.SessionTeam):\n"
" The ba.SessionTeam this Player is on. If the SessionPlayer\n" " The ba.SessionTeam this Player is on. If the SessionPlayer\n"
" is still in its lobby selecting a team/etc. then a\n" " is still in its lobby selecting a team/etc. then a\n"
" ba.SessionTeamNotFoundError will be raised.\n" " ba.SessionTeamNotFoundError will be raised.\n"
"\n" "\n"
" " ATTR_INPUT_DEVICE ": ba.InputDevice\n" " " ATTR_INPUT_DEVICE " (ba.InputDevice):\n"
" The input device associated with the player.\n" " The input device associated with the player.\n"
"\n" "\n"
" " ATTR_COLOR ": Sequence[float]\n" " " ATTR_COLOR " (Sequence[float]):\n"
" The base color for this Player.\n" " The base color for this Player.\n"
" In team games this will match the ba.SessionTeam's color.\n" " In team games this will match the ba.SessionTeam's color.\n"
"\n" "\n"
" " ATTR_HIGHLIGHT ": Sequence[float]\n" " " ATTR_HIGHLIGHT " (Sequence[float]):\n"
" A secondary color for this player.\n" " A secondary color for this player.\n"
" This is used for minor highlights and accents\n" " This is used for minor highlights and accents\n"
" to allow a player to stand apart from his teammates\n" " to allow a player to stand apart from his teammates\n"
" who may all share the same team (primary) color.\n" " who may all share the same team (primary) color.\n"
"\n" "\n"
" " ATTR_CHARACTER ": str\n" " " ATTR_CHARACTER " (str):\n"
" The character this player has selected in their profile.\n" " The character this player has selected in their profile.\n"
"\n" "\n"
" " ATTR_ACTIVITYPLAYER ": Optional[ba.Player]\n" " " ATTR_ACTIVITYPLAYER " (Optional[ba.Player]):\n"
" The current game-specific instance for this player.\n"; " The current game-specific instance for this player.\n";
// clang-format on // clang-format on
@ -734,7 +733,8 @@ PyMethodDef PythonClassSessionPlayer::tp_methods[] = {
{"get_icon", (PyCFunction)GetIcon, METH_NOARGS, {"get_icon", (PyCFunction)GetIcon, METH_NOARGS,
"get_icon() -> dict[str, Any]\n" "get_icon() -> dict[str, Any]\n"
"\n" "\n"
"Returns the character's icon (images, colors, etc contained in a dict)"}, "Returns the character's icon (images, colors, etc contained\n"
"in a dict."},
{"get_icon_info", (PyCFunction)GetIconInfo, METH_NOARGS, {"get_icon_info", (PyCFunction)GetIconInfo, METH_NOARGS,
"get_icon_info() -> dict[str, Any]\n" "get_icon_info() -> dict[str, Any]\n"
"\n" "\n"

View File

@ -24,7 +24,7 @@ void PythonClassSound::SetupType(PyTypeObject* obj) {
obj->tp_doc = obj->tp_doc =
"A reference to a sound.\n" "A reference to a sound.\n"
"\n" "\n"
"Category: Asset Classes\n" "Category: **Asset Classes**\n"
"\n" "\n"
"Use ba.getsound() to instantiate one."; "Use ba.getsound() to instantiate one.";
obj->tp_repr = (reprfunc)tp_repr; obj->tp_repr = (reprfunc)tp_repr;

View File

@ -24,7 +24,7 @@ void PythonClassTexture::SetupType(PyTypeObject* obj) {
obj->tp_doc = obj->tp_doc =
"A reference to a texture.\n" "A reference to a texture.\n"
"\n" "\n"
"Category: Asset Classes\n" "Category: **Asset Classes**\n"
"\n" "\n"
"Use ba.gettexture() to instantiate one."; "Use ba.gettexture() to instantiate one.";
obj->tp_repr = (reprfunc)tp_repr; obj->tp_repr = (reprfunc)tp_repr;

View File

@ -19,7 +19,7 @@ void PythonClassTimer::SetupType(PyTypeObject* obj) {
"\n" "\n"
"Timers are used to run code at later points in time.\n" "Timers are used to run code at later points in time.\n"
"\n" "\n"
"Category: General Utility Classes\n" "Category: **General Utility Classes**\n"
"\n" "\n"
"This class encapsulates a timer in the current ba.Context.\n" "This class encapsulates a timer in the current ba.Context.\n"
"The underlying timer will be destroyed when either this object is\n" "The underlying timer will be destroyed when either this object is\n"
@ -27,34 +27,41 @@ void PythonClassTimer::SetupType(PyTypeObject* obj) {
"do not want to worry about keeping a reference to your timer around,\n" "do not want to worry about keeping a reference to your timer around,\n"
"you should use the ba.timer() function instead.\n" "you should use the ba.timer() function instead.\n"
"\n" "\n"
"time: length of time (in seconds by default) that the timer will wait\n" "###### time\n"
"> Length of time (in seconds by default) that the timer will wait\n"
"before firing. Note that the actual delay experienced may vary\n" "before firing. Note that the actual delay experienced may vary\n"
"depending on the timetype. (see below)\n" "depending on the timetype. (see below)\n"
"\n" "\n"
"call: A callable Python object. Note that the timer will retain a\n" "###### call\n"
"> A callable Python object. Note that the timer will retain a\n"
"strong reference to the callable for as long as it exists, so you\n" "strong reference to the callable for as long as it exists, so you\n"
"may want to look into concepts such as ba.WeakCall if that is not\n" "may want to look into concepts such as ba.WeakCall if that is not\n"
"desired.\n" "desired.\n"
"\n" "\n"
"repeat: if True, the timer will fire repeatedly, with each successive\n" "###### repeat\n"
"> If True, the timer will fire repeatedly, with each successive\n"
"firing having the same delay as the first.\n" "firing having the same delay as the first.\n"
"\n" "\n"
"timetype: A ba.TimeType value determining which timeline the timer is\n" "###### timetype\n"
"> A ba.TimeType value determining which timeline the timer is\n"
"placed onto.\n" "placed onto.\n"
"\n" "\n"
"timeformat: A ba.TimeFormat value determining how the passed time is\n" "###### timeformat\n"
"> A ba.TimeFormat value determining how the passed time is\n"
"interpreted.\n" "interpreted.\n"
"\n" "\n"
"# Example: use a Timer object to print repeatedly for a few seconds:\n" "##### Example\n"
"def say_it():\n" "\n"
" ba.screenmessage('BADGER!')\n" "Use a Timer object to print repeatedly for a few seconds:\n"
"def stop_saying_it():\n" ">>> def say_it():\n"
" self.t = None\n" "... ba.screenmessage('BADGER!')\n"
" ba.screenmessage('MUSHROOM MUSHROOM!')\n" "... def stop_saying_it():\n"
"# Create our timer; it will run as long as we have the self.t ref.\n" "... self.t = None\n"
"self.t = ba.Timer(0.3, say_it, repeat=True)\n" "... ba.screenmessage('MUSHROOM MUSHROOM!')\n"
"# Now fire off a one-shot timer to kill it.\n" "... # Create our timer; it will run as long as we have the self.t ref.\n"
"ba.timer(3.89, stop_saying_it)"; "... self.t = ba.Timer(0.3, say_it, repeat=True)\n"
"... # Now fire off a one-shot timer to kill it.\n"
"... ba.timer(3.89, stop_saying_it)\n";
obj->tp_new = tp_new; obj->tp_new = tp_new;
obj->tp_dealloc = (destructor)tp_dealloc; obj->tp_dealloc = (destructor)tp_dealloc;
} }

View File

@ -29,7 +29,7 @@ void PythonClassVec3::SetupType(PyTypeObject* obj) {
obj->tp_doc = obj->tp_doc =
"A vector of 3 floats.\n" "A vector of 3 floats.\n"
"\n" "\n"
"Category: General Utility Classes\n" "Category: **General Utility Classes**\n"
"\n" "\n"
"These can be created the following ways (checked in this order):\n" "These can be created the following ways (checked in this order):\n"
"- with no args, all values are set to 0\n" "- with no args, all values are set to 0\n"
@ -38,14 +38,13 @@ void PythonClassVec3::SetupType(PyTypeObject* obj) {
"- otherwise assumes individual x/y/z args (positional or keywords)" "- otherwise assumes individual x/y/z args (positional or keywords)"
"\n" "\n"
"Attributes:\n" "Attributes:\n"
"\n" " x (float):\n"
" x: float\n"
" The vector's X component.\n" " The vector's X component.\n"
"\n" "\n"
" y: float\n" " y (float):\n"
" The vector's Y component.\n" " The vector's Y component.\n"
"\n" "\n"
" z: float\n" " z (float):\n"
" The vector's Z component.\n"; " The vector's Z component.\n";
obj->tp_new = tp_new; obj->tp_new = tp_new;

View File

@ -22,10 +22,10 @@ void PythonClassWidget::SetupType(PyTypeObject* obj) {
obj->tp_doc = obj->tp_doc =
"Internal type for low level UI elements; buttons, windows, etc.\n" "Internal type for low level UI elements; buttons, windows, etc.\n"
"\n" "\n"
"Category: User Interface Classes\n" "Category: **User Interface Classes**\n"
"\n" "\n"
"This class represents a weak reference to a widget object\n" "This class represents a weak reference to a widget object\n"
"in the internal c++ layer. Currently, functions such as\n" "in the internal C++ layer. Currently, functions such as\n"
"ba.buttonwidget() must be used to instantiate or edit these."; "ba.buttonwidget() must be used to instantiate or edit these.";
obj->tp_new = tp_new; obj->tp_new = tp_new;
obj->tp_dealloc = (destructor)tp_dealloc; obj->tp_dealloc = (destructor)tp_dealloc;
@ -260,9 +260,9 @@ PyMethodDef PythonClassWidget::tp_methods[] = {
{"get_widget_type", (PyCFunction)GetWidgetType, METH_NOARGS, {"get_widget_type", (PyCFunction)GetWidgetType, METH_NOARGS,
"get_widget_type() -> str\n" "get_widget_type() -> str\n"
"\n" "\n"
"Return the internal type of the Widget as a string. Note that this is\n" "Return the internal type of the Widget as a string. Note that this\n"
"different from the Python ba.Widget type, which is the same for all\n" "is different from the Python ba.Widget type, which is the same for\n"
"widgets."}, "all widgets."},
{"activate", (PyCFunction)Activate, METH_NOARGS, {"activate", (PyCFunction)Activate, METH_NOARGS,
"activate() -> None\n" "activate() -> None\n"
"\n" "\n"
@ -274,9 +274,9 @@ PyMethodDef PythonClassWidget::tp_methods[] = {
{"get_screen_space_center", (PyCFunction)GetScreenSpaceCenter, METH_NOARGS, {"get_screen_space_center", (PyCFunction)GetScreenSpaceCenter, METH_NOARGS,
"get_screen_space_center() -> tuple[float, float]\n" "get_screen_space_center() -> tuple[float, float]\n"
"\n" "\n"
"Returns the coords of the Widget center relative to the center of the\n" "Returns the coords of the ba.Widget center relative to the center\n"
"screen. This can be useful for placing pop-up windows and other special\n" "of the screen. This can be useful for placing pop-up windows and other\n"
"cases."}, "special cases."},
{"get_selected_child", (PyCFunction)GetSelectedChild, METH_NOARGS, {"get_selected_child", (PyCFunction)GetSelectedChild, METH_NOARGS,
"get_selected_child() -> Optional[ba.Widget]\n" "get_selected_child() -> Optional[ba.Widget]\n"
"\n" "\n"
@ -285,8 +285,8 @@ PyMethodDef PythonClassWidget::tp_methods[] = {
{"delete", (PyCFunction)Delete, METH_VARARGS | METH_KEYWORDS, {"delete", (PyCFunction)Delete, METH_VARARGS | METH_KEYWORDS,
"delete(ignore_missing: bool = True) -> None\n" "delete(ignore_missing: bool = True) -> None\n"
"\n" "\n"
"Delete the Widget. Ignores already-deleted Widgets if ignore_missing\n" "Delete the Widget. Ignores already-deleted Widgets if ignore_missing\n"
" is True; otherwise an Exception is thrown."}, "is True; otherwise an Exception is thrown."},
{"add_delete_callback", (PyCFunction)AddDeleteCallback, {"add_delete_callback", (PyCFunction)AddDeleteCallback,
METH_VARARGS | METH_KEYWORDS, // NOLINT (signed bitwise stuff) METH_VARARGS | METH_KEYWORDS, // NOLINT (signed bitwise stuff)
"add_delete_callback(call: Callable) -> None\n" "add_delete_callback(call: Callable) -> None\n"

View File

@ -926,7 +926,7 @@ auto PythonMethodsApp::GetMethods() -> std::vector<PyMethodDef> {
"log(message: str, to_stdout: bool = True,\n" "log(message: str, to_stdout: bool = True,\n"
" to_server: bool = True) -> None\n" " to_server: bool = True) -> None\n"
"\n" "\n"
"Category: General Utility Functions\n" "Category: **General Utility Functions**\n"
"\n" "\n"
"Log a message. This goes to the default logging mechanism depending\n" "Log a message. This goes to the default logging mechanism depending\n"
"on the platform (stdout on mac, android log on android, etc).\n" "on the platform (stdout on mac, android log on android, etc).\n"
@ -989,7 +989,7 @@ auto PythonMethodsApp::GetMethods() -> std::vector<PyMethodDef> {
"\n" "\n"
"Quit the game.\n" "Quit the game.\n"
"\n" "\n"
"Category: General Utility Functions\n" "Category: **General Utility Functions**\n"
"\n" "\n"
"On systems like android, 'soft' will end the activity but keep the\n" "On systems like android, 'soft' will end the activity but keep the\n"
"app running."}, "app running."},
@ -1003,7 +1003,7 @@ auto PythonMethodsApp::GetMethods() -> std::vector<PyMethodDef> {
"\n" "\n"
"Print a message to the local client's screen, in a given color.\n" "Print a message to the local client's screen, in a given color.\n"
"\n" "\n"
"Category: General Utility Functions\n" "Category: **General Utility Functions**\n"
"\n" "\n"
"If 'top' is True, the message will go to the top message area.\n" "If 'top' is True, the message will go to the top message area.\n"
"For 'top' messages, 'image' can be a texture to display alongside " "For 'top' messages, 'image' can be a texture to display alongside "
@ -1027,58 +1027,60 @@ auto PythonMethodsApp::GetMethods() -> std::vector<PyMethodDef> {
"\n" "\n"
"Schedule a call to run at a later point in time.\n" "Schedule a call to run at a later point in time.\n"
"\n" "\n"
"Category: General Utility Functions\n" "Category: **General Utility Functions**\n"
"\n" "\n"
"This function adds a timer to the current ba.Context.\n" "This function adds a timer to the current ba.Context.\n"
"This timer cannot be canceled or modified once created. If you\n" "This timer cannot be canceled or modified once created. If you\n"
" require the ability to do so, use the ba.Timer class instead.\n" " require the ability to do so, use the ba.Timer class instead.\n"
"\n" "\n"
"time: length of time (in seconds by default) that the timer will " "##### Arguments\n"
"wait\n" "###### time (float)\n"
"> Length of time (in seconds by default) that the timer will wait\n"
"before firing. Note that the actual delay experienced may vary\n " "before firing. Note that the actual delay experienced may vary\n "
"depending on the timetype. (see below)\n" "depending on the timetype. (see below)\n"
"\n" "\n"
"call: A callable Python object. Note that the timer will retain a\n" "###### call (Callable[[], Any])\n"
"> A callable Python object. Note that the timer will retain a\n"
"strong reference to the callable for as long as it exists, so you\n" "strong reference to the callable for as long as it exists, so you\n"
"may want to look into concepts such as ba.WeakCall if that is not\n" "may want to look into concepts such as ba.WeakCall if that is not\n"
"desired.\n" "desired.\n"
"\n" "\n"
"repeat: if True, the timer will fire repeatedly, with each " "###### repeat (bool)\n"
"successive\n" "> If True, the timer will fire repeatedly, with each successive\n"
"firing having the same delay as the first.\n" "firing having the same delay as the first.\n"
"\n" "\n"
"timetype can be either 'sim', 'base', or 'real'. It defaults to\n" "###### timetype (ba.TimeType)\n"
"'sim'. Types are explained below:\n" "> Can be either `SIM`, `BASE`, or `REAL`. It defaults to\n"
"`SIM`.\n"
"\n" "\n"
"'sim' time maps to local simulation time in ba.Activity or " "###### timeformat (ba.TimeFormat)\n"
"> Defaults to seconds but can also be milliseconds.\n"
"\n"
"- SIM time maps to local simulation time in ba.Activity or "
"ba.Session\n" "ba.Session\n"
"Contexts. This means that it may progress slower in slow-motion " "Contexts. This means that it may progress slower in slow-motion "
"play\n" "play\n"
"modes, stop when the game is paused, etc. This time type is not\n" "modes, stop when the game is paused, etc. This time type is not\n"
"available in UI contexts.\n" "available in UI contexts.\n"
"\n" "- BASE time is also linked to gameplay in ba.Activity or ba.Session\n"
"'base' time is also linked to gameplay in ba.Activity or ba.Session\n"
"Contexts, but it progresses at a constant rate regardless of\n " "Contexts, but it progresses at a constant rate regardless of\n "
"slow-motion states or pausing. It can, however, slow down or stop\n" "slow-motion states or pausing. It can, however, slow down or stop\n"
"in certain cases such as network outages or game slowdowns due to\n" "in certain cases such as network outages or game slowdowns due to\n"
"cpu load. Like 'sim' time, this is unavailable in UI contexts.\n" "cpu load. Like 'sim' time, this is unavailable in UI contexts.\n"
"\n" "- REAL time always maps to actual clock time with a bit of "
"'real' time always maps to actual clock time with a bit of "
"filtering\n" "filtering\n"
"added, regardless of Context. (the filtering prevents it from " "added, regardless of Context. (The filtering prevents it from going\n"
"going\n"
"backwards or jumping forward by large amounts due to the app being\n" "backwards or jumping forward by large amounts due to the app being\n"
"backgrounded, system time changing, etc.)\n" "backgrounded, system time changing, etc.)\n"
"Real time timers are currently only available in the UI context.\n" "Real time timers are currently only available in the UI context.\n"
"\n" "\n"
"the 'timeformat' arg defaults to seconds but can also be " "##### Examples\n"
"milliseconds.\n" "Print some stuff through time:\n"
"\n" ">>> ba.screenmessage('hello from now!')\n"
"# timer example: print some stuff through time:\n" ">>> ba.timer(1.0, ba.Call(ba.screenmessage, 'hello from the "
"ba.screenmessage('hello from now!')\n" "future!'))\n"
"ba.timer(1.0, ba.Call(ba.screenmessage, 'hello from the future!'))\n" ">>> ba.timer(2.0, ba.Call(ba.screenmessage,\n"
"ba.timer(2.0, ba.Call(ba.screenmessage, 'hello from the future " "... 'hello from the future 2!'))\n"},
"2!'))\n"},
{"time", (PyCFunction)PyTime, METH_VARARGS | METH_KEYWORDS, {"time", (PyCFunction)PyTime, METH_VARARGS | METH_KEYWORDS,
"time(timetype: ba.TimeType = TimeType.SIM,\n" "time(timetype: ba.TimeType = TimeType.SIM,\n"
@ -1087,32 +1089,32 @@ auto PythonMethodsApp::GetMethods() -> std::vector<PyMethodDef> {
"\n" "\n"
"Return the current time.\n" "Return the current time.\n"
"\n" "\n"
"Category: General Utility Functions\n" "Category: **General Utility Functions**\n"
"\n" "\n"
"The time returned depends on the current ba.Context and timetype.\n" "The time returned depends on the current ba.Context and timetype.\n"
"\n" "\n"
"timetype can be either SIM, BASE, or REAL. It defaults to\n" "timetype can be either SIM, BASE, or REAL. It defaults to\n"
"SIM. Types are explained below:\n" "SIM. Types are explained below:\n"
"\n" "\n"
"SIM time maps to local simulation time in ba.Activity or ba.Session\n" "- SIM time maps to local simulation time in ba.Activity or "
"ba.Session\n"
"Contexts. This means that it may progress slower in slow-motion " "Contexts. This means that it may progress slower in slow-motion "
"play\n" "play\n"
"modes, stop when the game is paused, etc. This time type is not\n" "modes, stop when the game is paused, etc. This time type is not\n"
"available in UI contexts.\n" "available in UI contexts.\n"
"\n" "- BASE time is also linked to gameplay in ba.Activity or ba.Session\n"
"BASE time is also linked to gameplay in ba.Activity or ba.Session\n"
"Contexts, but it progresses at a constant rate regardless of\n " "Contexts, but it progresses at a constant rate regardless of\n "
"slow-motion states or pausing. It can, however, slow down or stop\n" "slow-motion states or pausing. It can, however, slow down or stop\n"
"in certain cases such as network outages or game slowdowns due to\n" "in certain cases such as network outages or game slowdowns due to\n"
"cpu load. Like 'sim' time, this is unavailable in UI contexts.\n" "cpu load. Like 'sim' time, this is unavailable in UI contexts.\n"
"\n" "- REAL time always maps to actual clock time with a bit of "
"REAL time always maps to actual clock time with a bit of filtering\n" "filtering\n"
"added, regardless of Context. (the filtering prevents it from " "added, regardless of Context. (The filtering prevents it from going\n"
"going\n"
"backwards or jumping forward by large amounts due to the app being\n" "backwards or jumping forward by large amounts due to the app being\n"
"backgrounded, system time changing, etc.)\n" "backgrounded, system time changing, etc.)\n"
"Real time timers are currently only available in the UI context.\n"
"\n" "\n"
"the 'timeformat' arg defaults to SECONDS which returns float " "The 'timeformat' arg defaults to SECONDS which returns float "
"seconds,\n" "seconds,\n"
"but it can also be MILLISECONDS to return integer milliseconds.\n" "but it can also be MILLISECONDS to return integer milliseconds.\n"
"\n" "\n"
@ -1125,7 +1127,7 @@ auto PythonMethodsApp::GetMethods() -> std::vector<PyMethodDef> {
"\n" "\n"
"Pushes a call onto the event loop to be run during the next cycle.\n" "Pushes a call onto the event loop to be run during the next cycle.\n"
"\n" "\n"
"Category: General Utility Functions\n" "Category: **General Utility Functions**\n"
"\n" "\n"
"This can be handy for calls that are disallowed from within other\n" "This can be handy for calls that are disallowed from within other\n"
"callbacks, etc.\n" "callbacks, etc.\n"
@ -1144,7 +1146,7 @@ auto PythonMethodsApp::GetMethods() -> std::vector<PyMethodDef> {
"\n" "\n"
"Return the current ba.Activity instance.\n" "Return the current ba.Activity instance.\n"
"\n" "\n"
"Category: Gameplay Functions\n" "Category: **Gameplay Functions**\n"
"\n" "\n"
"Note that this is based on context; thus code run in a timer " "Note that this is based on context; thus code run in a timer "
"generated\n" "generated\n"
@ -1160,7 +1162,7 @@ auto PythonMethodsApp::GetMethods() -> std::vector<PyMethodDef> {
"\n" "\n"
"Instantiates a ba.Activity given a type object.\n" "Instantiates a ba.Activity given a type object.\n"
"\n" "\n"
"Category: General Utility Functions\n" "Category: **General Utility Functions**\n"
"\n" "\n"
"Activities require special setup and thus cannot be directly\n" "Activities require special setup and thus cannot be directly\n"
"instantiated; you must go through this function."}, "instantiated; you must go through this function."},
@ -1209,7 +1211,7 @@ auto PythonMethodsApp::GetMethods() -> std::vector<PyMethodDef> {
{"getsession", (PyCFunction)PyGetSession, METH_VARARGS | METH_KEYWORDS, {"getsession", (PyCFunction)PyGetSession, METH_VARARGS | METH_KEYWORDS,
"getsession(doraise: bool = True) -> <varies>\n" "getsession(doraise: bool = True) -> <varies>\n"
"\n" "\n"
"Category: Gameplay Functions\n" "Category: **Gameplay Functions**\n"
"\n" "\n"
"Returns the current ba.Session instance.\n" "Returns the current ba.Session instance.\n"
"Note that this is based on context; thus code being run in the UI\n" "Note that this is based on context; thus code being run in the UI\n"

View File

@ -685,7 +685,7 @@ auto PythonMethodsGameplay::GetMethods() -> std::vector<PyMethodDef> {
"\n" "\n"
"Emit particles, smoke, etc. into the fx sim layer.\n" "Emit particles, smoke, etc. into the fx sim layer.\n"
"\n" "\n"
"Category: Gameplay Functions\n" "Category: **Gameplay Functions**\n"
"\n" "\n"
"The fx sim layer is a secondary dynamics simulation that runs in\n" "The fx sim layer is a secondary dynamics simulation that runs in\n"
"the background and just looks pretty; it does not affect gameplay.\n" "the background and just looks pretty; it does not affect gameplay.\n"
@ -698,17 +698,17 @@ auto PythonMethodsGameplay::GetMethods() -> std::vector<PyMethodDef> {
"\n" "\n"
"Play a ba.Sound a single time.\n" "Play a ba.Sound a single time.\n"
"\n" "\n"
"Category: Gameplay Functions\n" "Category: **Gameplay Functions**\n"
"\n" "\n"
"If position is not provided, the sound will be at a constant volume\n" "If position is not provided, the sound will be at a constant volume\n"
"everywhere. Position should be a float tuple of size 3."}, "everywhere. Position should be a float tuple of size 3."},
{"camerashake", (PyCFunction)PyCameraShake, METH_VARARGS | METH_KEYWORDS, {"camerashake", (PyCFunction)PyCameraShake, METH_VARARGS | METH_KEYWORDS,
"camerashake(intensity: float = 1.0) -> None\n" "camerashake(intensity: float = 1.0) -> None\n"
"\n" "\n"
"Shake the camera.\n" "Shake the camera.\n"
"\n" "\n"
"Category: Gameplay Functions\n" "Category: **Gameplay Functions**\n"
"\n" "\n"
"Note that some cameras and/or platforms (such as VR) may not display\n" "Note that some cameras and/or platforms (such as VR) may not display\n"
"camera-shake, so do not rely on this always being visible to the\n" "camera-shake, so do not rely on this always being visible to the\n"
@ -719,7 +719,7 @@ auto PythonMethodsGameplay::GetMethods() -> std::vector<PyMethodDef> {
"\n" "\n"
"Return collision related values\n" "Return collision related values\n"
"\n" "\n"
"Category: Gameplay Functions\n" "Category: **Gameplay Functions**\n"
"\n" "\n"
"Returns a single collision value or tuple of values such as location,\n" "Returns a single collision value or tuple of values such as location,\n"
"depth, nodes involved, etc. Only call this in the handler of a\n" "depth, nodes involved, etc. Only call this in the handler of a\n"
@ -728,16 +728,16 @@ auto PythonMethodsGameplay::GetMethods() -> std::vector<PyMethodDef> {
{"getnodes", PyGetNodes, METH_VARARGS, {"getnodes", PyGetNodes, METH_VARARGS,
"getnodes() -> list\n" "getnodes() -> list\n"
"\n" "\n"
"Return all nodes in the current ba.Context." "Return all nodes in the current ba.Context.\n"
"\n" "\n"
"Category: Gameplay Functions"}, "Category: **Gameplay Functions**"},
{"printnodes", PyPrintNodes, METH_VARARGS, {"printnodes", PyPrintNodes, METH_VARARGS,
"printnodes() -> None\n" "printnodes() -> None\n"
"\n" "\n"
"Print various info about existing nodes; useful for debugging.\n" "Print various info about existing nodes; useful for debugging.\n"
"\n" "\n"
"Category: Gameplay Functions"}, "Category: **Gameplay Functions**"},
{"newnode", (PyCFunction)PyNewNode, METH_VARARGS | METH_KEYWORDS, {"newnode", (PyCFunction)PyNewNode, METH_VARARGS | METH_KEYWORDS,
"newnode(type: str, owner: ba.Node = None,\n" "newnode(type: str, owner: ba.Node = None,\n"
@ -746,7 +746,7 @@ auto PythonMethodsGameplay::GetMethods() -> std::vector<PyMethodDef> {
"\n" "\n"
"Add a node of the given type to the game.\n" "Add a node of the given type to the game.\n"
"\n" "\n"
"Category: Gameplay Functions\n" "Category: **Gameplay Functions**\n"
"\n" "\n"
"If a dict is provided for 'attributes', the node's initial attributes\n" "If a dict is provided for 'attributes', the node's initial attributes\n"
"will be set based on them.\n" "will be set based on them.\n"

View File

@ -423,7 +423,7 @@ auto PythonMethodsGraphics::GetMethods() -> std::vector<PyMethodDef> {
"\n" "\n"
"Given a color tuple, return a color safe to display as text.\n" "Given a color tuple, return a color safe to display as text.\n"
"\n" "\n"
"Category: General Utility Functions\n" "Category: **General Utility Functions**\n"
"\n" "\n"
"Accepts tuples of length 3 or 4. This will slightly brighten very\n" "Accepts tuples of length 3 or 4. This will slightly brighten very\n"
"dark colors, etc."}, "dark colors, etc."},
@ -433,13 +433,13 @@ auto PythonMethodsGraphics::GetMethods() -> std::vector<PyMethodDef> {
"\n" "\n"
"Get a unicode string representing a special character.\n" "Get a unicode string representing a special character.\n"
"\n" "\n"
"Category: General Utility Functions\n" "Category: **General Utility Functions**\n"
"\n" "\n"
"Note that these utilize the private-use block of unicode characters\n" "Note that these utilize the private-use block of unicode characters\n"
"(U+E000-U+F8FF) and are specific to the game; exporting or rendering\n" "(U+E000-U+F8FF) and are specific to the game; exporting or rendering\n"
"them elsewhere will be meaningless.\n" "them elsewhere will be meaningless.\n"
"\n" "\n"
"see ba.SpecialChar for the list of available characters."}, "See ba.SpecialChar for the list of available characters."},
}; };
} }

View File

@ -468,7 +468,7 @@ auto PythonMethodsMedia::GetMethods() -> std::vector<PyMethodDef> {
"\n" "\n"
"Return a collide-model, loading it if necessary.\n" "Return a collide-model, loading it if necessary.\n"
"\n" "\n"
"Category: Asset Functions\n" "Category: **Asset Functions**\n"
"\n" "\n"
"Collide-models are used in physics calculations for such things as\n" "Collide-models are used in physics calculations for such things as\n"
"terrain.\n" "terrain.\n"
@ -491,7 +491,7 @@ auto PythonMethodsMedia::GetMethods() -> std::vector<PyMethodDef> {
"\n" "\n"
"Return a model, loading it if necessary.\n" "Return a model, loading it if necessary.\n"
"\n" "\n"
"Category: Asset Functions\n" "Category: **Asset Functions**\n"
"\n" "\n"
"Note that this function returns immediately even if the media has yet\n" "Note that this function returns immediately even if the media has yet\n"
"to be loaded. To avoid hitches, instantiate your media objects in\n" "to be loaded. To avoid hitches, instantiate your media objects in\n"
@ -510,7 +510,7 @@ auto PythonMethodsMedia::GetMethods() -> std::vector<PyMethodDef> {
"\n" "\n"
"Return a sound, loading it if necessary.\n" "Return a sound, loading it if necessary.\n"
"\n" "\n"
"Category: Asset Functions\n" "Category: **Asset Functions**\n"
"\n" "\n"
"Note that this function returns immediately even if the media has yet\n" "Note that this function returns immediately even if the media has yet\n"
"to be loaded. To avoid hitches, instantiate your media objects in\n" "to be loaded. To avoid hitches, instantiate your media objects in\n"
@ -529,7 +529,7 @@ auto PythonMethodsMedia::GetMethods() -> std::vector<PyMethodDef> {
"\n" "\n"
"Return a data, loading it if necessary.\n" "Return a data, loading it if necessary.\n"
"\n" "\n"
"Category: Asset Functions\n" "Category: **Asset Functions**\n"
"\n" "\n"
"Note that this function returns immediately even if the media has yet\n" "Note that this function returns immediately even if the media has yet\n"
"to be loaded. To avoid hitches, instantiate your media objects in\n" "to be loaded. To avoid hitches, instantiate your media objects in\n"
@ -548,7 +548,7 @@ auto PythonMethodsMedia::GetMethods() -> std::vector<PyMethodDef> {
"\n" "\n"
"Return a texture, loading it if necessary.\n" "Return a texture, loading it if necessary.\n"
"\n" "\n"
"Category: Asset Functions\n" "Category: **Asset Functions**\n"
"\n" "\n"
"Note that this function returns immediately even if the media has yet\n" "Note that this function returns immediately even if the media has yet\n"
"to be loaded. To avoid hitches, instantiate your media objects in\n" "to be loaded. To avoid hitches, instantiate your media objects in\n"

View File

@ -801,7 +801,7 @@ auto PythonMethodsSystem::GetMethods() -> std::vector<PyMethodDef> {
"\n" "\n"
"Return whether this platform supports clipboard operations at all.\n" "Return whether this platform supports clipboard operations at all.\n"
"\n" "\n"
"Category: General Utility Functions\n" "Category: **General Utility Functions**\n"
"\n" "\n"
"If this returns False, UIs should not show 'copy to clipboard'\n" "If this returns False, UIs should not show 'copy to clipboard'\n"
"buttons, etc."}, "buttons, etc."},
@ -810,26 +810,26 @@ auto PythonMethodsSystem::GetMethods() -> std::vector<PyMethodDef> {
"\n" "\n"
"Return whether there is currently text on the clipboard.\n" "Return whether there is currently text on the clipboard.\n"
"\n" "\n"
"Category: General Utility Functions\n" "Category: **General Utility Functions**\n"
"\n" "\n"
"This will return False if no system clipboard is available; no need\n" "This will return False if no system clipboard is available; no need\n"
" to call ba.clipboard_available() separately."}, " to call ba.clipboard_is_supported() separately."},
{"clipboard_set_text", (PyCFunction)PyClipboardSetText, {"clipboard_set_text", (PyCFunction)PyClipboardSetText,
METH_VARARGS | METH_KEYWORDS, METH_VARARGS | METH_KEYWORDS,
"clipboard_set_text(value: str) -> None\n" "clipboard_set_text(value: str) -> None\n"
"\n" "\n"
"Copy a string to the system clipboard.\n" "Copy a string to the system clipboard.\n"
"\n" "\n"
"Category: General Utility Functions\n" "Category: **General Utility Functions**\n"
"\n" "\n"
"Ensure that ba.clipboard_available() returns True before adding\n" "Ensure that ba.clipboard_is_supported() returns True before adding\n"
" buttons/etc. that make use of this functionality."}, " buttons/etc. that make use of this functionality."},
{"clipboard_get_text", (PyCFunction)PyClipboardGetText, METH_NOARGS, {"clipboard_get_text", (PyCFunction)PyClipboardGetText, METH_NOARGS,
"clipboard_get_text() -> str\n" "clipboard_get_text() -> str\n"
"\n" "\n"
"Return text currently on the system clipboard.\n" "Return text currently on the system clipboard.\n"
"\n" "\n"
"Category: General Utility Functions\n" "Category: **General Utility Functions**\n"
"\n" "\n"
"Ensure that ba.clipboard_has_text() returns True before calling\n" "Ensure that ba.clipboard_has_text() returns True before calling\n"
" this function."}, " this function."},
@ -839,7 +839,7 @@ auto PythonMethodsSystem::GetMethods() -> std::vector<PyMethodDef> {
"\n" "\n"
"Print debugging info about game objects.\n" "Print debugging info about game objects.\n"
"\n" "\n"
"Category: General Utility Functions\n" "Category: **General Utility Functions**\n"
"\n" "\n"
"This call only functions in debug builds of the game.\n" "This call only functions in debug builds of the game.\n"
"It prints various info about the current object count, etc."}, "It prints various info about the current object count, etc."},
@ -849,17 +849,18 @@ auto PythonMethodsSystem::GetMethods() -> std::vector<PyMethodDef> {
"\n" "\n"
"Return whether this is the first time running a line of code.\n" "Return whether this is the first time running a line of code.\n"
"\n" "\n"
"Category: General Utility Functions\n" "Category: **General Utility Functions**\n"
"\n" "\n"
"This is used by 'print_once()' type calls to keep from overflowing\n" "This is used by 'print_once()' type calls to keep from overflowing\n"
"logs. The call functions by registering the filename and line where\n" "logs. The call functions by registering the filename and line where\n"
"The call is made from. Returns True if this location has not been\n" "The call is made from. Returns True if this location has not been\n"
"registered already, and False if it has.\n" "registered already, and False if it has.\n"
"\n" "\n"
"# Example: this print will only fire for the first loop iteration:\n" "##### Example\n"
"for i in range(10):\n" "This print will only fire for the first loop iteration:\n"
" if ba.do_once():\n" ">>> for i in range(10):\n"
" print('Hello once from loop!')"}, "... if ba.do_once():\n"
"... print('Hello once from loop!')\n"},
{"_app", (PyCFunction)PyApp, METH_VARARGS | METH_KEYWORDS, {"_app", (PyCFunction)PyApp, METH_VARARGS | METH_KEYWORDS,
"_app() -> ba.App\n" "_app() -> ba.App\n"
@ -911,7 +912,7 @@ auto PythonMethodsSystem::GetMethods() -> std::vector<PyMethodDef> {
"\n" "\n"
"Used for analytics to see where in the app players spend their time.\n" "Used for analytics to see where in the app players spend their time.\n"
"\n" "\n"
"Category: General Utility Functions\n" "Category: **General Utility Functions**\n"
"\n" "\n"
"Generally called when opening a new window or entering some UI.\n" "Generally called when opening a new window or entering some UI.\n"
"'screen' should be a string description of an app location\n" "'screen' should be a string description of an app location\n"
@ -1013,7 +1014,7 @@ auto PythonMethodsSystem::GetMethods() -> std::vector<PyMethodDef> {
"\n" "\n"
"(internal)\n" "(internal)\n"
"\n" "\n"
"Category: General Utility Functions"}, "Category: **General Utility Functions**"},
{"print_context", (PyCFunction)PyPrintContext, {"print_context", (PyCFunction)PyPrintContext,
METH_VARARGS | METH_KEYWORDS, METH_VARARGS | METH_KEYWORDS,

View File

@ -2318,7 +2318,7 @@ auto PythonMethodsUI::GetMethods() -> std::vector<PyMethodDef> {
"\n" "\n"
"Open a provided URL.\n" "Open a provided URL.\n"
"\n" "\n"
"Category: General Utility Functions\n" "Category: **General Utility Functions**\n"
"\n" "\n"
"Open the provided url in a web-browser, or display the URL\n" "Open the provided url in a web-browser, or display the URL\n"
"string in a window if that isn't possible.\n"}, "string in a window if that isn't possible.\n"},
@ -2382,7 +2382,7 @@ auto PythonMethodsUI::GetMethods() -> std::vector<PyMethodDef> {
"\n" "\n"
"(internal)\n" "(internal)\n"
"\n" "\n"
"Category: General Utility Functions"}, "Category: **General Utility Functions**"},
{"show_app_invite", (PyCFunction)PyShowAppInvite, {"show_app_invite", (PyCFunction)PyShowAppInvite,
METH_VARARGS | METH_KEYWORDS, METH_VARARGS | METH_KEYWORDS,
@ -2392,7 +2392,7 @@ auto PythonMethodsUI::GetMethods() -> std::vector<PyMethodDef> {
"\n" "\n"
"(internal)\n" "(internal)\n"
"\n" "\n"
"Category: General Utility Functions"}, "Category: **General Utility Functions**"},
{"show_ad", (PyCFunction)PyShowAd, METH_VARARGS | METH_KEYWORDS, {"show_ad", (PyCFunction)PyShowAd, METH_VARARGS | METH_KEYWORDS,
"show_ad(purpose: str, on_completion_call: Callable[[], None] = None)\n" "show_ad(purpose: str, on_completion_call: Callable[[], None] = None)\n"
@ -2487,7 +2487,7 @@ auto PythonMethodsUI::GetMethods() -> std::vector<PyMethodDef> {
"\n" "\n"
"Create or edit a button widget.\n" "Create or edit a button widget.\n"
"\n" "\n"
"Category: User Interface Functions\n" "Category: **User Interface Functions**\n"
"\n" "\n"
"Pass a valid existing ba.Widget as 'edit' to modify it; otherwise\n" "Pass a valid existing ba.Widget as 'edit' to modify it; otherwise\n"
"a new one is created and returned. Arguments that are not set to None\n" "a new one is created and returned. Arguments that are not set to None\n"
@ -2513,7 +2513,7 @@ auto PythonMethodsUI::GetMethods() -> std::vector<PyMethodDef> {
"\n" "\n"
"Create or edit a check-box widget.\n" "Create or edit a check-box widget.\n"
"\n" "\n"
"Category: User Interface Functions\n" "Category: **User Interface Functions**\n"
"\n" "\n"
"Pass a valid existing ba.Widget as 'edit' to modify it; otherwise\n" "Pass a valid existing ba.Widget as 'edit' to modify it; otherwise\n"
"a new one is created and returned. Arguments that are not set to None\n" "a new one is created and returned. Arguments that are not set to None\n"
@ -2534,7 +2534,7 @@ auto PythonMethodsUI::GetMethods() -> std::vector<PyMethodDef> {
"\n" "\n"
"Create or edit an image widget.\n" "Create or edit an image widget.\n"
"\n" "\n"
"Category: User Interface Functions\n" "Category: **User Interface Functions**\n"
"\n" "\n"
"Pass a valid existing ba.Widget as 'edit' to modify it; otherwise\n" "Pass a valid existing ba.Widget as 'edit' to modify it; otherwise\n"
"a new one is created and returned. Arguments that are not set to None\n" "a new one is created and returned. Arguments that are not set to None\n"
@ -2562,7 +2562,7 @@ auto PythonMethodsUI::GetMethods() -> std::vector<PyMethodDef> {
"\n" "\n"
"Create or edit a column widget.\n" "Create or edit a column widget.\n"
"\n" "\n"
"Category: User Interface Functions\n" "Category: **User Interface Functions**\n"
"\n" "\n"
"Pass a valid existing ba.Widget as 'edit' to modify it; otherwise\n" "Pass a valid existing ba.Widget as 'edit' to modify it; otherwise\n"
"a new one is created and returned. Arguments that are not set to None\n" "a new one is created and returned. Arguments that are not set to None\n"
@ -2604,7 +2604,7 @@ auto PythonMethodsUI::GetMethods() -> std::vector<PyMethodDef> {
"\n" "\n"
"Create or edit a container widget.\n" "Create or edit a container widget.\n"
"\n" "\n"
"Category: User Interface Functions\n" "Category: **User Interface Functions**\n"
"\n" "\n"
"Pass a valid existing ba.Widget as 'edit' to modify it; otherwise\n" "Pass a valid existing ba.Widget as 'edit' to modify it; otherwise\n"
"a new one is created and returned. Arguments that are not set to None\n" "a new one is created and returned. Arguments that are not set to None\n"
@ -2622,7 +2622,7 @@ auto PythonMethodsUI::GetMethods() -> std::vector<PyMethodDef> {
"\n" "\n"
"Create or edit a row widget.\n" "Create or edit a row widget.\n"
"\n" "\n"
"Category: User Interface Functions\n" "Category: **User Interface Functions**\n"
"\n" "\n"
"Pass a valid existing ba.Widget as 'edit' to modify it; otherwise\n" "Pass a valid existing ba.Widget as 'edit' to modify it; otherwise\n"
"a new one is created and returned. Arguments that are not set to None\n" "a new one is created and returned. Arguments that are not set to None\n"
@ -2645,7 +2645,7 @@ auto PythonMethodsUI::GetMethods() -> std::vector<PyMethodDef> {
"\n" "\n"
"Create or edit a scroll widget.\n" "Create or edit a scroll widget.\n"
"\n" "\n"
"Category: User Interface Functions\n" "Category: **User Interface Functions**\n"
"\n" "\n"
"Pass a valid existing ba.Widget as 'edit' to modify it; otherwise\n" "Pass a valid existing ba.Widget as 'edit' to modify it; otherwise\n"
"a new one is created and returned. Arguments that are not set to None\n" "a new one is created and returned. Arguments that are not set to None\n"
@ -2667,7 +2667,7 @@ auto PythonMethodsUI::GetMethods() -> std::vector<PyMethodDef> {
"\n" "\n"
"Create or edit a horizontal scroll widget.\n" "Create or edit a horizontal scroll widget.\n"
"\n" "\n"
"Category: User Interface Functions\n" "Category: **User Interface Functions**\n"
"\n" "\n"
"Pass a valid existing ba.Widget as 'edit' to modify it; otherwise\n" "Pass a valid existing ba.Widget as 'edit' to modify it; otherwise\n"
"a new one is created and returned. Arguments that are not set to None\n" "a new one is created and returned. Arguments that are not set to None\n"
@ -2698,7 +2698,7 @@ auto PythonMethodsUI::GetMethods() -> std::vector<PyMethodDef> {
"\n" "\n"
"Create or edit a text widget.\n" "Create or edit a text widget.\n"
"\n" "\n"
"Category: User Interface Functions\n" "Category: **User Interface Functions**\n"
"\n" "\n"
"Pass a valid existing ba.Widget as 'edit' to modify it; otherwise\n" "Pass a valid existing ba.Widget as 'edit' to modify it; otherwise\n"
"a new one is created and returned. Arguments that are not set to None\n" "a new one is created and returned. Arguments that are not set to None\n"
@ -2713,7 +2713,7 @@ auto PythonMethodsUI::GetMethods() -> std::vector<PyMethodDef> {
"\n" "\n"
"Edit common attributes of any widget.\n" "Edit common attributes of any widget.\n"
"\n" "\n"
"Category: User Interface Functions\n" "Category: **User Interface Functions**\n"
"\n" "\n"
"Unlike other UI calls, this can only be used to edit, not to " "Unlike other UI calls, this can only be used to edit, not to "
"create.\n"}, "create.\n"},

View File

@ -46,6 +46,7 @@ PIP_REQUIREMENTS = [
PipRequirement(modulename='ansiwrap'), PipRequirement(modulename='ansiwrap'),
PipRequirement(modulename='yaml', pipname='PyYAML'), PipRequirement(modulename='yaml', pipname='PyYAML'),
PipRequirement(modulename='requests'), PipRequirement(modulename='requests'),
PipRequirement(modulename='pdoc'),
PipRequirement(pipname='typing_extensions', minversion=[4, 0, 1]), PipRequirement(pipname='typing_extensions', minversion=[4, 0, 1]),
PipRequirement(pipname='types-filelock', minversion=[3, 2, 5]), PipRequirement(pipname='types-filelock', minversion=[3, 2, 5]),
PipRequirement(pipname='types-requests', minversion=[2, 27, 7]), PipRequirement(pipname='types-requests', minversion=[2, 27, 7]),

File diff suppressed because it is too large Load Diff

View File

@ -21,7 +21,7 @@ from efrotools import get_files_hash
if TYPE_CHECKING: if TYPE_CHECKING:
from types import ModuleType from types import ModuleType
from typing import Sequence, Any from typing import Sequence, Any, Optional
from batools.docs import AttributeInfo from batools.docs import AttributeInfo
@ -252,7 +252,8 @@ def _writefuncs(parent: Any, funcnames: Sequence[str], indent: int,
f'unknown returns value: {returns} for {funcname}') f'unknown returns value: {returns} for {funcname}')
returnspc = indstr + ' ' returnspc = indstr + ' '
returnstr = ('\n' + returnspc).join(returnstr.strip().splitlines()) returnstr = ('\n' + returnspc).join(returnstr.strip().splitlines())
docstr_out = _formatdoc(docstr, indent + 4) docstr_out = _formatdoc(_filterdoc(docstr, funcname=funcname),
indent + 4)
out += spcstr + defsline + docstr_out + f'{returnspc}{returnstr}\n' out += spcstr + defsline + docstr_out + f'{returnspc}{returnstr}\n'
return out return out
@ -470,18 +471,58 @@ def _special_class_cases(classname: str) -> str:
return out return out
def _formatdoc(docstr: str, indent: int) -> str: def _filterdoc(docstr: str, funcname: Optional[str] = None) -> str:
docslines = docstr.splitlines()
if (funcname and docslines and docslines[0]
and docslines[0].startswith(funcname)):
# Remove this signature from python docstring
# as not to repeat ourselves.
_, docstr = docstr.split('\n\n', maxsplit=1)
docslines = docstr.splitlines()
# Assuming that each line between 'Attributes:' and '\n\n' belongs to
# attrs descriptions.
empty_lines_count = 0
attributes_line: Optional[int] = None
attrs_definitions_last_line: Optional[int] = None
for i, line in enumerate(docslines):
if line.strip() in ['Attrs:', 'Attributes:']:
if attributes_line is not None:
raise Exception("Multiple 'Attributes:' lines found")
attributes_line = i
if not line.strip():
empty_lines_count += 1
else:
empty_lines_count = 0
if empty_lines_count >= 2 and attributes_line is not None:
# It seems attribute definitions ended.
attrs_definitions_last_line = i
break
if attrs_definitions_last_line is None:
attrs_definitions_last_line = len(docslines) - 1
return '\n'.join(docslines[:attributes_line] +
docslines[attrs_definitions_last_line + 1:])
def _formatdoc(docstr: str,
indent: int,
no_end_newline: bool = False,
inner_indent: int = 0) -> str:
out = '' out = ''
indentstr = indent * ' ' indentstr = indent * ' '
inner_indent_str = inner_indent * ' '
docslines = docstr.splitlines() docslines = docstr.splitlines()
if len(docslines) == 1: if len(docslines) == 1:
out += '\n' + indentstr + '"""' + docslines[0] + '"""\n' out += '\n' + indentstr + '"""' + docslines[0] + '"""\n'
else: else:
for i, line in enumerate(docslines): for i, line in enumerate(docslines):
if i != 0 and line != '': if i != 0 and line != '':
docslines[i] = indentstr + line docslines[i] = indentstr + inner_indent_str + line
out += ('\n' + indentstr + '"""' + '\n'.join(docslines) + '\n' + out += ('\n' + indentstr + '"""' + '\n'.join(docslines) +
indentstr + '"""\n') ('' if no_end_newline else '\n' + indentstr) + '"""\n')
return out return out
@ -503,7 +544,8 @@ def _writeclasses(module: ModuleType, classnames: Sequence[str]) -> str:
out += f'class {classname}:\n' out += f'class {classname}:\n'
docstr = cls.__doc__ docstr = cls.__doc__
out += _formatdoc(docstr, 4) # classname is constructor name
out += _formatdoc(_filterdoc(docstr, funcname=classname), 4)
# Create a public constructor if it has one. # Create a public constructor if it has one.
# If the first docs line appears to be a function signature # If the first docs line appears to be a function signature
@ -537,6 +579,12 @@ def _writeclasses(module: ModuleType, classnames: Sequence[str]) -> str:
for attr in attrs: for attr in attrs:
if attr.attr_type is not None: if attr.attr_type is not None:
out += f' {attr.name}: {attr.attr_type}\n' out += f' {attr.name}: {attr.attr_type}\n'
if attr.docs:
out += _formatdoc(_filterdoc(attr.docs),
indent=4,
inner_indent=3,
no_end_newline=True)
out += '\n'
else: else:
raise Exception(f'Found untyped attr in' raise Exception(f'Found untyped attr in'
f' {classname} docs: {attr.name}') f' {classname} docs: {attr.name}')
@ -581,7 +629,8 @@ def generate(sources_hash: str, outfilename: str) -> None:
# Ignore _ba.app. # Ignore _ba.app.
continue continue
else: else:
raise Exception(f'found unknown obj {entry}') raise Exception(
f'found unknown obj {entry}, {getattr(module, entry)}')
funcnames.sort() funcnames.sort()
classnames.sort() classnames.sort()
out = (get_public_license('python') out = (get_public_license('python')