mirror of
https://github.com/RYDE-WORK/ballistica.git
synced 2026-01-30 11:13:17 +08:00
Merge branch 'master' into pubsync
This commit is contained in:
commit
967d0f19d8
1
.idea/dictionaries/ericf.xml
generated
1
.idea/dictionaries/ericf.xml
generated
@ -1556,6 +1556,7 @@
|
||||
<w>spammy</w>
|
||||
<w>sparx</w>
|
||||
<w>spawner</w>
|
||||
<w>spawners</w>
|
||||
<w>spawnpoints</w>
|
||||
<w>spawnpt</w>
|
||||
<w>spawntype</w>
|
||||
|
||||
@ -34,6 +34,7 @@ if TYPE_CHECKING:
|
||||
from typing import (List, Optional, Dict, Type, Any, Callable, Sequence,
|
||||
Tuple, Union)
|
||||
from bastd.actor.playerspaz import PlayerSpaz
|
||||
from bastd.actor.bomb import TNTSpawner
|
||||
import ba
|
||||
|
||||
|
||||
@ -330,7 +331,7 @@ class GameActivity(Activity):
|
||||
self._map_type.preload()
|
||||
self._map: Optional[ba.Map] = None
|
||||
self._powerup_drop_timer: Optional[ba.Timer] = None
|
||||
self._tnt_objs: Optional[Dict[int, Any]] = None
|
||||
self._tnt_spawners: Optional[Dict[int, TNTSpawner]] = None
|
||||
self._tnt_drop_timer: Optional[ba.Timer] = None
|
||||
self.initial_player_info: Optional[List[Dict[str, Any]]] = None
|
||||
self._game_scoreboard_name_text: Optional[ba.Actor] = None
|
||||
@ -1111,12 +1112,8 @@ class GameActivity(Activity):
|
||||
repeat=True)
|
||||
self._standard_drop_powerups()
|
||||
if enable_tnt:
|
||||
self._tnt_objs = {}
|
||||
self._tnt_drop_timer = _ba.Timer(5.5,
|
||||
_general.WeakCall(
|
||||
self._standard_drop_tnt),
|
||||
repeat=True)
|
||||
self._standard_drop_tnt()
|
||||
self._tnt_spawners = {}
|
||||
self._setup_standard_tnt_drops()
|
||||
|
||||
def _standard_drop_powerup(self, index: int, expire: bool = True) -> None:
|
||||
# pylint: disable=cyclic-import
|
||||
@ -1136,24 +1133,15 @@ class GameActivity(Activity):
|
||||
_ba.timer(i * 0.4, _general.WeakCall(self._standard_drop_powerup,
|
||||
i))
|
||||
|
||||
def _standard_drop_tnt(self) -> None:
|
||||
def _setup_standard_tnt_drops(self) -> None:
|
||||
"""Standard tnt drop."""
|
||||
# pylint: disable=cyclic-import
|
||||
from bastd.actor import bomb
|
||||
from bastd.actor.bomb import TNTSpawner
|
||||
|
||||
# Drop TNT on the map for any tnt location with no existing tnt box.
|
||||
for i, point in enumerate(self.map.tnt_points):
|
||||
assert self._tnt_objs is not None
|
||||
if i not in self._tnt_objs:
|
||||
self._tnt_objs[i] = {'absent_ticks': 9999, 'obj': None}
|
||||
tnt_obj = self._tnt_objs[i]
|
||||
|
||||
# Respawn once its been dead for a while.
|
||||
if not tnt_obj['obj']:
|
||||
tnt_obj['absent_ticks'] += 1
|
||||
if tnt_obj['absent_ticks'] > 3:
|
||||
tnt_obj['obj'] = bomb.Bomb(position=point, bomb_type='tnt')
|
||||
tnt_obj['absent_ticks'] = 0
|
||||
assert self._tnt_spawners is not None
|
||||
if self._tnt_spawners.get(i) is None:
|
||||
self._tnt_spawners[i] = TNTSpawner(point)
|
||||
|
||||
def setup_standard_time_limit(self, duration: float) -> None:
|
||||
"""
|
||||
|
||||
@ -87,16 +87,18 @@ class ServerCallThread(threading.Thread):
|
||||
activity) if activity is not None else None
|
||||
|
||||
def _run_callback(self, arg: Union[None, Dict[str, Any]]) -> None:
|
||||
|
||||
# If we were created in an activity context and that activity has
|
||||
# since died, do nothing (hmm should we be using a context-call
|
||||
# instead of doing this manually?).
|
||||
activity = None if self._activity is None else self._activity()
|
||||
if activity is None or activity.is_expired():
|
||||
return
|
||||
# since died, do nothing.
|
||||
# FIXME: Should we just be using a ContextCall instead of doing
|
||||
# this check manually?
|
||||
if self._activity is not None:
|
||||
activity = self._activity()
|
||||
if activity is None or activity.is_expired():
|
||||
return
|
||||
|
||||
# Technically we could do the same check for session contexts,
|
||||
# but not gonna worry about it for now.
|
||||
assert self._context is not None
|
||||
assert self._callback is not None
|
||||
with self._context:
|
||||
self._callback(arg)
|
||||
|
||||
@ -29,6 +29,8 @@ from typing import TYPE_CHECKING
|
||||
import _ba
|
||||
import ba
|
||||
from ba.internal import get_achievements_for_coop_level
|
||||
from bastd.actor.text import Text
|
||||
from bastd.actor.zoomtext import ZoomText
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Optional, Tuple, List, Dict, Any, Sequence
|
||||
@ -50,9 +52,6 @@ class CoopScoreScreen(ba.Activity):
|
||||
self.inherits_music = True
|
||||
self.use_fixed_vr_overlay = True
|
||||
|
||||
self._tournament_time_remaining = None
|
||||
self._tournament_time_remaining_text = None
|
||||
|
||||
self._do_new_rating: bool = self.session.tournament_id is not None
|
||||
|
||||
self._score_display_sound = ba.getsound("scoreHit01")
|
||||
@ -134,6 +133,8 @@ class CoopScoreScreen(ba.Activity):
|
||||
self._name_str: Optional[str] = None
|
||||
self._friends_loading_status: Optional[ba.Actor] = None
|
||||
self._score_loading_status: Optional[ba.Actor] = None
|
||||
self._tournament_time_remaining: Optional[float] = None
|
||||
self._tournament_time_remaining_text: Optional[Text] = None
|
||||
self._tournament_time_remaining_text_timer: Optional[ba.Timer] = None
|
||||
|
||||
self._player_info = settings['player_info']
|
||||
@ -288,7 +289,6 @@ class CoopScoreScreen(ba.Activity):
|
||||
ba.open_url(self._score_link)
|
||||
|
||||
def _ui_error(self) -> None:
|
||||
from bastd.actor.text import Text
|
||||
with ba.Context(self):
|
||||
self._next_level_error = Text(
|
||||
ba.Lstr(resource='completeThisLevelToProceedText'),
|
||||
@ -515,8 +515,6 @@ class CoopScoreScreen(ba.Activity):
|
||||
# pylint: disable=too-many-statements
|
||||
# pylint: disable=too-many-branches
|
||||
# pylint: disable=too-many-locals
|
||||
from bastd.actor.text import Text
|
||||
from bastd.actor.zoomtext import ZoomText
|
||||
super().on_begin()
|
||||
|
||||
# Calc whether the level is complete and other stuff.
|
||||
@ -893,7 +891,6 @@ class CoopScoreScreen(ba.Activity):
|
||||
# pylint: disable=too-many-branches
|
||||
# pylint: disable=too-many-statements
|
||||
# delay a bit if results come in too fast
|
||||
from bastd.actor.text import Text
|
||||
base_delay = max(0, 1.9 - (ba.time() - self._begin_time))
|
||||
ts_height = 300
|
||||
ts_h_offs = -550
|
||||
@ -1009,7 +1006,6 @@ class CoopScoreScreen(ba.Activity):
|
||||
# We need to manually run this in the context of our activity
|
||||
# and only if we aren't shutting down.
|
||||
# (really should make the submit_score call handle that stuff itself)
|
||||
from bastd.actor.text import Text
|
||||
if self.is_expired():
|
||||
return
|
||||
with ba.Context(self):
|
||||
@ -1169,10 +1165,9 @@ class CoopScoreScreen(ba.Activity):
|
||||
# pylint: disable=too-many-branches
|
||||
# pylint: disable=too-many-statements
|
||||
from ba.internal import get_tournament_prize_strings
|
||||
from bastd.actor.text import Text
|
||||
from bastd.actor.zoomtext import ZoomText
|
||||
assert self._show_info is not None
|
||||
available = (self._show_info['results'] is not None)
|
||||
|
||||
if available:
|
||||
error = (self._show_info['results']['error']
|
||||
if 'error' in self._show_info['results'] else None)
|
||||
@ -1193,22 +1188,22 @@ class CoopScoreScreen(ba.Activity):
|
||||
Text(ba.Lstr(resource='coopSelectWindow.timeRemainingText'),
|
||||
position=(-360, -70 - 100),
|
||||
color=(1, 1, 1, 0.7),
|
||||
h_align='center',
|
||||
v_align='center',
|
||||
transition='fade_in',
|
||||
h_align=Text.HAlign.CENTER,
|
||||
v_align=Text.VAlign.CENTER,
|
||||
transition=Text.Transition.FADE_IN,
|
||||
scale=0.8,
|
||||
maxwidth=300,
|
||||
transition_delay=2.0).autoretain()
|
||||
self._tournament_time_remaining_text = Text('',
|
||||
position=(-360,
|
||||
-110 - 100),
|
||||
color=(1, 1, 1, 0.7),
|
||||
h_align='center',
|
||||
v_align='center',
|
||||
transition='fade_in',
|
||||
scale=1.6,
|
||||
maxwidth=150,
|
||||
transition_delay=2.0)
|
||||
self._tournament_time_remaining_text = Text(
|
||||
'',
|
||||
position=(-360, -110 - 100),
|
||||
color=(1, 1, 1, 0.7),
|
||||
h_align=Text.HAlign.CENTER,
|
||||
v_align=Text.VAlign.CENTER,
|
||||
transition=Text.Transition.FADE_IN,
|
||||
scale=1.6,
|
||||
maxwidth=150,
|
||||
transition_delay=2.0)
|
||||
|
||||
# If we're a tournament, show prizes.
|
||||
try:
|
||||
@ -1439,8 +1434,6 @@ class CoopScoreScreen(ba.Activity):
|
||||
ba.timer(0.35, ba.Call(ba.playsound, self.cymbal_sound))
|
||||
|
||||
def _show_fail(self) -> None:
|
||||
from bastd.actor.text import Text
|
||||
from bastd.actor.zoomtext import ZoomText
|
||||
ZoomText(ba.Lstr(resource='failText'),
|
||||
maxwidth=300,
|
||||
flash=False,
|
||||
@ -1460,8 +1453,6 @@ class CoopScoreScreen(ba.Activity):
|
||||
ba.timer(0.35, ba.Call(ba.playsound, self._score_display_sound))
|
||||
|
||||
def _show_score_val(self, offs_x: float) -> None:
|
||||
from bastd.actor.text import Text
|
||||
from bastd.actor.zoomtext import ZoomText
|
||||
assert self._score_type is not None
|
||||
assert self._score is not None
|
||||
ZoomText((str(self._score) if self._score_type == 'points' else
|
||||
|
||||
@ -1047,23 +1047,24 @@ class TNTSpawner:
|
||||
category: Gameplay Classes
|
||||
"""
|
||||
|
||||
def __init__(self, position: Sequence[float], respawn_time: float = 30.0):
|
||||
def __init__(self, position: Sequence[float], respawn_time: float = 20.0):
|
||||
"""Instantiate with given position and respawn_time (in seconds)."""
|
||||
self._position = position
|
||||
self._tnt: Optional[Bomb] = None
|
||||
self._respawn_time = random.uniform(0.8, 1.2) * respawn_time
|
||||
self._wait_time = 0.0
|
||||
self._update()
|
||||
# (go with slightly more than 1 second to avoid timer stacking)
|
||||
|
||||
# Go with slightly more than 1 second to avoid timer stacking.
|
||||
self._update_timer = ba.Timer(1.1,
|
||||
ba.WeakCall(self._update),
|
||||
repeat=True)
|
||||
self._respawn_time = random.uniform(0.8, 1.2) * respawn_time
|
||||
self._wait_time = 0.0
|
||||
|
||||
def _update(self) -> None:
|
||||
tnt_alive = self._tnt is not None and self._tnt.node
|
||||
if not tnt_alive:
|
||||
# respawn if its been long enough.. otherwise just increment our
|
||||
# how-long-since-we-died value
|
||||
# Respawn if its been long enough.. otherwise just increment our
|
||||
# how-long-since-we-died value.
|
||||
if self._tnt is None or self._wait_time >= self._respawn_time:
|
||||
self._tnt = Bomb(position=self._position, bomb_type='tnt')
|
||||
self._wait_time = 0.0
|
||||
|
||||
@ -164,7 +164,7 @@ class MeteorShowerGame(ba.TeamGameActivity):
|
||||
# Augment standard behavior.
|
||||
super().handlemessage(msg)
|
||||
|
||||
death_time = ba.time()
|
||||
death_time = ba.time(timeformat=ba.TimeFormat.MILLISECONDS)
|
||||
|
||||
# Record the player's moment of death.
|
||||
msg.spaz.player.gamedata['death_time'] = death_time
|
||||
@ -240,8 +240,10 @@ class MeteorShowerGame(ba.TeamGameActivity):
|
||||
self._meteor_time = max(0.01, self._meteor_time * 0.9)
|
||||
|
||||
def end_game(self) -> None:
|
||||
cur_time = ba.time()
|
||||
cur_time = ba.time(timeformat=ba.TimeFormat.MILLISECONDS)
|
||||
assert self._timer is not None
|
||||
start_time = self._timer.getstarttime(
|
||||
timeformat=ba.TimeFormat.MILLISECONDS)
|
||||
|
||||
# Mark 'death-time' as now for any still-living players
|
||||
# and award players points for how long they lasted.
|
||||
@ -252,13 +254,14 @@ class MeteorShowerGame(ba.TeamGameActivity):
|
||||
# Throw an extra fudge factor in so teams that
|
||||
# didn't die come out ahead of teams that did.
|
||||
if 'death_time' not in player.gamedata:
|
||||
player.gamedata['death_time'] = cur_time + 0.001
|
||||
player.gamedata['death_time'] = cur_time + 1
|
||||
|
||||
# Award a per-player score depending on how many seconds
|
||||
# they lasted (per-player scores only affect teams mode;
|
||||
# everywhere else just looks at the per-team score).
|
||||
score = int(player.gamedata['death_time'] -
|
||||
self._timer.getstarttime())
|
||||
self._timer.getstarttime(
|
||||
timeformat=ba.TimeFormat.MILLISECONDS))
|
||||
if 'death_time' not in player.gamedata:
|
||||
score += 50 # a bit extra for survivors
|
||||
self.stats.player_scored(player, score, screenmessage=False)
|
||||
@ -281,8 +284,7 @@ class MeteorShowerGame(ba.TeamGameActivity):
|
||||
longest_life = 0
|
||||
for player in team.players:
|
||||
longest_life = max(longest_life,
|
||||
(player.gamedata['death_time'] -
|
||||
self._timer.getstarttime()))
|
||||
player.gamedata['death_time'] - start_time)
|
||||
results.set_team_score(team, longest_life)
|
||||
|
||||
self.end(results=results)
|
||||
|
||||
@ -88,7 +88,7 @@ class StoreBrowserWindow(ba.Window):
|
||||
|
||||
self._request: Any = None
|
||||
self._r = 'store'
|
||||
self._last_buy_time = None
|
||||
self._last_buy_time: Optional[float] = None
|
||||
|
||||
super().__init__(root_widget=ba.containerwidget(
|
||||
size=(self._width, self._height + extra_top),
|
||||
@ -179,7 +179,7 @@ class StoreBrowserWindow(ba.Window):
|
||||
('minigames', ba.Lstr(resource=self._r + '.miniGamesText')),
|
||||
('characters', ba.Lstr(resource=self._r + '.charactersText')),
|
||||
('icons', ba.Lstr(resource=self._r + '.iconsText')),
|
||||
] # yapf : disable
|
||||
]
|
||||
|
||||
tab_results = tabs.create_tab_buttons(self._root_widget,
|
||||
tabs_def,
|
||||
@ -454,16 +454,19 @@ class StoreBrowserWindow(ba.Window):
|
||||
# purchase this. Better to fail now than after we've
|
||||
# paid locally.
|
||||
app = ba.app
|
||||
serverget('bsAccountPurchaseCheck', {
|
||||
'item': item,
|
||||
'platform': app.platform,
|
||||
'subplatform': app.subplatform,
|
||||
'version': app.version,
|
||||
'buildNumber': app.build_number,
|
||||
'purchaseType': 'ticket' if is_ticket_purchase else 'real'
|
||||
},
|
||||
callback=ba.WeakCall(self._purchase_check_result, item,
|
||||
is_ticket_purchase))
|
||||
serverget(
|
||||
'bsAccountPurchaseCheck',
|
||||
{
|
||||
'item': item,
|
||||
'platform': app.platform,
|
||||
'subplatform': app.subplatform,
|
||||
'version': app.version,
|
||||
'buildNumber': app.build_number,
|
||||
'purchaseType': 'ticket' if is_ticket_purchase else 'real'
|
||||
},
|
||||
callback=ba.WeakCall(self._purchase_check_result, item,
|
||||
is_ticket_purchase),
|
||||
)
|
||||
|
||||
def buy(self, item: str) -> None:
|
||||
"""Attempt to purchase the provided item."""
|
||||
@ -476,7 +479,8 @@ class StoreBrowserWindow(ba.Window):
|
||||
# Prevent pressing buy within a few seconds of the last press
|
||||
# (gives the buttons time to disable themselves and whatnot).
|
||||
curtime = ba.time(ba.TimeType.REAL)
|
||||
if self._last_buy_time is None or curtime - self._last_buy_time < 2.0:
|
||||
if self._last_buy_time is not None and (curtime -
|
||||
self._last_buy_time) < 2.0:
|
||||
ba.playsound(ba.getsound('error'))
|
||||
else:
|
||||
if _ba.get_account_state() != 'signed_in':
|
||||
@ -537,8 +541,7 @@ class StoreBrowserWindow(ba.Window):
|
||||
sales_raw = _ba.get_account_misc_read_val('sales', {})
|
||||
sales = {}
|
||||
try:
|
||||
# look at the current set of sales; filter any with
|
||||
# time remaining..
|
||||
# Look at the current set of sales; filter any with time remaining.
|
||||
for sale_item, sale_info in list(sales_raw.items()):
|
||||
to_end = (datetime.datetime.utcfromtimestamp(sale_info['e']) -
|
||||
datetime.datetime.utcnow()).total_seconds()
|
||||
@ -548,7 +551,7 @@ class StoreBrowserWindow(ba.Window):
|
||||
'original_price': sale_info['op']
|
||||
}
|
||||
except Exception:
|
||||
ba.print_exception("Error parsing sales")
|
||||
ba.print_exception("Error parsing sales.")
|
||||
|
||||
assert self.button_infos is not None
|
||||
for b_type, b_info in self.button_infos.items():
|
||||
@ -602,7 +605,8 @@ class StoreBrowserWindow(ba.Window):
|
||||
price_text_right = ''
|
||||
else:
|
||||
price = _ba.get_account_misc_read_val('price.' + b_type, 0)
|
||||
# color button differently if we cant afford this
|
||||
|
||||
# Color the button differently if we cant afford this.
|
||||
if _ba.get_account_state() == 'signed_in':
|
||||
if _ba.get_account_ticket_count() < price:
|
||||
color = (0.6, 0.61, 0.6)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user