mirror of
https://github.com/hypervortex/VH-Bombsquad-Modded-Server-Files
synced 2025-11-07 17:36:08 +00:00
640 lines
22 KiB
Python
640 lines
22 KiB
Python
|
|
# Released under the MIT License. See LICENSE for details.
|
||
|
|
#
|
||
|
|
"""Defines Actors related to controls guides."""
|
||
|
|
|
||
|
|
from __future__ import annotations
|
||
|
|
|
||
|
|
from typing import TYPE_CHECKING
|
||
|
|
|
||
|
|
import ba
|
||
|
|
import ba.internal
|
||
|
|
|
||
|
|
if TYPE_CHECKING:
|
||
|
|
from typing import Any, Sequence
|
||
|
|
|
||
|
|
|
||
|
|
class ControlsGuide(ba.Actor):
|
||
|
|
"""A screen overlay of game controls.
|
||
|
|
|
||
|
|
category: Gameplay Classes
|
||
|
|
|
||
|
|
Shows button mappings based on what controllers are connected.
|
||
|
|
Handy to show at the start of a series or whenever there might
|
||
|
|
be newbies watching.
|
||
|
|
"""
|
||
|
|
|
||
|
|
def __init__(
|
||
|
|
self,
|
||
|
|
position: tuple[float, float] = (390.0, 120.0),
|
||
|
|
scale: float = 1.0,
|
||
|
|
delay: float = 0.0,
|
||
|
|
lifespan: float | None = None,
|
||
|
|
bright: bool = False,
|
||
|
|
):
|
||
|
|
"""Instantiate an overlay.
|
||
|
|
|
||
|
|
delay: is the time in seconds before the overlay fades in.
|
||
|
|
|
||
|
|
lifespan: if not None, the overlay will fade back out and die after
|
||
|
|
that long (in milliseconds).
|
||
|
|
|
||
|
|
bright: if True, brighter colors will be used; handy when showing
|
||
|
|
over gameplay but may be too bright for join-screens, etc.
|
||
|
|
"""
|
||
|
|
# pylint: disable=too-many-statements
|
||
|
|
# pylint: disable=too-many-locals
|
||
|
|
super().__init__()
|
||
|
|
show_title = True
|
||
|
|
scale *= 0.75
|
||
|
|
image_size = 90.0 * scale
|
||
|
|
offs = 74.0 * scale
|
||
|
|
offs5 = 43.0 * scale
|
||
|
|
ouya = False
|
||
|
|
maxw = 50
|
||
|
|
self._lifespan = lifespan
|
||
|
|
self._dead = False
|
||
|
|
self._bright = bright
|
||
|
|
self._cancel_timer: ba.Timer | None = None
|
||
|
|
self._fade_in_timer: ba.Timer | None = None
|
||
|
|
self._update_timer: ba.Timer | None = None
|
||
|
|
self._title_text: ba.Node | None
|
||
|
|
clr: Sequence[float]
|
||
|
|
extra_pos_1: tuple[float, float] | None
|
||
|
|
extra_pos_2: tuple[float, float] | None
|
||
|
|
if ba.app.iircade_mode:
|
||
|
|
xtweak = 0.2
|
||
|
|
ytweak = 0.2
|
||
|
|
jump_pos = (
|
||
|
|
position[0] + offs * (-1.2 + xtweak),
|
||
|
|
position[1] + offs * (0.1 + ytweak),
|
||
|
|
)
|
||
|
|
bomb_pos = (
|
||
|
|
position[0] + offs * (0.0 + xtweak),
|
||
|
|
position[1] + offs * (0.5 + ytweak),
|
||
|
|
)
|
||
|
|
punch_pos = (
|
||
|
|
position[0] + offs * (1.2 + xtweak),
|
||
|
|
position[1] + offs * (0.5 + ytweak),
|
||
|
|
)
|
||
|
|
|
||
|
|
pickup_pos = (
|
||
|
|
position[0] + offs * (-1.4 + xtweak),
|
||
|
|
position[1] + offs * (-1.2 + ytweak),
|
||
|
|
)
|
||
|
|
extra_pos_1 = (
|
||
|
|
position[0] + offs * (-0.2 + xtweak),
|
||
|
|
position[1] + offs * (-0.8 + ytweak),
|
||
|
|
)
|
||
|
|
extra_pos_2 = (
|
||
|
|
position[0] + offs * (1.0 + xtweak),
|
||
|
|
position[1] + offs * (-0.8 + ytweak),
|
||
|
|
)
|
||
|
|
self._force_hide_button_names = True
|
||
|
|
else:
|
||
|
|
punch_pos = (position[0] - offs * 1.1, position[1])
|
||
|
|
jump_pos = (position[0], position[1] - offs)
|
||
|
|
bomb_pos = (position[0] + offs * 1.1, position[1])
|
||
|
|
pickup_pos = (position[0], position[1] + offs)
|
||
|
|
extra_pos_1 = None
|
||
|
|
extra_pos_2 = None
|
||
|
|
self._force_hide_button_names = False
|
||
|
|
|
||
|
|
if show_title:
|
||
|
|
self._title_text_pos_top = (
|
||
|
|
position[0],
|
||
|
|
position[1] + 139.0 * scale,
|
||
|
|
)
|
||
|
|
self._title_text_pos_bottom = (
|
||
|
|
position[0],
|
||
|
|
position[1] + 139.0 * scale,
|
||
|
|
)
|
||
|
|
clr = (1, 1, 1) if bright else (0.7, 0.7, 0.7)
|
||
|
|
tval = ba.Lstr(
|
||
|
|
value='${A}:', subs=[('${A}', ba.Lstr(resource='controlsText'))]
|
||
|
|
)
|
||
|
|
self._title_text = ba.newnode(
|
||
|
|
'text',
|
||
|
|
attrs={
|
||
|
|
'text': tval,
|
||
|
|
'host_only': True,
|
||
|
|
'scale': 1.1 * scale,
|
||
|
|
'shadow': 0.5,
|
||
|
|
'flatness': 1.0,
|
||
|
|
'maxwidth': 480,
|
||
|
|
'v_align': 'center',
|
||
|
|
'h_align': 'center',
|
||
|
|
'color': clr,
|
||
|
|
},
|
||
|
|
)
|
||
|
|
else:
|
||
|
|
self._title_text = None
|
||
|
|
pos = jump_pos
|
||
|
|
clr = (0.4, 1, 0.4)
|
||
|
|
self._jump_image = ba.newnode(
|
||
|
|
'image',
|
||
|
|
attrs={
|
||
|
|
'texture': ba.gettexture('buttonJump'),
|
||
|
|
'absolute_scale': True,
|
||
|
|
'host_only': True,
|
||
|
|
'vr_depth': 10,
|
||
|
|
'position': pos,
|
||
|
|
'scale': (image_size, image_size),
|
||
|
|
'color': clr,
|
||
|
|
},
|
||
|
|
)
|
||
|
|
self._jump_text = ba.newnode(
|
||
|
|
'text',
|
||
|
|
attrs={
|
||
|
|
'v_align': 'top',
|
||
|
|
'h_align': 'center',
|
||
|
|
'scale': 1.5 * scale,
|
||
|
|
'flatness': 1.0,
|
||
|
|
'host_only': True,
|
||
|
|
'shadow': 1.0,
|
||
|
|
'maxwidth': maxw,
|
||
|
|
'position': (pos[0], pos[1] - offs5),
|
||
|
|
'color': clr,
|
||
|
|
},
|
||
|
|
)
|
||
|
|
clr = (0.2, 0.6, 1) if ouya else (1, 0.7, 0.3)
|
||
|
|
pos = punch_pos
|
||
|
|
self._punch_image = ba.newnode(
|
||
|
|
'image',
|
||
|
|
attrs={
|
||
|
|
'texture': ba.gettexture('buttonPunch'),
|
||
|
|
'absolute_scale': True,
|
||
|
|
'host_only': True,
|
||
|
|
'vr_depth': 10,
|
||
|
|
'position': pos,
|
||
|
|
'scale': (image_size, image_size),
|
||
|
|
'color': clr,
|
||
|
|
},
|
||
|
|
)
|
||
|
|
self._punch_text = ba.newnode(
|
||
|
|
'text',
|
||
|
|
attrs={
|
||
|
|
'v_align': 'top',
|
||
|
|
'h_align': 'center',
|
||
|
|
'scale': 1.5 * scale,
|
||
|
|
'flatness': 1.0,
|
||
|
|
'host_only': True,
|
||
|
|
'shadow': 1.0,
|
||
|
|
'maxwidth': maxw,
|
||
|
|
'position': (pos[0], pos[1] - offs5),
|
||
|
|
'color': clr,
|
||
|
|
},
|
||
|
|
)
|
||
|
|
pos = bomb_pos
|
||
|
|
clr = (1, 0.3, 0.3)
|
||
|
|
self._bomb_image = ba.newnode(
|
||
|
|
'image',
|
||
|
|
attrs={
|
||
|
|
'texture': ba.gettexture('buttonBomb'),
|
||
|
|
'absolute_scale': True,
|
||
|
|
'host_only': True,
|
||
|
|
'vr_depth': 10,
|
||
|
|
'position': pos,
|
||
|
|
'scale': (image_size, image_size),
|
||
|
|
'color': clr,
|
||
|
|
},
|
||
|
|
)
|
||
|
|
self._bomb_text = ba.newnode(
|
||
|
|
'text',
|
||
|
|
attrs={
|
||
|
|
'h_align': 'center',
|
||
|
|
'v_align': 'top',
|
||
|
|
'scale': 1.5 * scale,
|
||
|
|
'flatness': 1.0,
|
||
|
|
'host_only': True,
|
||
|
|
'shadow': 1.0,
|
||
|
|
'maxwidth': maxw,
|
||
|
|
'position': (pos[0], pos[1] - offs5),
|
||
|
|
'color': clr,
|
||
|
|
},
|
||
|
|
)
|
||
|
|
pos = pickup_pos
|
||
|
|
clr = (1, 0.8, 0.3) if ouya else (0.8, 0.5, 1)
|
||
|
|
self._pickup_image = ba.newnode(
|
||
|
|
'image',
|
||
|
|
attrs={
|
||
|
|
'texture': ba.gettexture('buttonPickUp'),
|
||
|
|
'absolute_scale': True,
|
||
|
|
'host_only': True,
|
||
|
|
'vr_depth': 10,
|
||
|
|
'position': pos,
|
||
|
|
'scale': (image_size, image_size),
|
||
|
|
'color': clr,
|
||
|
|
},
|
||
|
|
)
|
||
|
|
self._pick_up_text = ba.newnode(
|
||
|
|
'text',
|
||
|
|
attrs={
|
||
|
|
'v_align': 'top',
|
||
|
|
'h_align': 'center',
|
||
|
|
'scale': 1.5 * scale,
|
||
|
|
'flatness': 1.0,
|
||
|
|
'host_only': True,
|
||
|
|
'shadow': 1.0,
|
||
|
|
'maxwidth': maxw,
|
||
|
|
'position': (pos[0], pos[1] - offs5),
|
||
|
|
'color': clr,
|
||
|
|
},
|
||
|
|
)
|
||
|
|
clr = (0.9, 0.9, 2.0, 1.0) if bright else (0.8, 0.8, 2.0, 1.0)
|
||
|
|
self._run_text_pos_top = (position[0], position[1] - 135.0 * scale)
|
||
|
|
self._run_text_pos_bottom = (position[0], position[1] - 172.0 * scale)
|
||
|
|
sval = 1.0 * scale if ba.app.vr_mode else 0.8 * scale
|
||
|
|
self._run_text = ba.newnode(
|
||
|
|
'text',
|
||
|
|
attrs={
|
||
|
|
'scale': sval,
|
||
|
|
'host_only': True,
|
||
|
|
'shadow': 1.0 if ba.app.vr_mode else 0.5,
|
||
|
|
'flatness': 1.0,
|
||
|
|
'maxwidth': 380,
|
||
|
|
'v_align': 'top',
|
||
|
|
'h_align': 'center',
|
||
|
|
'color': clr,
|
||
|
|
},
|
||
|
|
)
|
||
|
|
clr = (1, 1, 1) if bright else (0.7, 0.7, 0.7)
|
||
|
|
self._extra_text = ba.newnode(
|
||
|
|
'text',
|
||
|
|
attrs={
|
||
|
|
'scale': 0.8 * scale,
|
||
|
|
'host_only': True,
|
||
|
|
'shadow': 0.5,
|
||
|
|
'flatness': 1.0,
|
||
|
|
'maxwidth': 380,
|
||
|
|
'v_align': 'top',
|
||
|
|
'h_align': 'center',
|
||
|
|
'color': clr,
|
||
|
|
},
|
||
|
|
)
|
||
|
|
|
||
|
|
if extra_pos_1 is not None:
|
||
|
|
self._extra_image_1: ba.Node | None = ba.newnode(
|
||
|
|
'image',
|
||
|
|
attrs={
|
||
|
|
'texture': ba.gettexture('nub'),
|
||
|
|
'absolute_scale': True,
|
||
|
|
'host_only': True,
|
||
|
|
'vr_depth': 10,
|
||
|
|
'position': extra_pos_1,
|
||
|
|
'scale': (image_size, image_size),
|
||
|
|
'color': (0.5, 0.5, 0.5),
|
||
|
|
},
|
||
|
|
)
|
||
|
|
else:
|
||
|
|
self._extra_image_1 = None
|
||
|
|
if extra_pos_2 is not None:
|
||
|
|
self._extra_image_2: ba.Node | None = ba.newnode(
|
||
|
|
'image',
|
||
|
|
attrs={
|
||
|
|
'texture': ba.gettexture('nub'),
|
||
|
|
'absolute_scale': True,
|
||
|
|
'host_only': True,
|
||
|
|
'vr_depth': 10,
|
||
|
|
'position': extra_pos_2,
|
||
|
|
'scale': (image_size, image_size),
|
||
|
|
'color': (0.5, 0.5, 0.5),
|
||
|
|
},
|
||
|
|
)
|
||
|
|
else:
|
||
|
|
self._extra_image_2 = None
|
||
|
|
|
||
|
|
self._nodes = [
|
||
|
|
self._bomb_image,
|
||
|
|
self._bomb_text,
|
||
|
|
self._punch_image,
|
||
|
|
self._punch_text,
|
||
|
|
self._jump_image,
|
||
|
|
self._jump_text,
|
||
|
|
self._pickup_image,
|
||
|
|
self._pick_up_text,
|
||
|
|
self._run_text,
|
||
|
|
self._extra_text,
|
||
|
|
]
|
||
|
|
if show_title:
|
||
|
|
assert self._title_text
|
||
|
|
self._nodes.append(self._title_text)
|
||
|
|
if self._extra_image_1 is not None:
|
||
|
|
self._nodes.append(self._extra_image_1)
|
||
|
|
if self._extra_image_2 is not None:
|
||
|
|
self._nodes.append(self._extra_image_2)
|
||
|
|
|
||
|
|
# Start everything invisible.
|
||
|
|
for node in self._nodes:
|
||
|
|
node.opacity = 0.0
|
||
|
|
|
||
|
|
# Don't do anything until our delay has passed.
|
||
|
|
ba.timer(delay, ba.WeakCall(self._start_updating))
|
||
|
|
|
||
|
|
@staticmethod
|
||
|
|
def _meaningful_button_name(device: ba.InputDevice, button: int) -> str:
|
||
|
|
"""Return a flattened string button name; empty for non-meaningful."""
|
||
|
|
if not device.has_meaningful_button_names:
|
||
|
|
return ''
|
||
|
|
return device.get_button_name(button).evaluate()
|
||
|
|
|
||
|
|
def _start_updating(self) -> None:
|
||
|
|
|
||
|
|
# Ok, our delay has passed. Now lets periodically see if we can fade
|
||
|
|
# in (if a touch-screen is present we only want to show up if gamepads
|
||
|
|
# are connected, etc).
|
||
|
|
# Also set up a timer so if we haven't faded in by the end of our
|
||
|
|
# duration, abort.
|
||
|
|
if self._lifespan is not None:
|
||
|
|
self._cancel_timer = ba.Timer(
|
||
|
|
self._lifespan,
|
||
|
|
ba.WeakCall(self.handlemessage, ba.DieMessage(immediate=True)),
|
||
|
|
)
|
||
|
|
self._fade_in_timer = ba.Timer(
|
||
|
|
1.0, ba.WeakCall(self._check_fade_in), repeat=True
|
||
|
|
)
|
||
|
|
self._check_fade_in() # Do one check immediately.
|
||
|
|
|
||
|
|
def _check_fade_in(self) -> None:
|
||
|
|
from ba.internal import get_device_value
|
||
|
|
|
||
|
|
# If we have a touchscreen, we only fade in if we have a player with
|
||
|
|
# an input device that is *not* the touchscreen.
|
||
|
|
# (otherwise it is confusing to see the touchscreen buttons right
|
||
|
|
# next to our display buttons)
|
||
|
|
touchscreen: ba.InputDevice | None = ba.internal.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.inputdevice for p in ba.getsession().sessionplayers
|
||
|
|
]
|
||
|
|
input_devices = [
|
||
|
|
i for i in input_devices if i and i is not touchscreen
|
||
|
|
]
|
||
|
|
fade_in = False
|
||
|
|
if input_devices:
|
||
|
|
# Only count this one if it has non-empty button names
|
||
|
|
# (filters out wiimotes, the remote-app, etc).
|
||
|
|
for device in input_devices:
|
||
|
|
for name in (
|
||
|
|
'buttonPunch',
|
||
|
|
'buttonJump',
|
||
|
|
'buttonBomb',
|
||
|
|
'buttonPickUp',
|
||
|
|
):
|
||
|
|
if (
|
||
|
|
self._meaningful_button_name(
|
||
|
|
device, get_device_value(device, name)
|
||
|
|
)
|
||
|
|
!= ''
|
||
|
|
):
|
||
|
|
fade_in = True
|
||
|
|
break
|
||
|
|
if fade_in:
|
||
|
|
break # No need to keep looking.
|
||
|
|
else:
|
||
|
|
# No touch-screen; fade in immediately.
|
||
|
|
fade_in = True
|
||
|
|
if fade_in:
|
||
|
|
self._cancel_timer = None # Didn't need this.
|
||
|
|
self._fade_in_timer = None # Done with this.
|
||
|
|
self._fade_in()
|
||
|
|
|
||
|
|
def _fade_in(self) -> None:
|
||
|
|
for node in self._nodes:
|
||
|
|
ba.animate(node, 'opacity', {0: 0.0, 2.0: 1.0})
|
||
|
|
|
||
|
|
# If we were given a lifespan, transition out after it.
|
||
|
|
if self._lifespan is not None:
|
||
|
|
ba.timer(
|
||
|
|
self._lifespan, ba.WeakCall(self.handlemessage, ba.DieMessage())
|
||
|
|
)
|
||
|
|
self._update()
|
||
|
|
self._update_timer = ba.Timer(
|
||
|
|
1.0, ba.WeakCall(self._update), repeat=True
|
||
|
|
)
|
||
|
|
|
||
|
|
def _update(self) -> None:
|
||
|
|
# pylint: disable=too-many-statements
|
||
|
|
# pylint: disable=too-many-branches
|
||
|
|
# pylint: disable=too-many-locals
|
||
|
|
from ba.internal import get_device_value, get_remote_app_name
|
||
|
|
|
||
|
|
if self._dead:
|
||
|
|
return
|
||
|
|
punch_button_names = set()
|
||
|
|
jump_button_names = set()
|
||
|
|
pickup_button_names = set()
|
||
|
|
bomb_button_names = set()
|
||
|
|
|
||
|
|
# 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.inputdevice for p in ba.getsession().sessionplayers]
|
||
|
|
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.internal.getinputdevice('Keyboard', '#1', doraise=False)
|
||
|
|
if kbd is not None:
|
||
|
|
input_devices.append(kbd)
|
||
|
|
|
||
|
|
# We word things specially if we have nothing but keyboards.
|
||
|
|
all_keyboards = input_devices and all(
|
||
|
|
i.name == 'Keyboard' for i in input_devices
|
||
|
|
)
|
||
|
|
only_remote = len(input_devices) == 1 and all(
|
||
|
|
i.name == 'Amazon Fire TV Remote' for i in input_devices
|
||
|
|
)
|
||
|
|
|
||
|
|
right_button_names = set()
|
||
|
|
left_button_names = set()
|
||
|
|
up_button_names = set()
|
||
|
|
down_button_names = set()
|
||
|
|
|
||
|
|
# For each player in the game with an input device,
|
||
|
|
# get the name of the button for each of these 4 actions.
|
||
|
|
# If any of them are uniform across all devices, display the name.
|
||
|
|
for device in input_devices:
|
||
|
|
# We only care about movement buttons in the case of keyboards.
|
||
|
|
if all_keyboards:
|
||
|
|
right_button_names.add(
|
||
|
|
device.get_button_name(
|
||
|
|
get_device_value(device, 'buttonRight')
|
||
|
|
)
|
||
|
|
)
|
||
|
|
left_button_names.add(
|
||
|
|
device.get_button_name(
|
||
|
|
get_device_value(device, 'buttonLeft')
|
||
|
|
)
|
||
|
|
)
|
||
|
|
down_button_names.add(
|
||
|
|
device.get_button_name(
|
||
|
|
get_device_value(device, 'buttonDown')
|
||
|
|
)
|
||
|
|
)
|
||
|
|
up_button_names.add(
|
||
|
|
device.get_button_name(get_device_value(device, 'buttonUp'))
|
||
|
|
)
|
||
|
|
|
||
|
|
# Ignore empty values; things like the remote app or
|
||
|
|
# wiimotes can return these.
|
||
|
|
bname = self._meaningful_button_name(
|
||
|
|
device, get_device_value(device, 'buttonPunch')
|
||
|
|
)
|
||
|
|
if bname != '':
|
||
|
|
punch_button_names.add(bname)
|
||
|
|
bname = self._meaningful_button_name(
|
||
|
|
device, get_device_value(device, 'buttonJump')
|
||
|
|
)
|
||
|
|
if bname != '':
|
||
|
|
jump_button_names.add(bname)
|
||
|
|
bname = self._meaningful_button_name(
|
||
|
|
device, get_device_value(device, 'buttonBomb')
|
||
|
|
)
|
||
|
|
if bname != '':
|
||
|
|
bomb_button_names.add(bname)
|
||
|
|
bname = self._meaningful_button_name(
|
||
|
|
device, get_device_value(device, 'buttonPickUp')
|
||
|
|
)
|
||
|
|
if bname != '':
|
||
|
|
pickup_button_names.add(bname)
|
||
|
|
|
||
|
|
# If we have no values yet, we may want to throw out some sane
|
||
|
|
# defaults.
|
||
|
|
if all(
|
||
|
|
not lst
|
||
|
|
for lst in (
|
||
|
|
punch_button_names,
|
||
|
|
jump_button_names,
|
||
|
|
bomb_button_names,
|
||
|
|
pickup_button_names,
|
||
|
|
)
|
||
|
|
):
|
||
|
|
# Otherwise on android show standard buttons.
|
||
|
|
if ba.app.platform == 'android':
|
||
|
|
punch_button_names.add('X')
|
||
|
|
jump_button_names.add('A')
|
||
|
|
bomb_button_names.add('B')
|
||
|
|
pickup_button_names.add('Y')
|
||
|
|
|
||
|
|
run_text = ba.Lstr(
|
||
|
|
value='${R}: ${B}',
|
||
|
|
subs=[
|
||
|
|
('${R}', ba.Lstr(resource='runText')),
|
||
|
|
(
|
||
|
|
'${B}',
|
||
|
|
ba.Lstr(
|
||
|
|
resource='holdAnyKeyText'
|
||
|
|
if all_keyboards
|
||
|
|
else 'holdAnyButtonText'
|
||
|
|
),
|
||
|
|
),
|
||
|
|
],
|
||
|
|
)
|
||
|
|
|
||
|
|
# If we're all keyboards, lets show move keys too.
|
||
|
|
if (
|
||
|
|
all_keyboards
|
||
|
|
and len(up_button_names) == 1
|
||
|
|
and len(down_button_names) == 1
|
||
|
|
and len(left_button_names) == 1
|
||
|
|
and len(right_button_names) == 1
|
||
|
|
):
|
||
|
|
up_text = list(up_button_names)[0]
|
||
|
|
down_text = list(down_button_names)[0]
|
||
|
|
left_text = list(left_button_names)[0]
|
||
|
|
right_text = list(right_button_names)[0]
|
||
|
|
run_text = ba.Lstr(
|
||
|
|
value='${M}: ${U}, ${L}, ${D}, ${R}\n${RUN}',
|
||
|
|
subs=[
|
||
|
|
('${M}', ba.Lstr(resource='moveText')),
|
||
|
|
('${U}', up_text),
|
||
|
|
('${L}', left_text),
|
||
|
|
('${D}', down_text),
|
||
|
|
('${R}', right_text),
|
||
|
|
('${RUN}', run_text),
|
||
|
|
],
|
||
|
|
)
|
||
|
|
|
||
|
|
if self._force_hide_button_names:
|
||
|
|
jump_button_names.clear()
|
||
|
|
punch_button_names.clear()
|
||
|
|
bomb_button_names.clear()
|
||
|
|
pickup_button_names.clear()
|
||
|
|
|
||
|
|
self._run_text.text = run_text
|
||
|
|
w_text: ba.Lstr | str
|
||
|
|
if only_remote and self._lifespan is None:
|
||
|
|
w_text = ba.Lstr(
|
||
|
|
resource='fireTVRemoteWarningText',
|
||
|
|
subs=[('${REMOTE_APP_NAME}', get_remote_app_name())],
|
||
|
|
)
|
||
|
|
else:
|
||
|
|
w_text = ''
|
||
|
|
self._extra_text.text = w_text
|
||
|
|
if len(punch_button_names) == 1:
|
||
|
|
self._punch_text.text = list(punch_button_names)[0]
|
||
|
|
else:
|
||
|
|
self._punch_text.text = ''
|
||
|
|
|
||
|
|
if len(jump_button_names) == 1:
|
||
|
|
tval = list(jump_button_names)[0]
|
||
|
|
else:
|
||
|
|
tval = ''
|
||
|
|
self._jump_text.text = tval
|
||
|
|
if tval == '':
|
||
|
|
self._run_text.position = self._run_text_pos_top
|
||
|
|
self._extra_text.position = (
|
||
|
|
self._run_text_pos_top[0],
|
||
|
|
self._run_text_pos_top[1] - 50,
|
||
|
|
)
|
||
|
|
else:
|
||
|
|
self._run_text.position = self._run_text_pos_bottom
|
||
|
|
self._extra_text.position = (
|
||
|
|
self._run_text_pos_bottom[0],
|
||
|
|
self._run_text_pos_bottom[1] - 50,
|
||
|
|
)
|
||
|
|
if len(bomb_button_names) == 1:
|
||
|
|
self._bomb_text.text = list(bomb_button_names)[0]
|
||
|
|
else:
|
||
|
|
self._bomb_text.text = ''
|
||
|
|
|
||
|
|
# Also move our title up/down depending on if this is shown.
|
||
|
|
if len(pickup_button_names) == 1:
|
||
|
|
self._pick_up_text.text = list(pickup_button_names)[0]
|
||
|
|
if self._title_text is not None:
|
||
|
|
self._title_text.position = self._title_text_pos_top
|
||
|
|
else:
|
||
|
|
self._pick_up_text.text = ''
|
||
|
|
if self._title_text is not None:
|
||
|
|
self._title_text.position = self._title_text_pos_bottom
|
||
|
|
|
||
|
|
def _die(self) -> None:
|
||
|
|
for node in self._nodes:
|
||
|
|
node.delete()
|
||
|
|
self._nodes = []
|
||
|
|
self._update_timer = None
|
||
|
|
self._dead = True
|
||
|
|
|
||
|
|
def exists(self) -> bool:
|
||
|
|
return not self._dead
|
||
|
|
|
||
|
|
def handlemessage(self, msg: Any) -> Any:
|
||
|
|
assert not self.expired
|
||
|
|
if isinstance(msg, ba.DieMessage):
|
||
|
|
if msg.immediate:
|
||
|
|
self._die()
|
||
|
|
else:
|
||
|
|
# If they don't need immediate,
|
||
|
|
# fade out our nodes and die later.
|
||
|
|
for node in self._nodes:
|
||
|
|
ba.animate(node, 'opacity', {0: node.opacity, 3.0: 0.0})
|
||
|
|
ba.timer(3.1, ba.WeakCall(self._die))
|
||
|
|
return None
|
||
|
|
return super().handlemessage(msg)
|