fixed in-game resume and removed continues code

This commit is contained in:
Eric 2024-09-28 10:47:44 -07:00
parent bbbea7bfa6
commit 3d3d3a4885
No known key found for this signature in database
GPG Key ID: 89C93F0F8D6D5A98
14 changed files with 38 additions and 429 deletions

40
.efrocachemap generated
View File

@ -4096,26 +4096,26 @@
"build/assets/windows/Win32/ucrtbased.dll": "2def5335207d41b21b9823f6805997f1", "build/assets/windows/Win32/ucrtbased.dll": "2def5335207d41b21b9823f6805997f1",
"build/assets/windows/Win32/vc_redist.x86.exe": "b08a55e2e77623fe657bea24f223a3ae", "build/assets/windows/Win32/vc_redist.x86.exe": "b08a55e2e77623fe657bea24f223a3ae",
"build/assets/windows/Win32/vcruntime140d.dll": "865b2af4d1e26a1a8073c89acb06e599", "build/assets/windows/Win32/vcruntime140d.dll": "865b2af4d1e26a1a8073c89acb06e599",
"build/prefab/full/linux_arm64_gui/debug/ballisticakit": "51d7c59e2e4f3900c86593a3b4bc58e4", "build/prefab/full/linux_arm64_gui/debug/ballisticakit": "934beaf11fef829457ce148c66b5e585",
"build/prefab/full/linux_arm64_gui/release/ballisticakit": "b06acdcb8eeaae7d2057d38c4bae1483", "build/prefab/full/linux_arm64_gui/release/ballisticakit": "3a781083e1bad04cec163e9d16d45271",
"build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "0b1a09078dd8fb3355da26bcd712ccc5", "build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "6b32c8bfea5a1b4fc6f32844e2edcc57",
"build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "ae0c974ce5353900a6d4e271851e4e6e", "build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "eebd9448a29f673119df718380dc6dd8",
"build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "8ad0607d24d95c79230c74705ce77653", "build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "4c946813d6cc95bb1e8aed1881913ddf",
"build/prefab/full/linux_x86_64_gui/release/ballisticakit": "24acf39e9aee8bf121c6805df19105c7", "build/prefab/full/linux_x86_64_gui/release/ballisticakit": "3b26ce105d259eaee3d964f82956224f",
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "741106e84450bb7b77c639b217929806", "build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "b8c814d170feb2faadb69164515842a9",
"build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "e8ebc038d7d6358e68b7ccf7607d5dce", "build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "0e310eb8656a9d953155bbb8d976b2f2",
"build/prefab/full/mac_arm64_gui/debug/ballisticakit": "5503f0b09868f947fadb0d1895e80ec8", "build/prefab/full/mac_arm64_gui/debug/ballisticakit": "ed7a41e344cf334b50c87b1cd8dc7816",
"build/prefab/full/mac_arm64_gui/release/ballisticakit": "e4412a45302241e72046a2953e5b7941", "build/prefab/full/mac_arm64_gui/release/ballisticakit": "05977ff4eaa374af3d89c004e970568b",
"build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "938ea19a8306d78e2a8729f26b545a76", "build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "91a820ff8a95d9e3bb95602990dca61d",
"build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "757ba15790a8d7d0dbaec3bcd8c19558", "build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "46854a9414fc4ed0ad06993e1588f7e1",
"build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "65e48222cf0bdc9037c8cd612bd6e557", "build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "d5dfac17b713104c9c3eee62e5f9c66a",
"build/prefab/full/mac_x86_64_gui/release/ballisticakit": "47b7a2fdf91039955f9188732860cf40", "build/prefab/full/mac_x86_64_gui/release/ballisticakit": "1df8d35253f5165ff0c4c524abe629e9",
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "059d4a32feac25a0d3a33bc22cfe5fbd", "build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "081ec14d53192678f499152848688504",
"build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "3e40ffa4d7a2adee533aa770e84294fb", "build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "1e11c3a36ff8eb9ca6103eadf3d158ed",
"build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "e8983bd5f1e0d93a20e1bd7bf31ad40e", "build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "73979876a4682fded2c39de4f37d67af",
"build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "96a3b8424c5a8f544894bd8bd348fec9", "build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "7f66a8dba4b86e8a89d8d6f45cc84562",
"build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "0ad6d8294e6b0d62c040137d2562ad42", "build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "58fa4a304e1a2d07046dc705cc409002",
"build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "344e688d38f9d8340f96503d58622b6c", "build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "fbbc1d2d5c6d1e693a51c15c4e9295da",
"build/prefab/lib/linux_arm64_gui/debug/libballisticaplus.a": "0b5f8bdbe8221c4642d9f7f8584645ce", "build/prefab/lib/linux_arm64_gui/debug/libballisticaplus.a": "0b5f8bdbe8221c4642d9f7f8584645ce",
"build/prefab/lib/linux_arm64_gui/release/libballisticaplus.a": "e94dd06863796f17b9cfcbb5f79edd32", "build/prefab/lib/linux_arm64_gui/release/libballisticaplus.a": "e94dd06863796f17b9cfcbb5f79edd32",
"build/prefab/lib/linux_arm64_server/debug/libballisticaplus.a": "0b5f8bdbe8221c4642d9f7f8584645ce", "build/prefab/lib/linux_arm64_server/debug/libballisticaplus.a": "0b5f8bdbe8221c4642d9f7f8584645ce",

