mirror of
https://github.com/RYDE-WORK/ballistica.git
synced 2026-01-26 08:53:32 +08:00
More modernizing
This commit is contained in:
parent
808ea7dcdd
commit
06dfa73d01
@ -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/e4/f0/c3261a8a7391a2b654da82c35c21",
|
||||
"build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/33/e2/85a8cbf23404612e6761cf02348b",
|
||||
"build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/5b/0d/d906be5fc2a75b5214a94cafe6ca",
|
||||
"build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/6b/53/72d665caf5dfed84312ae6862642",
|
||||
"build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/d9/68/2d98f2d1ee67b6d54adbdf76c863",
|
||||
"build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/e5/3a/33f8f311260542126acea44d05e2",
|
||||
"build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/18/eb/dd39bcfa33983864089d3fb7f666",
|
||||
"build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/f8/1d/3440010fcbcf18c5a6b2966f7fca",
|
||||
"build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/9b/fa/b4ad4b8b82fefe1faad610065b9f",
|
||||
"build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/7f/b9/03af92db6140135ddfa467a1545d",
|
||||
"build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/69/b9/687fc5fa38c3faf7a47eb4241a3c",
|
||||
"build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/cf/2b/589db924b489972981e10850a4e3"
|
||||
"build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/a1/97/fd0e5553917019236912a7010d38",
|
||||
"build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/43/32/c48a4da7fcc8c17132077da852d7",
|
||||
"build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/75/13/2bc3ae9026386d1b515ede107e17",
|
||||
"build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/1f/9a/b112f788f528ec9e3627622698ac",
|
||||
"build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/a1/87/fdb3e925f3be1cc353db94d61c5a",
|
||||
"build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/fa/ba/125457c69bc2940850ab84c4cc6a",
|
||||
"build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/a1/d4/5efcef1f85b2bfea7bbb81800580",
|
||||
"build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/fa/66/75a3a0f27d07131473e804a5b937",
|
||||
"build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/51/6c/911ba80ba913e6dac1cafa5c8a74",
|
||||
"build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/01/cc/cf896173a8d5731ada2aace59146",
|
||||
"build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/a2/12/aa1f0ca5506f0b57f93ca9adf7be",
|
||||
"build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/e1/5f/f372d0ba9591b99284b9b50d7cdf"
|
||||
}
|
||||
8
.idea/dictionaries/ericf.xml
generated
8
.idea/dictionaries/ericf.xml
generated
@ -480,6 +480,7 @@
|
||||
<w>downmix</w>
|
||||
<w>dpad</w>
|
||||
<w>dpath</w>
|
||||
<w>dprofilename</w>
|
||||
<w>drawscore</w>
|
||||
<w>drawscreen</w>
|
||||
<w>dripity</w>
|
||||
@ -756,8 +757,10 @@
|
||||
<w>getcurrency</w>
|
||||
<w>getcwd</w>
|
||||
<w>getdata</w>
|
||||
<w>getinputdevice</w>
|
||||
<w>getkillerplayer</w>
|
||||
<w>getlevelname</w>
|
||||
<w>getlog</w>
|
||||
<w>getmaps</w>
|
||||
<w>getmodel</w>
|
||||
<w>getnodes</w>
|
||||
@ -937,6 +940,7 @@
|
||||
<w>joedeshon</w>
|
||||
<w>johab</w>
|
||||
<w>joinable</w>
|
||||
<w>joinmsg</w>
|
||||
<w>jovica</w>
|
||||
<w>jsonstr</w>
|
||||
<w>jsonstrbase</w>
|
||||
@ -1267,6 +1271,8 @@
|
||||
<w>openssh</w>
|
||||
<w>operasinger</w>
|
||||
<w>oppnode</w>
|
||||
<w>opposingbody</w>
|
||||
<w>opposingnode</w>
|
||||
<w>opstr</w>
|
||||
<w>optparse</w>
|
||||
<w>orchestrahitsound</w>
|
||||
@ -1504,6 +1510,7 @@
|
||||
<w>qrencode</w>
|
||||
<w>qual</w>
|
||||
<w>quoprimime</w>
|
||||
<w>rando</w>
|
||||
<w>randommodule</w>
|
||||
<w>randval</w>
|
||||
<w>rankbutton</w>
|
||||
@ -1672,6 +1679,7 @@
|
||||
<w>soundtrackname</w>
|
||||
<w>sourceimages</w>
|
||||
<w>sourcelines</w>
|
||||
<w>sourcenode</w>
|
||||
<w>spacelen</w>
|
||||
<w>spacingstr</w>
|
||||
<w>spammers</w>
|
||||
|
||||
@ -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=164420280597992494471294420110866243586
|
||||
# SOURCES_HASH=318889180473540875493180206824864665481
|
||||
|
||||
# I'm sorry Pylint. I know this file saddens you. Be strong.
|
||||
# pylint: disable=useless-suppression
|
||||
@ -691,8 +691,8 @@ class Node:
|
||||
def delete(self, ignore_missing: bool = True) -> None:
|
||||
"""delete(ignore_missing: bool = True) -> None
|
||||
|
||||
Delete the node. Ignores already-deleted nodes unless ignore_missing
|
||||
is False, in which case an Exception is thrown.
|
||||
Delete the node. Ignores already-deleted nodes if ignore_missing
|
||||
is True; otherwise a ba.NodeNotFoundError is thrown.
|
||||
"""
|
||||
return None
|
||||
|
||||
@ -716,6 +716,7 @@ class Node:
|
||||
"""
|
||||
return str()
|
||||
|
||||
# Show that ur return type varies based on "doraise" value:
|
||||
@overload
|
||||
def getdelegate(self,
|
||||
type: Type[_T],
|
||||
@ -733,7 +734,7 @@ class Node:
|
||||
|
||||
If the node has no delegate or it is not an instance of the passed
|
||||
type, then None will be returned. If 'doraise' is True, then an
|
||||
Exception will be raised instead in such cases.
|
||||
ba.DelegateNotFoundError will be raised instead.
|
||||
"""
|
||||
return None
|
||||
|
||||
@ -818,6 +819,9 @@ class SessionPlayer:
|
||||
storing data associated with this Player.
|
||||
This gets cleared for each new ba.Activity.
|
||||
|
||||
inputdevice: ba.InputDevice
|
||||
The input device associated with the player.
|
||||
|
||||
color: Sequence[float]
|
||||
The base color for this Player.
|
||||
In team games this will match the ba.SessionTeam's color.
|
||||
@ -839,6 +843,7 @@ class SessionPlayer:
|
||||
team: ba.SessionTeam
|
||||
sessiondata: Dict
|
||||
gamedata: Dict
|
||||
inputdevice: ba.InputDevice
|
||||
color: Sequence[float]
|
||||
highlight: Sequence[float]
|
||||
character: str
|
||||
@ -892,14 +897,6 @@ class SessionPlayer:
|
||||
"""
|
||||
return {'foo': 'bar'}
|
||||
|
||||
def get_input_device(self) -> ba.InputDevice:
|
||||
"""get_input_device() -> ba.InputDevice
|
||||
|
||||
Returns the player's input device.
|
||||
"""
|
||||
import ba # pylint: disable=cyclic-import
|
||||
return ba.InputDevice()
|
||||
|
||||
def get_name(self, full: bool = False, icon: bool = True) -> str:
|
||||
"""get_name(full: bool = False, icon: bool = True) -> str
|
||||
|
||||
@ -2065,22 +2062,6 @@ def get_idle_time() -> int:
|
||||
return int()
|
||||
|
||||
|
||||
def get_input_device(name: str,
|
||||
unique_id: str,
|
||||
doraise: bool = True) -> ba.InputDevice:
|
||||
"""get_input_device(name: str, unique_id: str, doraise: bool = True)
|
||||
-> ba.InputDevice
|
||||
|
||||
(internal)
|
||||
|
||||
Given a type name and a unique identifier, returns an InputDevice.
|
||||
Throws an Exception if the input-device is not found, or returns None
|
||||
if 'doraise' is False.
|
||||
"""
|
||||
import ba # pylint: disable=cyclic-import
|
||||
return ba.InputDevice()
|
||||
|
||||
|
||||
def get_local_active_input_devices_count() -> int:
|
||||
"""get_local_active_input_devices_count() -> int
|
||||
|
||||
@ -2089,14 +2070,6 @@ def get_local_active_input_devices_count() -> int:
|
||||
return int()
|
||||
|
||||
|
||||
def get_log() -> str:
|
||||
"""get_log() -> str
|
||||
|
||||
(internal)
|
||||
"""
|
||||
return str()
|
||||
|
||||
|
||||
def get_log_file_path() -> str:
|
||||
"""get_log_file_path() -> str
|
||||
|
||||
@ -2389,6 +2362,41 @@ def getdata(name: str) -> ba.Data:
|
||||
return ba.Data()
|
||||
|
||||
|
||||
# Show that our return type varies based on "doraise" value:
|
||||
@overload
|
||||
def getinputdevice(name: str,
|
||||
unique_id: str,
|
||||
doraise: Literal[True] = True) -> ba.InputDevice:
|
||||
...
|
||||
|
||||
|
||||
@overload
|
||||
def getinputdevice(name: str, unique_id: str,
|
||||
doraise: Literal[False]) -> Optional[ba.InputDevice]:
|
||||
...
|
||||
|
||||
|
||||
def getinputdevice(name: str, unique_id: str, doraise: bool = True) -> Any:
|
||||
"""getinputdevice(name: str, unique_id: str, doraise: bool = True)
|
||||
-> <varies>
|
||||
|
||||
(internal)
|
||||
|
||||
Given a type name and a unique identifier, returns an InputDevice.
|
||||
Throws an Exception if the input-device is not found, or returns None
|
||||
if 'doraise' is False.
|
||||
"""
|
||||
return None
|
||||
|
||||
|
||||
def getlog() -> str:
|
||||
"""getlog() -> str
|
||||
|
||||
(internal)
|
||||
"""
|
||||
return str()
|
||||
|
||||
|
||||
def getmodel(name: str) -> ba.Model:
|
||||
"""getmodel(name: str) -> ba.Model
|
||||
|
||||
|
||||
@ -53,7 +53,7 @@ from ba._error import (print_exception, print_error, NotFoundError,
|
||||
InputDeviceNotFoundError, WidgetNotFoundError,
|
||||
ActivityNotFoundError, TeamNotFoundError,
|
||||
SessionTeamNotFoundError, SessionNotFoundError,
|
||||
DependencyError)
|
||||
DelegateNotFoundError, DependencyError)
|
||||
from ba._freeforallsession import FreeForAllSession
|
||||
from ba._gameactivity import GameActivity
|
||||
from ba._gameresults import TeamGameResults
|
||||
|
||||
@ -22,6 +22,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import time
|
||||
import random
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import _ba
|
||||
@ -376,7 +377,7 @@ class App:
|
||||
|
||||
# Lobby.
|
||||
self.lobby_random_profile_index: int = 1
|
||||
self.lobby_random_char_index_offset: Optional[int] = None
|
||||
self.lobby_random_char_index_offset = random.randrange(1000)
|
||||
self.lobby_account_profile_device_id: Optional[int] = None
|
||||
|
||||
# Main Menu.
|
||||
@ -722,7 +723,7 @@ class App:
|
||||
game: str,
|
||||
force: bool = False,
|
||||
args: Dict = None) -> bool:
|
||||
"""High level way to launch a co-op session locally."""
|
||||
"""High level way to launch a local co-op session."""
|
||||
# pylint: disable=cyclic-import
|
||||
from ba._campaign import get_campaign
|
||||
from bastd.ui.coop.level import CoopLevelLockedWindow
|
||||
@ -788,7 +789,7 @@ class App:
|
||||
color=(1, 1, 0)),
|
||||
timetype=TimeType.REAL)
|
||||
|
||||
def shutdown(self) -> None:
|
||||
def on_app_shutdown(self) -> None:
|
||||
"""(internal)"""
|
||||
self.music.on_app_shutdown()
|
||||
|
||||
|
||||
@ -43,7 +43,7 @@ def is_browser_likely_available() -> bool:
|
||||
"""
|
||||
app = _ba.app
|
||||
platform = app.platform
|
||||
touchscreen = _ba.get_input_device('TouchScreen', '#1', doraise=False)
|
||||
touchscreen = _ba.getinputdevice('TouchScreen', '#1', doraise=False)
|
||||
|
||||
# If we're on a vr device or an android device with no touchscreen,
|
||||
# assume no browser.
|
||||
@ -100,7 +100,7 @@ def handle_log() -> None:
|
||||
except Exception:
|
||||
activityname = 'unavailable'
|
||||
info = {
|
||||
'log': _ba.get_log(),
|
||||
'log': _ba.getlog(),
|
||||
'version': app.version,
|
||||
'build': app.build_number,
|
||||
'userAgentString': app.user_agent_string,
|
||||
|
||||
@ -40,37 +40,37 @@ class Collision:
|
||||
return _ba.Vec3(_ba.get_collision_info('position'))
|
||||
|
||||
@property
|
||||
def source_node(self) -> ba.Node:
|
||||
def sourcenode(self) -> ba.Node:
|
||||
"""The node containing the material triggering the current callback.
|
||||
|
||||
Throws a ba.NodeNotFoundError if the node does not exist, though
|
||||
the node should always exist (at least at the start of the collision
|
||||
callback).
|
||||
"""
|
||||
node = _ba.get_collision_info('source_node')
|
||||
node = _ba.get_collision_info('sourcenode')
|
||||
assert isinstance(node, (_ba.Node, type(None)))
|
||||
if not node:
|
||||
raise NodeNotFoundError()
|
||||
return node
|
||||
|
||||
@property
|
||||
def opposing_node(self) -> ba.Node:
|
||||
def opposingnode(self) -> ba.Node:
|
||||
"""The node the current callback material node is hitting.
|
||||
|
||||
Throws a ba.NodeNotFoundError if the node does not exist.
|
||||
This can be expected in some cases such as in 'disconnect'
|
||||
callbacks triggered by deleting a currently-colliding node.
|
||||
"""
|
||||
node = _ba.get_collision_info('opposing_node')
|
||||
node = _ba.get_collision_info('opposingnode')
|
||||
assert isinstance(node, (_ba.Node, type(None)))
|
||||
if not node:
|
||||
raise NodeNotFoundError()
|
||||
return node
|
||||
|
||||
@property
|
||||
def opposing_body(self) -> int:
|
||||
def opposingbody(self) -> int:
|
||||
"""The body index on the opposing node in the current collision."""
|
||||
body = _ba.get_collision_info('opposing_body')
|
||||
body = _ba.get_collision_info('opposingbody')
|
||||
assert isinstance(body, int)
|
||||
return body
|
||||
|
||||
|
||||
@ -77,6 +77,13 @@ class TeamNotFoundError(NotFoundError):
|
||||
"""
|
||||
|
||||
|
||||
class DelegateNotFoundError(NotFoundError):
|
||||
"""Exception raised when an expected delegate object does not exist.
|
||||
|
||||
category: Exception Classes
|
||||
"""
|
||||
|
||||
|
||||
class SessionTeamNotFoundError(NotFoundError):
|
||||
"""Exception raised when an expected ba.SessionTeam does not exist.
|
||||
|
||||
|
||||
@ -194,10 +194,10 @@ def animate(node: ba.Node,
|
||||
|
||||
# Temp sanity check while we transition from milliseconds to seconds
|
||||
# based time values.
|
||||
if _ba.app.test_build and not suppress_format_warning:
|
||||
for item in items:
|
||||
# (PyCharm seems to think item is a float, not a tuple)
|
||||
_ba.time_format_check(timeformat, item[0])
|
||||
if __debug__:
|
||||
if not suppress_format_warning:
|
||||
for item in items:
|
||||
_ba.time_format_check(timeformat, item[0])
|
||||
|
||||
curve = _ba.newnode('animcurve',
|
||||
owner=node,
|
||||
@ -221,7 +221,6 @@ def animate(node: ba.Node,
|
||||
# FIXME: Even if we are looping we should have a way to die once we
|
||||
# get disconnected.
|
||||
if not loop:
|
||||
# (PyCharm seems to think item is a float, not a tuple)
|
||||
_ba.timer(int(mult * items[-1][0]) + 1000,
|
||||
curve.delete,
|
||||
timeformat=TimeFormat.MILLISECONDS)
|
||||
@ -259,10 +258,11 @@ def animate_array(node: ba.Node,
|
||||
|
||||
# Temp sanity check while we transition from milliseconds to seconds
|
||||
# based time values.
|
||||
if _ba.app.test_build and not suppress_format_warning:
|
||||
for item in items:
|
||||
# (PyCharm seems to think item is a float, not a tuple)
|
||||
_ba.time_format_check(timeformat, item[0])
|
||||
if __debug__:
|
||||
if not suppress_format_warning:
|
||||
for item in items:
|
||||
# (PyCharm seems to think item is a float, not a tuple)
|
||||
_ba.time_format_check(timeformat, item[0])
|
||||
|
||||
if timeformat is TimeFormat.SECONDS:
|
||||
mult = 1000
|
||||
@ -381,8 +381,9 @@ def timestring(timeval: float,
|
||||
|
||||
# Temp sanity check while we transition from milliseconds to seconds
|
||||
# based time values.
|
||||
if _ba.app.test_build and not suppress_format_warning:
|
||||
_ba.time_format_check(timeformat, timeval)
|
||||
if __debug__:
|
||||
if not suppress_format_warning:
|
||||
_ba.time_format_check(timeformat, timeval)
|
||||
|
||||
# We operate on milliseconds internally.
|
||||
if timeformat is TimeFormat.SECONDS:
|
||||
|
||||
@ -293,7 +293,7 @@ def do_quit() -> None:
|
||||
|
||||
|
||||
def shutdown() -> None:
|
||||
_ba.app.shutdown()
|
||||
_ba.app.on_app_shutdown()
|
||||
|
||||
|
||||
def gc_disable() -> None:
|
||||
|
||||
@ -19,16 +19,19 @@
|
||||
# SOFTWARE.
|
||||
# -----------------------------------------------------------------------------
|
||||
"""Implements lobby system for gathering before games, char select, etc."""
|
||||
# pylint: disable=too-many-lines
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import random
|
||||
import weakref
|
||||
from dataclasses import dataclass
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import _ba
|
||||
from ba._error import print_exception, print_error, NotFoundError
|
||||
from ba._gameutils import animate, animate_array
|
||||
from ba._lang import Lstr
|
||||
from ba._enums import SpecialChar
|
||||
from ba._profile import get_player_profile_colors
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Optional, List, Dict, Any, Sequence, Union
|
||||
@ -44,45 +47,22 @@ class JoinInfo:
|
||||
"""Display useful info for joiners."""
|
||||
|
||||
def __init__(self, lobby: ba.Lobby):
|
||||
# pylint: disable=too-many-locals
|
||||
from ba import _input
|
||||
from ba._lang import Lstr
|
||||
from ba._nodeactor import NodeActor
|
||||
from ba._general import WeakCall
|
||||
from ba._enums import SpecialChar
|
||||
can_switch_teams = (len(lobby.teams) > 1)
|
||||
self._state = 0
|
||||
press_to_punch: Union[str,
|
||||
ba.Lstr] = _ba.charstr(SpecialChar.LEFT_BUTTON)
|
||||
press_to_bomb: Union[str,
|
||||
ba.Lstr] = _ba.charstr(SpecialChar.RIGHT_BUTTON)
|
||||
self._press_to_punch: Union[str, ba.Lstr] = _ba.charstr(
|
||||
SpecialChar.LEFT_BUTTON)
|
||||
self._press_to_bomb: Union[str, ba.Lstr] = _ba.charstr(
|
||||
SpecialChar.RIGHT_BUTTON)
|
||||
self._joinmsg = Lstr(resource='pressAnyButtonToJoinText')
|
||||
can_switch_teams = (len(lobby.teams) > 1)
|
||||
|
||||
# If we have a keyboard, grab keys for punch and pickup.
|
||||
# FIXME: This of course is only correct on the local device;
|
||||
# Should change this for net games.
|
||||
keyboard: Optional[ba.InputDevice] = _ba.get_input_device(
|
||||
'Keyboard', '#1', doraise=False)
|
||||
keyboard = _ba.getinputdevice('Keyboard', '#1', doraise=False)
|
||||
if keyboard is not None:
|
||||
punch_key = keyboard.get_button_name(
|
||||
_input.get_device_value(keyboard, 'buttonPunch'))
|
||||
press_to_punch = Lstr(resource='orText',
|
||||
subs=[('${A}',
|
||||
Lstr(value='\'${K}\'',
|
||||
subs=[('${K}', punch_key)])),
|
||||
('${B}', press_to_punch)])
|
||||
bomb_key = keyboard.get_button_name(
|
||||
_input.get_device_value(keyboard, 'buttonBomb'))
|
||||
press_to_bomb = Lstr(resource='orText',
|
||||
subs=[('${A}',
|
||||
Lstr(value='\'${K}\'',
|
||||
subs=[('${K}', bomb_key)])),
|
||||
('${B}', press_to_bomb)])
|
||||
join_str = Lstr(value='${A} < ${B} >',
|
||||
subs=[('${A}',
|
||||
Lstr(resource='pressPunchToJoinText')),
|
||||
('${B}', press_to_punch)])
|
||||
else:
|
||||
join_str = Lstr(resource='pressAnyButtonToJoinText')
|
||||
self._update_for_keyboard(keyboard)
|
||||
|
||||
flatness = 1.0 if _ba.app.vr_mode else 0.0
|
||||
self._text = NodeActor(
|
||||
@ -94,11 +74,11 @@ class JoinInfo:
|
||||
'h_align': 'center',
|
||||
'color': (0.7, 0.7, 0.95, 1.0),
|
||||
'flatness': flatness,
|
||||
'text': join_str
|
||||
'text': self._joinmsg
|
||||
}))
|
||||
|
||||
if _ba.app.kiosk_mode:
|
||||
self._messages = [join_str]
|
||||
self._messages = [self._joinmsg]
|
||||
else:
|
||||
msg1 = Lstr(resource='pressToSelectProfileText',
|
||||
subs=[
|
||||
@ -108,15 +88,38 @@ class JoinInfo:
|
||||
msg2 = Lstr(resource='pressToOverrideCharacterText',
|
||||
subs=[('${BUTTONS}', Lstr(resource='bombBoldText'))])
|
||||
msg3 = Lstr(value='${A} < ${B} >',
|
||||
subs=[('${A}', msg2), ('${B}', press_to_bomb)])
|
||||
subs=[('${A}', msg2), ('${B}', self._press_to_bomb)])
|
||||
self._messages = (([
|
||||
Lstr(resource='pressToSelectTeamText',
|
||||
subs=[('${BUTTONS}', _ba.charstr(SpecialChar.LEFT_ARROW) +
|
||||
' ' + _ba.charstr(SpecialChar.RIGHT_ARROW))])
|
||||
] if can_switch_teams else []) + [msg1] + [msg3] + [join_str])
|
||||
Lstr(
|
||||
resource='pressToSelectTeamText',
|
||||
subs=[('${BUTTONS}', _ba.charstr(SpecialChar.LEFT_ARROW) +
|
||||
' ' + _ba.charstr(SpecialChar.RIGHT_ARROW))],
|
||||
)
|
||||
] if can_switch_teams else []) + [msg1] + [msg3] + [self._joinmsg])
|
||||
|
||||
self._timer = _ba.Timer(4.0, WeakCall(self._update), repeat=True)
|
||||
|
||||
def _update_for_keyboard(self, keyboard: ba.InputDevice) -> None:
|
||||
from ba import _input
|
||||
punch_key = keyboard.get_button_name(
|
||||
_input.get_device_value(keyboard, 'buttonPunch'))
|
||||
self._press_to_punch = Lstr(resource='orText',
|
||||
subs=[('${A}',
|
||||
Lstr(value='\'${K}\'',
|
||||
subs=[('${K}', punch_key)])),
|
||||
('${B}', self._press_to_punch)])
|
||||
bomb_key = keyboard.get_button_name(
|
||||
_input.get_device_value(keyboard, 'buttonBomb'))
|
||||
self._press_to_bomb = Lstr(resource='orText',
|
||||
subs=[('${A}',
|
||||
Lstr(value='\'${K}\'',
|
||||
subs=[('${K}', bomb_key)])),
|
||||
('${B}', self._press_to_bomb)])
|
||||
self._joinmsg = Lstr(value='${A} < ${B} >',
|
||||
subs=[('${A}',
|
||||
Lstr(resource='pressPunchToJoinText')),
|
||||
('${B}', self._press_to_punch)])
|
||||
|
||||
def _update(self) -> None:
|
||||
assert self._text.node
|
||||
self._text.node.text = self._messages[self._state]
|
||||
@ -150,13 +153,6 @@ class Chooser:
|
||||
|
||||
def __init__(self, vpos: float, player: _ba.SessionPlayer,
|
||||
lobby: 'Lobby') -> None:
|
||||
# FIXME: Tidy up around here.
|
||||
# pylint: disable=too-many-branches
|
||||
# pylint: disable=too-many-statements
|
||||
from ba import _gameutils
|
||||
from ba import _profile
|
||||
from ba import _lang
|
||||
app = _ba.app
|
||||
self._deek_sound = _ba.getsound('deek')
|
||||
self._click_sound = _ba.getsound('click01')
|
||||
self._punchsound = _ba.getsound('punch01')
|
||||
@ -172,11 +168,16 @@ class Chooser:
|
||||
self._profilename = ''
|
||||
self._profilenames: List[str] = []
|
||||
self._ready: bool = False
|
||||
self.character_names: List[str] = []
|
||||
self.last_change: Sequence[Union[float, int]] = (0, 0)
|
||||
self._character_names: List[str] = []
|
||||
self._last_change: Sequence[Union[float, int]] = (0, 0)
|
||||
self._profiles: Dict[str, Dict[str, Any]] = {}
|
||||
|
||||
# Hmm does this need to be public?
|
||||
self.profiles: Dict[str, Dict[str, Any]] = {}
|
||||
app = _ba.app
|
||||
|
||||
# try:
|
||||
# print(player.inputdevice)
|
||||
# except Exception as exc:
|
||||
# print('GOT EXC', type(exc))
|
||||
|
||||
# Load available profiles either from the local config or from the
|
||||
# remote device.
|
||||
@ -186,109 +187,26 @@ class Chooser:
|
||||
# the team-id!
|
||||
self._selected_team_index: int = self.lobby.next_add_team
|
||||
|
||||
# Store a persistent random character index; we'll use this for the
|
||||
# '_random' profile. Let's use their input_device id to seed it. This
|
||||
# will give a persistent character for them between games and will
|
||||
# distribute characters nicely if everyone is random.
|
||||
try:
|
||||
input_device_id = self._player.get_input_device().id
|
||||
except Exception:
|
||||
from ba import _error
|
||||
_error.print_exception('Error getting device-id on chooser create')
|
||||
input_device_id = 0
|
||||
# Store a persistent random character index and colors; we'll use this
|
||||
# for the '_random' profile. Let's use their input_device id to seed
|
||||
# it. This will give a persistent character for them between games
|
||||
# and will distribute characters nicely if everyone is random.
|
||||
self._random_color, self._random_highlight = (
|
||||
get_player_profile_colors(None))
|
||||
|
||||
if app.lobby_random_char_index_offset is None:
|
||||
|
||||
# We want the first device that asks for a chooser to always get
|
||||
# spaz as a random character..
|
||||
# scratch that.. we now kinda accomplish the same thing with
|
||||
# account profiles so lets just be fully random here.
|
||||
app.lobby_random_char_index_offset = (random.randrange(1000))
|
||||
|
||||
# To calc our random index we pick a random character out of our
|
||||
# To calc our random character we pick a random one out of our
|
||||
# unlocked list and then locate that character's index in the full
|
||||
# list.
|
||||
char_index_offset = app.lobby_random_char_index_offset
|
||||
assert char_index_offset is not None
|
||||
self._random_character_index = ((input_device_id + char_index_offset) %
|
||||
len(self.character_names))
|
||||
self._random_color, self._random_highlight = (
|
||||
_profile.get_player_profile_colors(None))
|
||||
self._random_character_index = (
|
||||
(player.inputdevice.id + char_index_offset) %
|
||||
len(self._character_names))
|
||||
|
||||
# Attempt to pick an initial profile based on what's been stored
|
||||
# for this input device.
|
||||
input_device = self._player.get_input_device()
|
||||
try:
|
||||
name = input_device.name
|
||||
unique_id = input_device.unique_identifier
|
||||
self._profilename = (
|
||||
app.config['Default Player Profiles'][name + ' ' + unique_id])
|
||||
self._profileindex = self._profilenames.index(self._profilename)
|
||||
# Attempt to set an initial profile based on what was used previously
|
||||
# for this input-device, etc.
|
||||
self._profileindex = self._select_initial_profile()
|
||||
self._profilename = self._profilenames[self._profileindex]
|
||||
|
||||
# If this one is __account__ and is local and we haven't marked
|
||||
# anyone as the account-profile device yet, mark this guy as it.
|
||||
# (prevents the next joiner from getting the account profile too).
|
||||
if (self._profilename == '__account__'
|
||||
and not input_device.is_remote_client
|
||||
and app.lobby_account_profile_device_id is None):
|
||||
app.lobby_account_profile_device_id = input_device_id
|
||||
|
||||
# Well hmm that didn't work.. pick __account__, _random, or some
|
||||
# other random profile.
|
||||
except Exception:
|
||||
|
||||
profilenames = self._profilenames
|
||||
|
||||
# We want the first local input-device in the game to latch on to
|
||||
# the account profile.
|
||||
if (not input_device.is_remote_client
|
||||
and not input_device.is_controller_app):
|
||||
if (app.lobby_account_profile_device_id is None
|
||||
and '__account__' in profilenames):
|
||||
app.lobby_account_profile_device_id = input_device_id
|
||||
|
||||
# If this is the designated account-profile-device, try to default
|
||||
# to the account profile.
|
||||
if (input_device_id == app.lobby_account_profile_device_id
|
||||
and '__account__' in profilenames):
|
||||
self._profileindex = profilenames.index('__account__')
|
||||
else:
|
||||
|
||||
# If this is the controller app, it defaults to using a random
|
||||
# profile (since we can pull the random name from the app).
|
||||
if input_device.is_controller_app:
|
||||
self._profileindex = profilenames.index('_random')
|
||||
else:
|
||||
|
||||
# If its a client connection, for now just force
|
||||
# the account profile if possible.. (need to provide a
|
||||
# way for clients to specify/remember their default
|
||||
# profile on remote servers that do not already know them).
|
||||
if (input_device.is_remote_client
|
||||
and '__account__' in profilenames):
|
||||
self._profileindex = profilenames.index('__account__')
|
||||
else:
|
||||
|
||||
# Cycle through our non-random profiles once; after
|
||||
# that, everyone gets random.
|
||||
while (app.lobby_random_profile_index <
|
||||
len(profilenames)
|
||||
and profilenames[app.lobby_random_profile_index]
|
||||
in ('_random', '__account__', '_edit')):
|
||||
app.lobby_random_profile_index += 1
|
||||
if (app.lobby_random_profile_index <
|
||||
len(profilenames)):
|
||||
self._profileindex = (
|
||||
app.lobby_random_profile_index)
|
||||
app.lobby_random_profile_index += 1
|
||||
else:
|
||||
self._profileindex = profilenames.index('_random')
|
||||
|
||||
self._profilename = profilenames[self._profileindex]
|
||||
|
||||
self.character_index = self._random_character_index
|
||||
self._color = self._random_color
|
||||
self._highlight = self._random_highlight
|
||||
self._text_node = _ba.newnode('text',
|
||||
delegate=self,
|
||||
attrs={
|
||||
@ -300,8 +218,7 @@ class Chooser:
|
||||
'v_align': 'center',
|
||||
'v_attach': 'top'
|
||||
})
|
||||
|
||||
_gameutils.animate(self._text_node, 'scale', {0: 0, 0.1: 1.0})
|
||||
animate(self._text_node, 'scale', {0: 0, 0.1: 1.0})
|
||||
self.icon = _ba.newnode('image',
|
||||
owner=self._text_node,
|
||||
attrs={
|
||||
@ -311,20 +228,83 @@ class Chooser:
|
||||
'attach': 'topCenter'
|
||||
})
|
||||
|
||||
_gameutils.animate_array(self.icon, 'scale', 2, {
|
||||
0: (0, 0),
|
||||
0.1: (45, 45)
|
||||
})
|
||||
animate_array(self.icon, 'scale', 2, {0: (0, 0), 0.1: (45, 45)})
|
||||
|
||||
# Set our initial name to '<choosing player>' in case anyone asks.
|
||||
self._player.set_name(Lstr(resource='choosingPlayerText').evaluate(),
|
||||
real=False)
|
||||
|
||||
# Init these to our rando but they should get switched to the
|
||||
# selected profile (if any) right after.
|
||||
self._character_index = self._random_character_index
|
||||
self._color = self._random_color
|
||||
self._highlight = self._random_highlight
|
||||
|
||||
self.update_from_profile()
|
||||
self.update_position()
|
||||
self._inited = True
|
||||
|
||||
self._set_ready(False)
|
||||
|
||||
# Set our initial name to '<choosing player>' in case anyone asks.
|
||||
self._player.set_name(
|
||||
_lang.Lstr(resource='choosingPlayerText').evaluate(), real=False)
|
||||
def _select_initial_profile(self) -> int:
|
||||
app = _ba.app
|
||||
profilenames = self._profilenames
|
||||
inputdevice = self._player.inputdevice
|
||||
|
||||
self.update_from_player_profiles()
|
||||
self.update_position()
|
||||
self._inited = True
|
||||
# If we've got a set profile name for this device, work backwards
|
||||
# from that to get our index.
|
||||
dprofilename = (app.config.get('Default Player Profiles',
|
||||
{}).get(inputdevice.name + ' ' +
|
||||
inputdevice.unique_identifier))
|
||||
if dprofilename is not None and dprofilename in profilenames:
|
||||
# If we got '__account__' and its local and we haven't marked
|
||||
# anyone as the 'account profile' device yet, mark this guy as
|
||||
# it. (prevents the next joiner from getting the account
|
||||
# profile too).
|
||||
if (dprofilename == '__account__'
|
||||
and not inputdevice.is_remote_client
|
||||
and app.lobby_account_profile_device_id is None):
|
||||
app.lobby_account_profile_device_id = inputdevice.id
|
||||
return profilenames.index(dprofilename)
|
||||
|
||||
# We want to mark the first local input-device in the game
|
||||
# as the 'account profile' device.
|
||||
if (not inputdevice.is_remote_client
|
||||
and not inputdevice.is_controller_app):
|
||||
if (app.lobby_account_profile_device_id is None
|
||||
and '__account__' in profilenames):
|
||||
app.lobby_account_profile_device_id = inputdevice.id
|
||||
|
||||
# If this is the designated account-profile-device, try to default
|
||||
# to the account profile.
|
||||
if (inputdevice.id == app.lobby_account_profile_device_id
|
||||
and '__account__' in profilenames):
|
||||
return profilenames.index('__account__')
|
||||
|
||||
# If this is the controller app, it defaults to using a random
|
||||
# profile (since we can pull the random name from the app).
|
||||
if inputdevice.is_controller_app and '_random' in profilenames:
|
||||
return profilenames.index('_random')
|
||||
|
||||
# If its a client connection, for now just force
|
||||
# the account profile if possible.. (need to provide a
|
||||
# way for clients to specify/remember their default
|
||||
# profile on remote servers that do not already know them).
|
||||
if inputdevice.is_remote_client and '__account__' in profilenames:
|
||||
return profilenames.index('__account__')
|
||||
|
||||
# Cycle through our non-random profiles once; after
|
||||
# that, everyone gets random.
|
||||
while (app.lobby_random_profile_index < len(profilenames)
|
||||
and profilenames[app.lobby_random_profile_index]
|
||||
in ('_random', '__account__', '_edit')):
|
||||
app.lobby_random_profile_index += 1
|
||||
if app.lobby_random_profile_index < len(profilenames):
|
||||
profileindex = app.lobby_random_profile_index
|
||||
app.lobby_random_profile_index += 1
|
||||
return profileindex
|
||||
assert '_random' in profilenames
|
||||
return profilenames.index('_random')
|
||||
|
||||
@property
|
||||
def player(self) -> ba.SessionPlayer:
|
||||
@ -353,44 +333,39 @@ class Chooser:
|
||||
"""The chooser's ba.Lobby."""
|
||||
lobby = self._lobby()
|
||||
if lobby is None:
|
||||
from ba import _error
|
||||
raise _error.NotFoundError('Lobby does not exist.')
|
||||
raise NotFoundError('Lobby does not exist.')
|
||||
return lobby
|
||||
|
||||
def get_lobby(self) -> Optional[ba.Lobby]:
|
||||
"""Return this chooser's lobby if it still exists; otherwise None."""
|
||||
return self._lobby()
|
||||
|
||||
def update_from_player_profiles(self) -> None:
|
||||
"""Set character based on profile; otherwise use pre-picked random."""
|
||||
try:
|
||||
from ba import _profile
|
||||
|
||||
# Store the name even though we usually use index (in case
|
||||
# the profile list changes)
|
||||
self._profilename = self._profilenames[self._profileindex]
|
||||
character = self.profiles[self._profilename]['character']
|
||||
def update_from_profile(self) -> None:
|
||||
"""Set character/colors based on the current profile."""
|
||||
self._profilename = self._profilenames[self._profileindex]
|
||||
if self._profilename == '_edit':
|
||||
pass
|
||||
elif self._profilename == '_random':
|
||||
self._character_index = self._random_character_index
|
||||
self._color = self._random_color
|
||||
self._highlight = self._random_highlight
|
||||
else:
|
||||
character = self._profiles[self._profilename]['character']
|
||||
|
||||
# At the moment we're not properly pulling the list
|
||||
# of available characters from clients, so profiles might use a
|
||||
# character not in their list. For now, just go ahead and add
|
||||
# a character name to their list as long as we're aware of it.
|
||||
# This just means they won't always be able to override their
|
||||
# character to others they own, but profile characters should work
|
||||
# (and we validate profiles on the master server so no exploit
|
||||
# opportunities)
|
||||
if (character not in self.character_names
|
||||
# character to others they own, but profile characters
|
||||
# should work (and we validate profiles on the master server
|
||||
# so no exploit opportunities)
|
||||
if (character not in self._character_names
|
||||
and character in _ba.app.spaz_appearances):
|
||||
self.character_names.append(character)
|
||||
self.character_index = self.character_names.index(character)
|
||||
self._color, self._highlight = (_profile.get_player_profile_colors(
|
||||
self._profilename, profiles=self.profiles))
|
||||
except Exception:
|
||||
# FIXME: Should never use top level Exception for logic; only
|
||||
# error catching (and they should always be logged).
|
||||
self.character_index = self._random_character_index
|
||||
self._color = self._random_color
|
||||
self._highlight = self._random_highlight
|
||||
self._character_names.append(character)
|
||||
self._character_index = self._character_names.index(character)
|
||||
self._color, self._highlight = (get_player_profile_colors(
|
||||
self._profilename, profiles=self._profiles))
|
||||
self._update_icon()
|
||||
self._update_text()
|
||||
|
||||
@ -401,52 +376,51 @@ class Chooser:
|
||||
|
||||
# Re-construct our profile index and other stuff since the profile
|
||||
# list might have changed.
|
||||
input_device = self._player.get_input_device()
|
||||
input_device = self._player.inputdevice
|
||||
is_remote = input_device.is_remote_client
|
||||
is_test_input = input_device.name.startswith('TestInput')
|
||||
|
||||
# Pull this player's list of unlocked characters.
|
||||
if is_remote:
|
||||
# FIXME: Pull this from remote player (but make sure to
|
||||
# filter it to ones we've got).
|
||||
self.character_names = ['Spaz']
|
||||
# TODO: Pull this from the remote player.
|
||||
# (but make sure to filter it to the ones we've got).
|
||||
self._character_names = ['Spaz']
|
||||
else:
|
||||
self.character_names = self.lobby.character_names_local_unlocked
|
||||
self._character_names = self.lobby.character_names_local_unlocked
|
||||
|
||||
# If we're a local player, pull our local profiles from the config.
|
||||
# Otherwise ask the remote-input-device for its profile list.
|
||||
if is_remote:
|
||||
self.profiles = input_device.get_player_profiles()
|
||||
self._profiles = input_device.get_player_profiles()
|
||||
else:
|
||||
self.profiles = app.config.get('Player Profiles', {})
|
||||
self._profiles = app.config.get('Player Profiles', {})
|
||||
|
||||
# These may have come over the wire from an older
|
||||
# (non-unicode/non-json) version.
|
||||
# Make sure they conform to our standards
|
||||
# (unicode strings, no tuples, etc)
|
||||
self.profiles = json_prep(self.profiles)
|
||||
self._profiles = json_prep(self._profiles)
|
||||
|
||||
# Filter out any characters we're unaware of.
|
||||
for profile in list(self.profiles.items()):
|
||||
for profile in list(self._profiles.items()):
|
||||
if profile[1].get('character', '') not in app.spaz_appearances:
|
||||
profile[1]['character'] = 'Spaz'
|
||||
|
||||
# Add in a random one so we're ok even if there's no
|
||||
# user-created profiles.
|
||||
self.profiles['_random'] = {}
|
||||
# Add in a random one so we're ok even if there's no user profiles.
|
||||
self._profiles['_random'] = {}
|
||||
|
||||
# In kiosk mode we disable account profiles to force random.
|
||||
if app.kiosk_mode:
|
||||
if '__account__' in self.profiles:
|
||||
del self.profiles['__account__']
|
||||
if '__account__' in self._profiles:
|
||||
del self._profiles['__account__']
|
||||
|
||||
# For local devices, add it an 'edit' option which will pop up
|
||||
# the profile window.
|
||||
if not is_remote and not is_test_input and not app.kiosk_mode:
|
||||
self.profiles['_edit'] = {}
|
||||
self._profiles['_edit'] = {}
|
||||
|
||||
# Build a sorted name list we can iterate through.
|
||||
self._profilenames = list(self.profiles.keys())
|
||||
self._profilenames = list(self._profiles.keys())
|
||||
self._profilenames.sort(key=lambda x: x.lower())
|
||||
|
||||
if self._profilename in self._profilenames:
|
||||
@ -457,90 +431,66 @@ class Chooser:
|
||||
|
||||
def update_position(self) -> None:
|
||||
"""Update this chooser's position."""
|
||||
from ba import _gameutils
|
||||
|
||||
# Hmmm this shouldn't be happening.
|
||||
if not self._text_node:
|
||||
print('Error: chooser text nonexistent..')
|
||||
import traceback
|
||||
traceback.print_stack()
|
||||
return
|
||||
assert self._text_node
|
||||
spacing = 350
|
||||
teams = self.lobby.teams
|
||||
offs = (spacing * -0.5 * len(teams) +
|
||||
spacing * self._selected_team_index + 250)
|
||||
if len(teams) > 1:
|
||||
offs -= 35
|
||||
_gameutils.animate_array(self._text_node, 'position', 2, {
|
||||
animate_array(self._text_node, 'position', 2, {
|
||||
0: self._text_node.position,
|
||||
0.1: (-100 + offs, self._vpos + 23)
|
||||
})
|
||||
_gameutils.animate_array(self.icon, 'position', 2, {
|
||||
animate_array(self.icon, 'position', 2, {
|
||||
0: self.icon.position,
|
||||
0.1: (-130 + offs, self._vpos + 22)
|
||||
})
|
||||
|
||||
def get_character_name(self) -> str:
|
||||
"""Return the selected character name."""
|
||||
return self.character_names[self.character_index]
|
||||
return self._character_names[self._character_index]
|
||||
|
||||
def _do_nothing(self) -> None:
|
||||
"""Does nothing! (hacky way to disable callbacks)"""
|
||||
|
||||
def _get_name(self, full: bool = False) -> str:
|
||||
# FIXME: Needs cleanup.
|
||||
# pylint: disable=too-many-branches
|
||||
from ba._lang import Lstr
|
||||
from ba._enums import SpecialChar
|
||||
name_raw = name = self._profilenames[self._profileindex]
|
||||
clamp = False
|
||||
if name == '_random':
|
||||
input_device: Optional[ba.InputDevice]
|
||||
try:
|
||||
input_device = self._player.get_input_device()
|
||||
name = (self._player.inputdevice.get_default_player_name())
|
||||
except Exception:
|
||||
input_device = None
|
||||
if input_device is not None:
|
||||
name = input_device.get_default_player_name()
|
||||
else:
|
||||
print_exception('Error getting _random chooser name.')
|
||||
name = 'Invalid'
|
||||
if not full:
|
||||
clamp = True
|
||||
clamp = not full
|
||||
elif name == '__account__':
|
||||
try:
|
||||
input_device = self._player.get_input_device()
|
||||
name = self._player.inputdevice.get_account_name(full)
|
||||
except Exception:
|
||||
input_device = None
|
||||
if input_device is not None:
|
||||
name = input_device.get_account_name(full)
|
||||
else:
|
||||
print_exception('Error getting account name for chooser.')
|
||||
name = 'Invalid'
|
||||
if not full:
|
||||
clamp = True
|
||||
clamp = not full
|
||||
elif name == '_edit':
|
||||
# FIXME: This causes problems as an Lstr, but its ok to
|
||||
# explicitly translate for now since this is only shown on the
|
||||
# host. (also should elaborate; don't remember what problems this
|
||||
# caused)
|
||||
# Explicitly flattening this to a str; it's only relevant on
|
||||
# the host so that's ok.
|
||||
name = (Lstr(
|
||||
resource='createEditPlayerText',
|
||||
fallback_resource='editProfileWindow.titleNewText').evaluate())
|
||||
else:
|
||||
|
||||
# If we have a regular profile marked as global with an icon,
|
||||
# use it (for full only).
|
||||
if full:
|
||||
try:
|
||||
if self.profiles[name_raw].get('global', False):
|
||||
icon = (self.profiles[name_raw]['icon']
|
||||
if 'icon' in self.profiles[name_raw] else
|
||||
if self._profiles[name_raw].get('global', False):
|
||||
icon = (self._profiles[name_raw]['icon']
|
||||
if 'icon' in self._profiles[name_raw] else
|
||||
_ba.charstr(SpecialChar.LOGO))
|
||||
name = icon + name
|
||||
except Exception:
|
||||
from ba import _error
|
||||
_error.print_exception('Error applying global icon')
|
||||
print_exception('Error applying global icon.')
|
||||
else:
|
||||
|
||||
# We now clamp non-full versions of names so there's at
|
||||
# least some hope of reading them in-game.
|
||||
clamp = True
|
||||
@ -561,9 +511,9 @@ class Chooser:
|
||||
with _ba.Context('ui'):
|
||||
pbrowser.ProfileBrowserWindow(in_main_menu=False)
|
||||
|
||||
# give their input-device UI ownership too
|
||||
# Give their input-device UI ownership too
|
||||
# (prevent someone else from snatching it in crowded games)
|
||||
_ba.set_ui_input_device(self._player.get_input_device())
|
||||
_ba.set_ui_input_device(self._player.inputdevice)
|
||||
return
|
||||
|
||||
if not ready:
|
||||
@ -597,7 +547,7 @@ class Chooser:
|
||||
Call(self.handlemessage, ChangeMessage('ready', 0)))
|
||||
|
||||
# Store the last profile picked by this input for reuse.
|
||||
input_device = self._player.get_input_device()
|
||||
input_device = self._player.inputdevice
|
||||
name = input_device.name
|
||||
unique_id = input_device.unique_identifier
|
||||
device_profiles = _ba.app.config.setdefault(
|
||||
@ -607,7 +557,8 @@ class Chooser:
|
||||
# to random; in that case we'll want to start picking up custom
|
||||
# profiles if/when one is made so keep our setting cleared.
|
||||
special = ('_random', '_edit', '__account__')
|
||||
have_custom_profiles = any(p not in special for p in self.profiles)
|
||||
have_custom_profiles = any(p not in special
|
||||
for p in self._profiles)
|
||||
|
||||
profilekey = name + ' ' + unique_id
|
||||
if profilename == '_random' and not have_custom_profiles:
|
||||
@ -643,7 +594,7 @@ class Chooser:
|
||||
# choosers that have been marked as ready.
|
||||
team_player_counts = {}
|
||||
for team in teams:
|
||||
team_player_counts[team.id] = (len(team.players))
|
||||
team_player_counts[team.id] = len(team.players)
|
||||
for chooser in lobby.choosers:
|
||||
if chooser.ready:
|
||||
team_player_counts[chooser.get_team().id] += 1
|
||||
@ -668,15 +619,14 @@ class Chooser:
|
||||
# TODO: should handle this at the engine layer so this is unnecessary.
|
||||
def _handle_repeat_message_attack(self) -> None:
|
||||
now = _ba.time()
|
||||
count = self.last_change[1]
|
||||
if now - self.last_change[0] < QUICK_CHANGE_INTERVAL:
|
||||
count = self._last_change[1]
|
||||
if now - self._last_change[0] < QUICK_CHANGE_INTERVAL:
|
||||
count += 1
|
||||
if count > MAX_QUICK_CHANGE_COUNT:
|
||||
_ba.disconnect_client(
|
||||
self._player.get_input_device().client_id)
|
||||
elif now - self.last_change[0] > QUICK_CHANGE_RESET_INTERVAL:
|
||||
_ba.disconnect_client(self._player.inputdevice.client_id)
|
||||
elif now - self._last_change[0] > QUICK_CHANGE_RESET_INTERVAL:
|
||||
count = 0
|
||||
self.last_change = (now, count)
|
||||
self._last_change = (now, count)
|
||||
|
||||
def handlemessage(self, msg: Any) -> Any:
|
||||
"""Standard generic message handler."""
|
||||
@ -686,13 +636,11 @@ class Chooser:
|
||||
|
||||
# If we've been removed from the lobby, ignore this stuff.
|
||||
if self._dead:
|
||||
from ba import _error
|
||||
_error.print_error('chooser got ChangeMessage after dying')
|
||||
print_error('chooser got ChangeMessage after dying')
|
||||
return
|
||||
|
||||
if not self._text_node:
|
||||
from ba import _error
|
||||
_error.print_error('got ChangeMessage after nodes died')
|
||||
print_error('got ChangeMessage after nodes died')
|
||||
return
|
||||
|
||||
if msg.what == 'team':
|
||||
@ -718,13 +666,13 @@ class Chooser:
|
||||
_ba.playsound(self._deek_sound)
|
||||
self._profileindex = ((self._profileindex + msg.value) %
|
||||
len(self._profilenames))
|
||||
self.update_from_player_profiles()
|
||||
self.update_from_profile()
|
||||
|
||||
elif msg.what == 'character':
|
||||
_ba.playsound(self._click_sound)
|
||||
# update our index in our local list of characters
|
||||
self.character_index = ((self.character_index + msg.value) %
|
||||
len(self.character_names))
|
||||
self._character_index = ((self._character_index + msg.value) %
|
||||
len(self._character_names))
|
||||
self._update_text()
|
||||
self._update_icon()
|
||||
|
||||
@ -732,8 +680,6 @@ class Chooser:
|
||||
self._handle_ready_msg(bool(msg.value))
|
||||
|
||||
def _update_text(self) -> None:
|
||||
from ba import _gameutils
|
||||
from ba._lang import Lstr
|
||||
assert self._text_node is not None
|
||||
if self._ready:
|
||||
|
||||
@ -751,7 +697,7 @@ class Chooser:
|
||||
# Flash as we're coming in.
|
||||
fin_color = _ba.safecolor(self.get_color()) + (1, )
|
||||
if not self._inited:
|
||||
_gameutils.animate_array(self._text_node, 'color', 4, {
|
||||
animate_array(self._text_node, 'color', 4, {
|
||||
0.15: fin_color,
|
||||
0.25: (2, 2, 2, 1),
|
||||
0.35: fin_color
|
||||
@ -760,7 +706,7 @@ class Chooser:
|
||||
|
||||
# Blend if we're in teams mode; switch instantly otherwise.
|
||||
if can_switch_teams:
|
||||
_gameutils.animate_array(self._text_node, 'color', 4, {
|
||||
animate_array(self._text_node, 'color', 4, {
|
||||
0: self._text_node.color,
|
||||
0.1: fin_color
|
||||
})
|
||||
@ -772,8 +718,6 @@ class Chooser:
|
||||
def get_color(self) -> Sequence[float]:
|
||||
"""Return the currently selected color."""
|
||||
val: Sequence[float]
|
||||
# if self._profilenames[self._profileindex] == '_edit':
|
||||
# val = (0, 1, 0)
|
||||
if self.lobby.use_team_colors:
|
||||
val = self.lobby.teams[self._selected_team_index].color
|
||||
else:
|
||||
@ -819,7 +763,6 @@ class Chooser:
|
||||
return self._player
|
||||
|
||||
def _update_icon(self) -> None:
|
||||
from ba import _gameutils
|
||||
if self._profilenames[self._profileindex] == '_edit':
|
||||
tex = _ba.gettexture('black')
|
||||
tint_tex = _ba.gettexture('black')
|
||||
@ -830,13 +773,12 @@ class Chooser:
|
||||
return
|
||||
|
||||
try:
|
||||
tex_name = (_ba.app.spaz_appearances[self.character_names[
|
||||
self.character_index]].icon_texture)
|
||||
tint_tex_name = (_ba.app.spaz_appearances[self.character_names[
|
||||
self.character_index]].icon_mask_texture)
|
||||
tex_name = (_ba.app.spaz_appearances[self._character_names[
|
||||
self._character_index]].icon_texture)
|
||||
tint_tex_name = (_ba.app.spaz_appearances[self._character_names[
|
||||
self._character_index]].icon_mask_texture)
|
||||
except Exception:
|
||||
from ba import _error
|
||||
_error.print_exception('Error updating char icon list')
|
||||
print_exception('Error updating char icon list')
|
||||
tex_name = 'neoSpazIcon'
|
||||
tint_tex_name = 'neoSpazIconColorMask'
|
||||
|
||||
@ -853,7 +795,7 @@ class Chooser:
|
||||
|
||||
# If we're initing, flash.
|
||||
if not self._inited:
|
||||
_gameutils.animate_array(self.icon, 'color', 3, {
|
||||
animate_array(self.icon, 'color', 3, {
|
||||
0.15: (1, 1, 1),
|
||||
0.25: (2, 2, 2),
|
||||
0.35: (1, 1, 1)
|
||||
@ -861,7 +803,7 @@ class Chooser:
|
||||
|
||||
# Blend in teams mode; switch instantly in ffa-mode.
|
||||
if can_switch_teams:
|
||||
_gameutils.animate_array(self.icon, 'tint_color', 3, {
|
||||
animate_array(self.icon, 'tint_color', 3, {
|
||||
0: self.icon.tint_color,
|
||||
0.1: clr
|
||||
})
|
||||
@ -963,10 +905,9 @@ class Lobby:
|
||||
for chooser in self.choosers:
|
||||
try:
|
||||
chooser.reload_profiles()
|
||||
chooser.update_from_player_profiles()
|
||||
chooser.update_from_profile()
|
||||
except Exception:
|
||||
from ba import _error
|
||||
_error.print_exception('error reloading profiles')
|
||||
print_exception('Error reloading profiles.')
|
||||
|
||||
def update_positions(self) -> None:
|
||||
"""Update positions for all choosers."""
|
||||
@ -1005,11 +946,9 @@ class Lobby:
|
||||
self.choosers.remove(chooser)
|
||||
break
|
||||
if not found:
|
||||
from ba import _error
|
||||
_error.print_error(f'remove_chooser did not find player {player}')
|
||||
print_error(f'remove_chooser did not find player {player}')
|
||||
elif chooser in self.choosers:
|
||||
from ba import _error
|
||||
_error.print_error(f'chooser remains after removal for {player}')
|
||||
print_error(f'chooser remains after removal for {player}')
|
||||
self.update_positions()
|
||||
|
||||
def remove_all_choosers(self) -> None:
|
||||
|
||||
@ -44,14 +44,14 @@ class PowerupMessage:
|
||||
The type of powerup to be granted (a string).
|
||||
See ba.Powerup.poweruptype for available type values.
|
||||
|
||||
source_node
|
||||
sourcenode
|
||||
The node the powerup game from, or None otherwise.
|
||||
If a powerup is accepted, a ba.PowerupAcceptMessage should be sent
|
||||
back to the source_node to inform it of the fact. This will generally
|
||||
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
|
||||
source_node: Optional[ba.Node] = None
|
||||
sourcenode: Optional[ba.Node] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
|
||||
@ -224,12 +224,12 @@ class Session:
|
||||
# Print a rejection message *only* to the client trying to
|
||||
# join (prevents spamming everyone else in the game).
|
||||
_ba.playsound(_ba.getsound('error'))
|
||||
_ba.screenmessage(
|
||||
Lstr(resource='playerLimitReachedText',
|
||||
subs=[('${COUNT}', str(self.max_players))]),
|
||||
color=(0.8, 0.0, 0.0),
|
||||
clients=[player.get_input_device().client_id],
|
||||
transient=True)
|
||||
_ba.screenmessage(Lstr(resource='playerLimitReachedText',
|
||||
subs=[('${COUNT}',
|
||||
str(self.max_players))]),
|
||||
color=(0.8, 0.0, 0.0),
|
||||
clients=[player.inputdevice.client_id],
|
||||
transient=True)
|
||||
return False
|
||||
|
||||
_ba.playsound(_ba.getsound('dripity'))
|
||||
|
||||
@ -601,7 +601,7 @@ class Blast(ba.Actor):
|
||||
self.node.delete()
|
||||
|
||||
elif isinstance(msg, ExplodeHitMessage):
|
||||
node = ba.getcollision().opposing_node
|
||||
node = ba.getcollision().opposingnode
|
||||
assert self.node
|
||||
nodepos = self.node.position
|
||||
mag = 2000.0
|
||||
@ -843,7 +843,7 @@ class Bomb(ba.Actor):
|
||||
self.handlemessage(ba.DieMessage())
|
||||
|
||||
def _handle_impact(self) -> None:
|
||||
node = ba.getcollision().opposing_node
|
||||
node = ba.getcollision().opposingnode
|
||||
|
||||
# If we're an impact bomb and we came from this node, don't explode...
|
||||
# alternately if we're hitting another impact-bomb from the same
|
||||
@ -875,7 +875,7 @@ class Bomb(ba.Actor):
|
||||
lambda: _safesetattr(self.node, 'stick_to_owner', True))
|
||||
|
||||
def _handle_splat(self) -> None:
|
||||
node = ba.getcollision().opposing_node
|
||||
node = ba.getcollision().opposingnode
|
||||
if (node is not self.owner
|
||||
and ba.time() - self._last_sticky_sound_time > 1.0):
|
||||
self._last_sticky_sound_time = ba.time()
|
||||
|
||||
@ -264,16 +264,14 @@ class ControlsGuide(ba.Actor):
|
||||
|
||||
# If we have a touchscreen, we only fade in if we have a player with
|
||||
# an input device that is *not* the touchscreen.
|
||||
touchscreen: Optional[ba.InputDevice] = _ba.get_input_device(
|
||||
touchscreen: Optional[ba.InputDevice] = _ba.getinputdevice(
|
||||
'TouchScreen', '#1', doraise=False)
|
||||
|
||||
if touchscreen is not None:
|
||||
# We look at the session's players; not the activity's.
|
||||
# We want to get ones who are still in the process of
|
||||
# selecting a character, etc.
|
||||
input_devices = [
|
||||
p.get_input_device() for p in ba.getsession().players
|
||||
]
|
||||
input_devices = [p.inputdevice for p in ba.getsession().players]
|
||||
input_devices = [
|
||||
i for i in input_devices if i and i is not touchscreen
|
||||
]
|
||||
@ -325,13 +323,13 @@ class ControlsGuide(ba.Actor):
|
||||
|
||||
# We look at the session's players; not the activity's - we want to
|
||||
# get ones who are still in the process of selecting a character, etc.
|
||||
input_devices = [p.get_input_device() for p in ba.getsession().players]
|
||||
input_devices = [p.inputdevice for p in ba.getsession().players]
|
||||
input_devices = [i for i in input_devices if i]
|
||||
|
||||
# If there's no players with input devices yet, try to default to
|
||||
# showing keyboard controls.
|
||||
if not input_devices:
|
||||
kbd = _ba.get_input_device('Keyboard', '#1', doraise=False)
|
||||
kbd = _ba.getinputdevice('Keyboard', '#1', doraise=False)
|
||||
if kbd is not None:
|
||||
input_devices.append(kbd)
|
||||
|
||||
|
||||
@ -305,9 +305,9 @@ class PowerupBox(ba.Actor):
|
||||
|
||||
elif isinstance(msg, _TouchedMessage):
|
||||
if not self._powersgiven:
|
||||
node = ba.getcollision().opposing_node
|
||||
node = ba.getcollision().opposingnode
|
||||
node.handlemessage(
|
||||
ba.PowerupMessage(self.poweruptype, source_node=self.node))
|
||||
ba.PowerupMessage(self.poweruptype, sourcenode=self.node))
|
||||
|
||||
elif isinstance(msg, ba.DieMessage):
|
||||
if self.node:
|
||||
|
||||
@ -851,8 +851,8 @@ class Spaz(ba.Actor):
|
||||
self._num_times_hit = 0
|
||||
|
||||
self.node.handlemessage('flash')
|
||||
if msg.source_node:
|
||||
msg.source_node.handlemessage(ba.PowerupAcceptMessage())
|
||||
if msg.sourcenode:
|
||||
msg.sourcenode.handlemessage(ba.PowerupAcceptMessage())
|
||||
return True
|
||||
|
||||
elif isinstance(msg, ba.FreezeMessage):
|
||||
@ -1143,7 +1143,7 @@ class Spaz(ba.Actor):
|
||||
elif isinstance(msg, PunchHitMessage):
|
||||
if not self.node:
|
||||
return None
|
||||
node = ba.getcollision().opposing_node
|
||||
node = ba.getcollision().opposingnode
|
||||
|
||||
# Only allow one hit per node per punch.
|
||||
if node and (node not in self._punched_nodes):
|
||||
@ -1204,23 +1204,23 @@ class Spaz(ba.Actor):
|
||||
|
||||
try:
|
||||
collision = ba.getcollision()
|
||||
opposing_node = collision.opposing_node
|
||||
opposing_body = collision.opposing_body
|
||||
opposingnode = collision.opposingnode
|
||||
opposingbody = collision.opposingbody
|
||||
except ba.NotFoundError:
|
||||
return True
|
||||
|
||||
# Don't allow picking up of invincible dudes.
|
||||
try:
|
||||
if opposing_node.invincible:
|
||||
if opposingnode.invincible:
|
||||
return True
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# If we're grabbing the pelvis of a non-shattered spaz, we wanna
|
||||
# grab the torso instead.
|
||||
if (opposing_node.getnodetype() == 'spaz'
|
||||
and not opposing_node.shattered and opposing_body == 4):
|
||||
opposing_body = 1
|
||||
if (opposingnode.getnodetype() == 'spaz'
|
||||
and not opposingnode.shattered and opposingbody == 4):
|
||||
opposingbody = 1
|
||||
|
||||
# Special case - if we're holding a flag, don't replace it
|
||||
# (hmm - should make this customizable or more low level).
|
||||
@ -1229,8 +1229,8 @@ class Spaz(ba.Actor):
|
||||
return True
|
||||
|
||||
# Note: hold_body needs to be set before hold_node.
|
||||
self.node.hold_body = opposing_body
|
||||
self.node.hold_node = opposing_node
|
||||
self.node.hold_body = opposingbody
|
||||
self.node.hold_node = opposingnode
|
||||
elif isinstance(msg, ba.CelebrateMessage):
|
||||
if self.node:
|
||||
self.node.handlemessage('celebrate', int(msg.duration * 1000))
|
||||
|
||||
@ -179,7 +179,7 @@ class AssaultGame(ba.TeamGameActivity[Player, Team]):
|
||||
ba.timer(length, light.delete)
|
||||
|
||||
def _handle_base_collide(self, team: Team) -> None:
|
||||
player = ba.getcollision().opposing_node.getdelegate(
|
||||
player = ba.getcollision().opposingnode.getdelegate(
|
||||
PlayerSpaz, True).getplayer(Player)
|
||||
if not player or not player.is_alive():
|
||||
return
|
||||
|
||||
@ -158,9 +158,9 @@ class CaptureTheFlagGame(ba.TeamGameActivity[Player, Team]):
|
||||
self._scoreboard = Scoreboard()
|
||||
self._alarmsound = ba.getsound('alarm')
|
||||
self._ticking_sound = ba.getsound('ticking')
|
||||
self._last_score_time = 0
|
||||
self._score_sound = ba.getsound('score')
|
||||
self._swipsound = ba.getsound('swip')
|
||||
self._last_score_time = 0
|
||||
self._all_bases_material = ba.Material()
|
||||
self._last_home_flag_notice_print_time = 0.0
|
||||
self._score_to_win = int(settings['Score to Win'])
|
||||
@ -237,20 +237,22 @@ class CaptureTheFlagGame(ba.TeamGameActivity[Player, Team]):
|
||||
))
|
||||
|
||||
# Other parts of our spazzes don't collide with our flags at all.
|
||||
spaz_mat_no_flag_collide.add_actions(conditions=('they_have_material',
|
||||
flagmat),
|
||||
actions=('modify_part_collision',
|
||||
'collide', False))
|
||||
spaz_mat_no_flag_collide.add_actions(
|
||||
conditions=('they_have_material', flagmat),
|
||||
actions=('modify_part_collision', 'collide', False),
|
||||
)
|
||||
|
||||
# We wanna know when *any* flag enters/leaves our base.
|
||||
base_region_mat.add_actions(
|
||||
conditions=('they_have_material', FlagFactory.get().flagmaterial),
|
||||
actions=(('modify_part_collision', 'collide',
|
||||
True), ('modify_part_collision', 'physical', False),
|
||||
('call', 'at_connect',
|
||||
lambda: self._handle_flag_entered_base(team)),
|
||||
('call', 'at_disconnect',
|
||||
lambda: self._handle_flag_left_base(team))))
|
||||
actions=(
|
||||
('modify_part_collision', 'collide', True),
|
||||
('modify_part_collision', 'physical', False),
|
||||
('call', 'at_connect',
|
||||
lambda: self._handle_flag_entered_base(team)),
|
||||
('call', 'at_disconnect',
|
||||
lambda: self._handle_flag_left_base(team)),
|
||||
))
|
||||
|
||||
return team
|
||||
|
||||
@ -274,7 +276,7 @@ class CaptureTheFlagGame(ba.TeamGameActivity[Player, Team]):
|
||||
ba.playsound(self._swipsound, position=team.flag.node.position)
|
||||
|
||||
def _handle_flag_entered_base(self, team: Team) -> None:
|
||||
flag = CTFFlag.from_node(ba.getcollision().opposing_node)
|
||||
flag = CTFFlag.from_node(ba.getcollision().opposingnode)
|
||||
if not flag:
|
||||
print('Unable to get flag in _handle_flag_entered_base')
|
||||
return
|
||||
@ -362,7 +364,7 @@ class CaptureTheFlagGame(ba.TeamGameActivity[Player, Team]):
|
||||
self._flash_base(team)
|
||||
self._update_scoreboard()
|
||||
|
||||
# Have teammates celebrate
|
||||
# Have teammates celebrate.
|
||||
for player in team.players:
|
||||
if player.actor:
|
||||
player.actor.handlemessage(ba.CelebrateMessage(2.0))
|
||||
@ -385,7 +387,7 @@ class CaptureTheFlagGame(ba.TeamGameActivity[Player, Team]):
|
||||
def _handle_flag_left_base(self, team: Team) -> None:
|
||||
cur_time = ba.time()
|
||||
try:
|
||||
flag = CTFFlag.from_node(ba.getcollision().opposing_node)
|
||||
flag = CTFFlag.from_node(ba.getcollision().opposingnode)
|
||||
except ba.NodeNotFoundError:
|
||||
# We still get this call even if the flag stopped touching us
|
||||
# because it was deleted; that's ok.
|
||||
@ -447,11 +449,12 @@ class CaptureTheFlagGame(ba.TeamGameActivity[Player, Team]):
|
||||
return None if delegate is None else delegate.getplayer(Player)
|
||||
|
||||
def _handle_hit_own_flag(self, team: Team, val: int) -> None:
|
||||
"""Called when a player touches their own team flag.
|
||||
|
||||
We keep track of when each player is touching their
|
||||
own flag so we can award points when returned.
|
||||
"""
|
||||
keep track of when each player is touching their
|
||||
own flag so we can award points when returned
|
||||
"""
|
||||
player = self._player_from_node(ba.getcollision().source_node)
|
||||
player = self._player_from_node(ba.getcollision().sourcenode)
|
||||
if player:
|
||||
player.touching_own_flag += (1 if val else -1)
|
||||
|
||||
@ -464,7 +467,7 @@ class CaptureTheFlagGame(ba.TeamGameActivity[Player, Team]):
|
||||
# Use a node message to kill the flag instead of just killing
|
||||
# our team's. (avoids redundantly killing new flags if
|
||||
# multiple body parts generate callbacks in one step).
|
||||
node = ba.getcollision().opposing_node
|
||||
node = ba.getcollision().opposingnode
|
||||
self._award_players_touching_own_flag(team)
|
||||
node.handlemessage(ba.DieMessage())
|
||||
|
||||
@ -484,8 +487,7 @@ class CaptureTheFlagGame(ba.TeamGameActivity[Player, Team]):
|
||||
team.touch_return_timer = None
|
||||
team.touch_return_timer_ticking = None
|
||||
if team.flag_return_touches < 0:
|
||||
ba.print_error(
|
||||
"CTF: flag_return_touches < 0; this shouldn't happen.")
|
||||
ba.print_error('CTF flag_return_touches < 0')
|
||||
|
||||
def _flash_base(self, team: Team, length: float = 2.0) -> None:
|
||||
light = ba.newnode('light',
|
||||
@ -536,13 +538,15 @@ class CaptureTheFlagGame(ba.TeamGameActivity[Player, Team]):
|
||||
self._score_to_win)
|
||||
|
||||
def handlemessage(self, msg: Any) -> Any:
|
||||
|
||||
if isinstance(msg, ba.PlayerDiedMessage):
|
||||
# Augment standard behavior.
|
||||
super().handlemessage(msg)
|
||||
super().handlemessage(msg) # Augment standard behavior.
|
||||
self.respawn_player(msg.getplayer(Player))
|
||||
|
||||
elif isinstance(msg, FlagDiedMessage):
|
||||
assert isinstance(msg.flag, CTFFlag)
|
||||
ba.timer(0.1, ba.Call(self._spawn_flag_for_team, msg.flag.team))
|
||||
|
||||
elif isinstance(msg, FlagPickedUpMessage):
|
||||
# Store the last player to hold the flag for scoring purposes.
|
||||
assert isinstance(msg.flag, CTFFlag)
|
||||
@ -550,9 +554,11 @@ class CaptureTheFlagGame(ba.TeamGameActivity[Player, Team]):
|
||||
PlayerSpaz, True).getplayer(Player)
|
||||
msg.flag.held_count += 1
|
||||
msg.flag.reset_return_times()
|
||||
|
||||
elif isinstance(msg, FlagDroppedMessage):
|
||||
# Store the last player to hold the flag for scoring purposes.
|
||||
assert isinstance(msg.flag, CTFFlag)
|
||||
msg.flag.held_count -= 1
|
||||
|
||||
else:
|
||||
super().handlemessage(msg)
|
||||
|
||||
@ -177,7 +177,7 @@ class ChosenOneGame(ba.TeamGameActivity[Player, Team]):
|
||||
# If we have a chosen one, ignore these.
|
||||
if self._get_chosen_one_player() is not None:
|
||||
return
|
||||
player = ba.getcollision().opposing_node.getdelegate(
|
||||
player = ba.getcollision().opposingnode.getdelegate(
|
||||
PlayerSpaz, True).getplayer(Player)
|
||||
if player is not None and player.is_alive():
|
||||
self._set_chosen_one_player(player)
|
||||
|
||||
@ -235,9 +235,9 @@ class ConquestGame(ba.TeamGameActivity[Player, Team]):
|
||||
|
||||
def _handle_flag_player_collide(self) -> None:
|
||||
collision = ba.getcollision()
|
||||
flag = collision.source_node.getdelegate(ConquestFlag)
|
||||
player = collision.opposing_node.getdelegate(PlayerSpaz,
|
||||
True).getplayer(Player)
|
||||
flag = collision.sourcenode.getdelegate(ConquestFlag)
|
||||
player = collision.opposingnode.getdelegate(PlayerSpaz,
|
||||
True).getplayer(Player)
|
||||
if not flag or not player:
|
||||
return
|
||||
assert flag.light
|
||||
|
||||
@ -137,9 +137,9 @@ class EasterEggHuntGame(ba.TeamGameActivity[Player, Team]):
|
||||
if self.has_ended():
|
||||
return
|
||||
collision = ba.getcollision()
|
||||
egg = collision.source_node.getdelegate(Egg)
|
||||
player = collision.opposing_node.getdelegate(PlayerSpaz,
|
||||
True).getplayer(Player)
|
||||
egg = collision.sourcenode.getdelegate(Egg)
|
||||
player = collision.opposingnode.getdelegate(PlayerSpaz,
|
||||
True).getplayer(Player)
|
||||
if player and egg:
|
||||
player.team.score += 1
|
||||
|
||||
|
||||
@ -209,7 +209,7 @@ class FootballTeamGame(ba.TeamGameActivity[Player, Team]):
|
||||
assert self._flag is not None
|
||||
if self._flag.scored:
|
||||
return
|
||||
region = ba.getcollision().source_node
|
||||
region = ba.getcollision().sourcenode
|
||||
i = None
|
||||
for i in range(len(self._score_regions)):
|
||||
if region == self._score_regions[i].node:
|
||||
@ -654,7 +654,7 @@ class FootballCoopGame(ba.CoopGameActivity[Player, Team]):
|
||||
return
|
||||
|
||||
# See which score region it was.
|
||||
region = ba.getcollision().source_node
|
||||
region = ba.getcollision().sourcenode
|
||||
i = None
|
||||
for i in range(len(self._score_regions)):
|
||||
if region == self._score_regions[i].node:
|
||||
|
||||
@ -245,9 +245,9 @@ class HockeyGame(ba.TeamGameActivity[Player, Team]):
|
||||
|
||||
def _handle_puck_player_collide(self) -> None:
|
||||
collision = ba.getcollision()
|
||||
puck = collision.source_node.getdelegate(Puck)
|
||||
player = collision.opposing_node.getdelegate(PlayerSpaz,
|
||||
True).getplayer(Player)
|
||||
puck = collision.sourcenode.getdelegate(Puck)
|
||||
player = collision.opposingnode.getdelegate(PlayerSpaz,
|
||||
True).getplayer(Player)
|
||||
if player and puck:
|
||||
puck.last_players_to_touch[player.team.id] = player
|
||||
|
||||
@ -265,7 +265,7 @@ class HockeyGame(ba.TeamGameActivity[Player, Team]):
|
||||
if self._puck.scored:
|
||||
return
|
||||
|
||||
region = ba.getcollision().source_node
|
||||
region = ba.getcollision().sourcenode
|
||||
index = 0
|
||||
for index in range(len(self._score_regions)):
|
||||
if region == self._score_regions[index].node:
|
||||
|
||||
@ -247,7 +247,7 @@ class KingOfTheHillGame(ba.TeamGameActivity[Player, Team]):
|
||||
ba.playsound(self._swipsound)
|
||||
|
||||
def _handle_player_flag_region_collide(self, colliding: bool) -> None:
|
||||
player = ba.getcollision().opposing_node.getdelegate(
|
||||
player = ba.getcollision().opposingnode.getdelegate(
|
||||
PlayerSpaz, True).getplayer(Player)
|
||||
if not player:
|
||||
return
|
||||
|
||||
@ -227,9 +227,9 @@ class RaceGame(ba.TeamGameActivity[Player, Team]):
|
||||
# pylint: disable=too-many-branches
|
||||
# pylint: disable=too-many-nested-blocks
|
||||
collision = ba.getcollision()
|
||||
region = collision.source_node.getdelegate(RaceRegion)
|
||||
playerspaz = collision.opposing_node.getdelegate(PlayerSpaz,
|
||||
doraise=False)
|
||||
region = collision.sourcenode.getdelegate(RaceRegion)
|
||||
playerspaz = collision.opposingnode.getdelegate(PlayerSpaz,
|
||||
doraise=False)
|
||||
player = playerspaz.getplayer(Player) if playerspaz else None
|
||||
if not player or not region:
|
||||
return
|
||||
|
||||
@ -406,7 +406,7 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]):
|
||||
ba.timer(2.0, self._start_updating_waves)
|
||||
|
||||
def _handle_reached_end(self) -> None:
|
||||
spaz = ba.getcollision().opposing_node.getdelegate(SpazBot, True)
|
||||
spaz = ba.getcollision().opposingnode.getdelegate(SpazBot, True)
|
||||
if not spaz.is_alive():
|
||||
return # Ignore bodies flying in.
|
||||
|
||||
|
||||
@ -91,7 +91,7 @@ class ControlsSettingsWindow(ba.Window):
|
||||
height += space_height
|
||||
|
||||
show_keyboard = False
|
||||
if _ba.get_input_device('Keyboard', '#1', doraise=False) is not None:
|
||||
if _ba.getinputdevice('Keyboard', '#1', doraise=False) is not None:
|
||||
show_keyboard = True
|
||||
height += spacing * 2
|
||||
show_keyboard_p2 = False if app.vr_mode else show_keyboard
|
||||
@ -393,7 +393,7 @@ class ControlsSettingsWindow(ba.Window):
|
||||
self._save_state()
|
||||
ba.containerwidget(edit=self._root_widget, transition='out_left')
|
||||
ba.app.main_menu_window = (keyboard.ConfigKeyboardWindow(
|
||||
_ba.get_input_device('Keyboard', '#1')).get_root_widget())
|
||||
_ba.getinputdevice('Keyboard', '#1')).get_root_widget())
|
||||
|
||||
def _config_keyboard2(self) -> None:
|
||||
# pylint: disable=cyclic-import
|
||||
@ -401,7 +401,7 @@ class ControlsSettingsWindow(ba.Window):
|
||||
self._save_state()
|
||||
ba.containerwidget(edit=self._root_widget, transition='out_left')
|
||||
ba.app.main_menu_window = (keyboard.ConfigKeyboardWindow(
|
||||
_ba.get_input_device('Keyboard', '#2')).get_root_widget())
|
||||
_ba.getinputdevice('Keyboard', '#2')).get_root_widget())
|
||||
|
||||
def _do_mobile_devices(self) -> None:
|
||||
# pylint: disable=cyclic-import
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<!-- THIS FILE IS AUTO GENERATED; DO NOT EDIT BY HAND -->
|
||||
<h4><em>last updated on 2020-05-25 for Ballistica version 1.5.0 build 20027</em></h4>
|
||||
<h4><em>last updated on 2020-05-25 for Ballistica version 1.5.0 build 20028</em></h4>
|
||||
<p>This page documents the Python classes and functions in the 'ba' module,
|
||||
which are the ones most relevant to modding in Ballistica. If you come across something you feel should be included here or could be better explained, please <a href="mailto:support@froemling.net">let me know</a>. Happy modding!</p>
|
||||
<hr>
|
||||
@ -189,6 +189,7 @@
|
||||
<ul>
|
||||
<li><a href="#class_ba_ActivityNotFoundError">ba.ActivityNotFoundError</a></li>
|
||||
<li><a href="#class_ba_ActorNotFoundError">ba.ActorNotFoundError</a></li>
|
||||
<li><a href="#class_ba_DelegateNotFoundError">ba.DelegateNotFoundError</a></li>
|
||||
<li><a href="#class_ba_InputDeviceNotFoundError">ba.InputDeviceNotFoundError</a></li>
|
||||
<li><a href="#class_ba_NodeNotFoundError">ba.NodeNotFoundError</a></li>
|
||||
<li><a href="#class_ba_PlayerNotFoundError">ba.PlayerNotFoundError</a></li>
|
||||
@ -918,7 +919,7 @@ likely result in errors.</p>
|
||||
<dt><h4><a name="method_ba_App__launch_coop_game">launch_coop_game()</a></dt></h4><dd>
|
||||
<p><span>launch_coop_game(self, game: str, force: bool = False, args: Dict = None) -> bool</span></p>
|
||||
|
||||
<p>High level way to launch a co-op session locally.</p>
|
||||
<p>High level way to launch a local co-op session.</p>
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="method_ba_App__on_app_pause">on_app_pause()</a></dt></h4><dd>
|
||||
@ -1298,7 +1299,7 @@ mycall()</pre>
|
||||
</dd>
|
||||
</dl>
|
||||
<h3>Methods:</h3>
|
||||
<h5><a href="#method_ba_Chooser____init__"><constructor></a>, <a href="#method_ba_Chooser__get_character_name">get_character_name()</a>, <a href="#method_ba_Chooser__get_color">get_color()</a>, <a href="#method_ba_Chooser__get_highlight">get_highlight()</a>, <a href="#method_ba_Chooser__get_lobby">get_lobby()</a>, <a href="#method_ba_Chooser__get_team">get_team()</a>, <a href="#method_ba_Chooser__getplayer">getplayer()</a>, <a href="#method_ba_Chooser__handlemessage">handlemessage()</a>, <a href="#method_ba_Chooser__reload_profiles">reload_profiles()</a>, <a href="#method_ba_Chooser__update_from_player_profiles">update_from_player_profiles()</a>, <a href="#method_ba_Chooser__update_position">update_position()</a></h5>
|
||||
<h5><a href="#method_ba_Chooser____init__"><constructor></a>, <a href="#method_ba_Chooser__get_character_name">get_character_name()</a>, <a href="#method_ba_Chooser__get_color">get_color()</a>, <a href="#method_ba_Chooser__get_highlight">get_highlight()</a>, <a href="#method_ba_Chooser__get_lobby">get_lobby()</a>, <a href="#method_ba_Chooser__get_team">get_team()</a>, <a href="#method_ba_Chooser__getplayer">getplayer()</a>, <a href="#method_ba_Chooser__handlemessage">handlemessage()</a>, <a href="#method_ba_Chooser__reload_profiles">reload_profiles()</a>, <a href="#method_ba_Chooser__update_from_profile">update_from_profile()</a>, <a href="#method_ba_Chooser__update_position">update_position()</a></h5>
|
||||
<dl>
|
||||
<dt><h4><a name="method_ba_Chooser____init__"><constructor></a></dt></h4><dd>
|
||||
<p><span>ba.Chooser(vpos: float, player: _<a href="#class_ba_SessionPlayer">ba.SessionPlayer</a>, lobby: "Lobby")</span></p>
|
||||
@ -1352,10 +1353,10 @@ mycall()</pre>
|
||||
<p>Reload all player profiles.</p>
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="method_ba_Chooser__update_from_player_profiles">update_from_player_profiles()</a></dt></h4><dd>
|
||||
<p><span>update_from_player_profiles(self) -> None</span></p>
|
||||
<dt><h4><a name="method_ba_Chooser__update_from_profile">update_from_profile()</a></dt></h4><dd>
|
||||
<p><span>update_from_profile(self) -> None</span></p>
|
||||
|
||||
<p>Set character based on profile; otherwise use pre-picked random.</p>
|
||||
<p>Set character/colors based on the current profile.</p>
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="method_ba_Chooser__update_position">update_position()</a></dt></h4><dd>
|
||||
@ -1382,14 +1383,14 @@ mycall()</pre>
|
||||
<p>A class providing info about occurring collisions.</p>
|
||||
|
||||
<h3>Attributes:</h3>
|
||||
<h5><a href="#attr_ba_Collision__opposing_body">opposing_body</a>, <a href="#attr_ba_Collision__opposing_node">opposing_node</a>, <a href="#attr_ba_Collision__position">position</a>, <a href="#attr_ba_Collision__source_node">source_node</a></h5>
|
||||
<h5><a href="#attr_ba_Collision__opposingbody">opposingbody</a>, <a href="#attr_ba_Collision__opposingnode">opposingnode</a>, <a href="#attr_ba_Collision__position">position</a>, <a href="#attr_ba_Collision__sourcenode">sourcenode</a></h5>
|
||||
<dl>
|
||||
<dt><h4><a name="attr_ba_Collision__opposing_body">opposing_body</a></h4></dt><dd>
|
||||
<dt><h4><a name="attr_ba_Collision__opposingbody">opposingbody</a></h4></dt><dd>
|
||||
<p><span>int</span></p>
|
||||
<p>The body index on the opposing node in the current collision.</p>
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="attr_ba_Collision__opposing_node">opposing_node</a></h4></dt><dd>
|
||||
<dt><h4><a name="attr_ba_Collision__opposingnode">opposingnode</a></h4></dt><dd>
|
||||
<p><span><a href="#class_ba_Node">ba.Node</a></span></p>
|
||||
<p>The node the current callback material node is hitting.</p>
|
||||
|
||||
@ -1403,7 +1404,7 @@ mycall()</pre>
|
||||
<p>The position of the current collision.</p>
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="attr_ba_Collision__source_node">source_node</a></h4></dt><dd>
|
||||
<dt><h4><a name="attr_ba_Collision__sourcenode">sourcenode</a></h4></dt><dd>
|
||||
<p><span><a href="#class_ba_Node">ba.Node</a></span></p>
|
||||
<p>The node containing the material triggering the current callback.</p>
|
||||
|
||||
@ -1734,6 +1735,16 @@ the data object is requested and when it's value is accessed.</p>
|
||||
<li>LEFT_GAME</li>
|
||||
</ul>
|
||||
<hr>
|
||||
<h2><strong><a name="class_ba_DelegateNotFoundError">ba.DelegateNotFoundError</a></strong></h3>
|
||||
<p>Inherits from: <a href="#class_ba_NotFoundError">ba.NotFoundError</a>, Exception, BaseException</p>
|
||||
<p>Exception raised when an expected delegate object does not exist.</p>
|
||||
|
||||
<p>Category: <a href="#class_category_Exception_Classes">Exception Classes</a>
|
||||
</p>
|
||||
|
||||
<h3>Methods:</h3>
|
||||
<p><all methods inherited from <a href="#class_ba_NotFoundError">ba.NotFoundError</a>></p>
|
||||
<hr>
|
||||
<h2><strong><a name="class_ba_Dependency">ba.Dependency</a></strong></h3>
|
||||
<p>Inherits from: <a href="#class_typing_Generic">typing.Generic</a></p>
|
||||
<p>A dependency on a DependencyComponent (with an optional config).</p>
|
||||
@ -3569,8 +3580,8 @@ loc.connectattr('position', light, 'position')</pre>
|
||||
<dt><h4><a name="method_ba_Node__delete">delete()</a></dt></h4><dd>
|
||||
<p><span>delete(ignore_missing: bool = True) -> None</span></p>
|
||||
|
||||
<p>Delete the node. Ignores already-deleted nodes unless ignore_missing
|
||||
is False, in which case an Exception is thrown.</p>
|
||||
<p>Delete the node. Ignores already-deleted nodes if ignore_missing
|
||||
is True; otherwise a <a href="#class_ba_NodeNotFoundError">ba.NodeNotFoundError</a> is thrown.</p>
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="method_ba_Node__exists">exists()</a></dt></h4><dd>
|
||||
@ -3598,7 +3609,7 @@ the right thing both for Node objects and values of None.</p>
|
||||
|
||||
<p>If the node has no delegate or it is not an instance of the passed
|
||||
type, then None will be returned. If 'doraise' is True, then an
|
||||
Exception will be raised instead in such cases.</p>
|
||||
<a href="#class_ba_DelegateNotFoundError">ba.DelegateNotFoundError</a> will be raised instead.</p>
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="method_ba_Node__getnodetype">getnodetype()</a></dt></h4><dd>
|
||||
@ -4094,7 +4105,7 @@ the type-checker properly identifies the returned value as one.</p>
|
||||
<p> This message is normally received by touching a ba.PowerupBox.</p>
|
||||
|
||||
<h3>Attributes:</h3>
|
||||
<h5><a href="#attr_ba_PowerupMessage__poweruptype">poweruptype</a>, <a href="#attr_ba_PowerupMessage__source_node">source_node</a></h5>
|
||||
<h5><a href="#attr_ba_PowerupMessage__poweruptype">poweruptype</a>, <a href="#attr_ba_PowerupMessage__sourcenode">sourcenode</a></h5>
|
||||
<dl>
|
||||
<dt><h4><a name="attr_ba_PowerupMessage__poweruptype">poweruptype</a></h4></dt><dd>
|
||||
<p><span>str</span></p>
|
||||
@ -4102,11 +4113,11 @@ the type-checker properly identifies the returned value as one.</p>
|
||||
See ba.Powerup.poweruptype for available type values.</p>
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="attr_ba_PowerupMessage__source_node">source_node</a></h4></dt><dd>
|
||||
<dt><h4><a name="attr_ba_PowerupMessage__sourcenode">sourcenode</a></h4></dt><dd>
|
||||
<p><span>Optional[<a href="#class_ba_Node">ba.Node</a>]</span></p>
|
||||
<p>The node the powerup game from, or None otherwise.
|
||||
If a powerup is accepted, a <a href="#class_ba_PowerupAcceptMessage">ba.PowerupAcceptMessage</a> should be sent
|
||||
back to the source_node to inform it of the fact. This will generally
|
||||
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.</p>
|
||||
|
||||
</dd>
|
||||
@ -4114,7 +4125,7 @@ cause the powerup box to make a sound and disappear or whatnot.</p>
|
||||
<h3>Methods:</h3>
|
||||
<dl>
|
||||
<dt><h4><a name="method_ba_PowerupMessage____init__"><constructor></a></dt></h4><dd>
|
||||
<p><span>ba.PowerupMessage(poweruptype: str, source_node: Optional[<a href="#class_ba_Node">ba.Node</a>] = None)</span></p>
|
||||
<p><span>ba.PowerupMessage(poweruptype: str, sourcenode: Optional[<a href="#class_ba_Node">ba.Node</a>] = None)</span></p>
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
@ -4443,7 +4454,7 @@ 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__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__inputdevice">inputdevice</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>
|
||||
@ -4490,6 +4501,11 @@ the right thing both for Player objects and values of None.</p>
|
||||
<p>This bool value will be True once the Player has completed
|
||||
any lobby character/team selection.</p>
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="attr_ba_SessionPlayer__inputdevice">inputdevice</a></h4></dt><dd>
|
||||
<p><span> <a href="#class_ba_InputDevice">ba.InputDevice</a></span></p>
|
||||
<p>The input device associated with the player.</p>
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="attr_ba_SessionPlayer__sessiondata">sessiondata</a></h4></dt><dd>
|
||||
<p><span> Dict</span></p>
|
||||
@ -4507,7 +4523,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__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>
|
||||
<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_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, ...]],
|
||||
@ -4544,12 +4560,6 @@ joins (while verification occurs).</p>
|
||||
|
||||
<p>Returns the character's icon (images, colors, etc contained in a dict)</p>
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="method_ba_SessionPlayer__get_input_device">get_input_device()</a></dt></h4><dd>
|
||||
<p><span>get_input_device() -> <a href="#class_ba_InputDevice">ba.InputDevice</a></span></p>
|
||||
|
||||
<p>Returns the player's input device.</p>
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="method_ba_SessionPlayer__get_name">get_name()</a></dt></h4><dd>
|
||||
<p><span>get_name(full: bool = False, icon: bool = True) -> str</span></p>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user