mirror of
https://github.com/RYDE-WORK/ballistica.git
synced 2026-01-24 16:06:51 +08:00
More type checking cleanup
This commit is contained in:
parent
e32aa01088
commit
783d1ccd19
@ -4132,16 +4132,16 @@
|
||||
"assets/build/windows/x64/python.exe": "https://files.ballistica.net/cache/ba1/25/a7/dc87c1be41605eb6fefd0145144c",
|
||||
"assets/build/windows/x64/python37.dll": "https://files.ballistica.net/cache/ba1/b9/e4/d912f56e42e9991bcbb4c804cfcb",
|
||||
"assets/build/windows/x64/pythonw.exe": "https://files.ballistica.net/cache/ba1/6c/bb/b6f52c306aa4e88061510e96cefe",
|
||||
"build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/86/fd/1edae1d48773436f72ceaf5c4588",
|
||||
"build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/07/88/2e60127c99cd8018f4b7a77c455b",
|
||||
"build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/01/ef/2c661b395a46f1abbd6c2042cb50",
|
||||
"build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/98/ad/d73757e8902b9c5c36c73469773b",
|
||||
"build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/94/e3/9ad5acc492f343a24e790be07ed0",
|
||||
"build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/9a/1f/5ae4c3d9b710b24ea2464c1f62ab",
|
||||
"build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/83/f9/de5c6a7a1dd65f305565bd5a0897",
|
||||
"build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/c7/29/1f1d904b57ef0379654421737c6b",
|
||||
"build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/bd/7b/308923feba6216c72c565cb9a942",
|
||||
"build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/ce/44/4d2658f31d74fb342604e38bf12a",
|
||||
"build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/53/d7/89dfbf816f8fe6824cf9f62f81f6",
|
||||
"build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/1c/b8/d9def95f52348a50d01b4a9a3996"
|
||||
"build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/66/68/37e1f6d2afd5d6a4cbbcebba2f3e",
|
||||
"build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/dc/d4/f954892306c82ca4d9c74d335c15",
|
||||
"build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/4d/b8/4cfc2035ec4cdeba78be2aee8aff",
|
||||
"build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/3f/98/9edf61a1b38432213e93b9342a4e",
|
||||
"build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/86/43/f76e498f45bb42f2383986d3c15b",
|
||||
"build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/a1/d6/a9dd60f83d58eb09b1b4c0771588",
|
||||
"build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/d8/4f/9ded4658cf6e8d8d7fdf9477ae86",
|
||||
"build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/a1/6b/56d9fa2709eb43be73c00aacb1b5",
|
||||
"build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/a9/41/2e78f2f5dfa4273ce70fc5a59e0e",
|
||||
"build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/9e/3d/12c0ba5235b6750ec0f37726de6e",
|
||||
"build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/8f/9c/edea76ee92634ef9565988c9ef6e",
|
||||
"build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/35/86/2aeb9cfac9f7639676e149e1323b"
|
||||
}
|
||||
4
.idea/dictionaries/ericf.xml
generated
4
.idea/dictionaries/ericf.xml
generated
@ -578,6 +578,8 @@
|
||||
<w>execlocals</w>
|
||||
<w>executils</w>
|
||||
<w>exhash</w>
|
||||
<w>existable</w>
|
||||
<w>existables</w>
|
||||
<w>expatbuilder</w>
|
||||
<w>expatreader</w>
|
||||
<w>explodable</w>
|
||||
@ -752,6 +754,7 @@
|
||||
<w>getcurrency</w>
|
||||
<w>getcwd</w>
|
||||
<w>getdata</w>
|
||||
<w>getkillerplayer</w>
|
||||
<w>getlevelname</w>
|
||||
<w>getmaps</w>
|
||||
<w>getmodel</w>
|
||||
@ -1688,6 +1691,7 @@
|
||||
<w>spinoff</w>
|
||||
<w>spinoffdata</w>
|
||||
<w>spinoffs</w>
|
||||
<w>splayer</w>
|
||||
<w>splitlen</w>
|
||||
<w>splitnumstr</w>
|
||||
<w>squadcore</w>
|
||||
|
||||
1
.idea/inspectionProfiles/Default.xml
generated
1
.idea/inspectionProfiles/Default.xml
generated
@ -50,6 +50,7 @@
|
||||
<scope name="UncheckedPython" level="WEAK WARNING" enabled="false" />
|
||||
</inspection_tool>
|
||||
<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="PyUnreachableCodeInspection" enabled="false" 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">
|
||||
|
||||
@ -34,7 +34,7 @@ NOTE: This file was autogenerated by gendummymodule; do not edit by hand.
|
||||
"""
|
||||
|
||||
# (hash we can use to see if this file is out of date)
|
||||
# SOURCES_HASH=68384686054944380533078060197841658129
|
||||
# SOURCES_HASH=86859069497661939825754704003122742687
|
||||
|
||||
# I'm sorry Pylint. I know this file saddens you. Be strong.
|
||||
# pylint: disable=useless-suppression
|
||||
@ -253,9 +253,6 @@ class InputDevice:
|
||||
|
||||
Attributes:
|
||||
|
||||
exists: bool
|
||||
Whether the underlying device for this object is still present.
|
||||
|
||||
allows_configuring: bool
|
||||
Whether the input-device can be configured.
|
||||
|
||||
@ -290,7 +287,6 @@ class InputDevice:
|
||||
client.
|
||||
|
||||
"""
|
||||
exists: bool
|
||||
allows_configuring: bool
|
||||
player: Optional[ba.SessionPlayer]
|
||||
client_id: int
|
||||
@ -301,6 +297,13 @@ class InputDevice:
|
||||
is_controller_app: bool
|
||||
is_remote_client: bool
|
||||
|
||||
def exists(self) -> bool:
|
||||
"""exists() -> bool
|
||||
|
||||
Return whether the underlying device for this object is still present.
|
||||
"""
|
||||
return bool()
|
||||
|
||||
def get_account_name(self, full: bool) -> str:
|
||||
"""get_account_name(full: bool) -> str
|
||||
|
||||
@ -767,7 +770,7 @@ class SessionPlayer:
|
||||
Be aware that, like ba.Nodes, ba.SessionPlayer objects are 'weak'
|
||||
references under-the-hood; a player can leave the game at
|
||||
any point. For this reason, you should make judicious use of the
|
||||
ba.SessionPlayer.exists attribute (or boolean operator) to ensure
|
||||
ba.SessionPlayer.exists() method (or boolean operator) to ensure
|
||||
that a SessionPlayer is still present if retaining references to one
|
||||
for any length of time.
|
||||
|
||||
@ -776,10 +779,6 @@ class SessionPlayer:
|
||||
id: int
|
||||
The unique numeric ID of the Player.
|
||||
|
||||
exists: bool
|
||||
Whether the player still exists.
|
||||
Most functionality will fail on a nonexistent player.
|
||||
|
||||
Note that you can also use the boolean operator for this same
|
||||
functionality, so a statement such as "if player" will do
|
||||
the right thing both for Player objects and values of None.
|
||||
@ -820,7 +819,6 @@ class SessionPlayer:
|
||||
The current game-specific instance for this player.
|
||||
"""
|
||||
id: int
|
||||
exists: bool
|
||||
in_game: bool
|
||||
team: ba.SessionTeam
|
||||
sessiondata: Dict
|
||||
@ -845,6 +843,13 @@ class SessionPlayer:
|
||||
"""
|
||||
return None
|
||||
|
||||
def exists(self) -> bool:
|
||||
"""exists() -> bool
|
||||
|
||||
Return whether the underlying player is still in the game.
|
||||
"""
|
||||
return bool()
|
||||
|
||||
def get_account_id(self) -> str:
|
||||
"""get_account_id() -> str
|
||||
|
||||
|
||||
@ -74,13 +74,13 @@ from ba._apputils import is_browser_likely_available
|
||||
from ba._campaign import Campaign
|
||||
from ba._gameutils import (animate, animate_array, show_damage_count,
|
||||
sharedobj, timestring, cameraflash)
|
||||
from ba._general import WeakCall, Call
|
||||
from ba._general import WeakCall, Call, existing
|
||||
from ba._level import Level
|
||||
from ba._lobby import Lobby, Chooser
|
||||
from ba._math import normalized_color, is_point_in_box, vec3validate
|
||||
from ba._messages import (UNHANDLED, OutOfBoundsMessage, DeathType, DieMessage,
|
||||
StandMessage, PickUpMessage, DropMessage,
|
||||
PickedUpMessage, DroppedMessage,
|
||||
PlayerDiedMessage, StandMessage, PickUpMessage,
|
||||
DropMessage, PickedUpMessage, DroppedMessage,
|
||||
ShouldShatterMessage, ImpactDamageMessage,
|
||||
FreezeMessage, ThawMessage, HitMessage,
|
||||
CelebrateMessage)
|
||||
|
||||
@ -29,6 +29,7 @@ from typing import TYPE_CHECKING, TypeVar
|
||||
from ba._activity import Activity
|
||||
from ba._score import ScoreInfo
|
||||
from ba._lang import Lstr
|
||||
from ba._messages import PlayerDiedMessage
|
||||
import _ba
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@ -645,21 +646,24 @@ class GameActivity(Activity[PlayerType, TeamType]):
|
||||
player.set_actor(None)
|
||||
|
||||
def handlemessage(self, msg: Any) -> Any:
|
||||
from bastd.actor.playerspaz import PlayerSpazDeathMessage
|
||||
if isinstance(msg, PlayerSpazDeathMessage):
|
||||
if isinstance(msg, PlayerDiedMessage):
|
||||
# pylint: disable=cyclic-import
|
||||
from bastd.actor.spaz import Spaz
|
||||
|
||||
player = msg.playerspaz(self).player
|
||||
killer = msg.killerplayer
|
||||
player = msg.getplayer(self.playertype)
|
||||
killer = msg.getkillerplayer(self.playertype)
|
||||
|
||||
# Inform our score-set of the demise.
|
||||
# Inform our stats of the demise.
|
||||
self.stats.player_was_killed(player,
|
||||
killed=msg.killed,
|
||||
killer=killer)
|
||||
|
||||
# Award the killer points if he's on a different team.
|
||||
# FIXME: This should not be linked to Spaz actors.
|
||||
# (should move get_death_points to Actor or make it a message)
|
||||
if killer and killer.team is not player.team:
|
||||
pts, importance = msg.playerspaz(self).get_death_points(
|
||||
msg.how)
|
||||
assert isinstance(killer.actor, Spaz)
|
||||
pts, importance = killer.actor.get_death_points(msg.how)
|
||||
if not self.has_ended():
|
||||
self.stats.player_scored(killer,
|
||||
pts,
|
||||
|
||||
@ -28,12 +28,40 @@ from typing import TYPE_CHECKING, TypeVar
|
||||
import _ba
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any, Type
|
||||
from typing import Any, Type, Optional
|
||||
from typing_extensions import Protocol
|
||||
from efro.call import Call as Call # 'as Call' so we re-export.
|
||||
|
||||
class Existable(Protocol):
|
||||
"""Protocol for objects supporting an exists() method."""
|
||||
|
||||
def exists(self) -> bool:
|
||||
"""Whether this object exists."""
|
||||
...
|
||||
|
||||
ExistableType = TypeVar('ExistableType', bound=Existable)
|
||||
|
||||
T = TypeVar('T')
|
||||
|
||||
|
||||
def existing(obj: Optional[ExistableType]) -> Optional[ExistableType]:
|
||||
"""Convert invalid references to None.
|
||||
|
||||
Category: Gameplay Functions
|
||||
|
||||
To best support type checking, it is important that invalid references
|
||||
not be passed around and instead get converted to values of None.
|
||||
That way the type checker can properly flag attempts to pass dead
|
||||
objects into functions expecting only live ones, etc.
|
||||
This call can be used on any 'existable' object (one with an exists()
|
||||
method) and will convert it to a None value if it does not exist.
|
||||
For more info, see notes on 'existables' here:
|
||||
https://github.com/efroemling/ballistica/wiki/Coding-Style-Guide
|
||||
"""
|
||||
assert obj is None or hasattr(obj, 'exists'), f'No "exists" on {obj}'
|
||||
return obj if obj is not None and obj.exists() else None
|
||||
|
||||
|
||||
def getclass(name: str, subclassof: Type[T]) -> Type[T]:
|
||||
"""Given a full class name such as foo.bar.MyClass, return the class.
|
||||
|
||||
|
||||
@ -23,13 +23,13 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
from typing import TYPE_CHECKING
|
||||
from typing import TYPE_CHECKING, TypeVar
|
||||
from enum import Enum
|
||||
|
||||
import _ba
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Sequence
|
||||
from typing import Sequence, Optional, Type, Any
|
||||
import ba
|
||||
|
||||
|
||||
@ -88,6 +88,64 @@ class DieMessage:
|
||||
how: DeathType = DeathType.GENERIC
|
||||
|
||||
|
||||
PlayerType = TypeVar('PlayerType', bound='ba.Player')
|
||||
|
||||
|
||||
class PlayerDiedMessage:
|
||||
"""A message saying a ba.PlayerSpaz has died.
|
||||
|
||||
category: Message Classes
|
||||
|
||||
Attributes:
|
||||
|
||||
killed
|
||||
If True, the spaz was killed;
|
||||
If False, they left the game or the round ended.
|
||||
|
||||
how
|
||||
The particular type of death.
|
||||
"""
|
||||
killed: bool
|
||||
how: ba.DeathType
|
||||
|
||||
def __init__(self, player: ba.Player, was_killed: bool,
|
||||
killerplayer: Optional[ba.Player], how: ba.DeathType):
|
||||
"""Instantiate a message with the given values."""
|
||||
|
||||
# Invalid refs should never be passed as args.
|
||||
assert player.exists()
|
||||
self._player = player
|
||||
|
||||
# Invalid refs should never be passed as args.
|
||||
assert killerplayer is None or killerplayer.exists()
|
||||
self._killerplayer = killerplayer
|
||||
self.killed = was_killed
|
||||
self.how = how
|
||||
|
||||
def getkillerplayer(self,
|
||||
playertype: Type[PlayerType]) -> Optional[PlayerType]:
|
||||
"""Return the ba.Player responsible for the killing, if any.
|
||||
|
||||
Pass the Player type being used by the current game.
|
||||
"""
|
||||
assert isinstance(self._killerplayer, (playertype, type(None)))
|
||||
return self._killerplayer
|
||||
|
||||
def getplayer(self, playertype: Type[PlayerType]) -> PlayerType:
|
||||
"""Return the spaz that died.
|
||||
|
||||
The current activity is required as an argument so the exact type of
|
||||
PlayerSpaz can be determined by the type checker.
|
||||
"""
|
||||
player: Any = self._player
|
||||
assert isinstance(player, playertype)
|
||||
|
||||
# We should never be delivering invalid refs.
|
||||
# (could theoretically happen if someone holds on to us)
|
||||
assert player.exists()
|
||||
return player
|
||||
|
||||
|
||||
@dataclass
|
||||
class StandMessage:
|
||||
"""A message telling an object to move to a position in space.
|
||||
@ -212,7 +270,6 @@ class CelebrateMessage:
|
||||
duration: float = 10.0
|
||||
|
||||
|
||||
@dataclass(init=False)
|
||||
class HitMessage:
|
||||
"""Tells an object it has been hit in some way.
|
||||
|
||||
@ -243,7 +300,10 @@ class HitMessage:
|
||||
self.magnitude = magnitude
|
||||
self.velocity_magnitude = velocity_magnitude
|
||||
self.radius = radius
|
||||
self.source_player = source_player
|
||||
|
||||
# Invalid refs should never be passed to things.
|
||||
assert source_player is None or source_player.exists()
|
||||
self._source_player = source_player
|
||||
self.kick_back = kick_back
|
||||
self.flat_damage = flat_damage
|
||||
self.hit_type = hit_type
|
||||
@ -251,6 +311,21 @@ class HitMessage:
|
||||
self.force_direction = (force_direction
|
||||
if force_direction is not None else velocity)
|
||||
|
||||
def get_source_player(
|
||||
self, playertype: Type[PlayerType]) -> Optional[PlayerType]:
|
||||
"""Return the spaz that died.
|
||||
|
||||
The current activity is required as an argument so the exact type of
|
||||
PlayerSpaz can be determined by the type checker.
|
||||
"""
|
||||
player: Any = self._source_player
|
||||
assert isinstance(player, (playertype, type(None)))
|
||||
|
||||
# We should not be delivering invalid refs.
|
||||
# (technically if someone holds on to this message this can happen)
|
||||
assert player is None or player.exists()
|
||||
return player
|
||||
|
||||
|
||||
@dataclass
|
||||
class PlayerProfilesChangedMessage:
|
||||
|
||||
@ -29,6 +29,7 @@ if TYPE_CHECKING:
|
||||
Callable)
|
||||
import ba
|
||||
|
||||
PlayerType = TypeVar('PlayerType', bound='ba.Player')
|
||||
TeamType = TypeVar('TeamType', bound='ba.Team')
|
||||
|
||||
|
||||
@ -117,7 +118,6 @@ class Player(Generic[TeamType]):
|
||||
raise _error.NodeNotFoundError
|
||||
return self._nodeactor.node
|
||||
|
||||
@property
|
||||
def exists(self) -> bool:
|
||||
"""Whether the underlying player still exists.
|
||||
|
||||
@ -126,7 +126,7 @@ class Player(Generic[TeamType]):
|
||||
functionality, so a statement such as "if player" will do
|
||||
the right thing both for Player objects and values of None.
|
||||
"""
|
||||
return bool(self._sessionplayer)
|
||||
return self._sessionplayer.exists()
|
||||
|
||||
def get_name(self, full: bool = False, icon: bool = True) -> str:
|
||||
"""get_name(full: bool = False, icon: bool = True) -> str
|
||||
@ -181,10 +181,7 @@ class Player(Generic[TeamType]):
|
||||
self._sessionplayer.reset_input()
|
||||
|
||||
def __bool__(self) -> bool:
|
||||
return bool(self._sessionplayer)
|
||||
|
||||
|
||||
PlayerType = TypeVar('PlayerType', bound='ba.Player')
|
||||
return self._sessionplayer.exists()
|
||||
|
||||
|
||||
def playercast(totype: Type[PlayerType], player: ba.Player) -> PlayerType:
|
||||
|
||||
@ -623,7 +623,8 @@ class Blast(ba.Actor):
|
||||
hit_type=self.hit_type,
|
||||
hit_subtype=self.hit_subtype,
|
||||
radius=self.radius,
|
||||
source_player=self.source_player))
|
||||
source_player=ba.existing(
|
||||
self.source_player)))
|
||||
if self.blast_type == 'ice':
|
||||
ba.playsound(get_factory().freeze_sound,
|
||||
10,
|
||||
@ -987,8 +988,9 @@ class Bomb(ba.Actor):
|
||||
# Also lets change the owner of the bomb to whoever is setting
|
||||
# us off. (this way points for big chain reactions go to the
|
||||
# person causing them).
|
||||
if msg.source_player not in [None]:
|
||||
self.source_player = msg.source_player
|
||||
source_player = msg.get_source_player(ba.Player)
|
||||
if source_player is not None:
|
||||
self.source_player = source_player
|
||||
|
||||
# Also inherit the hit type (if a landmine sets off by a bomb,
|
||||
# the credit should go to the mine)
|
||||
|
||||
@ -34,44 +34,6 @@ PlayerType = TypeVar('PlayerType', bound=ba.Player)
|
||||
TeamType = TypeVar('TeamType', bound=ba.Team)
|
||||
|
||||
|
||||
class PlayerSpazDeathMessage:
|
||||
"""A message saying a ba.PlayerSpaz has died.
|
||||
|
||||
category: Message Classes
|
||||
|
||||
Attributes:
|
||||
|
||||
killed
|
||||
If True, the spaz was killed;
|
||||
If False, they left the game or the round ended.
|
||||
|
||||
killerplayer
|
||||
The ba.Player that did the killing, or None.
|
||||
|
||||
how
|
||||
The particular type of death.
|
||||
"""
|
||||
|
||||
def __init__(self, spaz: PlayerSpaz, was_killed: bool,
|
||||
killerplayer: Optional[ba.Player], how: ba.DeathType):
|
||||
"""Instantiate a message with the given values."""
|
||||
self._spaz = spaz
|
||||
self.killed = was_killed
|
||||
self.killerplayer = killerplayer
|
||||
self.how = how
|
||||
|
||||
def playerspaz(
|
||||
self, activity: ba.Activity[PlayerType,
|
||||
TeamType]) -> PlayerSpaz[PlayerType]:
|
||||
"""Return the spaz that died.
|
||||
|
||||
The current activity is required as an argument so the exact type of
|
||||
PlayerSpaz can be determined by the type checker.
|
||||
"""
|
||||
del activity # Unused
|
||||
return self._spaz
|
||||
|
||||
|
||||
class PlayerSpazHurtMessage:
|
||||
"""A message saying a ba.PlayerSpaz was hurt.
|
||||
|
||||
@ -93,7 +55,7 @@ class PlayerSpaz(Spaz, Generic[PlayerType]):
|
||||
|
||||
category: Gameplay Classes
|
||||
|
||||
When a PlayerSpaz dies, it delivers a ba.PlayerSpazDeathMessage
|
||||
When a PlayerSpaz dies, it delivers a ba.PlayerDiedMessage
|
||||
to the current ba.Activity. (unless the death was the result of the
|
||||
player leaving the game, in which case no message is sent)
|
||||
|
||||
@ -302,16 +264,16 @@ class PlayerSpaz(Spaz, Generic[PlayerType]):
|
||||
# Only report if both the player and the activity still exist.
|
||||
if killed and activity is not None and self.getplayer():
|
||||
activity.handlemessage(
|
||||
PlayerSpazDeathMessage(self, killed, killerplayer,
|
||||
msg.how))
|
||||
ba.PlayerDiedMessage(self.player, killed, killerplayer,
|
||||
msg.how))
|
||||
|
||||
super().handlemessage(msg) # Augment standard behavior.
|
||||
|
||||
# Keep track of the player who last hit us for point rewarding.
|
||||
elif isinstance(msg, ba.HitMessage):
|
||||
if msg.source_player:
|
||||
srcplayer = ba.playercast_o(self.playertype, msg.source_player)
|
||||
self.last_player_attacked_by = srcplayer
|
||||
source_player = msg.get_source_player(self.playertype)
|
||||
if source_player:
|
||||
self.last_player_attacked_by = source_player
|
||||
self.last_attacked_time = ba.time()
|
||||
self.last_attacked_type = (msg.hit_type, msg.hit_subtype)
|
||||
super().handlemessage(msg) # Augment standard behavior.
|
||||
|
||||
@ -1089,8 +1089,9 @@ class Spaz(ba.Actor):
|
||||
# If we're cursed, *any* damage blows us up.
|
||||
if self._cursed and damage > 0:
|
||||
ba.timer(
|
||||
0.05, ba.WeakCall(self.curse_explode,
|
||||
msg.source_player))
|
||||
0.05,
|
||||
ba.WeakCall(self.curse_explode,
|
||||
msg.get_source_player(ba.Player)))
|
||||
# if we're frozen, shatter.. otherwise die if we hit zero
|
||||
if self.frozen and (damage > 200 or self.hitpoints <= 0):
|
||||
self.shatter()
|
||||
|
||||
@ -574,8 +574,9 @@ class SpazBot(Spaz):
|
||||
|
||||
# Keep track of the player who last hit us for point rewarding.
|
||||
elif isinstance(msg, ba.HitMessage):
|
||||
if msg.source_player:
|
||||
self.last_player_attacked_by = msg.source_player
|
||||
source_player = msg.get_source_player(ba.Player)
|
||||
if source_player:
|
||||
self.last_player_attacked_by = source_player
|
||||
self.last_attacked_time = ba.time()
|
||||
self.last_attacked_type = (msg.hit_type, msg.hit_subtype)
|
||||
super().handlemessage(msg)
|
||||
|
||||
@ -29,7 +29,7 @@ import random
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import ba
|
||||
from bastd.actor.playerspaz import PlayerSpaz, PlayerSpazDeathMessage
|
||||
from bastd.actor.playerspaz import PlayerSpaz
|
||||
from bastd.actor.flag import Flag
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@ -161,9 +161,9 @@ class AssaultGame(ba.TeamGameActivity[Player, Team]):
|
||||
self.setup_standard_powerup_drops()
|
||||
|
||||
def handlemessage(self, msg: Any) -> Any:
|
||||
if isinstance(msg, PlayerSpazDeathMessage):
|
||||
if isinstance(msg, ba.PlayerDiedMessage):
|
||||
super().handlemessage(msg) # Augment standard.
|
||||
self.respawn_player(msg.playerspaz(self).player)
|
||||
self.respawn_player(msg.getplayer(Player))
|
||||
else:
|
||||
super().handlemessage(msg)
|
||||
|
||||
|
||||
@ -29,7 +29,7 @@ from typing import TYPE_CHECKING
|
||||
|
||||
import ba
|
||||
from bastd.actor import flag as stdflag
|
||||
from bastd.actor.playerspaz import PlayerSpaz, PlayerSpazDeathMessage
|
||||
from bastd.actor.playerspaz import PlayerSpaz
|
||||
from bastd.actor.scoreboard import Scoreboard
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@ -548,10 +548,10 @@ class CaptureTheFlagGame(ba.TeamGameActivity[Player, Team]):
|
||||
self._score_to_win)
|
||||
|
||||
def handlemessage(self, msg: Any) -> Any:
|
||||
if isinstance(msg, PlayerSpazDeathMessage):
|
||||
if isinstance(msg, ba.PlayerDiedMessage):
|
||||
# Augment standard behavior.
|
||||
super().handlemessage(msg)
|
||||
self.respawn_player(msg.playerspaz(self).player)
|
||||
self.respawn_player(msg.getplayer(Player))
|
||||
elif isinstance(msg, stdflag.FlagDeathMessage):
|
||||
assert isinstance(msg.flag, CTFFlag)
|
||||
ba.timer(0.1, ba.Call(self._spawn_flag_for_team, msg.flag.team))
|
||||
|
||||
@ -28,7 +28,7 @@ from typing import TYPE_CHECKING
|
||||
|
||||
import ba
|
||||
from bastd.actor.flag import Flag
|
||||
from bastd.actor.playerspaz import PlayerSpaz, PlayerSpazDeathMessage
|
||||
from bastd.actor.playerspaz import PlayerSpaz
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any, Type, List, Dict, Optional, Sequence, Union
|
||||
@ -312,12 +312,13 @@ class ChosenOneGame(ba.TeamGameActivity[Player, Team]):
|
||||
'position')
|
||||
|
||||
def handlemessage(self, msg: Any) -> Any:
|
||||
if isinstance(msg, PlayerSpazDeathMessage):
|
||||
if isinstance(msg, ba.PlayerDiedMessage):
|
||||
# Augment standard behavior.
|
||||
super().handlemessage(msg)
|
||||
player = msg.playerspaz(self).player
|
||||
player = msg.getplayer(Player)
|
||||
if player is self._get_chosen_one_player():
|
||||
killerplayer = ba.playercast_o(Player, msg.killerplayer)
|
||||
killerplayer = ba.playercast_o(Player,
|
||||
msg.getkillerplayer(Player))
|
||||
self._set_chosen_one_player(None if (
|
||||
killerplayer is None or killerplayer is player
|
||||
or not killerplayer.is_alive()) else killerplayer)
|
||||
|
||||
@ -30,7 +30,6 @@ from typing import TYPE_CHECKING
|
||||
|
||||
import ba
|
||||
from bastd.actor.flag import Flag
|
||||
from bastd.actor.playerspaz import PlayerSpazDeathMessage
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any, Optional, Type, List, Dict, Sequence, Union
|
||||
@ -41,22 +40,30 @@ class ConquestFlag(Flag):
|
||||
|
||||
def __init__(self, *args: Any, **keywds: Any):
|
||||
super().__init__(*args, **keywds)
|
||||
self._team: Optional[ba.Team] = None
|
||||
self._team: Optional[Team] = None
|
||||
self.light: Optional[ba.Node] = None
|
||||
|
||||
@property
|
||||
def team(self) -> Optional[ba.Team]:
|
||||
def team(self) -> Optional[Team]:
|
||||
"""The team that owns this flag."""
|
||||
return self._team
|
||||
|
||||
@team.setter
|
||||
def team(self, team: ba.Team) -> None:
|
||||
def team(self, team: Team) -> None:
|
||||
"""Set the team that owns this flag."""
|
||||
self._team = team
|
||||
|
||||
|
||||
class Player(ba.Player['Team']):
|
||||
"""Our player type for this game."""
|
||||
|
||||
|
||||
class Team(ba.Team[Player]):
|
||||
"""Our team type for this game."""
|
||||
|
||||
|
||||
# ba_meta export game
|
||||
class ConquestGame(ba.TeamGameActivity[ba.Player, ba.Team]):
|
||||
class ConquestGame(ba.TeamGameActivity[Player, Team]):
|
||||
"""A game where teams try to claim all flags on the map."""
|
||||
|
||||
name = 'Conquest'
|
||||
@ -115,12 +122,12 @@ class ConquestGame(ba.TeamGameActivity[ba.Player, ba.Team]):
|
||||
ba.MusicType.GRAND_ROMP)
|
||||
super().on_transition_in()
|
||||
|
||||
def on_team_join(self, team: ba.Team) -> None:
|
||||
def on_team_join(self, team: Team) -> None:
|
||||
if self.has_begun():
|
||||
self._update_scores()
|
||||
team.gamedata['flags_held'] = 0
|
||||
|
||||
def on_player_join(self, player: ba.Player) -> None:
|
||||
def on_player_join(self, player: Player) -> None:
|
||||
player.gamedata['respawn_timer'] = None
|
||||
|
||||
# Only spawn if this player's team has a flag currently.
|
||||
@ -213,7 +220,7 @@ class ConquestGame(ba.TeamGameActivity[ba.Player, ba.Team]):
|
||||
flag = flagnode.getdelegate()
|
||||
except Exception:
|
||||
return # Player may have left and his body hit the flag.
|
||||
assert isinstance(player, ba.Player)
|
||||
assert isinstance(player, Player)
|
||||
assert isinstance(flag, ConquestFlag)
|
||||
assert flag.light
|
||||
|
||||
@ -236,12 +243,12 @@ class ConquestGame(ba.TeamGameActivity[ba.Player, ba.Team]):
|
||||
self.spawn_player(otherplayer)
|
||||
|
||||
def handlemessage(self, msg: Any) -> Any:
|
||||
if isinstance(msg, PlayerSpazDeathMessage):
|
||||
if isinstance(msg, ba.PlayerDiedMessage):
|
||||
# Augment standard behavior.
|
||||
super().handlemessage(msg)
|
||||
|
||||
# Respawn only if this team has a flag.
|
||||
player = msg.playerspaz(self).player
|
||||
player = msg.getplayer(Player)
|
||||
if player.team.gamedata['flags_held'] > 0:
|
||||
self.respawn_player(player)
|
||||
else:
|
||||
@ -250,12 +257,12 @@ class ConquestGame(ba.TeamGameActivity[ba.Player, ba.Team]):
|
||||
else:
|
||||
super().handlemessage(msg)
|
||||
|
||||
def spawn_player(self, player: ba.Player) -> ba.Actor:
|
||||
def spawn_player(self, player: Player) -> ba.Actor:
|
||||
# We spawn players at different places based on what flags are held.
|
||||
return self.spawn_player_spaz(player,
|
||||
self._get_player_spawn_position(player))
|
||||
|
||||
def _get_player_spawn_position(self, player: ba.Player) -> Sequence[float]:
|
||||
def _get_player_spawn_position(self, player: Player) -> Sequence[float]:
|
||||
|
||||
# Iterate until we find a spawn owned by this team.
|
||||
spawn_count = len(self.map.spawn_by_flag_points)
|
||||
|
||||
@ -27,11 +27,10 @@ from __future__ import annotations
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import ba
|
||||
from bastd.actor import playerspaz
|
||||
from bastd.actor import spaz as stdspaz
|
||||
from bastd.actor.playerspaz import PlayerSpaz
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any, Type, List, Dict, Tuple, Union, Sequence
|
||||
from typing import Any, Type, List, Dict, Tuple, Union, Sequence, Optional
|
||||
|
||||
|
||||
class Player(ba.Player['Team']):
|
||||
@ -42,7 +41,7 @@ class Team(ba.Team[Player]):
|
||||
"""Our team type for this game."""
|
||||
|
||||
def __init__(self) -> None:
|
||||
pass
|
||||
self.score = 0
|
||||
|
||||
|
||||
# ba_meta export game
|
||||
@ -104,9 +103,14 @@ class DeathMatchGame(ba.TeamGameActivity[Player, Team]):
|
||||
from bastd.actor.scoreboard import Scoreboard
|
||||
super().__init__(settings)
|
||||
self._scoreboard = Scoreboard()
|
||||
self._score_to_win = None
|
||||
self._score_to_win: Optional[int] = None
|
||||
self._dingsound = ba.getsound('dingSmall')
|
||||
self._epic_mode = bool(settings['Epic Mode'])
|
||||
self._kills_to_win_per_player = int(
|
||||
settings['Kills to Win Per Player'])
|
||||
self._time_limit = float(settings['Time Limit'])
|
||||
self._allow_negative_scores = bool(
|
||||
settings.get('Allow Negative Scores', False))
|
||||
|
||||
# Base class overrides.
|
||||
self.slow_motion = self._epic_mode
|
||||
@ -120,34 +124,30 @@ class DeathMatchGame(ba.TeamGameActivity[Player, Team]):
|
||||
return 'kill ${ARG1} enemies', self._score_to_win
|
||||
|
||||
def on_team_join(self, team: Team) -> None:
|
||||
team.gamedata['score'] = 0
|
||||
if self.has_begun():
|
||||
self._update_scoreboard()
|
||||
|
||||
def on_begin(self) -> None:
|
||||
super().on_begin()
|
||||
self.setup_standard_time_limit(self.settings_raw['Time Limit'])
|
||||
self.setup_standard_time_limit(self._time_limit)
|
||||
self.setup_standard_powerup_drops()
|
||||
if self.teams:
|
||||
self._score_to_win = (
|
||||
self.settings_raw['Kills to Win Per Player'] *
|
||||
max(1, max(len(t.players) for t in self.teams)))
|
||||
else:
|
||||
self._score_to_win = self.settings_raw['Kills to Win Per Player']
|
||||
|
||||
# Base kills needed to win on the size of the largest team.
|
||||
self._score_to_win = (self._kills_to_win_per_player *
|
||||
max(1, max(len(t.players) for t in self.teams)))
|
||||
self._update_scoreboard()
|
||||
|
||||
def handlemessage(self, msg: Any) -> Any:
|
||||
# pylint: disable=too-many-branches
|
||||
|
||||
if isinstance(msg, playerspaz.PlayerSpazDeathMessage):
|
||||
if isinstance(msg, ba.PlayerDiedMessage):
|
||||
|
||||
# Augment standard behavior.
|
||||
super().handlemessage(msg)
|
||||
|
||||
player = msg.playerspaz(self).player
|
||||
player = msg.getplayer(Player)
|
||||
self.respawn_player(player)
|
||||
|
||||
killer = msg.killerplayer
|
||||
killer = msg.getkillerplayer(Player)
|
||||
if killer is None:
|
||||
return
|
||||
|
||||
@ -156,41 +156,37 @@ class DeathMatchGame(ba.TeamGameActivity[Player, Team]):
|
||||
|
||||
# In free-for-all, killing yourself loses you a point.
|
||||
if isinstance(self.session, ba.FreeForAllSession):
|
||||
new_score = player.team.gamedata['score'] - 1
|
||||
if not self.settings_raw['Allow Negative Scores']:
|
||||
new_score = player.team.score - 1
|
||||
if not self._allow_negative_scores:
|
||||
new_score = max(0, new_score)
|
||||
player.team.gamedata['score'] = new_score
|
||||
player.team.score = new_score
|
||||
|
||||
# In teams-mode it gives a point to the other team.
|
||||
else:
|
||||
ba.playsound(self._dingsound)
|
||||
for team in self.teams:
|
||||
if team is not killer.team:
|
||||
team.gamedata['score'] += 1
|
||||
team.score += 1
|
||||
|
||||
# Killing someone on another team nets a kill.
|
||||
else:
|
||||
killer.team.gamedata['score'] += 1
|
||||
killer.team.score += 1
|
||||
ba.playsound(self._dingsound)
|
||||
|
||||
# In FFA show scores since its hard to find on the scoreboard.
|
||||
try:
|
||||
if isinstance(killer.actor, stdspaz.Spaz):
|
||||
killer.actor.set_score_text(
|
||||
str(killer.team.gamedata['score']) + '/' +
|
||||
str(self._score_to_win),
|
||||
color=killer.team.color,
|
||||
flash=True)
|
||||
except Exception:
|
||||
pass
|
||||
if isinstance(killer.actor, PlayerSpaz) and killer.actor:
|
||||
killer.actor.set_score_text(str(killer.team.score) + '/' +
|
||||
str(self._score_to_win),
|
||||
color=killer.team.color,
|
||||
flash=True)
|
||||
|
||||
self._update_scoreboard()
|
||||
|
||||
# If someone has won, set a timer to end shortly.
|
||||
# (allows the dust to clear and draws to occur if deaths are
|
||||
# close enough)
|
||||
if any(team.gamedata['score'] >= self._score_to_win
|
||||
for team in self.teams):
|
||||
assert self._score_to_win is not None
|
||||
if any(team.score >= self._score_to_win for team in self.teams):
|
||||
ba.timer(0.5, self.end_game)
|
||||
|
||||
else:
|
||||
@ -198,11 +194,11 @@ class DeathMatchGame(ba.TeamGameActivity[Player, Team]):
|
||||
|
||||
def _update_scoreboard(self) -> None:
|
||||
for team in self.teams:
|
||||
self._scoreboard.set_team_value(team, team.gamedata['score'],
|
||||
self._scoreboard.set_team_value(team, team.score,
|
||||
self._score_to_win)
|
||||
|
||||
def end_game(self) -> None:
|
||||
results = ba.TeamGameResults()
|
||||
for team in self.teams:
|
||||
results.set_team_score(team, team.gamedata['score'])
|
||||
results.set_team_score(team, team.score)
|
||||
self.end(results=results)
|
||||
|
||||
@ -29,9 +29,9 @@ import random
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import ba
|
||||
from bastd.actor import bomb
|
||||
from bastd.actor import playerspaz
|
||||
from bastd.actor import spazbot
|
||||
from bastd.actor.bomb import Bomb
|
||||
from bastd.actor.playerspaz import PlayerSpaz
|
||||
from bastd.actor.spazbot import BotSet, BouncyBot, SpazBotDeathMessage
|
||||
from bastd.actor.onscreencountdown import OnScreenCountdown
|
||||
from bastd.actor.scoreboard import Scoreboard
|
||||
|
||||
@ -39,8 +39,16 @@ if TYPE_CHECKING:
|
||||
from typing import Any, Type, Dict, List, Tuple, Optional
|
||||
|
||||
|
||||
class Player(ba.Player['Team']):
|
||||
"""Our player type for this game."""
|
||||
|
||||
|
||||
class Team(ba.Team[Player]):
|
||||
"""Our team type for this game."""
|
||||
|
||||
|
||||
# ba_meta export game
|
||||
class EasterEggHuntGame(ba.TeamGameActivity[ba.Player, ba.Team]):
|
||||
class EasterEggHuntGame(ba.TeamGameActivity[Player, Team]):
|
||||
"""A game where score is based on collecting eggs."""
|
||||
|
||||
name = 'Easter Egg Hunt'
|
||||
@ -78,7 +86,7 @@ class EasterEggHuntGame(ba.TeamGameActivity[ba.Player, ba.Team]):
|
||||
self._eggs: List[Egg] = []
|
||||
self._update_timer: Optional[ba.Timer] = None
|
||||
self._countdown: Optional[OnScreenCountdown] = None
|
||||
self._bots: Optional[spazbot.BotSet] = None
|
||||
self._bots: Optional[BotSet] = None
|
||||
|
||||
# Called when our game is transitioning in but not ready to start.
|
||||
# ..we can go ahead and set our music and whatnot.
|
||||
@ -87,7 +95,7 @@ class EasterEggHuntGame(ba.TeamGameActivity[ba.Player, ba.Team]):
|
||||
self.default_music = ba.MusicType.FORWARD_MARCH
|
||||
super().on_transition_in()
|
||||
|
||||
def on_team_join(self, team: ba.Team) -> None:
|
||||
def on_team_join(self, team: Team) -> None:
|
||||
team.gamedata['score'] = 0
|
||||
if self.has_begun():
|
||||
self._update_scoreboard()
|
||||
@ -106,23 +114,21 @@ class EasterEggHuntGame(ba.TeamGameActivity[ba.Player, ba.Team]):
|
||||
self._update_timer = ba.Timer(0.25, self._update, repeat=True)
|
||||
self._countdown = OnScreenCountdown(60, endcall=self.end_game)
|
||||
ba.timer(4.0, self._countdown.start)
|
||||
self._bots = spazbot.BotSet()
|
||||
self._bots = BotSet()
|
||||
|
||||
# Spawn evil bunny in co-op only.
|
||||
if isinstance(self.session, ba.CoopSession) and self._pro_mode:
|
||||
self._spawn_evil_bunny()
|
||||
|
||||
# Overriding the default character spawning.
|
||||
def spawn_player(self, player: ba.Player) -> ba.Actor:
|
||||
def spawn_player(self, player: Player) -> ba.Actor:
|
||||
spaz = self.spawn_player_spaz(player)
|
||||
spaz.connect_controls_to_player()
|
||||
return spaz
|
||||
|
||||
def _spawn_evil_bunny(self) -> None:
|
||||
assert self._bots is not None
|
||||
self._bots.spawn_bot(spazbot.BouncyBot,
|
||||
pos=(6, 4, -7.8),
|
||||
spawn_time=10.0)
|
||||
self._bots.spawn_bot(BouncyBot, pos=(6, 4, -7.8), spawn_time=10.0)
|
||||
|
||||
def _on_egg_player_collide(self) -> None:
|
||||
if not self.has_ended():
|
||||
@ -132,7 +138,7 @@ class EasterEggHuntGame(ba.TeamGameActivity[ba.Player, ba.Team]):
|
||||
egg = egg_node.getdelegate()
|
||||
assert isinstance(egg, Egg)
|
||||
spaz = playernode.getdelegate()
|
||||
assert isinstance(spaz, playerspaz.PlayerSpaz)
|
||||
assert isinstance(spaz, PlayerSpaz)
|
||||
player = (spaz.getplayer()
|
||||
if hasattr(spaz, 'getplayer') else None)
|
||||
if player and egg:
|
||||
@ -184,8 +190,8 @@ class EasterEggHuntGame(ba.TeamGameActivity[ba.Player, ba.Team]):
|
||||
|
||||
# Occasionally spawn a land-mine in addition.
|
||||
if self._pro_mode and random.random() < 0.25:
|
||||
mine = bomb.Bomb(position=(xpos, ypos, zpos),
|
||||
bomb_type='land_mine').autoretain()
|
||||
mine = Bomb(position=(xpos, ypos, zpos),
|
||||
bomb_type='land_mine').autoretain()
|
||||
mine.arm()
|
||||
else:
|
||||
self._eggs.append(Egg(position=(xpos, ypos, zpos)))
|
||||
@ -194,12 +200,12 @@ class EasterEggHuntGame(ba.TeamGameActivity[ba.Player, ba.Team]):
|
||||
def handlemessage(self, msg: Any) -> Any:
|
||||
|
||||
# Respawn dead players.
|
||||
if isinstance(msg, playerspaz.PlayerSpazDeathMessage):
|
||||
if isinstance(msg, ba.PlayerDiedMessage):
|
||||
from bastd.actor import respawnicon
|
||||
|
||||
# Augment standard behavior.
|
||||
super().handlemessage(msg)
|
||||
player = msg.playerspaz(self).getplayer()
|
||||
player = msg.getplayer(Player)
|
||||
if not player:
|
||||
return
|
||||
self.stats.player_was_killed(player)
|
||||
@ -213,7 +219,7 @@ class EasterEggHuntGame(ba.TeamGameActivity[ba.Player, ba.Team]):
|
||||
player, respawn_time)
|
||||
|
||||
# Whenever our evil bunny dies, respawn him and spew some eggs.
|
||||
elif isinstance(msg, spazbot.SpazBotDeathMessage):
|
||||
elif isinstance(msg, SpazBotDeathMessage):
|
||||
self._spawn_evil_bunny()
|
||||
assert msg.badguy.node
|
||||
pos = msg.badguy.node.position
|
||||
|
||||
@ -28,8 +28,7 @@ from __future__ import annotations
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import ba
|
||||
from bastd.actor import playerspaz
|
||||
from bastd.actor import spaz
|
||||
from bastd.actor.spaz import get_factory
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import (Any, Tuple, Dict, Type, List, Sequence, Optional,
|
||||
@ -489,11 +488,11 @@ class EliminationGame(ba.TeamGameActivity[Player, Team]):
|
||||
return sum(player.lives for player in team.players)
|
||||
|
||||
def handlemessage(self, msg: Any) -> Any:
|
||||
if isinstance(msg, playerspaz.PlayerSpazDeathMessage):
|
||||
if isinstance(msg, ba.PlayerDiedMessage):
|
||||
|
||||
# Augment standard behavior.
|
||||
super().handlemessage(msg)
|
||||
player: Player = msg.playerspaz(self).player
|
||||
player: Player = msg.getplayer(Player)
|
||||
|
||||
player.lives -= 1
|
||||
if player.lives < 0:
|
||||
@ -509,7 +508,7 @@ class EliminationGame(ba.TeamGameActivity[Player, Team]):
|
||||
# Play big death sound on our last death
|
||||
# or for every one in solo mode.
|
||||
if self._solo_mode or player.lives == 0:
|
||||
ba.playsound(spaz.get_factory().single_player_death_sound)
|
||||
ba.playsound(get_factory().single_player_death_sound)
|
||||
|
||||
# If we hit zero lives, we're dead (and our team might be too).
|
||||
if player.lives == 0:
|
||||
|
||||
@ -33,8 +33,9 @@ import ba
|
||||
from bastd.actor import spazbot
|
||||
from bastd.actor import flag as stdflag
|
||||
from bastd.actor.bomb import TNTSpawner
|
||||
from bastd.actor.playerspaz import PlayerSpaz, PlayerSpazDeathMessage
|
||||
from bastd.actor.playerspaz import PlayerSpaz
|
||||
from bastd.actor.scoreboard import Scoreboard
|
||||
from bastd.actor.respawnicon import RespawnIcon
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any, List, Type, Dict, Sequence, Optional, Union
|
||||
@ -268,10 +269,10 @@ class FootballTeamGame(ba.TeamGameActivity[Player, Team]):
|
||||
msg.flag.held_count -= 1
|
||||
|
||||
# Respawn dead players if they're still in the game.
|
||||
elif isinstance(msg, PlayerSpazDeathMessage):
|
||||
elif isinstance(msg, ba.PlayerDiedMessage):
|
||||
# Augment standard behavior.
|
||||
super().handlemessage(msg)
|
||||
self.respawn_player(msg.playerspaz(self).player)
|
||||
self.respawn_player(msg.getplayer(Player))
|
||||
|
||||
# Respawn dead flags.
|
||||
elif isinstance(msg, stdflag.FlagDeathMessage):
|
||||
@ -798,11 +799,10 @@ class FootballCoopGame(ba.CoopGameActivity[Player, Team]):
|
||||
|
||||
def handlemessage(self, msg: Any) -> Any:
|
||||
""" handle high-level game messages """
|
||||
if isinstance(msg, PlayerSpazDeathMessage):
|
||||
from bastd.actor import respawnicon
|
||||
if isinstance(msg, ba.PlayerDiedMessage):
|
||||
|
||||
# Respawn dead players.
|
||||
player = msg.playerspaz(self).player
|
||||
player = msg.getplayer(Player)
|
||||
self.stats.player_was_killed(player)
|
||||
assert self.initial_player_info is not None
|
||||
respawn_time = 2.0 + len(self.initial_player_info) * 1.0
|
||||
@ -810,8 +810,7 @@ class FootballCoopGame(ba.CoopGameActivity[Player, Team]):
|
||||
# Respawn them shortly.
|
||||
player.gamedata['respawn_timer'] = ba.Timer(
|
||||
respawn_time, ba.Call(self.spawn_player_if_exists, player))
|
||||
player.gamedata['respawn_icon'] = respawnicon.RespawnIcon(
|
||||
player, respawn_time)
|
||||
player.gamedata['respawn_icon'] = RespawnIcon(player, respawn_time)
|
||||
|
||||
# Augment standard behavior.
|
||||
super().handlemessage(msg)
|
||||
|
||||
@ -28,7 +28,6 @@ from __future__ import annotations
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import ba
|
||||
from bastd.actor import playerspaz
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any, Sequence, Dict, Type, List, Optional, Union
|
||||
@ -50,7 +49,7 @@ class Puck(ba.Actor):
|
||||
|
||||
# Spawn just above the provided point.
|
||||
self._spawn_pos = (position[0], position[1] + 1.0, position[2])
|
||||
self.last_players_to_touch: Dict[int, ba.Player] = {}
|
||||
self.last_players_to_touch: Dict[int, Player] = {}
|
||||
self.scored = False
|
||||
assert activity is not None
|
||||
assert isinstance(activity, HockeyGame)
|
||||
@ -94,18 +93,26 @@ class Puck(ba.Actor):
|
||||
msg.force_direction[2])
|
||||
|
||||
# If this hit came from a player, log them as the last to touch us.
|
||||
if msg.source_player is not None:
|
||||
splayer = msg.get_source_player(Player)
|
||||
if splayer is not None:
|
||||
activity = self._activity()
|
||||
if activity:
|
||||
if msg.source_player in activity.players:
|
||||
self.last_players_to_touch[
|
||||
msg.source_player.team.id] = msg.source_player
|
||||
if splayer in activity.players:
|
||||
self.last_players_to_touch[splayer.team.id] = splayer
|
||||
else:
|
||||
super().handlemessage(msg)
|
||||
|
||||
|
||||
class Player(ba.Player['Team']):
|
||||
"""Our player type for this game."""
|
||||
|
||||
|
||||
class Team(ba.Team[Player]):
|
||||
"""Our team type for this game."""
|
||||
|
||||
|
||||
# ba_meta export game
|
||||
class HockeyGame(ba.TeamGameActivity[ba.Player, ba.Team]):
|
||||
class HockeyGame(ba.TeamGameActivity[Player, Team]):
|
||||
"""Ice hockey game."""
|
||||
|
||||
name = 'Hockey'
|
||||
@ -234,7 +241,7 @@ class HockeyGame(ba.TeamGameActivity[ba.Player, ba.Team]):
|
||||
self._update_scoreboard()
|
||||
ba.playsound(self._chant_sound)
|
||||
|
||||
def on_team_join(self, team: ba.Team) -> None:
|
||||
def on_team_join(self, team: Team) -> None:
|
||||
team.gamedata['score'] = 0
|
||||
self._update_scoreboard()
|
||||
|
||||
@ -246,7 +253,7 @@ class HockeyGame(ba.TeamGameActivity[ba.Player, ba.Team]):
|
||||
player = playernode.getdelegate().getplayer()
|
||||
except Exception:
|
||||
player = puck = None
|
||||
assert isinstance(player, ba.Player)
|
||||
assert isinstance(player, Player)
|
||||
assert isinstance(puck, Puck)
|
||||
if player and puck:
|
||||
puck.last_players_to_touch[player.team.id] = player
|
||||
@ -330,10 +337,10 @@ class HockeyGame(ba.TeamGameActivity[ba.Player, ba.Team]):
|
||||
def handlemessage(self, msg: Any) -> Any:
|
||||
|
||||
# Respawn dead players if they're still in the game.
|
||||
if isinstance(msg, playerspaz.PlayerSpazDeathMessage):
|
||||
if isinstance(msg, ba.PlayerDiedMessage):
|
||||
# Augment standard behavior...
|
||||
super().handlemessage(msg)
|
||||
self.respawn_player(msg.playerspaz(self).player)
|
||||
self.respawn_player(msg.getplayer(Player))
|
||||
|
||||
# Respawn dead pucks.
|
||||
elif isinstance(msg, PuckDeathMessage):
|
||||
|
||||
@ -29,9 +29,9 @@ from enum import Enum
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import ba
|
||||
from bastd.actor.playerspaz import PlayerSpaz
|
||||
from bastd.actor.flag import (Flag, FlagDroppedMessage, FlagDeathMessage,
|
||||
FlagPickedUpMessage)
|
||||
from bastd.actor.playerspaz import PlayerSpaz, PlayerSpazDeathMessage
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any, Type, List, Dict, Optional, Sequence, Union
|
||||
@ -266,10 +266,10 @@ class KeepAwayGame(ba.TeamGameActivity[Player, Team]):
|
||||
countdown=True)
|
||||
|
||||
def handlemessage(self, msg: Any) -> Any:
|
||||
if isinstance(msg, PlayerSpazDeathMessage):
|
||||
if isinstance(msg, ba.PlayerDiedMessage):
|
||||
# Augment standard behavior.
|
||||
super().handlemessage(msg)
|
||||
self.respawn_player(msg.playerspaz(self).player)
|
||||
self.respawn_player(msg.getplayer(Player))
|
||||
elif isinstance(msg, FlagDeathMessage):
|
||||
self._spawn_flag()
|
||||
elif isinstance(msg, (FlagDroppedMessage, FlagPickedUpMessage)):
|
||||
|
||||
@ -31,7 +31,7 @@ from typing import TYPE_CHECKING
|
||||
|
||||
import ba
|
||||
from bastd.actor.flag import Flag
|
||||
from bastd.actor.playerspaz import PlayerSpaz, PlayerSpazDeathMessage
|
||||
from bastd.actor.playerspaz import PlayerSpaz
|
||||
from bastd.actor.scoreboard import Scoreboard
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@ -272,11 +272,11 @@ class KingOfTheHillGame(ba.TeamGameActivity[Player, Team]):
|
||||
countdown=True)
|
||||
|
||||
def handlemessage(self, msg: Any) -> Any:
|
||||
if isinstance(msg, PlayerSpazDeathMessage):
|
||||
if isinstance(msg, ba.PlayerDiedMessage):
|
||||
super().handlemessage(msg) # Augment default.
|
||||
|
||||
# No longer can count as time_at_flag once dead.
|
||||
player = msg.playerspaz(self).player
|
||||
player = msg.getplayer(Player)
|
||||
player.time_at_flag = 0
|
||||
self._update_flag_state()
|
||||
self.respawn_player(player)
|
||||
|
||||
@ -30,7 +30,6 @@ from typing import TYPE_CHECKING
|
||||
|
||||
import ba
|
||||
from bastd.actor.bomb import Bomb
|
||||
from bastd.actor.playerspaz import PlayerSpazDeathMessage
|
||||
from bastd.actor.onscreentimer import OnScreenTimer
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@ -151,7 +150,7 @@ class MeteorShowerGame(ba.TeamGameActivity[Player, Team]):
|
||||
|
||||
# Various high-level game events come through this method.
|
||||
def handlemessage(self, msg: Any) -> Any:
|
||||
if isinstance(msg, PlayerSpazDeathMessage):
|
||||
if isinstance(msg, ba.PlayerDiedMessage):
|
||||
|
||||
# Augment standard behavior.
|
||||
super().handlemessage(msg)
|
||||
@ -160,7 +159,7 @@ class MeteorShowerGame(ba.TeamGameActivity[Player, Team]):
|
||||
|
||||
# Record the player's moment of death.
|
||||
# assert isinstance(msg.spaz.player
|
||||
msg.playerspaz(self).player.death_time = curtime
|
||||
msg.getplayer(Player).death_time = curtime
|
||||
|
||||
# In co-op mode, end the game the instant everyone dies
|
||||
# (more accurate looking).
|
||||
|
||||
@ -29,9 +29,8 @@ import random
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import ba
|
||||
from bastd.actor import onscreentimer
|
||||
from bastd.actor import playerspaz
|
||||
from bastd.actor import spazbot
|
||||
from bastd.actor.onscreentimer import OnScreenTimer
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any, Type, Dict, List, Optional
|
||||
@ -76,7 +75,7 @@ class NinjaFightGame(ba.TeamGameActivity[Player, Team]):
|
||||
super().__init__(settings)
|
||||
self._winsound = ba.getsound('score')
|
||||
self._won = False
|
||||
self._timer: Optional[onscreentimer.OnScreenTimer] = None
|
||||
self._timer: Optional[OnScreenTimer] = None
|
||||
self._bots = spazbot.BotSet()
|
||||
|
||||
# Called when our game is transitioning in but not ready to begin;
|
||||
@ -95,7 +94,7 @@ class NinjaFightGame(ba.TeamGameActivity[Player, Team]):
|
||||
self.setup_standard_powerup_drops()
|
||||
|
||||
# Make our on-screen timer and start it roughly when our bots appear.
|
||||
self._timer = onscreentimer.OnScreenTimer()
|
||||
self._timer = OnScreenTimer()
|
||||
ba.timer(4.0, self._timer.start)
|
||||
|
||||
# Spawn some baddies.
|
||||
@ -146,10 +145,9 @@ class NinjaFightGame(ba.TeamGameActivity[Player, Team]):
|
||||
def handlemessage(self, msg: Any) -> Any:
|
||||
|
||||
# A player has died.
|
||||
if isinstance(msg, playerspaz.PlayerSpazDeathMessage):
|
||||
super().handlemessage(msg) # do standard stuff
|
||||
self.respawn_player(
|
||||
msg.playerspaz(self).player) # kick off a respawn
|
||||
if isinstance(msg, ba.PlayerDiedMessage):
|
||||
super().handlemessage(msg) # Augment standard behavior.
|
||||
self.respawn_player(msg.getplayer(Player))
|
||||
|
||||
# A spaz-bot has died.
|
||||
elif isinstance(msg, spazbot.SpazBotDeathMessage):
|
||||
|
||||
@ -1164,10 +1164,9 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]):
|
||||
self._score += msg.score
|
||||
self._update_scores()
|
||||
|
||||
elif isinstance(msg, playerspaz.PlayerSpazDeathMessage):
|
||||
elif isinstance(msg, ba.PlayerDiedMessage):
|
||||
super().handlemessage(msg) # Augment standard behavior.
|
||||
player = msg.playerspaz(self).getplayer()
|
||||
assert player is not None
|
||||
player = msg.getplayer(Player)
|
||||
self._a_player_has_been_hurt = True
|
||||
|
||||
# Make note with the player when they can respawn:
|
||||
|
||||
@ -31,7 +31,7 @@ from dataclasses import dataclass
|
||||
|
||||
import ba
|
||||
from bastd.actor.bomb import Bomb
|
||||
from bastd.actor.playerspaz import PlayerSpaz, PlayerSpazDeathMessage
|
||||
from bastd.actor.playerspaz import PlayerSpaz
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import (Any, Type, Tuple, List, Sequence, Optional, Dict,
|
||||
@ -734,12 +734,12 @@ class RaceGame(ba.TeamGameActivity[Player, Team]):
|
||||
ba.DualTeamSession))
|
||||
|
||||
def handlemessage(self, msg: Any) -> Any:
|
||||
if isinstance(msg, PlayerSpazDeathMessage):
|
||||
if isinstance(msg, ba.PlayerDiedMessage):
|
||||
# Augment default behavior.
|
||||
super().handlemessage(msg)
|
||||
player = msg.playerspaz(self).getplayer()
|
||||
player = msg.getplayer(Player)
|
||||
if not player:
|
||||
ba.print_error('got no player in PlayerSpazDeathMessage')
|
||||
ba.print_error('got no player in PlayerDiedMessage')
|
||||
return
|
||||
if not player.gamedata['finished']:
|
||||
self.respawn_player(player, respawn_time=1)
|
||||
|
||||
@ -29,16 +29,24 @@ import random
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import ba
|
||||
from bastd.actor import playerspaz
|
||||
from bastd.actor import spazbot
|
||||
from bastd.actor.bomb import TNTSpawner
|
||||
from bastd.actor.scoreboard import Scoreboard
|
||||
from bastd.actor.respawnicon import RespawnIcon
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Type, Any, List, Dict, Tuple, Sequence, Optional
|
||||
|
||||
|
||||
class RunaroundGame(ba.CoopGameActivity[ba.Player, ba.Team]):
|
||||
class Player(ba.Player['Team']):
|
||||
"""Our player type for this game."""
|
||||
|
||||
|
||||
class Team(ba.Team[Player]):
|
||||
"""Our team type for this game."""
|
||||
|
||||
|
||||
class RunaroundGame(ba.CoopGameActivity[Player, Team]):
|
||||
"""Game involving trying to bomb bots as they walk through the map."""
|
||||
|
||||
name = 'Runaround'
|
||||
@ -457,7 +465,7 @@ class RunaroundGame(ba.CoopGameActivity[ba.Player, ba.Team]):
|
||||
self._lives_text.node.text = str(self._lives)
|
||||
self._bots.start_moving()
|
||||
|
||||
def spawn_player(self, player: ba.Player) -> ba.Actor:
|
||||
def spawn_player(self, player: Player) -> ba.Actor:
|
||||
pos = (self._spawn_center[0] + random.uniform(-1.5, 1.5),
|
||||
self._spawn_center[1],
|
||||
self._spawn_center[2] + random.uniform(-1.5, 1.5))
|
||||
@ -1118,16 +1126,9 @@ class RunaroundGame(ba.CoopGameActivity[ba.Player, ba.Team]):
|
||||
self._update_scores()
|
||||
|
||||
# Respawn dead players.
|
||||
elif isinstance(msg, playerspaz.PlayerSpazDeathMessage):
|
||||
from bastd.actor import respawnicon
|
||||
elif isinstance(msg, ba.PlayerDiedMessage):
|
||||
self._a_player_has_been_killed = True
|
||||
player = msg.playerspaz(self).getplayer()
|
||||
if player is None:
|
||||
ba.print_error('FIXME: getplayer() should no'
|
||||
' longer ever be returning None')
|
||||
return
|
||||
if not player:
|
||||
return
|
||||
player = msg.getplayer(Player)
|
||||
self.stats.player_was_killed(player)
|
||||
|
||||
# Respawn them shortly.
|
||||
@ -1135,8 +1136,7 @@ class RunaroundGame(ba.CoopGameActivity[ba.Player, ba.Team]):
|
||||
respawn_time = 2.0 + len(self.initial_player_info) * 1.0
|
||||
player.gamedata['respawn_timer'] = ba.Timer(
|
||||
respawn_time, ba.Call(self.spawn_player_if_exists, player))
|
||||
player.gamedata['respawn_icon'] = respawnicon.RespawnIcon(
|
||||
player, respawn_time)
|
||||
player.gamedata['respawn_icon'] = RespawnIcon(player, respawn_time)
|
||||
|
||||
elif isinstance(msg, spazbot.SpazBotDeathMessage):
|
||||
if msg.how is ba.DeathType.REACHED_GOAL:
|
||||
|
||||
@ -29,7 +29,6 @@ import random
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import ba
|
||||
from bastd.actor.playerspaz import PlayerSpazDeathMessage
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any, Type, List, Dict, Optional, Sequence
|
||||
@ -193,9 +192,9 @@ class TargetPracticeGame(ba.TeamGameActivity[Player, Team]):
|
||||
|
||||
def handlemessage(self, msg: Any) -> Any:
|
||||
# When players die, respawn them.
|
||||
if isinstance(msg, PlayerSpazDeathMessage):
|
||||
if isinstance(msg, ba.PlayerDiedMessage):
|
||||
super().handlemessage(msg) # Do standard stuff.
|
||||
player = msg.playerspaz(self).getplayer()
|
||||
player = msg.getplayer(Player)
|
||||
assert player is not None
|
||||
self.respawn_player(player) # Kick off a respawn.
|
||||
elif isinstance(msg, Target.TargetHitMessage):
|
||||
|
||||
@ -257,14 +257,8 @@ class TheLastStandGame(ba.CoopGameActivity[Player, Team]):
|
||||
self._scoreboard.set_team_value(self.teams[0], score, max_score=None)
|
||||
|
||||
def handlemessage(self, msg: Any) -> Any:
|
||||
if isinstance(msg, playerspaz.PlayerSpazDeathMessage):
|
||||
player = msg.playerspaz(self).getplayer()
|
||||
if player is None:
|
||||
ba.print_error('FIXME: getplayer() should no longer '
|
||||
'ever be returning None.')
|
||||
return
|
||||
if not player:
|
||||
return
|
||||
if isinstance(msg, ba.PlayerDiedMessage):
|
||||
player = msg.getplayer(Player)
|
||||
self.stats.player_was_killed(player)
|
||||
ba.timer(0.1, self._checkroundover)
|
||||
|
||||
|
||||
@ -836,7 +836,7 @@ class AwaitGamepadInputWindow(ba.Window):
|
||||
assert isinstance(input_device, ba.InputDevice)
|
||||
|
||||
# Update - we now allow *any* input device of this type.
|
||||
if input_device.exists and input_device.name == self._input.name:
|
||||
if input_device.exists() and input_device.name == self._input.name:
|
||||
self._callback(self._capture_button, event, self)
|
||||
|
||||
def _decrement(self) -> None:
|
||||
|
||||
@ -50,6 +50,7 @@
|
||||
<li><a href="#function_ba_cameraflash">ba.cameraflash()</a></li>
|
||||
<li><a href="#function_ba_camerashake">ba.camerashake()</a></li>
|
||||
<li><a href="#function_ba_emitfx">ba.emitfx()</a></li>
|
||||
<li><a href="#function_ba_existing">ba.existing()</a></li>
|
||||
<li><a href="#function_ba_get_collision_info">ba.get_collision_info()</a></li>
|
||||
<li><a href="#function_ba_getactivity">ba.getactivity()</a></li>
|
||||
<li><a href="#function_ba_getnodes">ba.getnodes()</a></li>
|
||||
@ -127,6 +128,7 @@
|
||||
<li><a href="#class_ba_OutOfBoundsMessage">ba.OutOfBoundsMessage</a></li>
|
||||
<li><a href="#class_ba_PickedUpMessage">ba.PickedUpMessage</a></li>
|
||||
<li><a href="#class_ba_PickUpMessage">ba.PickUpMessage</a></li>
|
||||
<li><a href="#class_ba_PlayerDiedMessage">ba.PlayerDiedMessage</a></li>
|
||||
<li><a href="#class_ba_PlayerScoredMessage">ba.PlayerScoredMessage</a></li>
|
||||
<li><a href="#class_ba_PowerupAcceptMessage">ba.PowerupAcceptMessage</a></li>
|
||||
<li><a href="#class_ba_PowerupMessage">ba.PowerupMessage</a></li>
|
||||
@ -2453,12 +2455,22 @@ and short description of the game.</p>
|
||||
</p>
|
||||
|
||||
<h3>Methods:</h3>
|
||||
<h5><a href="#method_ba_HitMessage____init__"><constructor></a>, <a href="#method_ba_HitMessage__get_source_player">get_source_player()</a></h5>
|
||||
<dl>
|
||||
<dt><h4><a name="method_ba_HitMessage____init__"><constructor></a></dt></h4><dd>
|
||||
<p><span>ba.HitMessage(srcnode: '<a href="#class_ba_Node">ba.Node</a>' = None, pos: 'Sequence[float]' = None, velocity: 'Sequence[float]' = None, magnitude: 'float' = 1.0, velocity_magnitude: 'float' = 0.0, radius: 'float' = 1.0, source_player: '<a href="#class_ba_Player">ba.Player</a>' = None, kick_back: 'float' = 1.0, flat_damage: 'float' = None, hit_type: 'str' = 'generic', force_direction: 'Sequence[float]' = None, hit_subtype: 'str' = 'default')</span></p>
|
||||
|
||||
<p>Instantiate a message with given values.</p>
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="method_ba_HitMessage__get_source_player">get_source_player()</a></dt></h4><dd>
|
||||
<p><span>get_source_player(self, playertype: Type[PlayerType]) -> Optional[PlayerType]</span></p>
|
||||
|
||||
<p>Return the spaz that died.</p>
|
||||
|
||||
<p>The current activity is required as an argument so the exact type of
|
||||
PlayerSpaz can be determined by the type checker.</p>
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
<hr>
|
||||
@ -2493,7 +2505,7 @@ and short description of the game.</p>
|
||||
<p>Category: <a href="#class_category_Gameplay_Classes">Gameplay Classes</a></p>
|
||||
|
||||
<h3>Attributes:</h3>
|
||||
<h5><a href="#attr_ba_InputDevice__allows_configuring">allows_configuring</a>, <a href="#attr_ba_InputDevice__client_id">client_id</a>, <a href="#attr_ba_InputDevice__exists">exists</a>, <a href="#attr_ba_InputDevice__id">id</a>, <a href="#attr_ba_InputDevice__instance_number">instance_number</a>, <a href="#attr_ba_InputDevice__is_controller_app">is_controller_app</a>, <a href="#attr_ba_InputDevice__is_remote_client">is_remote_client</a>, <a href="#attr_ba_InputDevice__name">name</a>, <a href="#attr_ba_InputDevice__player">player</a>, <a href="#attr_ba_InputDevice__unique_identifier">unique_identifier</a></h5>
|
||||
<h5><a href="#attr_ba_InputDevice__allows_configuring">allows_configuring</a>, <a href="#attr_ba_InputDevice__client_id">client_id</a>, <a href="#attr_ba_InputDevice__id">id</a>, <a href="#attr_ba_InputDevice__instance_number">instance_number</a>, <a href="#attr_ba_InputDevice__is_controller_app">is_controller_app</a>, <a href="#attr_ba_InputDevice__is_remote_client">is_remote_client</a>, <a href="#attr_ba_InputDevice__name">name</a>, <a href="#attr_ba_InputDevice__player">player</a>, <a href="#attr_ba_InputDevice__unique_identifier">unique_identifier</a></h5>
|
||||
<dl>
|
||||
<dt><h4><a name="attr_ba_InputDevice__allows_configuring">allows_configuring</a></h4></dt><dd>
|
||||
<p><span> bool</span></p>
|
||||
@ -2506,11 +2518,6 @@ and short description of the game.</p>
|
||||
This is only meaningful for remote client inputs; for
|
||||
all local devices this will be -1.</p>
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="attr_ba_InputDevice__exists">exists</a></h4></dt><dd>
|
||||
<p><span> bool</span></p>
|
||||
<p>Whether the underlying device for this object is still present.</p>
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="attr_ba_InputDevice__id">id</a></h4></dt><dd>
|
||||
<p><span> int</span></p>
|
||||
@ -2553,8 +2560,14 @@ prefs, etc.</p>
|
||||
</dd>
|
||||
</dl>
|
||||
<h3>Methods:</h3>
|
||||
<h5><a href="#method_ba_InputDevice__get_account_name">get_account_name()</a>, <a href="#method_ba_InputDevice__get_axis_name">get_axis_name()</a>, <a href="#method_ba_InputDevice__get_button_name">get_button_name()</a></h5>
|
||||
<h5><a href="#method_ba_InputDevice__exists">exists()</a>, <a href="#method_ba_InputDevice__get_account_name">get_account_name()</a>, <a href="#method_ba_InputDevice__get_axis_name">get_axis_name()</a>, <a href="#method_ba_InputDevice__get_button_name">get_button_name()</a></h5>
|
||||
<dl>
|
||||
<dt><h4><a name="method_ba_InputDevice__exists">exists()</a></dt></h4><dd>
|
||||
<p><span>exists() -> bool</span></p>
|
||||
|
||||
<p>Return whether the underlying device for this object is still present.</p>
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="method_ba_InputDevice__get_account_name">get_account_name()</a></dt></h4><dd>
|
||||
<p><span>get_account_name(full: bool) -> str</span></p>
|
||||
|
||||
@ -3717,18 +3730,8 @@ even if myactor is set to None.</p>
|
||||
</p>
|
||||
|
||||
<h3>Attributes:</h3>
|
||||
<h5><a href="#attr_ba_Player__exists">exists</a>, <a href="#attr_ba_Player__node">node</a>, <a href="#attr_ba_Player__sessionplayer">sessionplayer</a></h5>
|
||||
<h5><a href="#attr_ba_Player__node">node</a>, <a href="#attr_ba_Player__sessionplayer">sessionplayer</a></h5>
|
||||
<dl>
|
||||
<dt><h4><a name="attr_ba_Player__exists">exists</a></h4></dt><dd>
|
||||
<p><span>bool</span></p>
|
||||
<p>Whether the underlying player still exists.</p>
|
||||
|
||||
<p> Most functionality will fail on a nonexistent player.
|
||||
Note that you can also use the boolean operator for this same
|
||||
functionality, so a statement such as "if player" will do
|
||||
the right thing both for Player objects and values of None.</p>
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="attr_ba_Player__node">node</a></h4></dt><dd>
|
||||
<p><span><a href="#class_ba_Node">ba.Node</a></span></p>
|
||||
<p>A <a href="#class_ba_Node">ba.Node</a> of type 'player' associated with this Player.</p>
|
||||
@ -3745,7 +3748,7 @@ even if myactor is set to None.</p>
|
||||
</dd>
|
||||
</dl>
|
||||
<h3>Methods:</h3>
|
||||
<h5><a href="#method_ba_Player__assign_input_call">assign_input_call()</a>, <a href="#method_ba_Player__get_icon">get_icon()</a>, <a href="#method_ba_Player__get_name">get_name()</a>, <a href="#method_ba_Player__is_alive">is_alive()</a>, <a href="#method_ba_Player__reset_input">reset_input()</a>, <a href="#method_ba_Player__set_actor">set_actor()</a></h5>
|
||||
<h5><a href="#method_ba_Player__assign_input_call">assign_input_call()</a>, <a href="#method_ba_Player__exists">exists()</a>, <a href="#method_ba_Player__get_icon">get_icon()</a>, <a href="#method_ba_Player__get_name">get_name()</a>, <a href="#method_ba_Player__is_alive">is_alive()</a>, <a href="#method_ba_Player__reset_input">reset_input()</a>, <a href="#method_ba_Player__set_actor">set_actor()</a></h5>
|
||||
<dl>
|
||||
<dt><h4><a name="method_ba_Player__assign_input_call">assign_input_call()</a></dt></h4><dd>
|
||||
<p><span>assign_input_call(self, inputtype: Union[str, Tuple[str, ...]], call: Callable) -> None</span></p>
|
||||
@ -3761,6 +3764,17 @@ Valid type values are: 'jumpPress', 'jumpRelease', 'punchPress',
|
||||
'rightRelease', 'run', 'flyPress', 'flyRelease', 'startPress',
|
||||
'startRelease'</p>
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="method_ba_Player__exists">exists()</a></dt></h4><dd>
|
||||
<p><span>exists(self) -> bool</span></p>
|
||||
|
||||
<p>Whether the underlying player still exists.</p>
|
||||
|
||||
<p>Most functionality will fail on a nonexistent player.
|
||||
Note that you can also use the boolean operator for this same
|
||||
functionality, so a statement such as "if player" will do
|
||||
the right thing both for Player objects and values of None.</p>
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="method_ba_Player__get_icon">get_icon()</a></dt></h4><dd>
|
||||
<p><span>get_icon(self) -> Dict[str, Any]</span></p>
|
||||
@ -3803,6 +3817,56 @@ is_alive() method return True. False is returned otherwise.</p>
|
||||
|
||||
<p>Set the player's associated <a href="#class_ba_Actor">ba.Actor</a>.</p>
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
<hr>
|
||||
<h2><strong><a name="class_ba_PlayerDiedMessage">ba.PlayerDiedMessage</a></strong></h3>
|
||||
<p><em><top level class></em>
|
||||
</p>
|
||||
<p>A message saying a ba.PlayerSpaz has died.</p>
|
||||
|
||||
<p>Category: <a href="#class_category_Message_Classes">Message Classes</a></p>
|
||||
|
||||
<h3>Attributes:</h3>
|
||||
<h5><a href="#attr_ba_PlayerDiedMessage__how">how</a>, <a href="#attr_ba_PlayerDiedMessage__killed">killed</a></h5>
|
||||
<dl>
|
||||
<dt><h4><a name="attr_ba_PlayerDiedMessage__how">how</a></h4></dt><dd>
|
||||
<p><span><a href="#class_ba_DeathType">ba.DeathType</a></span></p>
|
||||
<p>The particular type of death.</p>
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="attr_ba_PlayerDiedMessage__killed">killed</a></h4></dt><dd>
|
||||
<p><span>bool</span></p>
|
||||
<p>If True, the spaz was killed;
|
||||
If False, they left the game or the round ended.</p>
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
<h3>Methods:</h3>
|
||||
<h5><a href="#method_ba_PlayerDiedMessage____init__"><constructor></a>, <a href="#method_ba_PlayerDiedMessage__getkillerplayer">getkillerplayer()</a>, <a href="#method_ba_PlayerDiedMessage__getplayer">getplayer()</a></h5>
|
||||
<dl>
|
||||
<dt><h4><a name="method_ba_PlayerDiedMessage____init__"><constructor></a></dt></h4><dd>
|
||||
<p><span>ba.PlayerDiedMessage(player: <a href="#class_ba_Player">ba.Player</a>, was_killed: bool, killerplayer: Optional[<a href="#class_ba_Player">ba.Player</a>], how: <a href="#class_ba_DeathType">ba.DeathType</a>)</span></p>
|
||||
|
||||
<p>Instantiate a message with the given values.</p>
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="method_ba_PlayerDiedMessage__getkillerplayer">getkillerplayer()</a></dt></h4><dd>
|
||||
<p><span>getkillerplayer(self, playertype: Type[PlayerType]) -> Optional[PlayerType]</span></p>
|
||||
|
||||
<p>Return the <a href="#class_ba_Player">ba.Player</a> responsible for the killing, if any.</p>
|
||||
|
||||
<p>Pass the Player type being used by the current game.</p>
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="method_ba_PlayerDiedMessage__getplayer">getplayer()</a></dt></h4><dd>
|
||||
<p><span>getplayer(self, playertype: Type[PlayerType]) -> PlayerType</span></p>
|
||||
|
||||
<p>Return the spaz that died.</p>
|
||||
|
||||
<p>The current activity is required as an argument so the exact type of
|
||||
PlayerSpaz can be determined by the type checker.</p>
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
<hr>
|
||||
@ -4297,12 +4361,12 @@ provided to your Session/Activity instances.
|
||||
Be aware that, like <a href="#class_ba_Node">ba.Nodes</a>, <a href="#class_ba_SessionPlayer">ba.SessionPlayer</a> objects are 'weak'
|
||||
references under-the-hood; a player can leave the game at
|
||||
any point. For this reason, you should make judicious use of the
|
||||
<a href="#attr_ba_SessionPlayer__exists">ba.SessionPlayer.exists</a> attribute (or boolean operator) to ensure
|
||||
<a href="#method_ba_SessionPlayer__exists">ba.SessionPlayer.exists</a>() method (or boolean operator) to ensure
|
||||
that a SessionPlayer is still present if retaining references to one
|
||||
for any length of time.</p>
|
||||
|
||||
<h3>Attributes:</h3>
|
||||
<h5><a href="#attr_ba_SessionPlayer__character">character</a>, <a href="#attr_ba_SessionPlayer__color">color</a>, <a href="#attr_ba_SessionPlayer__exists">exists</a>, <a href="#attr_ba_SessionPlayer__gamedata">gamedata</a>, <a href="#attr_ba_SessionPlayer__gameplayer">gameplayer</a>, <a href="#attr_ba_SessionPlayer__highlight">highlight</a>, <a href="#attr_ba_SessionPlayer__id">id</a>, <a href="#attr_ba_SessionPlayer__in_game">in_game</a>, <a href="#attr_ba_SessionPlayer__sessiondata">sessiondata</a>, <a href="#attr_ba_SessionPlayer__team">team</a></h5>
|
||||
<h5><a href="#attr_ba_SessionPlayer__character">character</a>, <a href="#attr_ba_SessionPlayer__color">color</a>, <a href="#attr_ba_SessionPlayer__gamedata">gamedata</a>, <a href="#attr_ba_SessionPlayer__gameplayer">gameplayer</a>, <a href="#attr_ba_SessionPlayer__highlight">highlight</a>, <a href="#attr_ba_SessionPlayer__id">id</a>, <a href="#attr_ba_SessionPlayer__in_game">in_game</a>, <a href="#attr_ba_SessionPlayer__sessiondata">sessiondata</a>, <a href="#attr_ba_SessionPlayer__team">team</a></h5>
|
||||
<dl>
|
||||
<dt><h4><a name="attr_ba_SessionPlayer__character">character</a></h4></dt><dd>
|
||||
<p><span> str</span></p>
|
||||
@ -4314,16 +4378,6 @@ for any length of time.</p>
|
||||
<p>The base color for this Player.
|
||||
In team games this will match the <a href="#class_ba_SessionTeam">ba.SessionTeam</a>'s color.</p>
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="attr_ba_SessionPlayer__exists">exists</a></h4></dt><dd>
|
||||
<p><span> bool</span></p>
|
||||
<p>Whether the player still exists.
|
||||
Most functionality will fail on a nonexistent player.</p>
|
||||
|
||||
<p>Note that you can also use the boolean operator for this same
|
||||
functionality, so a statement such as "if player" will do
|
||||
the right thing both for Player objects and values of None.</p>
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="attr_ba_SessionPlayer__gamedata">gamedata</a></h4></dt><dd>
|
||||
<p><span> Dict</span></p>
|
||||
@ -4349,6 +4403,10 @@ who may all share the same team (primary) color.</p>
|
||||
<p><span> int</span></p>
|
||||
<p>The unique numeric ID of the Player.</p>
|
||||
|
||||
<p>Note that you can also use the boolean operator for this same
|
||||
functionality, so a statement such as "if player" will do
|
||||
the right thing both for Player objects and values of None.</p>
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="attr_ba_SessionPlayer__in_game">in_game</a></h4></dt><dd>
|
||||
<p><span> bool</span></p>
|
||||
@ -4372,7 +4430,7 @@ is still in its lobby selecting a team/etc. then a
|
||||
</dd>
|
||||
</dl>
|
||||
<h3>Methods:</h3>
|
||||
<h5><a href="#method_ba_SessionPlayer__assign_input_call">assign_input_call()</a>, <a href="#method_ba_SessionPlayer__get_account_id">get_account_id()</a>, <a href="#method_ba_SessionPlayer__get_icon">get_icon()</a>, <a href="#method_ba_SessionPlayer__get_input_device">get_input_device()</a>, <a href="#method_ba_SessionPlayer__get_name">get_name()</a>, <a href="#method_ba_SessionPlayer__remove_from_game">remove_from_game()</a>, <a href="#method_ba_SessionPlayer__reset_input">reset_input()</a>, <a href="#method_ba_SessionPlayer__set_name">set_name()</a></h5>
|
||||
<h5><a href="#method_ba_SessionPlayer__assign_input_call">assign_input_call()</a>, <a href="#method_ba_SessionPlayer__exists">exists()</a>, <a href="#method_ba_SessionPlayer__get_account_id">get_account_id()</a>, <a href="#method_ba_SessionPlayer__get_icon">get_icon()</a>, <a href="#method_ba_SessionPlayer__get_input_device">get_input_device()</a>, <a href="#method_ba_SessionPlayer__get_name">get_name()</a>, <a href="#method_ba_SessionPlayer__remove_from_game">remove_from_game()</a>, <a href="#method_ba_SessionPlayer__reset_input">reset_input()</a>, <a href="#method_ba_SessionPlayer__set_name">set_name()</a></h5>
|
||||
<dl>
|
||||
<dt><h4><a name="method_ba_SessionPlayer__assign_input_call">assign_input_call()</a></dt></h4><dd>
|
||||
<p><span>assign_input_call(type: Union[str, Tuple[str, ...]],
|
||||
@ -4386,6 +4444,12 @@ Valid type values are: 'jumpPress', 'jumpRelease', 'punchPress',
|
||||
'rightRelease', 'run', 'flyPress', 'flyRelease', 'startPress',
|
||||
'startRelease'</p>
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="method_ba_SessionPlayer__exists">exists()</a></dt></h4><dd>
|
||||
<p><span>exists() -> bool</span></p>
|
||||
|
||||
<p>Return whether the underlying player is still in the game.</p>
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="method_ba_SessionPlayer__get_account_id">get_account_id()</a></dt></h4><dd>
|
||||
<p><span>get_account_id() -> str</span></p>
|
||||
@ -5622,6 +5686,23 @@ the background and just looks pretty; it does not affect gameplay.
|
||||
Note that the actual amount emitted may vary depending on graphics
|
||||
settings, exiting element counts, or other factors.</p>
|
||||
|
||||
<hr>
|
||||
<h2><strong><a name="function_ba_existing">ba.existing()</a></strong></h3>
|
||||
<p><span>existing(obj: Optional[ExistableType]) -> Optional[ExistableType]</span></p>
|
||||
|
||||
<p>Convert invalid references to None.</p>
|
||||
|
||||
<p>Category: <a href="#function_category_Gameplay_Functions">Gameplay Functions</a></p>
|
||||
|
||||
<p>To best support type checking, it is important that invalid references
|
||||
not be passed around and instead get converted to values of None.
|
||||
That way the type checker can properly flag attempts to pass dead
|
||||
objects into functions expecting only live ones, etc.
|
||||
This call can be used on any 'existable' object (one with an exists()
|
||||
method) and will convert it to a None value if it does not exist.
|
||||
For more info, see notes on 'existables' here:
|
||||
https://github.com/efroemling/ballistica/wiki/Coding-Style-Guide</p>
|
||||
|
||||
<hr>
|
||||
<h2><strong><a name="function_ba_get_collision_info">ba.get_collision_info()</a></strong></h3>
|
||||
<p><span>get_collision_info(*args: Any) -> Any</span></p>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user