mirror of
https://github.com/RYDE-WORK/ballistica.git
synced 2026-01-23 15:33:26 +08:00
Restored NodeActor, tidying, minor gameplay fixes.
This commit is contained in:
parent
3e7ed8c0e3
commit
bc600f602e
2
.idea/dictionaries/ericf.xml
generated
2
.idea/dictionaries/ericf.xml
generated
@ -479,6 +479,7 @@
|
||||
<w>dxml</w>
|
||||
<w>dynload</w>
|
||||
<w>eachother</w>
|
||||
<w>eaddrnotavail</w>
|
||||
<w>easteregghunt</w>
|
||||
<w>edcc</w>
|
||||
<w>editcontroller</w>
|
||||
@ -1132,6 +1133,7 @@
|
||||
<w>nline</w>
|
||||
<w>nlines</w>
|
||||
<w>nntplib</w>
|
||||
<w>nodeactor</w>
|
||||
<w>nodepos</w>
|
||||
<w>nodpi</w>
|
||||
<w>nofiles</w>
|
||||
|
||||
@ -35,6 +35,7 @@
|
||||
"ba_data/python/ba/__pycache__/_modutils.cpython-37.opt-1.pyc",
|
||||
"ba_data/python/ba/__pycache__/_music.cpython-37.opt-1.pyc",
|
||||
"ba_data/python/ba/__pycache__/_netutils.cpython-37.opt-1.pyc",
|
||||
"ba_data/python/ba/__pycache__/_nodeactor.cpython-37.opt-1.pyc",
|
||||
"ba_data/python/ba/__pycache__/_playlist.cpython-37.opt-1.pyc",
|
||||
"ba_data/python/ba/__pycache__/_powerup.cpython-37.opt-1.pyc",
|
||||
"ba_data/python/ba/__pycache__/_profile.cpython-37.opt-1.pyc",
|
||||
@ -84,6 +85,7 @@
|
||||
"ba_data/python/ba/_modutils.py",
|
||||
"ba_data/python/ba/_music.py",
|
||||
"ba_data/python/ba/_netutils.py",
|
||||
"ba_data/python/ba/_nodeactor.py",
|
||||
"ba_data/python/ba/_playlist.py",
|
||||
"ba_data/python/ba/_powerup.py",
|
||||
"ba_data/python/ba/_profile.py",
|
||||
|
||||
@ -207,6 +207,7 @@ SCRIPT_TARGETS_PY_1 = \
|
||||
build/ba_data/python/ba/_account.py \
|
||||
build/ba_data/python/ba/_music.py \
|
||||
build/ba_data/python/ba/_lang.py \
|
||||
build/ba_data/python/ba/_nodeactor.py \
|
||||
build/ba_data/python/ba/_teamgame.py \
|
||||
build/ba_data/python/ba/ui/__init__.py \
|
||||
build/ba_data/python/bastd/mainmenu.py \
|
||||
@ -444,6 +445,7 @@ SCRIPT_TARGETS_PYC_1 = \
|
||||
build/ba_data/python/ba/__pycache__/_account.cpython-37.opt-1.pyc \
|
||||
build/ba_data/python/ba/__pycache__/_music.cpython-37.opt-1.pyc \
|
||||
build/ba_data/python/ba/__pycache__/_lang.cpython-37.opt-1.pyc \
|
||||
build/ba_data/python/ba/__pycache__/_nodeactor.cpython-37.opt-1.pyc \
|
||||
build/ba_data/python/ba/__pycache__/_teamgame.cpython-37.opt-1.pyc \
|
||||
build/ba_data/python/ba/ui/__pycache__/__init__.cpython-37.opt-1.pyc \
|
||||
build/ba_data/python/bastd/__pycache__/mainmenu.cpython-37.opt-1.pyc \
|
||||
@ -953,6 +955,11 @@ build/ba_data/python/ba/__pycache__/_lang.cpython-37.opt-1.pyc: \
|
||||
@echo Compiling script: $^
|
||||
@rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@
|
||||
|
||||
build/ba_data/python/ba/__pycache__/_nodeactor.cpython-37.opt-1.pyc: \
|
||||
build/ba_data/python/ba/_nodeactor.py
|
||||
@echo Compiling script: $^
|
||||
@rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@
|
||||
|
||||
build/ba_data/python/ba/__pycache__/_teamgame.cpython-37.opt-1.pyc: \
|
||||
build/ba_data/python/ba/_teamgame.py
|
||||
@echo Compiling script: $^
|
||||
|
||||
@ -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=279775284016994471710131432123768789736
|
||||
# SOURCES_HASH=92329394206923431348342003830010439152
|
||||
|
||||
# I'm sorry Pylint. I know this file saddens you. Be strong.
|
||||
# pylint: disable=useless-suppression
|
||||
@ -161,8 +161,8 @@ class Context:
|
||||
sets the context as current on entry and resets it to the previous
|
||||
value on exit.
|
||||
|
||||
# example: load a few textures into the UI context
|
||||
# (for use in widgets, etc)
|
||||
# Example: load a few textures into the UI context
|
||||
# (for use in widgets, etc):
|
||||
with ba.Context('ui'):
|
||||
tex1 = ba.gettexture('foo_tex_1')
|
||||
tex2 = ba.gettexture('foo_tex_2')
|
||||
@ -667,7 +667,7 @@ class Node:
|
||||
target attribute to any value or connecting another node attribute
|
||||
to it.
|
||||
|
||||
# example: create a locator and attach a light to it
|
||||
# Example: create a locator and attach a light to it:
|
||||
light = ba.newnode('light')
|
||||
loc = ba.newnode('locator', attrs={'position': (0,10,0)})
|
||||
loc.connectattr('position', light, 'position')
|
||||
@ -1044,7 +1044,7 @@ class Timer:
|
||||
the 'timeformat' arg defaults to SECONDS but can also be MILLISECONDS
|
||||
if you want to pass time as milliseconds.
|
||||
|
||||
# example: use a Timer object to print repeatedly for a few seconds:
|
||||
# Example: use a Timer object to print repeatedly for a few seconds:
|
||||
def say_it():
|
||||
ba.screenmessage('BADGER!')
|
||||
def stop_saying_it():
|
||||
@ -1745,6 +1745,11 @@ def do_once() -> bool:
|
||||
logs. The call functions by registering the filename and line where
|
||||
The call is made from. Returns True if this location has not been
|
||||
registered already, and False if it has.
|
||||
|
||||
# Example: this print will only fire for the first loop iteration:
|
||||
for i in range(10):
|
||||
if ba.do_once():
|
||||
print('Hello once from loop!')
|
||||
"""
|
||||
return bool()
|
||||
|
||||
|
||||
@ -40,6 +40,7 @@ from _ba import (CollideModel, Context, ContextCall, Data, InputDevice,
|
||||
charstr, textwidget, time, timer, open_url, widget)
|
||||
from ba._activity import Activity
|
||||
from ba._actor import Actor
|
||||
from ba._nodeactor import NodeActor
|
||||
from ba._app import App
|
||||
from ba._coopgame import CoopGameActivity
|
||||
from ba._coopsession import CoopSession
|
||||
|
||||
@ -558,12 +558,12 @@ class Activity(DependencyComponent):
|
||||
|
||||
def create_player_node(self, player: ba.Player) -> ba.Node:
|
||||
"""Create the 'player' node associated with the provided ba.Player."""
|
||||
from ba import _actor
|
||||
from ba._nodeactor import NodeActor
|
||||
with _ba.Context(self):
|
||||
node = _ba.newnode('player', attrs={'playerID': player.get_id()})
|
||||
# FIXME: Should add a dedicated slot for this on ba.Player
|
||||
# instead of cluttering up their gamedata dict.
|
||||
player.gamedata['_playernode'] = _actor.Actor(node)
|
||||
player.gamedata['_playernode'] = NodeActor(node)
|
||||
return node
|
||||
|
||||
def begin(self, session: ba.Session) -> None:
|
||||
|
||||
@ -37,24 +37,25 @@ T = TypeVar('T', bound='Actor')
|
||||
class Actor:
|
||||
"""High level logical entities in a game/activity.
|
||||
|
||||
category: Gameplay Classes
|
||||
Category: Gameplay Classes
|
||||
|
||||
Actors act as controllers, combining some number of ba.Nodes,
|
||||
ba.Textures, ba.Sounds, etc. into one cohesive unit.
|
||||
ba.Textures, ba.Sounds, etc. into a high-level cohesive unit.
|
||||
|
||||
Some example actors include ba.Bomb, ba.Flag, and ba.Spaz.
|
||||
Some example actors include Bomb, Flag, and Spaz classes in bastd.
|
||||
|
||||
One key feature of Actors is that they generally 'die'
|
||||
(killing off or transitioning out their nodes) when the last Python
|
||||
reference to them disappears, so you can use logic such as:
|
||||
|
||||
# create a flag Actor in our game activity
|
||||
self.flag = ba.Flag(position=(0, 10, 0))
|
||||
# Create a flag Actor in our game activity:
|
||||
from bastd.actor.flag import Flag
|
||||
self.flag = Flag(position=(0, 10, 0))
|
||||
|
||||
# later, destroy the flag..
|
||||
# Later, destroy the flag.
|
||||
# (provided nothing else is holding a reference to it)
|
||||
# we could also just assign a new flag to this value.
|
||||
# either way, the old flag disappears.
|
||||
# We could also just assign a new flag to this value.
|
||||
# Either way, the old flag disappears.
|
||||
self.flag = None
|
||||
|
||||
This is in contrast to the behavior of the more low level ba.Nodes,
|
||||
@ -69,30 +70,25 @@ class Actor:
|
||||
takes a single arbitrary object as an argument. This provides a safe way
|
||||
to communicate between ba.Actor, ba.Activity, ba.Session, and any other
|
||||
class providing a handlemessage() method. The most universally handled
|
||||
message type for actors is the ba.DieMessage.
|
||||
message type for Actors is the ba.DieMessage.
|
||||
|
||||
# another way to kill the flag from the example above:
|
||||
# we can safely call this on any type with a 'handlemessage' method
|
||||
# (though its not guaranteed to always have a meaningful effect)
|
||||
# in this case the Actor instance will still be around, but its exists()
|
||||
# and is_alive() methods will both return False
|
||||
# Another way to kill the flag from the example above:
|
||||
# We can safely call this on any type with a 'handlemessage' method
|
||||
# (though its not guaranteed to always have a meaningful effect).
|
||||
# In this case the Actor instance will still be around, but its exists()
|
||||
# and is_alive() methods will both return False.
|
||||
self.flag.handlemessage(ba.DieMessage())
|
||||
"""
|
||||
|
||||
def __init__(self, node: ba.Node = None):
|
||||
"""Instantiates an Actor in the current ba.Activity.
|
||||
def __init__(self) -> None:
|
||||
"""Instantiates an Actor in the current ba.Activity."""
|
||||
|
||||
If 'node' is provided, it is stored as the 'node' attribute
|
||||
and the default ba.Actor.handlemessage() and ba.Actor.exists()
|
||||
implementations will apply to it. This allows the creation of
|
||||
simple node-wrapping Actors without having to create a new subclass.
|
||||
"""
|
||||
# FIXME: Actor should not be require to have a 'node' attr.
|
||||
self.node: Optional[ba.Node] = None
|
||||
|
||||
activity = _ba.getactivity()
|
||||
self._activity = weakref.ref(activity)
|
||||
activity.add_actor_weak_ref(self)
|
||||
if node is not None:
|
||||
self.node = node
|
||||
|
||||
def __del__(self) -> None:
|
||||
try:
|
||||
@ -112,14 +108,9 @@ class Actor:
|
||||
The default implementation will handle ba.DieMessages by
|
||||
calling self.node.delete() if self contains a 'node' attribute.
|
||||
"""
|
||||
from ba import _messages
|
||||
from ba import _error
|
||||
if isinstance(msg, _messages.DieMessage):
|
||||
node = getattr(self, 'node', None)
|
||||
if node is not None:
|
||||
node.delete()
|
||||
return None
|
||||
return _error.UNHANDLED
|
||||
from ba._error import UNHANDLED
|
||||
del msg # Unused.
|
||||
return UNHANDLED
|
||||
|
||||
def _handlemessage_sanity_check(self) -> None:
|
||||
if self.is_expired():
|
||||
@ -178,18 +169,13 @@ class Actor:
|
||||
deleted without affecting the game; this call is often used
|
||||
when pruning lists of Actors, such as with ba.Actor.autoretain()
|
||||
|
||||
The default implementation of this method returns 'node.exists()'
|
||||
if the Actor has a 'node' attr; otherwise True.
|
||||
The default implementation of this method always return True.
|
||||
|
||||
Note that the boolean operator for the Actor class calls this method,
|
||||
so a simple "if myactor" test will conveniently do the right thing
|
||||
even if myactor is set to None.
|
||||
"""
|
||||
|
||||
# As a default, if we have a 'node' attr, return whether it exists.
|
||||
node: ba.Node = getattr(self, 'node', None)
|
||||
if node is not None:
|
||||
return node.exists()
|
||||
return True
|
||||
|
||||
def __bool__(self) -> bool:
|
||||
|
||||
@ -638,7 +638,8 @@ class App:
|
||||
activity = _ba.get_foreground_host_activity()
|
||||
if (activity is not None and activity.allow_pausing
|
||||
and not _ba.have_connected_clients()):
|
||||
from ba import _gameutils, _actor, _lang
|
||||
from ba import _gameutils, _lang
|
||||
from ba._nodeactor import NodeActor
|
||||
# FIXME: Shouldn't be touching scene stuff here;
|
||||
# should just pass the request on to the host-session.
|
||||
with _ba.Context(activity):
|
||||
@ -648,7 +649,7 @@ class App:
|
||||
globs.paused = True
|
||||
|
||||
# FIXME: This should not be an attr on Actor.
|
||||
activity.paused_text = _actor.Actor(
|
||||
activity.paused_text = NodeActor(
|
||||
_ba.newnode(
|
||||
'text',
|
||||
attrs={
|
||||
|
||||
@ -80,8 +80,8 @@ class CoopGameActivity(GameActivity):
|
||||
|
||||
def _show_standard_scores_to_beat_ui(self,
|
||||
scores: List[Dict[str, Any]]) -> None:
|
||||
from ba import _gameutils
|
||||
from ba import _actor
|
||||
from ba._gameutils import timestring, animate
|
||||
from ba._nodeactor import NodeActor
|
||||
from ba._enums import TimeFormat
|
||||
display_type = self.get_score_type()
|
||||
if scores is not None:
|
||||
@ -92,16 +92,14 @@ class CoopGameActivity(GameActivity):
|
||||
# Now make a display for the most recent challenge.
|
||||
for score in scores:
|
||||
if score['type'] == 'score_challenge':
|
||||
tval = (
|
||||
score['player'] + ': ' +
|
||||
(_gameutils.timestring(
|
||||
int(score['value']) * 10,
|
||||
timeformat=TimeFormat.MILLISECONDS).evaluate()
|
||||
if display_type == 'time' else str(score['value'])))
|
||||
tval = (score['player'] + ': ' + timestring(
|
||||
int(score['value']) * 10,
|
||||
timeformat=TimeFormat.MILLISECONDS).evaluate()
|
||||
if display_type == 'time' else str(score['value']))
|
||||
hattach = 'center' if display_type == 'time' else 'left'
|
||||
halign = 'center' if display_type == 'time' else 'left'
|
||||
pos = (20, -70) if display_type == 'time' else (20, -130)
|
||||
txt = _actor.Actor(
|
||||
txt = NodeActor(
|
||||
_ba.newnode('text',
|
||||
attrs={
|
||||
'v_attach': 'top',
|
||||
@ -115,11 +113,7 @@ class CoopGameActivity(GameActivity):
|
||||
'text': tval
|
||||
})).autoretain()
|
||||
assert txt.node is not None
|
||||
_gameutils.animate(txt.node, 'scale', {
|
||||
1.0: 0.0,
|
||||
1.1: 0.7,
|
||||
1.2: 0.6
|
||||
})
|
||||
animate(txt.node, 'scale', {1.0: 0.0, 1.1: 0.7, 1.2: 0.6})
|
||||
break
|
||||
|
||||
# FIXME: this is now redundant with activityutils.get_score_info();
|
||||
@ -279,8 +273,8 @@ class CoopGameActivity(GameActivity):
|
||||
should_beep = True
|
||||
break
|
||||
if should_beep and self._life_warning_beep is None:
|
||||
from ba import _actor
|
||||
self._life_warning_beep = _actor.Actor(
|
||||
from ba._nodeactor import NodeActor
|
||||
self._life_warning_beep = NodeActor(
|
||||
_ba.newnode('sound',
|
||||
attrs={
|
||||
'sound': self._warn_beeps_sound,
|
||||
|
||||
@ -703,7 +703,7 @@ class GameActivity(Activity):
|
||||
# pylint: disable=too-many-locals
|
||||
from ba._freeforallsession import FreeForAllSession
|
||||
from ba._gameutils import animate
|
||||
from ba._actor import Actor
|
||||
from ba._nodeactor import NodeActor
|
||||
sb_name = self.get_instance_scoreboard_display_string()
|
||||
|
||||
# the description can be either a string or a sequence with args
|
||||
@ -731,7 +731,7 @@ class GameActivity(Activity):
|
||||
yval -= 16
|
||||
sbpos = ((15, yval) if isinstance(self.session, FreeForAllSession) else
|
||||
(15, yval))
|
||||
self._game_scoreboard_name_text = Actor(
|
||||
self._game_scoreboard_name_text = NodeActor(
|
||||
_ba.newnode("text",
|
||||
attrs={
|
||||
'text': sb_name,
|
||||
@ -756,7 +756,7 @@ class GameActivity(Activity):
|
||||
descpos = (((17, -44 +
|
||||
10) if isinstance(self.session, FreeForAllSession) else
|
||||
(17, -44 + 10)))
|
||||
self._game_scoreboard_description_text = Actor(
|
||||
self._game_scoreboard_description_text = NodeActor(
|
||||
_ba.newnode(
|
||||
"text",
|
||||
attrs={
|
||||
@ -1163,13 +1163,13 @@ class GameActivity(Activity):
|
||||
"""
|
||||
from ba._gameutils import sharedobj
|
||||
from ba._general import WeakCall
|
||||
from ba._actor import Actor
|
||||
from ba._nodeactor import NodeActor
|
||||
if duration <= 0.0:
|
||||
return
|
||||
self._standard_time_limit_time = int(duration)
|
||||
self._standard_time_limit_timer = _ba.Timer(
|
||||
1.0, WeakCall(self._standard_time_limit_tick), repeat=True)
|
||||
self._standard_time_limit_text = Actor(
|
||||
self._standard_time_limit_text = NodeActor(
|
||||
_ba.newnode('text',
|
||||
attrs={
|
||||
'v_attach': 'top',
|
||||
@ -1180,7 +1180,7 @@ class GameActivity(Activity):
|
||||
'flatness': 1.0,
|
||||
'scale': 0.9
|
||||
}))
|
||||
self._standard_time_limit_text_input = Actor(
|
||||
self._standard_time_limit_text_input = NodeActor(
|
||||
_ba.newnode('timedisplay',
|
||||
attrs={
|
||||
'time2': duration * 1000,
|
||||
@ -1237,7 +1237,7 @@ class GameActivity(Activity):
|
||||
If the time-limit expires, end_game() will be called.
|
||||
"""
|
||||
from ba._general import WeakCall
|
||||
from ba._actor import Actor
|
||||
from ba._nodeactor import NodeActor
|
||||
from ba._enums import TimeType
|
||||
if duration <= 0.0:
|
||||
return
|
||||
@ -1251,7 +1251,7 @@ class GameActivity(Activity):
|
||||
WeakCall(self._tournament_time_limit_tick),
|
||||
repeat=True,
|
||||
timetype=TimeType.BASE)
|
||||
self._tournament_time_limit_title_text = Actor(
|
||||
self._tournament_time_limit_title_text = NodeActor(
|
||||
_ba.newnode('text',
|
||||
attrs={
|
||||
'v_attach': 'bottom',
|
||||
@ -1266,7 +1266,7 @@ class GameActivity(Activity):
|
||||
'scale': 0.5,
|
||||
'text': Lstr(resource='tournamentText')
|
||||
}))
|
||||
self._tournament_time_limit_text = Actor(
|
||||
self._tournament_time_limit_text = NodeActor(
|
||||
_ba.newnode('text',
|
||||
attrs={
|
||||
'v_attach': 'bottom',
|
||||
@ -1280,7 +1280,7 @@ class GameActivity(Activity):
|
||||
'flatness': 1.0,
|
||||
'scale': 0.9
|
||||
}))
|
||||
self._tournament_time_limit_text_input = Actor(
|
||||
self._tournament_time_limit_text_input = NodeActor(
|
||||
_ba.newnode('timedisplay',
|
||||
attrs={
|
||||
'timemin': 0,
|
||||
|
||||
@ -441,7 +441,7 @@ def cameraflash(duration: float = 999.0) -> None:
|
||||
"""
|
||||
# pylint: disable=too-many-locals
|
||||
import random
|
||||
from ba._actor import Actor
|
||||
from ba._nodeactor import NodeActor
|
||||
x_spread = 10
|
||||
y_spread = 5
|
||||
positions = [[-x_spread, -y_spread], [0, -y_spread], [0, y_spread],
|
||||
@ -455,7 +455,7 @@ def cameraflash(duration: float = 999.0) -> None:
|
||||
# noinspection PyTypeHints
|
||||
activity.camera_flash_data = [] # type: ignore
|
||||
for i in range(6):
|
||||
light = Actor(
|
||||
light = NodeActor(
|
||||
_ba.newnode("light",
|
||||
attrs={
|
||||
'position': (positions[i][0], 0, positions[i][1]),
|
||||
|
||||
@ -159,7 +159,7 @@ class _WeakCall:
|
||||
Instantiate a WeakCall; pass a callable as the first
|
||||
arg, followed by any number of arguments or keywords.
|
||||
|
||||
# example: wrap a method call with some positional and
|
||||
# Example: wrap a method call with some positional and
|
||||
# keyword args:
|
||||
myweakcall = ba.WeakCall(myobj.dostuff, argval1, namedarg=argval2)
|
||||
|
||||
@ -211,7 +211,7 @@ class _Call:
|
||||
Instantiate a Call; pass a callable as the first
|
||||
arg, followed by any number of arguments or keywords.
|
||||
|
||||
# Example: wrap a method call with 1 positional and 1 keyword arg.
|
||||
# Example: wrap a method call with 1 positional and 1 keyword arg:
|
||||
mycall = ba.Call(myobj.dostuff, argval1, namedarg=argval2)
|
||||
|
||||
# Now we have a single callable to run that whole mess.
|
||||
|
||||
@ -42,8 +42,8 @@ class JoinInfo:
|
||||
# pylint: disable=too-many-locals
|
||||
from ba import _input
|
||||
from ba._lang import Lstr
|
||||
from ba import _actor
|
||||
from ba import _general
|
||||
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
|
||||
@ -79,7 +79,7 @@ class JoinInfo:
|
||||
join_str = Lstr(resource='pressAnyButtonToJoinText')
|
||||
|
||||
flatness = 1.0 if _ba.app.vr_mode else 0.0
|
||||
self._text = _actor.Actor(
|
||||
self._text = NodeActor(
|
||||
_ba.newnode('text',
|
||||
attrs={
|
||||
'position': (0, -40),
|
||||
@ -109,9 +109,7 @@ class JoinInfo:
|
||||
' ' + _ba.charstr(SpecialChar.RIGHT_ARROW))])
|
||||
] if can_switch_teams else []) + [msg1] + [msg3] + [join_str])
|
||||
|
||||
self._timer = _ba.Timer(4.0,
|
||||
_general.WeakCall(self._update),
|
||||
repeat=True)
|
||||
self._timer = _ba.Timer(4.0, WeakCall(self._update), repeat=True)
|
||||
|
||||
def _update(self) -> None:
|
||||
assert self._text.node
|
||||
@ -393,7 +391,7 @@ class Chooser:
|
||||
|
||||
def reload_profiles(self) -> None:
|
||||
"""Reload all player profiles."""
|
||||
from ba import _general
|
||||
from ba._general import json_prep
|
||||
app = _ba.app
|
||||
|
||||
# Re-construct our profile index and other stuff since the profile
|
||||
@ -422,7 +420,7 @@ class Chooser:
|
||||
# (non-unicode/non-json) version.
|
||||
# Make sure they conform to our standards
|
||||
# (unicode strings, no tuples, etc)
|
||||
self.profiles = _general.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()):
|
||||
@ -551,7 +549,7 @@ class Chooser:
|
||||
def _set_ready(self, ready: bool) -> None:
|
||||
# pylint: disable=cyclic-import
|
||||
from bastd.ui.profile import browser as pbrowser
|
||||
from ba import _general
|
||||
from ba._general import Call
|
||||
profilename = self._profilenames[self._profileindex]
|
||||
|
||||
# Handle '_edit' as a special case.
|
||||
@ -566,26 +564,23 @@ class Chooser:
|
||||
|
||||
if not ready:
|
||||
self._player.assign_input_call(
|
||||
'leftPress',
|
||||
_general.Call(self.handlemessage, ChangeMessage('team', -1)))
|
||||
'leftPress', Call(self.handlemessage,
|
||||
ChangeMessage('team', -1)))
|
||||
self._player.assign_input_call(
|
||||
'rightPress',
|
||||
_general.Call(self.handlemessage, ChangeMessage('team', 1)))
|
||||
'rightPress', Call(self.handlemessage,
|
||||
ChangeMessage('team', 1)))
|
||||
self._player.assign_input_call(
|
||||
'bombPress',
|
||||
_general.Call(self.handlemessage,
|
||||
ChangeMessage('character', 1)))
|
||||
Call(self.handlemessage, ChangeMessage('character', 1)))
|
||||
self._player.assign_input_call(
|
||||
'upPress',
|
||||
_general.Call(self.handlemessage,
|
||||
ChangeMessage('profileindex', -1)))
|
||||
Call(self.handlemessage, ChangeMessage('profileindex', -1)))
|
||||
self._player.assign_input_call(
|
||||
'downPress',
|
||||
_general.Call(self.handlemessage,
|
||||
ChangeMessage('profileindex', 1)))
|
||||
Call(self.handlemessage, ChangeMessage('profileindex', 1)))
|
||||
self._player.assign_input_call(
|
||||
('jumpPress', 'pickUpPress', 'punchPress'),
|
||||
_general.Call(self.handlemessage, ChangeMessage('ready', 1)))
|
||||
Call(self.handlemessage, ChangeMessage('ready', 1)))
|
||||
self._ready = False
|
||||
self._update_text()
|
||||
self._player.set_name('untitled', real=False)
|
||||
@ -595,7 +590,7 @@ class Chooser:
|
||||
'jumpPress', 'bombPress', 'pickUpPress'), self._do_nothing)
|
||||
self._player.assign_input_call(
|
||||
('jumpPress', 'bombPress', 'pickUpPress', 'punchPress'),
|
||||
_general.Call(self.handlemessage, ChangeMessage('ready', 0)))
|
||||
Call(self.handlemessage, ChangeMessage('ready', 0)))
|
||||
|
||||
# Store the last profile picked by this input for reuse.
|
||||
input_device = self._player.get_input_device()
|
||||
|
||||
53
assets/src/ba_data/python/ba/_nodeactor.py
Normal file
53
assets/src/ba_data/python/ba/_nodeactor.py
Normal file
@ -0,0 +1,53 @@
|
||||
# Copyright (c) 2011-2020 Eric Froemling
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
# -----------------------------------------------------------------------------
|
||||
"""Defines NodeActor class."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from ba._messages import DieMessage
|
||||
from ba._actor import Actor
|
||||
|
||||
if TYPE_CHECKING:
|
||||
import ba
|
||||
from typing import Any
|
||||
|
||||
|
||||
class NodeActor(Actor):
|
||||
"""A simple ba.Actor type that wraps a single ba.Node.
|
||||
|
||||
Category: Gameplay Classes
|
||||
|
||||
This Actor will delete its Node when told to die, and it's
|
||||
exists() call will return whether the Node still exists or not.
|
||||
"""
|
||||
|
||||
def __init__(self, node: ba.Node):
|
||||
super().__init__()
|
||||
self.node = node
|
||||
|
||||
def handlemessage(self, msg: Any) -> Any:
|
||||
if isinstance(msg, DieMessage):
|
||||
if self.node:
|
||||
self.node.delete()
|
||||
return None
|
||||
return super().handlemessage(msg)
|
||||
@ -65,7 +65,7 @@ class TeamBaseSession(Session):
|
||||
team_names = None
|
||||
team_colors = None
|
||||
|
||||
print('FIXME: TEAM BASE SESSION WOULD CALC DEPS.')
|
||||
# print('FIXME: TEAM BASE SESSION WOULD CALC DEPS.')
|
||||
depsets: Sequence[ba.DependencySet] = []
|
||||
super().__init__(depsets,
|
||||
team_names=team_names,
|
||||
|
||||
@ -867,7 +867,7 @@ class CoopScoreScreen(ba.Activity):
|
||||
ba.timer(5.0, ba.WeakCall(self._show_tips))
|
||||
|
||||
def _play_drumroll(self) -> None:
|
||||
ba.Actor(
|
||||
ba.NodeActor(
|
||||
ba.newnode('sound',
|
||||
attrs={
|
||||
'sound': self.drum_roll_sound,
|
||||
@ -1314,7 +1314,7 @@ class CoopScoreScreen(ba.Activity):
|
||||
star_tex = ba.gettexture('star')
|
||||
star_x = 135 + offs_x
|
||||
for _i in range(stars):
|
||||
img = ba.Actor(
|
||||
img = ba.NodeActor(
|
||||
ba.newnode('image',
|
||||
attrs={
|
||||
'texture': star_tex,
|
||||
@ -1329,7 +1329,7 @@ class CoopScoreScreen(ba.Activity):
|
||||
ba.animate(img.node, 'opacity', {0.15: 0, 0.4: 1})
|
||||
star_x += 60
|
||||
for _i in range(3 - stars):
|
||||
img = ba.Actor(
|
||||
img = ba.NodeActor(
|
||||
ba.newnode('image',
|
||||
attrs={
|
||||
'texture': star_tex,
|
||||
@ -1355,7 +1355,7 @@ class CoopScoreScreen(ba.Activity):
|
||||
transition_delay=1.0).autoretain()
|
||||
stx = xval + 20
|
||||
for _i2 in range(count):
|
||||
img2 = ba.Actor(
|
||||
img2 = ba.NodeActor(
|
||||
ba.newnode('image',
|
||||
attrs={
|
||||
'texture': star_tex,
|
||||
|
||||
@ -89,7 +89,7 @@ class RespawnIcon:
|
||||
texture = icon['texture']
|
||||
h_offs = -10
|
||||
ipos = (-40 - h_offs if on_right else 40 + h_offs, -180 + offs)
|
||||
self._image: Optional[ba.Actor] = ba.Actor(
|
||||
self._image: Optional[ba.NodeActor] = ba.NodeActor(
|
||||
ba.newnode('image',
|
||||
attrs={
|
||||
'texture': texture,
|
||||
@ -108,7 +108,7 @@ class RespawnIcon:
|
||||
ba.animate(self._image.node, 'opacity', {0.0: 0, 0.2: 0.7})
|
||||
|
||||
npos = (-40 - h_offs if on_right else 40 + h_offs, -205 + 49 + offs)
|
||||
self._name: Optional[ba.Actor] = ba.Actor(
|
||||
self._name: Optional[ba.NodeActor] = ba.NodeActor(
|
||||
ba.newnode('text',
|
||||
attrs={
|
||||
'v_attach': 'top',
|
||||
@ -128,7 +128,7 @@ class RespawnIcon:
|
||||
ba.animate(self._name.node, 'scale', {0: 0, 0.1: 0.5})
|
||||
|
||||
tpos = (-60 - h_offs if on_right else 60 + h_offs, -192 + offs)
|
||||
self._text: Optional[ba.Actor] = ba.Actor(
|
||||
self._text: Optional[ba.NodeActor] = ba.NodeActor(
|
||||
ba.newnode('text',
|
||||
attrs={
|
||||
'position': tpos,
|
||||
|
||||
@ -72,7 +72,7 @@ class _Entry:
|
||||
self._backing_color = [0.05 + c * 0.1 for c in safe_team_color]
|
||||
|
||||
opacity = (0.8 if vrmode else 0.8) if self._do_cover else 0.5
|
||||
self._backing = ba.Actor(
|
||||
self._backing = ba.NodeActor(
|
||||
ba.newnode('image',
|
||||
attrs={
|
||||
'scale': (self._width, self._height),
|
||||
@ -84,7 +84,7 @@ class _Entry:
|
||||
}))
|
||||
|
||||
self._barcolor = safe_team_color
|
||||
self._bar = ba.Actor(
|
||||
self._bar = ba.NodeActor(
|
||||
ba.newnode('image',
|
||||
attrs={
|
||||
'opacity': 0.7,
|
||||
@ -112,7 +112,7 @@ class _Entry:
|
||||
self._bar_position.connectattr('output', self._bar.node, 'position')
|
||||
self._cover_color = safe_team_color
|
||||
if self._do_cover:
|
||||
self._cover = ba.Actor(
|
||||
self._cover = ba.NodeActor(
|
||||
ba.newnode('image',
|
||||
attrs={
|
||||
'scale':
|
||||
@ -128,7 +128,7 @@ class _Entry:
|
||||
clr = safe_team_color
|
||||
maxwidth = 130.0 * (1.0 - scoreboard.score_split)
|
||||
flatness = ((1.0 if vrmode else 0.5) if self._do_cover else 1.0)
|
||||
self._score_text = ba.Actor(
|
||||
self._score_text = ba.NodeActor(
|
||||
ba.newnode('text',
|
||||
attrs={
|
||||
'h_attach': 'left',
|
||||
@ -169,7 +169,7 @@ class _Entry:
|
||||
team_name_label = ba.Lstr(value=team_name_label)
|
||||
|
||||
flatness = ((1.0 if vrmode else 0.5) if self._do_cover else 1.0)
|
||||
self._name_text = ba.Actor(
|
||||
self._name_text = ba.NodeActor(
|
||||
ba.newnode('text',
|
||||
attrs={
|
||||
'h_attach': 'left',
|
||||
|
||||
@ -58,10 +58,10 @@ class BombDiedMessage:
|
||||
def get_factory() -> SpazFactory:
|
||||
"""Return the shared ba.SpazFactory object, creating it if necessary."""
|
||||
# pylint: disable=cyclic-import
|
||||
from bastd.actor.spazfactory import SpazFactory
|
||||
activity = ba.getactivity()
|
||||
factory = getattr(activity, 'shared_spaz_factory', None)
|
||||
if factory is None:
|
||||
from bastd.actor.spazfactory import SpazFactory
|
||||
# noinspection PyTypeHints
|
||||
factory = activity.shared_spaz_factory = SpazFactory() # type: ignore
|
||||
assert isinstance(factory, SpazFactory)
|
||||
@ -693,11 +693,11 @@ class Spaz(ba.Actor):
|
||||
# pylint: disable=too-many-branches
|
||||
if __debug__ is True:
|
||||
self._handlemessage_sanity_check()
|
||||
assert self.node
|
||||
|
||||
if isinstance(msg, ba.PickedUpMessage):
|
||||
self.node.handlemessage("hurt_sound")
|
||||
self.node.handlemessage("picked_up")
|
||||
if self.node:
|
||||
self.node.handlemessage("hurt_sound")
|
||||
self.node.handlemessage("picked_up")
|
||||
# this counts as a hit
|
||||
self._num_times_hit += 1
|
||||
|
||||
@ -713,7 +713,7 @@ class Spaz(ba.Actor):
|
||||
ba.timer(0.001, ba.WeakCall(self._hit_self, msg.intensity))
|
||||
|
||||
elif isinstance(msg, ba.PowerupMessage):
|
||||
if self._dead:
|
||||
if self._dead or not self.node:
|
||||
return True
|
||||
if self.pick_up_powerup_callback is not None:
|
||||
self.pick_up_powerup_callback(self)
|
||||
@ -1069,14 +1069,15 @@ class Spaz(ba.Actor):
|
||||
newdamage = max(damage - 200, self.hitpoints - 10)
|
||||
damage = newdamage
|
||||
self.node.handlemessage("flash")
|
||||
# if we're holding something, drop it
|
||||
|
||||
# If we're holding something, drop it.
|
||||
if damage > 0.0 and self.node.hold_node:
|
||||
# self.node.hold_node = ba.Node(None)
|
||||
self.node.hold_node = None
|
||||
self.hitpoints -= damage
|
||||
self.node.hurt = 1.0 - float(
|
||||
self.hitpoints) / self.hitpoints_max
|
||||
# if we're cursed, *any* damage blows us up
|
||||
# If we're cursed, *any* damage blows us up.
|
||||
if self._cursed and damage > 0:
|
||||
ba.timer(
|
||||
0.05, ba.WeakCall(self.curse_explode,
|
||||
@ -1103,7 +1104,8 @@ class Spaz(ba.Actor):
|
||||
self._dead = True
|
||||
self.hitpoints = 0
|
||||
if msg.immediate:
|
||||
self.node.delete()
|
||||
if self.node:
|
||||
self.node.delete()
|
||||
elif self.node:
|
||||
self.node.hurt = 1.0
|
||||
if self.play_big_death_sound and not wasdead:
|
||||
@ -1117,11 +1119,15 @@ class Spaz(ba.Actor):
|
||||
elif isinstance(msg, ba.StandMessage):
|
||||
self._last_stand_pos = (msg.position[0], msg.position[1],
|
||||
msg.position[2])
|
||||
self.node.handlemessage("stand", msg.position[0], msg.position[1],
|
||||
msg.position[2], msg.angle)
|
||||
if self.node:
|
||||
self.node.handlemessage("stand", msg.position[0],
|
||||
msg.position[1], msg.position[2],
|
||||
msg.angle)
|
||||
elif isinstance(msg, CurseExplodeMessage):
|
||||
self.curse_explode()
|
||||
elif isinstance(msg, PunchHitMessage):
|
||||
if not self.node:
|
||||
return None
|
||||
node = ba.get_collision_info("opposing_node")
|
||||
|
||||
# only allow one hit per node per punch
|
||||
@ -1178,6 +1184,9 @@ class Spaz(ba.Actor):
|
||||
ppos[2], punchdir[0], punchdir[1],
|
||||
punchdir[2], mag)
|
||||
elif isinstance(msg, PickupMessage):
|
||||
if not self.node:
|
||||
return None
|
||||
|
||||
opposing_node, opposing_body = ba.get_collision_info(
|
||||
'opposing_node', 'opposing_body')
|
||||
|
||||
|
||||
@ -354,7 +354,7 @@ class CaptureTheFlagGame(ba.TeamGameActivity):
|
||||
team.gamedata['touch_return_timer_ticking'] = None
|
||||
return # No need to return when its at home.
|
||||
if team.gamedata['touch_return_timer_ticking'] is None:
|
||||
team.gamedata['touch_return_timer_ticking'] = ba.Actor(
|
||||
team.gamedata['touch_return_timer_ticking'] = ba.NodeActor(
|
||||
ba.newnode('sound',
|
||||
attrs={
|
||||
'sound': self._ticking_sound,
|
||||
|
||||
@ -293,7 +293,7 @@ class ChosenOneGame(ba.TeamGameActivity):
|
||||
0.3 + c * 0.7
|
||||
for c in ba.normalized_color(player.team.color)
|
||||
]
|
||||
light = player.gamedata['chosen_light'] = ba.Actor(
|
||||
light = player.gamedata['chosen_light'] = ba.NodeActor(
|
||||
ba.newnode('light',
|
||||
attrs={
|
||||
"intensity": 0.6,
|
||||
|
||||
@ -449,7 +449,7 @@ class EliminationGame(ba.TeamGameActivity):
|
||||
self.setup_standard_time_limit(self.settings['Time Limit'])
|
||||
self.setup_standard_powerup_drops()
|
||||
if self._solo_mode:
|
||||
self._vs_text = ba.Actor(
|
||||
self._vs_text = ba.NodeActor(
|
||||
ba.newnode("text",
|
||||
attrs={
|
||||
'position': (0, 105),
|
||||
|
||||
@ -157,7 +157,7 @@ class FootballTeamGame(ba.TeamGameActivity):
|
||||
self._spawn_flag()
|
||||
defs = self.map.defs
|
||||
self._score_regions.append(
|
||||
ba.Actor(
|
||||
ba.NodeActor(
|
||||
ba.newnode('region',
|
||||
attrs={
|
||||
'position': defs.boxes['goal1'][0:3],
|
||||
@ -166,7 +166,7 @@ class FootballTeamGame(ba.TeamGameActivity):
|
||||
'materials': (self.score_region_material, )
|
||||
})))
|
||||
self._score_regions.append(
|
||||
ba.Actor(
|
||||
ba.NodeActor(
|
||||
ba.newnode('region',
|
||||
attrs={
|
||||
'position': defs.boxes['goal2'][0:3],
|
||||
@ -279,7 +279,7 @@ class FootballTeamGame(ba.TeamGameActivity):
|
||||
elif isinstance(msg, stdflag.FlagDeathMessage):
|
||||
if not self.has_ended():
|
||||
self._flag_respawn_timer = ba.Timer(3.0, self._spawn_flag)
|
||||
self._flag_respawn_light = ba.Actor(
|
||||
self._flag_respawn_light = ba.NodeActor(
|
||||
ba.newnode('light',
|
||||
attrs={
|
||||
'position': self._flag_spawn_pos,
|
||||
@ -406,7 +406,7 @@ class FootballCoopGame(ba.CoopGameActivity):
|
||||
# Set up the two score regions.
|
||||
defs = self.map.defs
|
||||
self.score_regions.append(
|
||||
ba.Actor(
|
||||
ba.NodeActor(
|
||||
ba.newnode('region',
|
||||
attrs={
|
||||
'position': defs.boxes['goal1'][0:3],
|
||||
@ -415,7 +415,7 @@ class FootballCoopGame(ba.CoopGameActivity):
|
||||
'materials': [self._score_region_material]
|
||||
})))
|
||||
self.score_regions.append(
|
||||
ba.Actor(
|
||||
ba.NodeActor(
|
||||
ba.newnode('region',
|
||||
attrs={
|
||||
'position': defs.boxes['goal2'][0:3],
|
||||
@ -516,7 +516,7 @@ class FootballCoopGame(ba.CoopGameActivity):
|
||||
starttime_ms = ba.time(timeformat=ba.TimeFormat.MILLISECONDS)
|
||||
assert isinstance(starttime_ms, int)
|
||||
self._starttime_ms = starttime_ms
|
||||
self._time_text = ba.Actor(
|
||||
self._time_text = ba.NodeActor(
|
||||
ba.newnode('text',
|
||||
attrs={
|
||||
'v_attach': 'top',
|
||||
@ -529,7 +529,7 @@ class FootballCoopGame(ba.CoopGameActivity):
|
||||
'scale': 1.3,
|
||||
'text': ''
|
||||
}))
|
||||
self._time_text_input = ba.Actor(
|
||||
self._time_text_input = ba.NodeActor(
|
||||
ba.newnode('timedisplay', attrs={'showsubseconds': True}))
|
||||
ba.sharedobj('globals').connectattr('time', self._time_text_input.node,
|
||||
'time2')
|
||||
@ -844,7 +844,7 @@ class FootballCoopGame(ba.CoopGameActivity):
|
||||
elif isinstance(msg, stdflag.FlagDeathMessage):
|
||||
assert isinstance(msg.flag, FootballFlag)
|
||||
msg.flag.respawn_timer = ba.Timer(3.0, self._spawn_flag)
|
||||
self._flag_respawn_light = ba.Actor(
|
||||
self._flag_respawn_light = ba.NodeActor(
|
||||
ba.newnode('light',
|
||||
attrs={
|
||||
'position': self._flag_spawn_pos,
|
||||
|
||||
@ -222,7 +222,7 @@ class HockeyGame(ba.TeamGameActivity):
|
||||
defs = self.map.defs
|
||||
self._score_regions = []
|
||||
self._score_regions.append(
|
||||
ba.Actor(
|
||||
ba.NodeActor(
|
||||
ba.newnode("region",
|
||||
attrs={
|
||||
'position': defs.boxes["goal1"][0:3],
|
||||
@ -231,7 +231,7 @@ class HockeyGame(ba.TeamGameActivity):
|
||||
'materials': [self._score_region_material]
|
||||
})))
|
||||
self._score_regions.append(
|
||||
ba.Actor(
|
||||
ba.NodeActor(
|
||||
ba.newnode("region",
|
||||
attrs={
|
||||
'position': defs.boxes["goal2"][0:3],
|
||||
|
||||
@ -170,7 +170,7 @@ class OnslaughtGame(ba.CoopGameActivity):
|
||||
'sound': ba.getsound('ding')
|
||||
}]
|
||||
|
||||
self._spawn_info_text = ba.Actor(
|
||||
self._spawn_info_text = ba.NodeActor(
|
||||
ba.newnode("text",
|
||||
attrs={
|
||||
'position': (15, -130),
|
||||
@ -1049,7 +1049,7 @@ class OnslaughtGame(ba.CoopGameActivity):
|
||||
('${A}', ba.Lstr(resource='timeBonusText')),
|
||||
('${B}', str(self._time_bonus)),
|
||||
])
|
||||
self._time_bonus_text = ba.Actor(
|
||||
self._time_bonus_text = ba.NodeActor(
|
||||
ba.newnode('text',
|
||||
attrs={
|
||||
'v_attach': 'top',
|
||||
@ -1075,7 +1075,7 @@ class OnslaughtGame(ba.CoopGameActivity):
|
||||
('' if self._preset in ['endless', 'endless_tournament'] else
|
||||
('/' + str(len(self._waves)))))
|
||||
])
|
||||
self._wave_text = ba.Actor(
|
||||
self._wave_text = ba.NodeActor(
|
||||
ba.newnode('text',
|
||||
attrs={
|
||||
'v_attach': 'top',
|
||||
|
||||
@ -406,7 +406,7 @@ class RaceGame(ba.TeamGameActivity):
|
||||
self._team_finish_pts = 100
|
||||
|
||||
# Throw a timer up on-screen.
|
||||
self._time_text = ba.Actor(
|
||||
self._time_text = ba.NodeActor(
|
||||
ba.newnode('text',
|
||||
attrs={
|
||||
'v_attach': 'top',
|
||||
|
||||
@ -134,7 +134,7 @@ class RunaroundGame(ba.CoopGameActivity):
|
||||
super().on_transition_in()
|
||||
self._scoreboard = Scoreboard(label=ba.Lstr(resource='scoreText'),
|
||||
score_split=0.5)
|
||||
self._score_region = ba.Actor(
|
||||
self._score_region = ba.NodeActor(
|
||||
ba.newnode(
|
||||
'region',
|
||||
attrs={
|
||||
@ -365,7 +365,7 @@ class RunaroundGame(ba.CoopGameActivity):
|
||||
l_offs = (-80 if interface_type == 'small' else
|
||||
-40 if interface_type == 'medium' else 0)
|
||||
|
||||
self._lives_bg = ba.Actor(
|
||||
self._lives_bg = ba.NodeActor(
|
||||
ba.newnode('image',
|
||||
attrs={
|
||||
'texture': self._heart_tex,
|
||||
@ -379,7 +379,7 @@ class RunaroundGame(ba.CoopGameActivity):
|
||||
# FIXME; should not set things based on vr mode.
|
||||
# (won't look right to non-vr connected clients, etc)
|
||||
vrmode = ba.app.vr_mode
|
||||
self._lives_text = ba.Actor(
|
||||
self._lives_text = ba.NodeActor(
|
||||
ba.newnode(
|
||||
'text',
|
||||
attrs={
|
||||
@ -943,7 +943,7 @@ class RunaroundGame(ba.CoopGameActivity):
|
||||
subs=[('${A}', ba.Lstr(resource='timeBonusText')),
|
||||
('${B}', str(int(self._time_bonus * self._time_bonus_mult)))
|
||||
])
|
||||
self._time_bonus_text = ba.Actor(
|
||||
self._time_bonus_text = ba.NodeActor(
|
||||
ba.newnode('text',
|
||||
attrs={
|
||||
'v_attach': 'top',
|
||||
@ -973,7 +973,7 @@ class RunaroundGame(ba.CoopGameActivity):
|
||||
('' if self._preset in ['endless', 'endless_tournament'] else
|
||||
('/' + str(len(self._waves)))))
|
||||
])
|
||||
self._wave_text = ba.Actor(
|
||||
self._wave_text = ba.NodeActor(
|
||||
ba.newnode('text',
|
||||
attrs={
|
||||
'v_attach': 'top',
|
||||
|
||||
@ -67,7 +67,7 @@ class MainMenuActivity(ba.Activity):
|
||||
# FIXME: Need a node attr for vr-specific-scale.
|
||||
scale = (0.9 if
|
||||
(app.interface_type == 'small' or vr_mode) else 0.7)
|
||||
self.my_name = ba.Actor(
|
||||
self.my_name = ba.NodeActor(
|
||||
ba.newnode('text',
|
||||
attrs={
|
||||
'v_attach': 'bottom',
|
||||
@ -86,7 +86,7 @@ class MainMenuActivity(ba.Activity):
|
||||
# empty-ish screen.
|
||||
tval = ba.Lstr(resource='hostIsNavigatingMenusText',
|
||||
subs=[('${HOST}', _ba.get_account_display_string())])
|
||||
self._host_is_navigating_text = ba.Actor(
|
||||
self._host_is_navigating_text = ba.NodeActor(
|
||||
ba.newnode('text',
|
||||
attrs={
|
||||
'text': tval,
|
||||
@ -130,7 +130,7 @@ class MainMenuActivity(ba.Activity):
|
||||
text = ba.Lstr(value='${V}', subs=[('${V}', app.version)])
|
||||
scale = 0.9 if (interface_type == 'small' or vr_mode) else 0.7
|
||||
color = (1, 1, 1, 1) if vr_mode else (0.5, 0.6, 0.5, 0.7)
|
||||
self.version = ba.Actor(
|
||||
self.version = ba.NodeActor(
|
||||
ba.newnode(
|
||||
'text',
|
||||
attrs={
|
||||
@ -153,7 +153,7 @@ class MainMenuActivity(ba.Activity):
|
||||
self.beta_info = self.beta_info_2 = None
|
||||
if app.test_build and not app.kiosk_mode:
|
||||
pos = (230, 125) if app.kiosk_mode else (230, 35)
|
||||
self.beta_info = ba.Actor(
|
||||
self.beta_info = ba.NodeActor(
|
||||
ba.newnode('text',
|
||||
attrs={
|
||||
'v_attach': 'center',
|
||||
@ -191,7 +191,7 @@ class MainMenuActivity(ba.Activity):
|
||||
gnode.vignette_outer = (0.45, 0.55, 0.54)
|
||||
gnode.vignette_inner = (0.99, 0.98, 0.98)
|
||||
|
||||
self.bottom = ba.Actor(
|
||||
self.bottom = ba.NodeActor(
|
||||
ba.newnode('terrain',
|
||||
attrs={
|
||||
'model': bottom_model,
|
||||
@ -200,7 +200,7 @@ class MainMenuActivity(ba.Activity):
|
||||
'reflection_scale': [0.45],
|
||||
'color_texture': color_texture
|
||||
}))
|
||||
self.vr_bottom_fill = ba.Actor(
|
||||
self.vr_bottom_fill = ba.NodeActor(
|
||||
ba.newnode('terrain',
|
||||
attrs={
|
||||
'model': vr_bottom_fill_model,
|
||||
@ -208,7 +208,7 @@ class MainMenuActivity(ba.Activity):
|
||||
'vr_only': True,
|
||||
'color_texture': color_texture
|
||||
}))
|
||||
self.vr_top_fill = ba.Actor(
|
||||
self.vr_top_fill = ba.NodeActor(
|
||||
ba.newnode('terrain',
|
||||
attrs={
|
||||
'model': vr_top_fill_model,
|
||||
@ -216,7 +216,7 @@ class MainMenuActivity(ba.Activity):
|
||||
'lighting': False,
|
||||
'color_texture': bgtex
|
||||
}))
|
||||
self.terrain = ba.Actor(
|
||||
self.terrain = ba.NodeActor(
|
||||
ba.newnode('terrain',
|
||||
attrs={
|
||||
'model': model,
|
||||
@ -224,7 +224,7 @@ class MainMenuActivity(ba.Activity):
|
||||
'reflection': 'soft',
|
||||
'reflection_scale': [0.3]
|
||||
}))
|
||||
self.trees = ba.Actor(
|
||||
self.trees = ba.NodeActor(
|
||||
ba.newnode('terrain',
|
||||
attrs={
|
||||
'model': trees_model,
|
||||
@ -233,7 +233,7 @@ class MainMenuActivity(ba.Activity):
|
||||
'reflection_scale': [0.1],
|
||||
'color_texture': trees_texture
|
||||
}))
|
||||
self.bgterrain = ba.Actor(
|
||||
self.bgterrain = ba.NodeActor(
|
||||
ba.newnode('terrain',
|
||||
attrs={
|
||||
'model': bgmodel,
|
||||
@ -380,7 +380,7 @@ class MainMenuActivity(ba.Activity):
|
||||
color2 = ((1, 1, 1, 1) if ba.app.vr_mode else
|
||||
(0.7, 0.65, 0.75, 1.0))
|
||||
shadow = (1.0 if ba.app.vr_mode else 0.4)
|
||||
self._text = ba.Actor(
|
||||
self._text = ba.NodeActor(
|
||||
ba.newnode('text',
|
||||
attrs={
|
||||
'v_attach': 'top',
|
||||
@ -652,7 +652,7 @@ class MainMenuActivity(ba.Activity):
|
||||
vr_depth_offset: float = 0.0,
|
||||
shadow: bool = False) -> None:
|
||||
if shadow:
|
||||
word_obj = ba.Actor(
|
||||
word_obj = ba.NodeActor(
|
||||
ba.newnode('text',
|
||||
attrs={
|
||||
'position': (x, y),
|
||||
@ -669,7 +669,7 @@ class MainMenuActivity(ba.Activity):
|
||||
}))
|
||||
self._word_actors.append(word_obj)
|
||||
else:
|
||||
word_obj = ba.Actor(
|
||||
word_obj = ba.NodeActor(
|
||||
ba.newnode('text',
|
||||
attrs={
|
||||
'position': (x, y),
|
||||
@ -776,7 +776,7 @@ class MainMenuActivity(ba.Activity):
|
||||
mopaque = (None if custom_texture is not None else ba.getmodel('logo'))
|
||||
mtrans = (None if custom_texture is not None else
|
||||
ba.getmodel('logoTransparent'))
|
||||
logo = ba.Actor(
|
||||
logo = ba.NodeActor(
|
||||
ba.newnode('image',
|
||||
attrs={
|
||||
'texture': ltex,
|
||||
|
||||
@ -180,7 +180,7 @@ class GatherWindow(ba.Window):
|
||||
self._scroll_width = self._width - scroll_buffer_h
|
||||
self._scroll_height = self._height - 180.0
|
||||
|
||||
# not actually using a scroll widget anymore; just an image
|
||||
# Not actually using a scroll widget anymore; just an image.
|
||||
scroll_left = (self._width - self._scroll_width) * 0.5
|
||||
scroll_bottom = self._height - self._scroll_height - 79 - 48
|
||||
buffer_h = 10
|
||||
@ -214,8 +214,8 @@ class GatherWindow(ba.Window):
|
||||
or _ba.get_account_type() != 'Google Play'):
|
||||
account.show_sign_in_prompt('Google Play')
|
||||
else:
|
||||
# if there's google play people connected to us, inform the user
|
||||
# that they will get disconnected.. otherwise just go ahead..
|
||||
# If there's google play people connected to us, inform the user
|
||||
# that they will get disconnected. Otherwise just go ahead.
|
||||
google_player_count = (_ba.get_google_play_party_client_count())
|
||||
if google_player_count > 0:
|
||||
confirm.ConfirmWindow(
|
||||
@ -246,25 +246,25 @@ class GatherWindow(ba.Window):
|
||||
return
|
||||
self._current_tab = tab
|
||||
|
||||
# we wanna preserve our current tab between runs
|
||||
# We wanna preserve our current tab between runs.
|
||||
cfg = ba.app.config
|
||||
cfg['Gather Tab'] = tab
|
||||
cfg.commit()
|
||||
|
||||
# update tab colors based on which is selected
|
||||
# Update tab colors based on which is selected.
|
||||
tabs.update_tab_button_colors(self._tab_buttons, tab)
|
||||
|
||||
# (re)create scroll widget
|
||||
# (Re)create scroll widget.
|
||||
if self._tab_container:
|
||||
self._tab_container.delete()
|
||||
scroll_left = (self._width - self._scroll_width) * 0.5
|
||||
scroll_bottom = self._height - self._scroll_height - 79 - 48
|
||||
|
||||
# a place where tabs can store data to get cleared when switching to
|
||||
# a different tab
|
||||
# A place where tabs can store data to get cleared when switching to
|
||||
# a different tab.
|
||||
self._tab_data = {}
|
||||
|
||||
# so we can still select root level widgets with direction buttons
|
||||
# So we can still select root level widgets with direction buttons.
|
||||
def _simple_message(tab2: str,
|
||||
message: ba.Lstr,
|
||||
string_height: float,
|
||||
@ -331,7 +331,7 @@ class GatherWindow(ba.Window):
|
||||
('${BUTTON}',
|
||||
ba.charstr(ba.SpecialChar.TOP_BUTTON))])
|
||||
|
||||
# let's not talk about sharing in vr-mode; its tricky to fit more
|
||||
# Let's not talk about sharing in vr-mode; its tricky to fit more
|
||||
# than one head in a VR-headset ;-)
|
||||
if not ba.app.vr_mode:
|
||||
msg = ba.Lstr(
|
||||
@ -472,8 +472,8 @@ class GatherWindow(ba.Window):
|
||||
up_widget=self._tab_buttons[tab])
|
||||
ba.widget(edit=self._internet_join_text, right_widget=txt)
|
||||
|
||||
# attempt to fetch our local address so we have it for
|
||||
# error messages
|
||||
# Attempt to fetch our local address so we have it for
|
||||
# error messages.
|
||||
self._internet_local_address = None
|
||||
|
||||
class AddrFetchThread(threading.Thread):
|
||||
@ -501,9 +501,9 @@ class GatherWindow(ba.Window):
|
||||
ba.pushcall(ba.Call(self._call, val),
|
||||
from_other_thread=True)
|
||||
except Exception:
|
||||
# FIXME: Should filter out expected errors and
|
||||
# report others here.
|
||||
ba.print_exception()
|
||||
# FIXME: Should screen out expected errors and
|
||||
# report others here.
|
||||
|
||||
AddrFetchThread(ba.WeakCall(
|
||||
self._internet_fetch_local_addr_cb)).start()
|
||||
@ -518,8 +518,8 @@ class GatherWindow(ba.Window):
|
||||
timetype=ba.TimeType.REAL)
|
||||
}
|
||||
|
||||
# also update it immediately so we don't have to wait for the
|
||||
# initial query..
|
||||
# Also update it immediately so we don't have to wait for the
|
||||
# initial query.
|
||||
self._update_internet_tab()
|
||||
|
||||
elif tab == 'local_network':
|
||||
@ -545,8 +545,8 @@ class GatherWindow(ba.Window):
|
||||
ba.WeakCall(self.update),
|
||||
timetype=ba.TimeType.REAL,
|
||||
repeat=True)
|
||||
# go ahead and run a few *almost* immediately so we don't
|
||||
# have to wait a second
|
||||
# Go ahead and run a few *almost* immediately so we don't
|
||||
# have to wait a second.
|
||||
self.update()
|
||||
ba.timer(0.25,
|
||||
ba.WeakCall(self.update),
|
||||
@ -566,7 +566,8 @@ class GatherWindow(ba.Window):
|
||||
t_scale = 1.6
|
||||
for child in self._columnwidget.get_children():
|
||||
child.delete()
|
||||
# grab this now this since adding widgets will change it
|
||||
|
||||
# Grab this now this since adding widgets will change it.
|
||||
last_selected_host = self._last_selected_host
|
||||
hosts = _ba.host_scan_cycle()
|
||||
for i, host in enumerate(hosts):
|
||||
@ -843,7 +844,7 @@ class GatherWindow(ba.Window):
|
||||
color=(1, 0, 0))
|
||||
ba.playsound(ba.getsound('error'))
|
||||
else:
|
||||
# store for later
|
||||
# Store for later.
|
||||
cfg2 = ba.app.config
|
||||
cfg2['Last Manual Party Connect Address'] = addr2
|
||||
cfg2.commit()
|
||||
@ -866,7 +867,6 @@ class GatherWindow(ba.Window):
|
||||
tscl = 0.85
|
||||
tspc = 25
|
||||
|
||||
# v -= 35
|
||||
def _safe_set_text(txt3: ba.Widget,
|
||||
val: Union[str, ba.Lstr],
|
||||
success: bool = True) -> None:
|
||||
@ -875,11 +875,10 @@ class GatherWindow(ba.Window):
|
||||
text=val,
|
||||
color=(0, 1, 0) if success else (1, 1, 0))
|
||||
|
||||
# this currently doesn't work from china since we go through a
|
||||
# reverse proxy there
|
||||
# EDIT - it should work now; our proxy server forwards along
|
||||
# original IPs
|
||||
# app = ba.app
|
||||
# This currently doesn't work from china since we go through a
|
||||
# reverse proxy there.
|
||||
# UPDATE: it should work now; our proxy server forwards along
|
||||
# original IPs.
|
||||
do_internet_check = True
|
||||
|
||||
def do_it(v2: float, cnt2: Optional[ba.Widget]) -> None:
|
||||
@ -940,6 +939,7 @@ class GatherWindow(ba.Window):
|
||||
from_other_thread=True)
|
||||
except Exception as exc:
|
||||
err_str = str(exc)
|
||||
|
||||
# FIXME: Should look at exception types here,
|
||||
# not strings.
|
||||
if 'Network is unreachable' in err_str:
|
||||
@ -1024,14 +1024,15 @@ class GatherWindow(ba.Window):
|
||||
text='')
|
||||
|
||||
self._doing_access_check = False
|
||||
self._access_check_count = 0 # cap our refreshes eventually..
|
||||
self._access_check_count = 0 # Cap our refreshes eventually.
|
||||
self._tab_data['access_check_timer'] = ba.Timer(
|
||||
10.0,
|
||||
ba.WeakCall(self._access_check_update, t_addr,
|
||||
t_accessible, t_accessible_extra),
|
||||
repeat=True,
|
||||
timetype=ba.TimeType.REAL)
|
||||
# kick initial off
|
||||
|
||||
# Kick initial off.
|
||||
self._access_check_update(t_addr, t_accessible,
|
||||
t_accessible_extra)
|
||||
if check_button:
|
||||
@ -1061,7 +1062,7 @@ class GatherWindow(ba.Window):
|
||||
if playsound:
|
||||
ba.playsound(ba.getsound('click01'))
|
||||
|
||||
# if we're switching in from elsewhere, reset our selection
|
||||
# If we're switching in from elsewhere, reset our selection.
|
||||
# (prevents selecting something way down the list if we switched away
|
||||
# and came back)
|
||||
if self._internet_tab != value:
|
||||
@ -1077,7 +1078,7 @@ class GatherWindow(ba.Window):
|
||||
edit=self._internet_host_text,
|
||||
color=active_color if value == 'host' else inactive_color)
|
||||
|
||||
# clear anything in existence..
|
||||
# Clear anything in existence.
|
||||
for widget in [
|
||||
self._internet_host_scrollwidget,
|
||||
self._internet_host_name_text,
|
||||
@ -1095,7 +1096,6 @@ class GatherWindow(ba.Window):
|
||||
self._internet_join_status_text,
|
||||
self._internet_host_dedicated_server_info_text
|
||||
]:
|
||||
# widget = getattr(self, attr, None)
|
||||
if widget is not None:
|
||||
widget.delete()
|
||||
|
||||
@ -1107,9 +1107,10 @@ class GatherWindow(ba.Window):
|
||||
v -= 25
|
||||
is_public_enabled = _ba.get_public_party_enabled()
|
||||
if value == 'join':
|
||||
# reset this so we do an immediate refresh query
|
||||
# Reset this so we do an immediate refresh query.
|
||||
self._internet_join_last_refresh_time = -99999.0
|
||||
# reset our list of public parties
|
||||
|
||||
# Reset our list of public parties.
|
||||
self._public_parties = {}
|
||||
self._last_public_party_list_rebuild_time = 0
|
||||
self._first_public_party_list_rebuild_time = None
|
||||
@ -1125,8 +1126,7 @@ class GatherWindow(ba.Window):
|
||||
shadow=0.0,
|
||||
h_align='center',
|
||||
v_align='center')
|
||||
# noinspection PyUnreachableCode
|
||||
if False: # pylint: disable=using-constant-test
|
||||
if bool(False):
|
||||
self._internet_join_party_language_label = ba.textwidget(
|
||||
text=ba.Lstr(
|
||||
resource='settingsWindowAdvanced.languageText'),
|
||||
@ -1192,8 +1192,6 @@ class GatherWindow(ba.Window):
|
||||
color=(0.6, 0.6, 0.6),
|
||||
position=(c_width * 0.5, c_height * 0.5))
|
||||
|
||||
# t_scale = 1.6
|
||||
|
||||
if value == 'host':
|
||||
v -= 30
|
||||
party_name_text = ba.Lstr(
|
||||
@ -1313,15 +1311,15 @@ class GatherWindow(ba.Window):
|
||||
color=ba.app.infotextcolor,
|
||||
position=(c_width * 0.5, v))
|
||||
|
||||
# if public sharing is already on,
|
||||
# launch a status-check immediately
|
||||
# If public sharing is already on,
|
||||
# launch a status-check immediately.
|
||||
if _ba.get_public_party_enabled():
|
||||
self._do_internet_status_check()
|
||||
|
||||
# now add a lock icon overlay for if we don't have pro
|
||||
# Now add a lock icon overlay for if we don't have pro.
|
||||
icon = self._internet_lock_icon
|
||||
if icon and self._internet_lock_icon:
|
||||
self._internet_lock_icon.delete() # kill any existing
|
||||
self._internet_lock_icon.delete() # Kill any existing.
|
||||
self._internet_lock_icon = ba.imagewidget(
|
||||
parent=self._tab_container,
|
||||
position=(c_width * 0.5 - 60, c_height * 0.5 - 50),
|
||||
@ -1354,11 +1352,11 @@ class GatherWindow(ba.Window):
|
||||
def _on_public_party_query_result(
|
||||
self, result: Optional[Dict[str, Any]]) -> None:
|
||||
with ba.Context('ui'):
|
||||
# any time we get any result at all, kill our loading status
|
||||
# Any time we get any result at all, kill our loading status.
|
||||
status_text = self._internet_join_status_text
|
||||
if status_text:
|
||||
# don't show results if not signed in (probably didn't get any
|
||||
# anyway)
|
||||
# Don't show results if not signed in
|
||||
# (probably didn't get any anyway).
|
||||
if _ba.get_account_state() != 'signed_in':
|
||||
ba.textwidget(edit=status_text,
|
||||
text=ba.Lstr(resource='notSignedInText'))
|
||||
@ -1378,11 +1376,11 @@ class GatherWindow(ba.Window):
|
||||
partyval['claimed'] = False
|
||||
|
||||
for party_in in parties_in:
|
||||
# party is indexed by (ADDR)_(PORT)
|
||||
# Party is indexed by (ADDR)_(PORT)
|
||||
party_key = party_in['a'] + '_' + str(party_in['p'])
|
||||
party = self._public_parties.get(party_key)
|
||||
if party is None:
|
||||
# if this party is new to us, init it..
|
||||
# If this party is new to us, init it.
|
||||
index = self._next_public_party_entry_index
|
||||
self._next_public_party_entry_index = index + 1
|
||||
party = self._public_parties[party_key] = {
|
||||
@ -1395,7 +1393,8 @@ class GatherWindow(ba.Window):
|
||||
'index':
|
||||
index,
|
||||
}
|
||||
# now, new or not, update its values
|
||||
|
||||
# Now, new or not, update its values.
|
||||
party['queue'] = party_in.get('q')
|
||||
party['port'] = party_in.get('p')
|
||||
party['name'] = party_in['n']
|
||||
@ -1407,7 +1406,7 @@ class GatherWindow(ba.Window):
|
||||
party['ping_interval'] = 0.001 * party_in['pi']
|
||||
party['stats_addr'] = party_in['sa']
|
||||
|
||||
# prune unclaimed party entries
|
||||
# Prune unclaimed party entries.
|
||||
self._public_parties = {
|
||||
key: val
|
||||
for key, val in list(self._public_parties.items())
|
||||
@ -1423,8 +1422,9 @@ class GatherWindow(ba.Window):
|
||||
cur_time = ba.time(ba.TimeType.REAL)
|
||||
if self._first_public_party_list_rebuild_time is None:
|
||||
self._first_public_party_list_rebuild_time = cur_time
|
||||
# update faster for the first few seconds;
|
||||
# then ease off to keep the list from jumping around
|
||||
|
||||
# Update faster for the first few seconds;
|
||||
# then ease off to keep the list from jumping around.
|
||||
since_first = cur_time - self._first_public_party_list_rebuild_time
|
||||
wait_time = (1.0 if since_first < 2.0 else
|
||||
2.5 if since_first < 10.0 else 5.0)
|
||||
@ -1433,23 +1433,23 @@ class GatherWindow(ba.Window):
|
||||
return
|
||||
self._last_public_party_list_rebuild_time = cur_time
|
||||
|
||||
# first off, check for the existence of our column widget;
|
||||
# if we don't have this, we're done
|
||||
# First off, check for the existence of our column widget;
|
||||
# if we don't have this, we're done.
|
||||
columnwidget = self._internet_host_columnwidget
|
||||
if not columnwidget:
|
||||
return
|
||||
|
||||
with ba.Context('ui'):
|
||||
|
||||
# now kill and recreate all widgets
|
||||
# Now kill and recreate all widgets.
|
||||
for widget in columnwidget.get_children():
|
||||
widget.delete()
|
||||
|
||||
# sort - show queue-enabled ones first and sort by lowest ping
|
||||
# Sort - show queue-enabled ones first and sort by lowest ping.
|
||||
ordered_parties = sorted(
|
||||
list(self._public_parties.values()),
|
||||
key=lambda p: (
|
||||
p['queue'] is None, # show non-queued last
|
||||
p['queue'] is None, # Show non-queued last.
|
||||
p['ping'] if p['ping'] is not None else 999999,
|
||||
p['index'],
|
||||
p))
|
||||
@ -1457,22 +1457,19 @@ class GatherWindow(ba.Window):
|
||||
first = True
|
||||
|
||||
sub_scroll_width = 830
|
||||
# rval = random.randrange(4, 10)
|
||||
# print 'doing', rval
|
||||
# ordered_parties = ordered_parties[:rval]
|
||||
lineheight = 42
|
||||
sub_scroll_height = lineheight * len(ordered_parties) + 50
|
||||
ba.containerwidget(edit=columnwidget,
|
||||
size=(sub_scroll_width, sub_scroll_height))
|
||||
|
||||
# ew; this rebuilding generates deferred selection callbacks
|
||||
# so we need to generated deferred ignore notices for ourself
|
||||
# Ew; this rebuilding generates deferred selection callbacks
|
||||
# so we need to generated deferred ignore notices for ourself.
|
||||
def refresh_on() -> None:
|
||||
self._refreshing_public_party_list = True
|
||||
|
||||
ba.pushcall(refresh_on)
|
||||
|
||||
# janky - allow escaping if there's nothing in us
|
||||
# Janky - allow escaping if there's nothing in us.
|
||||
ba.containerwidget(edit=self._internet_host_scrollwidget,
|
||||
claims_up_down=(len(ordered_parties) > 0))
|
||||
|
||||
@ -1504,8 +1501,7 @@ class GatherWindow(ba.Window):
|
||||
if existing_selection == (party['address'], 'name'):
|
||||
ba.containerwidget(edit=columnwidget,
|
||||
selected_child=party['name_widget'])
|
||||
# noinspection PyUnreachableCode
|
||||
if False: # pylint: disable=using-constant-test
|
||||
if bool(False):
|
||||
party['language_widget'] = ba.textwidget(
|
||||
text=ba.Lstr(translate=('languages',
|
||||
party['language'])),
|
||||
@ -1621,20 +1617,20 @@ class GatherWindow(ba.Window):
|
||||
def _update_internet_tab(self) -> None:
|
||||
# pylint: disable=too-many-statements
|
||||
|
||||
# special case - if a party-queue window is up, don't do any of this
|
||||
# (keeps things smoother)
|
||||
# Special case: if a party-queue window is up, don't do any of this
|
||||
# (keeps things smoother).
|
||||
if ba.app.have_party_queue_window:
|
||||
return
|
||||
|
||||
# if we've got a party-name text widget, keep its value plugged
|
||||
# into our public host name...
|
||||
# If we've got a party-name text widget, keep its value plugged
|
||||
# into our public host name.
|
||||
text = self._internet_host_name_text
|
||||
if text:
|
||||
name = cast(str,
|
||||
ba.textwidget(query=self._internet_host_name_text))
|
||||
_ba.set_public_party_name(name)
|
||||
|
||||
# show/hide the lock icon depending on if we've got pro
|
||||
# Show/hide the lock icon depending on if we've got pro.
|
||||
icon = self._internet_lock_icon
|
||||
if icon:
|
||||
if self._is_internet_locked():
|
||||
@ -1657,17 +1653,17 @@ class GatherWindow(ba.Window):
|
||||
callback=ba.WeakCall(self._on_public_party_query_result))
|
||||
_ba.run_transactions()
|
||||
|
||||
# go through our existing public party entries firing off pings
|
||||
# for any that have timed out
|
||||
# Go through our existing public party entries firing off pings
|
||||
# for any that have timed out.
|
||||
for party in list(self._public_parties.values()):
|
||||
if (party['next_ping_time'] <= now
|
||||
and ba.app.ping_thread_count < 15):
|
||||
|
||||
# make sure to fully catch up and not to multi-ping if
|
||||
# we're way behind somehow..
|
||||
# Make sure to fully catch up and not to multi-ping if
|
||||
# we're way behind somehow.
|
||||
while party['next_ping_time'] <= now:
|
||||
# crank the interval up for high-latency parties to
|
||||
# save us some work
|
||||
# Crank the interval up for high-latency parties to
|
||||
# save us some work.
|
||||
mult = 1
|
||||
if party['ping'] is not None:
|
||||
mult = (10 if party['ping'] > 300 else
|
||||
@ -1682,8 +1678,6 @@ class GatherWindow(ba.Window):
|
||||
call: Callable[[str, int, Optional[int]],
|
||||
Optional[int]]):
|
||||
super().__init__()
|
||||
# need utf8 here to avoid an error on our minimum
|
||||
# bundled python
|
||||
self._address = address
|
||||
self._port = port
|
||||
self._call = call
|
||||
@ -1701,11 +1695,9 @@ class GatherWindow(ba.Window):
|
||||
|
||||
accessible = False
|
||||
starttime = time.time()
|
||||
# send a simple ping and wait for a response;
|
||||
# if we get it, they're accessible...
|
||||
|
||||
# send a few pings and wait a second for
|
||||
# a response
|
||||
# Send a few pings and wait a second for
|
||||
# a response.
|
||||
sock.settimeout(1)
|
||||
for _i in range(3):
|
||||
sock.send(b'\x0b')
|
||||
@ -1728,12 +1720,25 @@ class GatherWindow(ba.Window):
|
||||
from_other_thread=True)
|
||||
except OSError as exc:
|
||||
import errno
|
||||
# ignore harmless errors
|
||||
if exc.errno != errno.EHOSTUNREACH:
|
||||
ba.print_exception('error on ping',
|
||||
|
||||
# Ignore harmless errors.
|
||||
if exc.errno == errno.EHOSTUNREACH:
|
||||
pass
|
||||
elif exc.errno == errno.EADDRNOTAVAIL:
|
||||
if self._port == 0:
|
||||
# This has happened. Ignore.
|
||||
pass
|
||||
elif ba.do_once():
|
||||
print(
|
||||
f'Got EADDRNOTAVAIL on gather ping'
|
||||
f' for addr {self._address}'
|
||||
f' port {self._port}.')
|
||||
else:
|
||||
ba.print_exception('Error on gather ping.',
|
||||
once=True)
|
||||
except Exception:
|
||||
ba.print_exception('error on ping', once=True)
|
||||
ba.print_exception('Error on gather ping',
|
||||
once=True)
|
||||
ba.app.ping_thread_count -= 1
|
||||
|
||||
PingThread(party['address'], party['port'],
|
||||
@ -1741,8 +1746,8 @@ class GatherWindow(ba.Window):
|
||||
|
||||
def _ping_callback(self, address: str, port: Optional[int],
|
||||
result: Optional[int]) -> None:
|
||||
# Look for a widget corresponding to this target; if we find one,
|
||||
# update our list.
|
||||
# Look for a widget corresponding to this target.
|
||||
# If we find one, update our list.
|
||||
party = self._public_parties.get(address + '_' + str(port))
|
||||
if party is not None:
|
||||
# We now smooth ping a bit to reduce jumping around in the list
|
||||
@ -1755,9 +1760,11 @@ class GatherWindow(ba.Window):
|
||||
(1.0 - smoothing) * result)
|
||||
else:
|
||||
party['ping'] = result
|
||||
if 'ping_widget' not in party:
|
||||
pass # This can happen if we switch away and then back to the
|
||||
|
||||
# This can happen if we switch away and then back to the
|
||||
# client tab while pings are in flight.
|
||||
if 'ping_widget' not in party:
|
||||
pass
|
||||
elif party['ping_widget']:
|
||||
self._rebuild_public_party_list()
|
||||
|
||||
@ -1946,7 +1953,7 @@ class GatherWindow(ba.Window):
|
||||
ba.app.window_states[self.__class__.__name__] = {
|
||||
'sel_name': sel_name,
|
||||
'tab': self._current_tab,
|
||||
'internetTab': self._internet_tab
|
||||
'internet_tab': self._internet_tab
|
||||
}
|
||||
except Exception:
|
||||
ba.print_exception('error saving state for', self.__class__)
|
||||
@ -1955,7 +1962,7 @@ class GatherWindow(ba.Window):
|
||||
try:
|
||||
winstate = ba.app.window_states.get(self.__class__.__name__, {})
|
||||
sel_name = winstate.get('sel_name', None)
|
||||
self._internet_tab = winstate.get('internetTab', 'join')
|
||||
self._internet_tab = winstate.get('internet_tab', 'join')
|
||||
current_tab = ba.app.config.get('Gather Tab', None)
|
||||
if current_tab is None or current_tab not in self._tab_buttons:
|
||||
current_tab = 'about'
|
||||
|
||||
@ -75,7 +75,7 @@ class CallbackSet(Generic[CT]):
|
||||
# passed.
|
||||
|
||||
# To use this, simply assign your call type to this Call for type checking:
|
||||
# example:
|
||||
# Example:
|
||||
# class _MyCallWrapper:
|
||||
# <runtime class defined here>
|
||||
# if TYPE_CHECKING:
|
||||
|
||||
@ -17,6 +17,7 @@
|
||||
<li><a href="#class_ba_Actor">ba.Actor</a></li>
|
||||
<ul>
|
||||
<li><a href="#class_ba_Map">ba.Map</a></li>
|
||||
<li><a href="#class_ba_NodeActor">ba.NodeActor</a></li>
|
||||
</ul>
|
||||
<li><a href="#class_ba_Chooser">ba.Chooser</a></li>
|
||||
<li><a href="#class_ba_InputDevice">ba.InputDevice</a></li>
|
||||
@ -537,21 +538,22 @@ is a convenient way to access this same functionality.</p>
|
||||
<p>Category: <a href="#class_category_Gameplay_Classes">Gameplay Classes</a></p>
|
||||
|
||||
<p> Actors act as controllers, combining some number of <a href="#class_ba_Node">ba.Nodes</a>,
|
||||
<a href="#class_ba_Texture">ba.Textures</a>, <a href="#class_ba_Sound">ba.Sounds</a>, etc. into one cohesive unit.</p>
|
||||
<a href="#class_ba_Texture">ba.Textures</a>, <a href="#class_ba_Sound">ba.Sounds</a>, etc. into a high-level cohesive unit.</p>
|
||||
|
||||
<p> Some example actors include ba.Bomb, ba.Flag, and ba.Spaz.</p>
|
||||
<p> Some example actors include Bomb, Flag, and Spaz classes in bastd.</p>
|
||||
|
||||
<p> One key feature of Actors is that they generally 'die'
|
||||
(killing off or transitioning out their nodes) when the last Python
|
||||
reference to them disappears, so you can use logic such as:</p>
|
||||
|
||||
<pre><span><em><small> # create a flag Actor in our game activity</small></em></span>
|
||||
self.flag = ba.Flag(position=(0, 10, 0))</pre>
|
||||
<pre><span><em><small> # Create a flag Actor in our game activity:</small></em></span>
|
||||
from bastd.actor.flag import Flag
|
||||
self.flag = Flag(position=(0, 10, 0))</pre>
|
||||
|
||||
<pre><span><em><small> # later, destroy the flag..</small></em></span>
|
||||
<pre><span><em><small> # Later, destroy the flag.</small></em></span>
|
||||
<span><em><small> # (provided nothing else is holding a reference to it)</small></em></span>
|
||||
<span><em><small> # we could also just assign a new flag to this value.</small></em></span>
|
||||
<span><em><small> # either way, the old flag disappears.</small></em></span>
|
||||
<span><em><small> # We could also just assign a new flag to this value.</small></em></span>
|
||||
<span><em><small> # Either way, the old flag disappears.</small></em></span>
|
||||
self.flag = None</pre>
|
||||
|
||||
<p> This is in contrast to the behavior of the more low level <a href="#class_ba_Node">ba.Nodes</a>,
|
||||
@ -566,13 +568,13 @@ is a convenient way to access this same functionality.</p>
|
||||
takes a single arbitrary object as an argument. This provides a safe way
|
||||
to communicate between <a href="#class_ba_Actor">ba.Actor</a>, <a href="#class_ba_Activity">ba.Activity</a>, <a href="#class_ba_Session">ba.Session</a>, and any other
|
||||
class providing a handlemessage() method. The most universally handled
|
||||
message type for actors is the <a href="#class_ba_DieMessage">ba.DieMessage</a>.</p>
|
||||
message type for Actors is the <a href="#class_ba_DieMessage">ba.DieMessage</a>.</p>
|
||||
|
||||
<pre><span><em><small> # another way to kill the flag from the example above:</small></em></span>
|
||||
<span><em><small> # we can safely call this on any type with a 'handlemessage' method</small></em></span>
|
||||
<span><em><small> # (though its not guaranteed to always have a meaningful effect)</small></em></span>
|
||||
<span><em><small> # in this case the Actor instance will still be around, but its exists()</small></em></span>
|
||||
<span><em><small> # and is_alive() methods will both return False</small></em></span>
|
||||
<pre><span><em><small> # Another way to kill the flag from the example above:</small></em></span>
|
||||
<span><em><small> # We can safely call this on any type with a 'handlemessage' method</small></em></span>
|
||||
<span><em><small> # (though its not guaranteed to always have a meaningful effect).</small></em></span>
|
||||
<span><em><small> # In this case the Actor instance will still be around, but its exists()</small></em></span>
|
||||
<span><em><small> # and is_alive() methods will both return False.</small></em></span>
|
||||
self.flag.handlemessage(<a href="#class_ba_DieMessage">ba.DieMessage</a>())
|
||||
</pre>
|
||||
|
||||
@ -590,15 +592,10 @@ is a convenient way to access this same functionality.</p>
|
||||
<h5><a href="#method_ba_Actor____init__"><constructor></a>, <a href="#method_ba_Actor__autoretain">autoretain()</a>, <a href="#method_ba_Actor__exists">exists()</a>, <a href="#method_ba_Actor__getactivity">getactivity()</a>, <a href="#method_ba_Actor__handlemessage">handlemessage()</a>, <a href="#method_ba_Actor__is_alive">is_alive()</a>, <a href="#method_ba_Actor__is_expired">is_expired()</a>, <a href="#method_ba_Actor__on_expire">on_expire()</a></h5>
|
||||
<dl>
|
||||
<dt><h4><a name="method_ba_Actor____init__"><constructor></a></dt></h4><dd>
|
||||
<p><span>ba.Actor(node: <a href="#class_ba_Node">ba.Node</a> = None)</span></p>
|
||||
<p><span>ba.Actor()</span></p>
|
||||
|
||||
<p>Instantiates an Actor in the current <a href="#class_ba_Activity">ba.Activity</a>.</p>
|
||||
|
||||
<p>If 'node' is provided, it is stored as the 'node' attribute
|
||||
and the default <a href="#method_ba_Actor__handlemessage">ba.Actor.handlemessage</a>() and <a href="#method_ba_Actor__exists">ba.Actor.exists</a>()
|
||||
implementations will apply to it. This allows the creation of
|
||||
simple node-wrapping Actors without having to create a new subclass.</p>
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="method_ba_Actor__autoretain">autoretain()</a></dt></h4><dd>
|
||||
<p><span>autoretain(self: T) -> T</span></p>
|
||||
@ -627,8 +624,7 @@ their corpse is visible; this is about presence, not being 'alive'
|
||||
deleted without affecting the game; this call is often used
|
||||
when pruning lists of Actors, such as with <a href="#method_ba_Actor__autoretain">ba.Actor.autoretain</a>()</p>
|
||||
|
||||
<p>The default implementation of this method returns 'node.exists()'
|
||||
if the Actor has a 'node' attr; otherwise True.</p>
|
||||
<p>The default implementation of this method always return True.</p>
|
||||
|
||||
<p>Note that the boolean operator for the Actor class calls this method,
|
||||
so a simple "if myactor" test will conveniently do the right thing
|
||||
@ -1106,7 +1102,7 @@ when done.</p>
|
||||
<p>Instantiate a Call; pass a callable as the first
|
||||
arg, followed by any number of arguments or keywords.</p>
|
||||
|
||||
<pre><span><em><small># Example: wrap a method call with 1 positional and 1 keyword arg.</small></em></span>
|
||||
<pre><span><em><small># Example: wrap a method call with 1 positional and 1 keyword arg:</small></em></span>
|
||||
mycall = ba.Call(myobj.dostuff, argval1, namedarg=argval2)</pre>
|
||||
|
||||
<pre><span><em><small># Now we have a single callable to run that whole mess.</small></em></span>
|
||||
@ -1345,8 +1341,8 @@ Usage:</strong></p>
|
||||
sets the context as current on entry and resets it to the previous
|
||||
value on exit.</p>
|
||||
|
||||
<pre><span><em><small># example: load a few textures into the UI context</small></em></span>
|
||||
<span><em><small># (for use in widgets, etc)</small></em></span>
|
||||
<pre><span><em><small># Example: load a few textures into the UI context</small></em></span>
|
||||
<span><em><small># (for use in widgets, etc):</small></em></span>
|
||||
with <a href="#class_ba_Context">ba.Context</a>('ui'):
|
||||
tex1 = <a href="#function_ba_gettexture">ba.gettexture</a>('foo_tex_1')
|
||||
tex2 = <a href="#function_ba_gettexture">ba.gettexture</a>('foo_tex_2')</pre>
|
||||
@ -3250,7 +3246,7 @@ the two nodes exist. The connection can be severed by setting the
|
||||
target attribute to any value or connecting another node attribute
|
||||
to it.</p>
|
||||
|
||||
<pre><span><em><small># example: create a locator and attach a light to it</small></em></span>
|
||||
<pre><span><em><small># Example: create a locator and attach a light to it:</small></em></span>
|
||||
light = <a href="#function_ba_newnode">ba.newnode</a>('light')
|
||||
loc = <a href="#function_ba_newnode">ba.newnode</a>('locator', attrs={'position': (0,10,0)})
|
||||
loc.connectattr('position', light, 'position')</pre>
|
||||
@ -3311,6 +3307,48 @@ Node-messages communicate directly with the low-level node layer
|
||||
and are delivered simultaneously on all game clients,
|
||||
acting as an alternative to setting node attributes.</p>
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
<hr>
|
||||
<h2><strong><a name="class_ba_NodeActor">ba.NodeActor</a></strong></h3>
|
||||
<p>inherits from: <a href="#class_ba_Actor">ba.Actor</a></p>
|
||||
<p>A simple <a href="#class_ba_Actor">ba.Actor</a> type that wraps a single <a href="#class_ba_Node">ba.Node</a>.</p>
|
||||
|
||||
<p>Category: <a href="#class_category_Gameplay_Classes">Gameplay Classes</a></p>
|
||||
|
||||
<p> This Actor will delete its Node when told to die, and it's
|
||||
exists() call will return whether the Node still exists or not.
|
||||
</p>
|
||||
|
||||
<h3>Attributes:</h3>
|
||||
<dl>
|
||||
<dt><h4><a name="attr_ba_NodeActor__activity">activity</a></h4></dt><dd>
|
||||
<p><span><a href="#class_ba_Activity">ba.Activity</a></span></p>
|
||||
<p>The Activity this Actor was created in.</p>
|
||||
|
||||
<p> Raises a <a href="#class_ba_ActivityNotFoundError">ba.ActivityNotFoundError</a> if the Activity no longer exists.</p>
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
<h3>Methods Inherited:</h3>
|
||||
<h5><a href="#method_ba_Actor__autoretain">autoretain()</a>, <a href="#method_ba_Actor__exists">exists()</a>, <a href="#method_ba_Actor__getactivity">getactivity()</a>, <a href="#method_ba_Actor__is_alive">is_alive()</a>, <a href="#method_ba_Actor__is_expired">is_expired()</a>, <a href="#method_ba_Actor__on_expire">on_expire()</a></h5>
|
||||
<h3>Methods Defined or Overridden:</h3>
|
||||
<h5><a href="#method_ba_NodeActor____init__"><constructor></a>, <a href="#method_ba_NodeActor__handlemessage">handlemessage()</a></h5>
|
||||
<dl>
|
||||
<dt><h4><a name="method_ba_NodeActor____init__"><constructor></a></dt></h4><dd>
|
||||
<p><span>ba.NodeActor(node: <a href="#class_ba_Node">ba.Node</a>)</span></p>
|
||||
|
||||
<p>Instantiates an Actor in the current <a href="#class_ba_Activity">ba.Activity</a>.</p>
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="method_ba_NodeActor__handlemessage">handlemessage()</a></dt></h4><dd>
|
||||
<p><span>handlemessage(self, msg: Any) -> Any</span></p>
|
||||
|
||||
<p>General message handling; can be passed any <a href="#class_category_Message_Classes">message object</a>.</p>
|
||||
|
||||
<p>The default implementation will handle <a href="#class_ba_DieMessage">ba.DieMessages</a> by
|
||||
calling self.node.delete() if self contains a 'node' attribute.</p>
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
<hr>
|
||||
@ -4652,7 +4690,7 @@ Real time timers are currently only available in the UI context.</p>
|
||||
<p>the 'timeformat' arg defaults to SECONDS but can also be MILLISECONDS
|
||||
if you want to pass time as milliseconds.</p>
|
||||
|
||||
<pre><span><em><small># example: use a Timer object to print repeatedly for a few seconds:</small></em></span>
|
||||
<pre><span><em><small># Example: use a Timer object to print repeatedly for a few seconds:</small></em></span>
|
||||
def say_it():
|
||||
<a href="#function_ba_screenmessage">ba.screenmessage</a>('BADGER!')
|
||||
def stop_saying_it():
|
||||
@ -4817,7 +4855,7 @@ self.t = <a href="#class_ba_Timer">ba.Timer</a>(0.3, say_it, repeat=True)
|
||||
<p>Instantiate a WeakCall; pass a callable as the first
|
||||
arg, followed by any number of arguments or keywords.</p>
|
||||
|
||||
<pre><span><em><small># example: wrap a method call with some positional and</small></em></span>
|
||||
<pre><span><em><small># Example: wrap a method call with some positional and</small></em></span>
|
||||
<span><em><small># keyword args:</small></em></span>
|
||||
myweakcall = ba.WeakCall(myobj.dostuff, argval1, namedarg=argval2)</pre>
|
||||
|
||||
@ -5149,6 +5187,11 @@ logs. The call functions by registering the filename and line where
|
||||
The call is made from. Returns True if this location has not been
|
||||
registered already, and False if it has.</p>
|
||||
|
||||
<pre><span><em><small># Example: this print will only fire for the first loop iteration:</small></em></span>
|
||||
for i in range(10):
|
||||
if <a href="#function_ba_do_once">ba.do_once</a>():
|
||||
print('Hello once from loop!')</pre>
|
||||
|
||||
<hr>
|
||||
<h2><strong><a name="function_ba_emitfx">ba.emitfx()</a></strong></h3>
|
||||
<p><span>emitfx(position: Sequence[float],
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user