View File

@ -1,4 +1,4 @@
### 1.7.37 (build 22017, api 9, 2024-09-27) ### 1.7.37 (build 22018, api 9, 2024-09-28)
- Bumping api version to 9. As you'll see below, there's some UI changes that - Bumping api version to 9. As you'll see below, there's some UI changes that
will require a bit of work for any UI mods to adapt to. If your mods don't will require a bit of work for any UI mods to adapt to. If your mods don't
touch UI stuff at all you can simply bump your api version and call it a day. touch UI stuff at all you can simply bump your api version and call it a day.
@ -17,6 +17,8 @@
- Campaign hard mode no longer requires pro. - Campaign hard mode no longer requires pro.
- Full player profile color customization no longer requires pro. - Full player profile color customization no longer requires pro.
- Removed nag screens for purchasing pro or bundle offers. - Removed nag screens for purchasing pro or bundle offers.
- Removed continue logic. Continues have been disabled server-side for a while
but now removing the client code to clean things up a bit.
- Switching over to the new 'toolbar mode' UI that has been in the works for - Switching over to the new 'toolbar mode' UI that has been in the works for
several years. This includes a number of handy things such as consistent several years. This includes a number of handy things such as consistent
buttons and widgets for league status, currencies, inventory, and the store. buttons and widgets for league status, currencies, inventory, and the store.

View File

@ -372,7 +372,6 @@
"ba_data/python/bauiv1lib/__pycache__/config.cpython-312.opt-1.pyc", "ba_data/python/bauiv1lib/__pycache__/config.cpython-312.opt-1.pyc",
"ba_data/python/bauiv1lib/__pycache__/confirm.cpython-312.opt-1.pyc", "ba_data/python/bauiv1lib/__pycache__/confirm.cpython-312.opt-1.pyc",
"ba_data/python/bauiv1lib/__pycache__/connectivity.cpython-312.opt-1.pyc", "ba_data/python/bauiv1lib/__pycache__/connectivity.cpython-312.opt-1.pyc",
"ba_data/python/bauiv1lib/__pycache__/continues.cpython-312.opt-1.pyc",
"ba_data/python/bauiv1lib/__pycache__/credits.cpython-312.opt-1.pyc", "ba_data/python/bauiv1lib/__pycache__/credits.cpython-312.opt-1.pyc",
"ba_data/python/bauiv1lib/__pycache__/discord.cpython-312.opt-1.pyc", "ba_data/python/bauiv1lib/__pycache__/discord.cpython-312.opt-1.pyc",
"ba_data/python/bauiv1lib/__pycache__/feedback.cpython-312.opt-1.pyc", "ba_data/python/bauiv1lib/__pycache__/feedback.cpython-312.opt-1.pyc",
@ -425,7 +424,6 @@
"ba_data/python/bauiv1lib/config.py", "ba_data/python/bauiv1lib/config.py",
"ba_data/python/bauiv1lib/confirm.py", "ba_data/python/bauiv1lib/confirm.py",
"ba_data/python/bauiv1lib/connectivity.py", "ba_data/python/bauiv1lib/connectivity.py",
"ba_data/python/bauiv1lib/continues.py",
"ba_data/python/bauiv1lib/coop/__init__.py", "ba_data/python/bauiv1lib/coop/__init__.py",
"ba_data/python/bauiv1lib/coop/__pycache__/__init__.cpython-312.opt-1.pyc", "ba_data/python/bauiv1lib/coop/__pycache__/__init__.cpython-312.opt-1.pyc",
"ba_data/python/bauiv1lib/coop/__pycache__/browser.cpython-312.opt-1.pyc", "ba_data/python/bauiv1lib/coop/__pycache__/browser.cpython-312.opt-1.pyc",

