diff --git a/.efrocachemap b/.efrocachemap index 47882764..7a5d1fc0 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -4174,22 +4174,22 @@ "build/assets/windows/Win32/ucrtbased.dll": "bfd1180c269d3950b76f35a63655e9e1", "build/assets/windows/Win32/vc_redist.x86.exe": "15a5f1f876503885adbdf5b3989b3718", "build/assets/windows/Win32/vcruntime140d.dll": "865b2af4d1e26a1a8073c89acb06e599", - "build/prefab/full/linux_arm64_gui/debug/ballisticakit": "31209ca509f46fde3450eb8b7a39a520", - "build/prefab/full/linux_arm64_gui/release/ballisticakit": "03ec26492ef7dc28370cbb7f9902b0b9", - "build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "9331d3a163409aa08b5b1e681d923231", - "build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "7aeb21b72648fa81d27d18251fb60f68", - "build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "cecba50ac68398a3c4f8ddbaa9211d48", - "build/prefab/full/linux_x86_64_gui/release/ballisticakit": "683ff26a659c420a3738b5c58e17b37e", - "build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "5e2f2dc71bd451900d7ece96e098dc00", - "build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "4745da922028681b1b5cc63a584030b3", - "build/prefab/full/mac_arm64_gui/debug/ballisticakit": "a6527c54deee04b51029b1023a0b27fd", - "build/prefab/full/mac_arm64_gui/release/ballisticakit": "c6ceb3702ea22a2e187145a86bd51a13", - "build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "4ee039201fdaa4c9a5afbefd5a31c064", - "build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "15f71fc2ee8e71c657c159edceaec719", - "build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "1a56770399e5f6c91c25be77a68f38da", - "build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "bcb3448df41f7a7e91f2823e55253a57", - "build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "6805beb9c0d1f967fe6a4344b5735aad", - "build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "b15bc3743c8021d1069568071e734a13", + "build/prefab/full/linux_arm64_gui/debug/ballisticakit": "ce8f860eca1987d08245184f86996182", + "build/prefab/full/linux_arm64_gui/release/ballisticakit": "50d39660fa219c8d6cf2efb61685a61a", + "build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "6ba96618dd57e6937abe9d1919dfa572", + "build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "cecc7cee479a3d34f9b2fc9e9d9ded23", + "build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "e62e0586da50386f4f363ec018a5db5e", + "build/prefab/full/linux_x86_64_gui/release/ballisticakit": "60c86684724816e72fe123a4181e9b5e", + "build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "652e6dad52ffa1c7166ffad2da52e5cd", + "build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "7a54b3311d70edc58f6f2953df088e92", + "build/prefab/full/mac_arm64_gui/debug/ballisticakit": "2e43eceb3930606383de961285d539d5", + "build/prefab/full/mac_arm64_gui/release/ballisticakit": "02967dc5ba24c1b85ff0626934c3e1ae", + "build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "e93d6a9a363e7b769c1b4504bd24e34d", + "build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "f65ae7e22fba795c6368fd4d652eeff1", + "build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "5c6b347ac1a4f2a9cd0e253520355e66", + "build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "5ee86d89f53f1da49e9f35f6bb510ec5", + "build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "eb531ec851c84295fad13f48d420a673", + "build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "9d55662daa82013b697d0715002fd950", "build/prefab/lib/linux_arm64_gui/debug/libballisticaplus.a": "cbacac5a846cf8a0f6db760aaddcd13a", "build/prefab/lib/linux_arm64_gui/release/libballisticaplus.a": "3d16bac10d8f15bac7fe20e3a927b275", "build/prefab/lib/linux_arm64_server/debug/libballisticaplus.a": "cbacac5a846cf8a0f6db760aaddcd13a", @@ -4202,14 +4202,14 @@ "build/prefab/lib/mac_arm64_gui/release/libballisticaplus.a": "7dd182733a34da0ca5f5c97e5cb0b7f0", "build/prefab/lib/mac_arm64_server/debug/libballisticaplus.a": "6121591b94d920ee541194b65d93958a", "build/prefab/lib/mac_arm64_server/release/libballisticaplus.a": "7dd182733a34da0ca5f5c97e5cb0b7f0", - "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "c512e7bacb6c8654b517a38604e0ccf2", - "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "21b911b0ee5e354d25e8acf740140188", - "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "6313af7210edecf7e9cf026550bbb161", - "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "dc7d359250c39d0e636da2bf7d859deb", - "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "4c4c93e32beb69743b63f963748e1136", - "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "70f5185b13ab6e799dbfc9bdd0a9e997", - "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "f6adec2b792bc36c2cea2b395e827471", - "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "e674baf0049c634e6342cae5a266b567", + "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "3aae8d5bb14498fa8c38a90f92e6eb61", + "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "8ca4eb60a623835aedded88a2c43d786", + "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "4d69eddf79b7e53a354b0148ba3af821", + "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "2d283c2d49f668594e858c33831354e8", + "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "bd3a90924b3dd122143cc99b9d054eaf", + "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "4a9d7d32618519f04c4cc7b1cbdfb028", + "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "4ff97a62a991a2af73bfcf23faeac8fe", + "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "dbf2ed253e622c90939ce31cec3f04e8", "src/assets/ba_data/python/babase/_mgen/__init__.py": "f885fed7f2ed98ff2ba271f9dbe3391c", "src/assets/ba_data/python/babase/_mgen/enums.py": "794d258d59fd17a61752843a9a0551ad", "src/ballistica/base/mgen/pyembed/binding_base.inc": "06042d31df0ff9af96b99477162e2a91", diff --git a/CHANGELOG.md b/CHANGELOG.md index 0430af6a..176dd843 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -### 1.7.37 (build 22202, api 9, 2025-01-18) +### 1.7.37 (build 22204, api 9, 2025-01-18) - 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 touch UI stuff at all you can simply bump your api version and call it a day. diff --git a/src/assets/ba_data/python/baclassic/_appsubsystem.py b/src/assets/ba_data/python/baclassic/_appsubsystem.py index 880835df..b1e63393 100644 --- a/src/assets/ba_data/python/baclassic/_appsubsystem.py +++ b/src/assets/ba_data/python/baclassic/_appsubsystem.py @@ -906,3 +906,67 @@ class ClassicAppSubsystem(babase.AppSubsystem): assert_never(label) return babase.Lstr(resource=rsrc) + + def required_purchase_for_game(self, game: str) -> str | None: + """Return which purchase (if any) is required for a game.""" + # pylint: disable=too-many-return-statements + + if game in ( + 'Challenges:Infinite Runaround', + 'Challenges:Tournament Infinite Runaround', + ): + # Special case: Pro used to unlock this. + return ( + None + if self.accounts.have_pro() + else 'upgrades.infinite_runaround' + ) + if game in ( + 'Challenges:Infinite Onslaught', + 'Challenges:Tournament Infinite Onslaught', + ): + # Special case: Pro used to unlock this. + return ( + None + if self.accounts.have_pro() + else 'upgrades.infinite_onslaught' + ) + if game in ( + 'Challenges:Meteor Shower', + 'Challenges:Epic Meteor Shower', + ): + return 'games.meteor_shower' + + if game in ( + 'Challenges:Target Practice', + 'Challenges:Target Practice B', + ): + return 'games.target_practice' + + if game in ( + 'Challenges:Ninja Fight', + 'Challenges:Pro Ninja Fight', + ): + return 'games.ninja_fight' + + if game in ('Challenges:Lake Frigid Race',): + return 'maps.lake_frigid' + + if game in ( + 'Challenges:Easter Egg Hunt', + 'Challenges:Pro Easter Egg Hunt', + ): + return 'games.easter_egg_hunt' + + return None + + def is_game_unlocked(self, game: str) -> bool: + """Is a particular game unlocked?""" + plus = babase.app.plus + assert plus is not None + + purchase = self.required_purchase_for_game(game) + if purchase is None: + return True + + return plus.get_v1_account_product_purchased(purchase) diff --git a/src/assets/ba_data/python/baenv.py b/src/assets/ba_data/python/baenv.py index 472ab2c4..d461ac85 100644 --- a/src/assets/ba_data/python/baenv.py +++ b/src/assets/ba_data/python/baenv.py @@ -53,7 +53,7 @@ if TYPE_CHECKING: # Build number and version of the ballistica binary we expect to be # using. -TARGET_BALLISTICA_BUILD = 22202 +TARGET_BALLISTICA_BUILD = 22204 TARGET_BALLISTICA_VERSION = '1.7.37' diff --git a/src/assets/ba_data/python/bauiv1lib/coop/browser.py b/src/assets/ba_data/python/bauiv1lib/coop/browser.py index 4d4e928f..c44b817c 100644 --- a/src/assets/ba_data/python/bauiv1lib/coop/browser.py +++ b/src/assets/ba_data/python/bauiv1lib/coop/browser.py @@ -326,8 +326,10 @@ class CoopBrowserWindow(bui.MainWindow): ): self._tourney_data_up_to_date = False - # If our account state has changed, do a full request. + # If our account login state has changed, do a + # full request. account_state_num = plus.get_v1_account_state_num() + if account_state_num != self._account_state_num: self._account_state_num = account_state_num self._save_state() @@ -405,6 +407,7 @@ class CoopBrowserWindow(bui.MainWindow): logging.exception('Error updating campaign lock.') def _update_for_data(self, data: list[dict[str, Any]] | None) -> None: + # If the number of tournaments or challenges in the data differs # from our current arrangement, refresh with the new number. if (data is None and self._tournament_button_count != 0) or ( @@ -985,9 +988,10 @@ class CoopBrowserWindow(bui.MainWindow): """Return whether our tourney data is up to date.""" return self._tourney_data_up_to_date - def run_game(self, game: str) -> None: + def run_game( + self, game: str, origin_widget: bui.Widget | None = None + ) -> None: """Run the provided game.""" - # pylint: disable=too-many-branches # pylint: disable=cyclic-import from bauiv1lib.confirm import ConfirmWindow from bauiv1lib.purchase import PurchaseWindow @@ -1012,38 +1016,7 @@ class CoopBrowserWindow(bui.MainWindow): ) return - required_purchase: str | None - - # Infinite onslaught requires pro or the newer standalone - # upgrade. - if ( - game in ['Challenges:Infinite Runaround'] - and not bui.app.classic.accounts.have_pro() - ): - required_purchase = 'upgrades.infinite_runaround' - elif ( - game in ['Challenges:Infinite Onslaught'] - and not bui.app.classic.accounts.have_pro() - ): - required_purchase = 'upgrades.infinite_onslaught' - elif game in ['Challenges:Meteor Shower']: - required_purchase = 'games.meteor_shower' - elif game in [ - 'Challenges:Target Practice', - 'Challenges:Target Practice B', - ]: - required_purchase = 'games.target_practice' - elif game in ['Challenges:Ninja Fight']: - required_purchase = 'games.ninja_fight' - elif game in ['Challenges:Pro Ninja Fight']: - required_purchase = 'games.ninja_fight' - elif game in [ - 'Challenges:Easter Egg Hunt', - 'Challenges:Pro Easter Egg Hunt', - ]: - required_purchase = 'games.easter_egg_hunt' - else: - required_purchase = None + required_purchase = bui.app.classic.required_purchase_for_game(game) if ( required_purchase is not None @@ -1052,7 +1025,9 @@ class CoopBrowserWindow(bui.MainWindow): if plus.get_v1_account_state() != 'signed_in': show_sign_in_prompt() else: - PurchaseWindow(items=[required_purchase]) + PurchaseWindow( + items=[required_purchase], origin_widget=origin_widget + ) return self._save_state() @@ -1062,12 +1037,18 @@ class CoopBrowserWindow(bui.MainWindow): def run_tournament(self, tournament_button: TournamentButton) -> None: """Run the provided tournament game.""" + # pylint: disable=too-many-return-statements + + from bauiv1lib.purchase import PurchaseWindow from bauiv1lib.account.signin import show_sign_in_prompt from bauiv1lib.tournamententry import TournamentEntryWindow plus = bui.app.plus assert plus is not None + classic = bui.app.classic + assert classic is not None + if plus.get_v1_account_state() != 'signed_in': show_sign_in_prompt() return @@ -1117,6 +1098,22 @@ class CoopBrowserWindow(bui.MainWindow): bui.getsound('error').play() return + if tournament_button.game is not None and not classic.is_game_unlocked( + tournament_button.game + ): + required_purchase = classic.required_purchase_for_game( + tournament_button.game + ) + assert required_purchase is not None + if plus.get_v1_account_state() != 'signed_in': + show_sign_in_prompt() + else: + PurchaseWindow( + items=[required_purchase], + origin_widget=tournament_button.button, + ) + return + if tournament_button.time_remaining <= 0: bui.screenmessage( bui.Lstr(resource='tournamentEndedText'), color=(1, 0, 0) @@ -1138,10 +1135,6 @@ class CoopBrowserWindow(bui.MainWindow): sel = self._root_widget.get_selected_child() if sel == self._back_button: sel_name = 'Back' - # elif sel == self._store_button_widget: - # sel_name = 'Store' - # elif sel == self._league_rank_button_widget: - # sel_name = 'PowerRanking' elif sel == self._scrollwidget: sel_name = 'Scroll' else: diff --git a/src/assets/ba_data/python/bauiv1lib/coop/gamebutton.py b/src/assets/ba_data/python/bauiv1lib/coop/gamebutton.py index 7589716c..691e77fd 100644 --- a/src/assets/ba_data/python/bauiv1lib/coop/gamebutton.py +++ b/src/assets/ba_data/python/bauiv1lib/coop/gamebutton.py @@ -5,6 +5,7 @@ from __future__ import annotations import random +import weakref from typing import TYPE_CHECKING import bauiv1 as bui @@ -59,12 +60,15 @@ class GameButton: else: stars = 1 + self._window = weakref.ref(window) + self._game = game + self._button = btn = bui.buttonwidget( parent=parent, position=(x + 23, y + 4), size=(sclx, scly), label='', - on_activate_call=bui.Call(window.run_game, game), + on_activate_call=bui.WeakCall(self._on_press), button_type='square', autoselect=True, on_select_call=bui.Call(window.sel_change, row, game), @@ -187,12 +191,16 @@ class GameButton: ) self._update() + def _on_press(self) -> None: + window = self._window() + if window is not None: + window.run_game(self._game, origin_widget=self._button) + def get_button(self) -> bui.Widget: """Return the underlying button bui.Widget.""" return self._button def _update(self) -> None: - # pylint: disable=too-many-boolean-expressions plus = bui.app.plus assert plus is not None @@ -232,64 +240,7 @@ class GameButton: # Hard-code games we haven't unlocked. assert bui.app.classic is not None - if ( - ( - game in ('Challenges:Infinite Runaround',) - and not ( - bui.app.classic.accounts.have_pro() - or plus.get_v1_account_product_purchased( - 'upgrades.infinite_runaround' - ) - ) - ) - or ( - game in ('Challenges:Infinite Onslaught',) - and not ( - bui.app.classic.accounts.have_pro() - or plus.get_v1_account_product_purchased( - 'upgrades.infinite_onslaught' - ) - ) - ) - or ( - game in ('Challenges:Meteor Shower',) - and not plus.get_v1_account_product_purchased( - 'games.meteor_shower' - ) - ) - or ( - game - in ( - 'Challenges:Target Practice', - 'Challenges:Target Practice B', - ) - and not plus.get_v1_account_product_purchased( - 'games.target_practice' - ) - ) - or ( - game in ('Challenges:Ninja Fight',) - and not plus.get_v1_account_product_purchased( - 'games.ninja_fight' - ) - ) - or ( - game in ('Challenges:Pro Ninja Fight',) - and not plus.get_v1_account_product_purchased( - 'games.ninja_fight' - ) - ) - or ( - game - in ( - 'Challenges:Easter Egg Hunt', - 'Challenges:Pro Easter Egg Hunt', - ) - and not plus.get_v1_account_product_purchased( - 'games.easter_egg_hunt' - ) - ) - ): + if not bui.app.classic.is_game_unlocked(game): unlocked = False # Let's tint levels a slightly different color when easy mode diff --git a/src/assets/ba_data/python/bauiv1lib/coop/tournamentbutton.py b/src/assets/ba_data/python/bauiv1lib/coop/tournamentbutton.py index fa31930c..8723c5ec 100644 --- a/src/assets/ba_data/python/bauiv1lib/coop/tournamentbutton.py +++ b/src/assets/ba_data/python/bauiv1lib/coop/tournamentbutton.py @@ -39,6 +39,7 @@ class TournamentButton: self.lsbo = bui.getmesh('level_select_button_opaque') self.allow_ads = False self.tournament_id: str | None = None + self.game: str | None = None self.time_remaining: int = 0 self.has_time_remaining: bool = False self.leader: Any = None @@ -400,6 +401,9 @@ class TournamentButton: color=(0.4, 0.4, 0.5), flatness=1.0, ) + self._lock_update_timer = bui.AppTimer( + 1.03, bui.WeakCall(self._update_lock_state), repeat=True + ) def _pressed(self) -> None: self.on_pressed(self) @@ -440,6 +444,33 @@ class TournamentButton: position=self.more_scores_button.get_screen_space_center(), ) + def _update_lock_state(self) -> None: + + if self.game is None: + return + + assert bui.app.classic is not None + + campaignname, levelname = self.game.split(':') + campaign = bui.app.classic.getcampaign(campaignname) + + enabled = ( + self.required_league is None + and bui.app.classic.is_game_unlocked(self.game) + ) + bui.buttonwidget( + edit=self.button, + color=(0.5, 0.7, 0.2) if enabled else (0.5, 0.5, 0.5), + ) + bui.imagewidget(edit=self.lock_image, opacity=0.0 if enabled else 1.0) + bui.imagewidget( + edit=self.image, + texture=bui.gettexture( + campaign.getlevel(levelname).preview_texture_name + ), + opacity=1.0 if enabled else 0.5, + ) + def update_for_data(self, entry: dict[str, Any]) -> None: """Update for new incoming data.""" # pylint: disable=too-many-statements @@ -470,12 +501,22 @@ class TournamentButton: entry, include_tickets=False ) - enabled = 'requiredLeague' not in entry - bui.buttonwidget( - edit=self.button, - color=(0.5, 0.7, 0.2) if enabled else (0.5, 0.5, 0.5), - ) - bui.imagewidget(edit=self.lock_image, opacity=0.0 if enabled else 1.0) + self.time_remaining = entry['timeRemaining'] + self.has_time_remaining = entry is not None + self.tournament_id = entry['tournamentID'] + self.required_league = entry.get('requiredLeague') + + assert bui.app.classic is not None + self.game = bui.app.classic.accounts.tournament_info[ + self.tournament_id + ]['game'] + assert isinstance(self.game, str) + + campaignname, levelname = self.game.split(':') + campaign = bui.app.classic.getcampaign(campaignname) + + self._update_lock_state() + bui.textwidget( edit=self.prize_range_1_text, text='-' if pr1 == '' else pr1, @@ -604,51 +645,30 @@ class TournamentButton: edit=self.time_remaining_out_of_text, text=out_of_time_text ) - self.time_remaining = entry['timeRemaining'] - self.has_time_remaining = entry is not None - self.tournament_id = entry['tournamentID'] - self.required_league = ( - None if 'requiredLeague' not in entry else entry['requiredLeague'] - ) + # if self.game is None: + # bui.textwidget(edit=self.button_text, text='-') + # bui.imagewidget( + # edit=self.image, texture=bui.gettexture('black'), opacity=0.2 + # ) + # else: + max_players = bui.app.classic.accounts.tournament_info[ + self.tournament_id + ]['maxPlayers'] - assert bui.app.classic is not None - game = bui.app.classic.accounts.tournament_info[self.tournament_id][ - 'game' - ] - - if game is None: - bui.textwidget(edit=self.button_text, text='-') - bui.imagewidget( - edit=self.image, texture=bui.gettexture('black'), opacity=0.2 - ) - else: - campaignname, levelname = game.split(':') - campaign = bui.app.classic.getcampaign(campaignname) - max_players = bui.app.classic.accounts.tournament_info[ - self.tournament_id - ]['maxPlayers'] - - txt = bui.Lstr( - value='${A} ${B}', - subs=[ - ('${A}', campaign.getlevel(levelname).displayname), - ( - '${B}', - bui.Lstr( - resource='playerCountAbbreviatedText', - subs=[('${COUNT}', str(max_players))], - ), + txt = bui.Lstr( + value='${A} ${B}', + subs=[ + ('${A}', campaign.getlevel(levelname).displayname), + ( + '${B}', + bui.Lstr( + resource='playerCountAbbreviatedText', + subs=[('${COUNT}', str(max_players))], ), - ], - ) - bui.textwidget(edit=self.button_text, text=txt) - bui.imagewidget( - edit=self.image, - texture=bui.gettexture( - campaign.getlevel(levelname).preview_texture_name ), - opacity=1.0 if enabled else 0.5, - ) + ], + ) + bui.textwidget(edit=self.button_text, text=txt) fee = entry['fee'] assert isinstance(fee, int | None) diff --git a/src/assets/ba_data/python/bauiv1lib/purchase.py b/src/assets/ba_data/python/bauiv1lib/purchase.py index 9d20efeb..68c231b7 100644 --- a/src/assets/ba_data/python/bauiv1lib/purchase.py +++ b/src/assets/ba_data/python/bauiv1lib/purchase.py @@ -18,7 +18,7 @@ class PurchaseWindow(bui.Window): def __init__( self, items: list[str], - transition: str = 'in_right', + origin_widget: bui.Widget | None = None, header_text: bui.Lstr | None = None, ): from bauiv1lib.store.item import instantiate_store_item_display @@ -40,16 +40,24 @@ class PurchaseWindow(bui.Window): self._width = 580 self._height = 520 uiscale = bui.app.ui_v1.uiscale + + if origin_widget is not None: + scale_origin = origin_widget.get_screen_space_center() + else: + scale_origin = None + super().__init__( root_widget=bui.containerwidget( + parent=bui.get_special_widget('overlay_stack'), size=(self._width, self._height), - transition=transition, + transition='in_scale', toolbar_visibility='menu_store', scale=( 1.2 if uiscale is bui.UIScale.SMALL else 1.1 if uiscale is bui.UIScale.MEDIUM else 1.0 ), + scale_origin_stack_offset=scale_origin, stack_offset=( (0, -15) if uiscale is bui.UIScale.SMALL else (0, 0) ), @@ -159,7 +167,7 @@ class PurchaseWindow(bui.Window): can_die = True if can_die: - bui.containerwidget(edit=self._root_widget, transition='out_left') + bui.containerwidget(edit=self._root_widget, transition='out_scale') def _purchase(self) -> None: @@ -192,4 +200,4 @@ class PurchaseWindow(bui.Window): do_it() def _cancel(self) -> None: - bui.containerwidget(edit=self._root_widget, transition='out_right') + bui.containerwidget(edit=self._root_widget, transition='out_scale') diff --git a/src/ballistica/shared/ballistica.cc b/src/ballistica/shared/ballistica.cc index 68539b58..14827c77 100644 --- a/src/ballistica/shared/ballistica.cc +++ b/src/ballistica/shared/ballistica.cc @@ -39,7 +39,7 @@ auto main(int argc, char** argv) -> int { namespace ballistica { // These are set automatically via script; don't modify them here. -const int kEngineBuildNumber = 22202; +const int kEngineBuildNumber = 22204; const char* kEngineVersion = "1.7.37"; const int kEngineApiVersion = 9;