View File

@ -346,7 +346,6 @@ SCRIPT_TARGETS_PY_PUBLIC = \
$(BUILD_DIR)/ba_data/python/bauiv1lib/config.py \ $(BUILD_DIR)/ba_data/python/bauiv1lib/config.py \
$(BUILD_DIR)/ba_data/python/bauiv1lib/confirm.py \ $(BUILD_DIR)/ba_data/python/bauiv1lib/confirm.py \
$(BUILD_DIR)/ba_data/python/bauiv1lib/connectivity.py \ $(BUILD_DIR)/ba_data/python/bauiv1lib/connectivity.py \
$(BUILD_DIR)/ba_data/python/bauiv1lib/continues.py \
$(BUILD_DIR)/ba_data/python/bauiv1lib/coop/__init__.py \ $(BUILD_DIR)/ba_data/python/bauiv1lib/coop/__init__.py \
$(BUILD_DIR)/ba_data/python/bauiv1lib/coop/browser.py \ $(BUILD_DIR)/ba_data/python/bauiv1lib/coop/browser.py \
$(BUILD_DIR)/ba_data/python/bauiv1lib/coop/gamebutton.py \ $(BUILD_DIR)/ba_data/python/bauiv1lib/coop/gamebutton.py \
@ -624,7 +623,6 @@ SCRIPT_TARGETS_PYC_PUBLIC = \
$(BUILD_DIR)/ba_data/python/bauiv1lib/__pycache__/config.cpython-312.opt-1.pyc \ $(BUILD_DIR)/ba_data/python/bauiv1lib/__pycache__/config.cpython-312.opt-1.pyc \
$(BUILD_DIR)/ba_data/python/bauiv1lib/__pycache__/confirm.cpython-312.opt-1.pyc \ $(BUILD_DIR)/ba_data/python/bauiv1lib/__pycache__/confirm.cpython-312.opt-1.pyc \
$(BUILD_DIR)/ba_data/python/bauiv1lib/__pycache__/connectivity.cpython-312.opt-1.pyc \ $(BUILD_DIR)/ba_data/python/bauiv1lib/__pycache__/connectivity.cpython-312.opt-1.pyc \
$(BUILD_DIR)/ba_data/python/bauiv1lib/__pycache__/continues.cpython-312.opt-1.pyc \
$(BUILD_DIR)/ba_data/python/bauiv1lib/coop/__pycache__/__init__.cpython-312.opt-1.pyc \ $(BUILD_DIR)/ba_data/python/bauiv1lib/coop/__pycache__/__init__.cpython-312.opt-1.pyc \
$(BUILD_DIR)/ba_data/python/bauiv1lib/coop/__pycache__/browser.cpython-312.opt-1.pyc \ $(BUILD_DIR)/ba_data/python/bauiv1lib/coop/__pycache__/browser.cpython-312.opt-1.pyc \
$(BUILD_DIR)/ba_data/python/bauiv1lib/coop/__pycache__/gamebutton.cpython-312.opt-1.pyc \ $(BUILD_DIR)/ba_data/python/bauiv1lib/coop/__pycache__/gamebutton.cpython-312.opt-1.pyc \

View File

@ -131,9 +131,15 @@ class ClassicAppMode(AppMode):
ui = app.ui_v1 ui = app.ui_v1
# If *any* main-window is up, kill it. # If *any* main-window is up, kill it and resume play.
old_window = ui.get_main_window() old_window = ui.get_main_window()
if old_window is not None: if old_window is not None:
classic = app.classic
assert classic is not None
classic.resume()
ui.clear_main_window() ui.clear_main_window()
return return

View File

@ -720,18 +720,6 @@ class ClassicAppSubsystem(babase.AppSubsystem):
return MainMenuSession return MainMenuSession
def continues_window(
self,
activity: bascenev1.Activity,
cost: int,
continue_call: Callable[[], Any],
cancel_call: Callable[[], Any],
) -> None:
"""(internal)"""
from bauiv1lib.continues import ContinuesWindow
ContinuesWindow(activity, cost, continue_call, cancel_call)
def profile_browser_window( def profile_browser_window(
self, self,
transition: str = 'in_right', transition: str = 'in_right',

View File

@ -52,7 +52,7 @@ if TYPE_CHECKING:
# Build number and version of the ballistica binary we expect to be # Build number and version of the ballistica binary we expect to be
# using. # using.
TARGET_BALLISTICA_BUILD = 22017 TARGET_BALLISTICA_BUILD = 22018
TARGET_BALLISTICA_VERSION = '1.7.37' TARGET_BALLISTICA_VERSION = '1.7.37'

View File

@ -208,8 +208,6 @@ class GameActivity(Activity[PlayerT, TeamT]):
"""Instantiate the Activity.""" """Instantiate the Activity."""
super().__init__(settings) super().__init__(settings)
plus = babase.app.plus
# Holds some flattened info about the player set at the point # Holds some flattened info about the player set at the point
# when on_begin() is called. # when on_begin() is called.
self.initialplayerinfos: list[bascenev1.PlayerInfo] | None = None self.initialplayerinfos: list[bascenev1.PlayerInfo] | None = None
@ -239,23 +237,6 @@ class GameActivity(Activity[PlayerT, TeamT]):
None None
) )
self._zoom_message_times: dict[int, float] = {} self._zoom_message_times: dict[int, float] = {}
self._is_waiting_for_continue = False
self._continue_cost = (
25
if plus is None
else plus.get_v1_account_misc_read_val('continueStartCost', 25)
)
self._continue_cost_mult = (
2
if plus is None
else plus.get_v1_account_misc_read_val('continuesMult', 2)
)
self._continue_cost_offset = (
0
if plus is None
else plus.get_v1_account_misc_read_val('continuesOffset', 0)
)
@property @property
def map(self) -> _map.Map: def map(self) -> _map.Map:
@ -362,103 +343,6 @@ class GameActivity(Activity[PlayerT, TeamT]):
if music is not None: if music is not None:
_music.setmusic(music) _music.setmusic(music)
def on_continue(self) -> None:
"""
This is called if a game supports and offers a continue and the player
accepts. In this case the player should be given an extra life or
whatever is relevant to keep the game going.
"""
def _continue_choice(self, do_continue: bool) -> None:
plus = babase.app.plus
assert plus is not None
self._is_waiting_for_continue = False
if self.has_ended():
return
with self.context:
if do_continue:
_bascenev1.getsound('shieldUp').play()
_bascenev1.getsound('cashRegister').play()
plus.add_v1_account_transaction(
{'type': 'CONTINUE', 'cost': self._continue_cost}
)
if plus is not None:
plus.run_v1_account_transactions()
self._continue_cost = (
self._continue_cost * self._continue_cost_mult
+ self._continue_cost_offset
)
self.on_continue()
else:
self.end_game()
def is_waiting_for_continue(self) -> bool:
"""Returns whether or not this activity is currently waiting for the
player to continue (or timeout)"""
return self._is_waiting_for_continue
def continue_or_end_game(self) -> None:
"""If continues are allowed, prompts the player to purchase a continue
and calls either end_game or continue_game depending on the result
"""
# pylint: disable=too-many-nested-blocks
# pylint: disable=cyclic-import
from bascenev1._coopsession import CoopSession
classic = babase.app.classic
assert classic is not None
continues_window = classic.continues_window
# Turning these off. I want to migrate towards monetization that
# feels less pay-to-win-ish.
allow_continues = False
plus = babase.app.plus
try:
if (
plus is not None
and plus.get_v1_account_misc_read_val('enableContinues', False)
and allow_continues
):
session = self.session
# We only support continuing in non-tournament games.
tournament_id = session.tournament_id
if tournament_id is None:
# We currently only support continuing in sequential
# co-op campaigns.
if isinstance(session, CoopSession):
assert session.campaign is not None
if session.campaign.sequential:
gnode = self.globalsnode
# Only attempt this if we're not currently paused
# and there appears to be no UI.
assert babase.app.classic is not None
hmmw = babase.app.ui_v1.has_main_window()
if not gnode.paused and not hmmw:
self._is_waiting_for_continue = True
with babase.ContextRef.empty():
babase.apptimer(
0.5,
lambda: continues_window(
self,
self._continue_cost,
continue_call=babase.WeakCall(
self._continue_choice, True
),
cancel_call=babase.WeakCall(
self._continue_choice, False
),
),
)
return
except Exception:
logging.exception('Error handling continues.')
self.end_game()
@override @override
def on_begin(self) -> None: def on_begin(self) -> None:
super().on_begin() super().on_begin()

View File

@ -1,6 +1,5 @@
# Released under the MIT License. See LICENSE for details. # Released under the MIT License. See LICENSE for details.
# #
# pylint: disable=too-many-lines
"""Implements football games (both co-op and teams varieties).""" """Implements football games (both co-op and teams varieties)."""
# ba_meta require api 9 # ba_meta require api 9
@ -655,11 +654,6 @@ class FootballCoopGame(bs.CoopGameActivity[Player, Team]):
for bot in bots: for bot in bots:
bot.target_flag = None bot.target_flag = None
# If we're waiting on a continue, stop here so they don't keep scoring.
if self.is_waiting_for_continue():
self._bots.stop_moving()
return
# If we've got a flag and no player are holding it, find the closest # If we've got a flag and no player are holding it, find the closest
# bot to it, and make them the designated flag-bearer. # bot to it, and make them the designated flag-bearer.
assert self._flag is not None assert self._flag is not None
@ -816,14 +810,6 @@ class FootballCoopGame(bs.CoopGameActivity[Player, Team]):
self._bots.final_celebrate() self._bots.final_celebrate()
bs.timer(0.001, bs.Call(self.do_end, 'defeat')) bs.timer(0.001, bs.Call(self.do_end, 'defeat'))
@override
def on_continue(self) -> None:
# Subtract one touchdown from the bots and get them moving again.
assert self._bot_team is not None
self._bot_team.score -= 7
self._bots.start_moving()
self.update_scores()
def update_scores(self) -> None: def update_scores(self) -> None:
"""update scoreboard and check for winners""" """update scoreboard and check for winners"""
# FIXME: tidy this up # FIXME: tidy this up
@ -838,7 +824,7 @@ class FootballCoopGame(bs.CoopGameActivity[Player, Team]):
if not have_scoring_team: if not have_scoring_team:
self._scoring_team = team self._scoring_team = team
if team is self._bot_team: if team is self._bot_team:
self.continue_or_end_game() self.end_game()
else: else:
bs.setmusic(bs.MusicType.VICTORY) bs.setmusic(bs.MusicType.VICTORY)

View File

@ -1195,7 +1195,7 @@ class OnslaughtGame(bs.CoopGameActivity[Player, Team]):
def _respawn_players_for_wave(self) -> None: def _respawn_players_for_wave(self) -> None:
# Respawn applicable players. # Respawn applicable players.
if self._wavenum > 1 and not self.is_waiting_for_continue(): if self._wavenum > 1:
for player in self.players: for player in self.players:
if ( if (
not player.is_alive() not player.is_alive()
@ -1642,19 +1642,9 @@ class OnslaughtGame(bs.CoopGameActivity[Player, Team]):
self.do_end('defeat', delay=2.0) self.do_end('defeat', delay=2.0)
bs.setmusic(None) bs.setmusic(None)
@override
def on_continue(self) -> None:
for player in self.players:
if not player.is_alive():
self.spawn_player(player)
def _checkroundover(self) -> None: def _checkroundover(self) -> None:
"""Potentially end the round based on the state of the game.""" """Potentially end the round based on the state of the game."""
if self.has_ended(): if self.has_ended():
return return
if not any(player.is_alive() for player in self.teams[0].players): if not any(player.is_alive() for player in self.teams[0].players):
# Allow continuing after wave 1. self.end_game()
if self._wavenum > 1:
self.continue_or_end_game()
else:
self.end_game()

View File

@ -550,7 +550,7 @@ class RunaroundGame(bs.CoopGameActivity[Player, Team]):
self._lives -= 1 self._lives -= 1
if self._lives == 0: if self._lives == 0:
self._bots.stop_moving() self._bots.stop_moving()
self.continue_or_end_game() self.end_game()
# Heartbeat behavior # Heartbeat behavior
if self._lives < 5: if self._lives < 5:
@ -613,14 +613,6 @@ class RunaroundGame(bs.CoopGameActivity[Player, Team]):
), ),
) )
@override
def on_continue(self) -> None:
self._lives = 3
assert self._lives_text is not None
assert self._lives_text.node
self._lives_text.node.text = str(self._lives)
self._bots.start_moving()
@override @override
def spawn_player(self, player: Player) -> bs.Actor: def spawn_player(self, player: Player) -> bs.Actor:
pos = ( pos = (

View File

@ -1,235 +0,0 @@
# Released under the MIT License. See LICENSE for details.
#
"""Provides a popup window to continue a game."""
from __future__ import annotations
import weakref
from typing import TYPE_CHECKING
import bauiv1 as bui
if TYPE_CHECKING:
from typing import Any, Callable
import bascenev1 as bs
class ContinuesWindow(bui.Window):
"""A window to continue a game."""
def __init__(
self,
activity: bs.Activity,
cost: int,
continue_call: Callable[[], Any],
cancel_call: Callable[[], Any],
):
assert bui.app.classic is not None
self._activity = weakref.ref(activity)
self._cost = cost
self._continue_call = continue_call
self._cancel_call = cancel_call
self._start_count = self._count = 20
self._width = 300
self._height = 200
self._transitioning_out = False
super().__init__(
bui.containerwidget(
size=(self._width, self._height),
background=False,
toolbar_visibility='menu_store',
transition='in_scale',
scale=1.5,
)
)
txt = (
bui.Lstr(resource='continuePurchaseText')
.evaluate()
.split('${PRICE}')
)
t_left = txt[0]
t_left_width = bui.get_string_width(t_left, suppress_warning=True)
t_price = bui.charstr(bui.SpecialChar.TICKET) + str(self._cost)
t_price_width = bui.get_string_width(t_price, suppress_warning=True)
t_right = txt[-1]
t_right_width = bui.get_string_width(t_right, suppress_warning=True)
width_total_half = (t_left_width + t_price_width + t_right_width) * 0.5
bui.textwidget(
parent=self._root_widget,
text=t_left,
flatness=1.0,
shadow=1.0,
size=(0, 0),
h_align='left',
v_align='center',
position=(self._width * 0.5 - width_total_half, self._height - 30),
)
bui.textwidget(
parent=self._root_widget,
text=t_price,
flatness=1.0,
shadow=1.0,
color=(0.2, 1.0, 0.2),
size=(0, 0),
position=(
self._width * 0.5 - width_total_half + t_left_width,
self._height - 30,
),
h_align='left',
v_align='center',
)
bui.textwidget(
parent=self._root_widget,
text=t_right,
flatness=1.0,
shadow=1.0,
size=(0, 0),
h_align='left',
v_align='center',
position=(
self._width * 0.5
- width_total_half
+ t_left_width
+ t_price_width
+ 5,
self._height - 30,
),
)
self._tickets_text_base: str | None
self._tickets_text: bui.Widget | None
self._tickets_text_base = None
self._tickets_text = None
self._counter_text = bui.textwidget(
parent=self._root_widget,
text=str(self._count),
color=(0.7, 0.7, 0.7),
scale=1.2,
size=(0, 0),
big=True,
position=(self._width * 0.5, self._height - 80),
flatness=1.0,
shadow=1.0,
h_align='center',
v_align='center',
)
self._cancel_button = bui.buttonwidget(
parent=self._root_widget,
position=(30, 30),
size=(120, 50),
label=bui.Lstr(resource='endText', fallback_resource='cancelText'),
autoselect=True,
enable_sound=False,
on_activate_call=self._on_cancel_press,
)
self._continue_button = bui.buttonwidget(
parent=self._root_widget,
label=bui.Lstr(resource='continueText'),
autoselect=True,
position=(self._width - 130, 30),
size=(120, 50),
on_activate_call=self._on_continue_press,
)
bui.containerwidget(
edit=self._root_widget,
cancel_button=self._cancel_button,
start_button=self._continue_button,
selected_child=self._cancel_button,
)
self._counting_down = True
self._countdown_timer = bui.AppTimer(
1.0, bui.WeakCall(self._tick), repeat=True
)
# If there is foreground activity, suspend it.
bui.app.classic.pause()
self._tick()
def __del__(self) -> None:
# If there is suspended foreground activity, resume it.
assert bui.app.classic is not None
bui.app.classic.resume()
def _tick(self) -> None:
plus = bui.app.plus
assert plus is not None
# if our target activity is gone or has ended, go away
activity = self._activity()
if activity is None or activity.has_ended():
self._on_cancel()
return
if plus.get_v1_account_state() == 'signed_in':
sval = bui.charstr(bui.SpecialChar.TICKET) + str(
plus.get_v1_account_ticket_count()
)
else:
sval = '?'
if self._tickets_text is not None:
assert self._tickets_text_base is not None
bui.textwidget(
edit=self._tickets_text,
text=self._tickets_text_base.replace('${COUNT}', sval),
)
if self._counting_down:
self._count -= 1
bui.getsound('tick').play()
if self._count <= 0:
self._on_cancel()
else:
bui.textwidget(edit=self._counter_text, text=str(self._count))
def _on_cancel_press(self) -> None:
# disallow for first second
if self._start_count - self._count < 2:
bui.getsound('error').play()
else:
self._on_cancel()
def _on_continue_press(self) -> None:
# from bauiv1lib import gettickets
plus = bui.app.plus
assert plus is not None
# Disallow for first second.
if self._start_count - self._count < 2:
bui.getsound('error').play()
else:
# If somehow we got signed out...
if plus.get_v1_account_state() != 'signed_in':
bui.screenmessage(
bui.Lstr(resource='notSignedInText'), color=(1, 0, 0)
)
bui.getsound('error').play()
return
# If it appears we don't have enough tickets, offer to buy more.
tickets = plus.get_v1_account_ticket_count()
if tickets < self._cost:
# FIXME: Should we start the timer back up again after?
self._counting_down = False
bui.textwidget(edit=self._counter_text, text='')
bui.getsound('error').play()
# gettickets.show_get_tickets_prompt()
return
if not self._transitioning_out:
bui.getsound('swish').play()
self._transitioning_out = True
bui.containerwidget(
edit=self._root_widget, transition='out_scale'
)
self._continue_call()
def _on_cancel(self) -> None:
if not self._transitioning_out:
bui.getsound('swish').play()
self._transitioning_out = True
bui.containerwidget(edit=self._root_widget, transition='out_scale')
self._cancel_call()

View File

@ -593,5 +593,5 @@ class InGameMenuWindow(bui.MainWindow):
classic.main_menu_resume_callbacks.clear() classic.main_menu_resume_callbacks.clear()
def __del__(self) -> None: # def __del__(self) -> None:
self._resume() # self._resume()

View File

@ -39,7 +39,7 @@ auto main(int argc, char** argv) -> int {
namespace ballistica { namespace ballistica {
// These are set automatically via script; don't modify them here. // These are set automatically via script; don't modify them here.
const int kEngineBuildNumber = 22017; const int kEngineBuildNumber = 22018;
const char* kEngineVersion = "1.7.37"; const char* kEngineVersion = "1.7.37";
const int kEngineApiVersion = 9; const int kEngineApiVersion = 9;