removed pro and bundle nag screens

This commit is contained in:
Eric 2024-08-30 20:02:15 -07:00
parent 64c6613c23
commit 5b778890cf
No known key found for this signature in database
GPG Key ID: 89C93F0F8D6D5A98
9 changed files with 50 additions and 638 deletions

56
.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": "512c99d6d32d3f7ca27de9d00b3f6bee", "build/prefab/full/linux_arm64_gui/debug/ballisticakit": "d6246c930e7e2d2d9a6aff6788f33b69",
"build/prefab/full/linux_arm64_gui/release/ballisticakit": "407a6d564f35c7db571702ef6996adc1", "build/prefab/full/linux_arm64_gui/release/ballisticakit": "001c67c4d4d33e20755399e0b2ed1593",
"build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "03c278694182a2a7cd6e39d7cf0cdde8", "build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "6f6bfaf19daf6e866f4fecbc889b8854",
"build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "8c0f3132135f6a392b31dccce44ecc72", "build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "ebc7449903d7868c631c504aed10f371",
"build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "399783ec75c825a7c0ceffb6b66546a6", "build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "91f03e7dbfc0d7eb75568704f681fba5",
"build/prefab/full/linux_x86_64_gui/release/ballisticakit": "7d5f43f891ddbc0e68e1e4b924717941", "build/prefab/full/linux_x86_64_gui/release/ballisticakit": "0b32b6eb05df0a7e23e55ff2e7235a8f",
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "97b462045118ca81436452c19e50ead3", "build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "4ed4b63cc506815f759412a295bfe088",
"build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "daedf2d4f2c7012f9f1146ef5e675a51", "build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "1890731fb8a2fb43c4cde72af9d7a4e6",
"build/prefab/full/mac_arm64_gui/debug/ballisticakit": "ef571b31a6175b391c70cde46587afc6", "build/prefab/full/mac_arm64_gui/debug/ballisticakit": "1a4764a504dcb20591ac3472c48db8d9",
"build/prefab/full/mac_arm64_gui/release/ballisticakit": "fcbe9cb15740f5569d32daaef838bae3", "build/prefab/full/mac_arm64_gui/release/ballisticakit": "9bfd6234aac4ffd7d7601a40017a73be",
"build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "06d8ed9ca06ed1fb12437708b117621f", "build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "941f8fb79d54522ca5df97a735c3babe",
"build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "eff858f25a173f090731401c42fcfad7", "build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "290a3d9840efc5e88532e13b76b3ae6b",
"build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "21401c4a1bb13c6a50fbcc2413a34bc6", "build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "621a6684b54b0a9101f808209bcca1ee",
"build/prefab/full/mac_x86_64_gui/release/ballisticakit": "a5f6bf1f1a675a60b43674cbe06ee740", "build/prefab/full/mac_x86_64_gui/release/ballisticakit": "43c8b0b29e5fb257e4cde0f7fce1c680",
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "4965d74db093926f890d37a2d2bcb0cf", "build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "9a30c6b88ffc11bdf6765780616d8ba1",
"build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "527d364caa4c68cb3a5e70575a834333", "build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "8a8f63850fc296b060a994f4e001d74f",
"build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "f3e69ff8d4928b52fb301c911d6e01cb", "build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "2864e9ae1d2d566def85f1cdf6e863fe",
"build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "82dd100621de502523d9feca94de7fc5", "build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "dc0db7ca99661a896634fc05187a5c75",
"build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "6c66e68c95330200d339ec5a44706491", "build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "f56bb0fafe0a45cecdcd06a10a6924c9",
"build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "f6903fb7071440ee807963cf34fd220f", "build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "e3a58b09fea193d78187f97cf922717d",
"build/prefab/lib/linux_arm64_gui/debug/libballisticaplus.a": "73ad3303fe1a82005918fbc5dae3446c", "build/prefab/lib/linux_arm64_gui/debug/libballisticaplus.a": "73ad3303fe1a82005918fbc5dae3446c",
"build/prefab/lib/linux_arm64_gui/release/libballisticaplus.a": "fa659b5d6119acba6570c92ce4d35ae2", "build/prefab/lib/linux_arm64_gui/release/libballisticaplus.a": "fa659b5d6119acba6570c92ce4d35ae2",
"build/prefab/lib/linux_arm64_server/debug/libballisticaplus.a": "73ad3303fe1a82005918fbc5dae3446c", "build/prefab/lib/linux_arm64_server/debug/libballisticaplus.a": "73ad3303fe1a82005918fbc5dae3446c",
@ -4132,14 +4132,14 @@
"build/prefab/lib/mac_x86_64_gui/release/libballisticaplus.a": "3e5c5fd0a09f55ba7b05ce1e2ec7171e", "build/prefab/lib/mac_x86_64_gui/release/libballisticaplus.a": "3e5c5fd0a09f55ba7b05ce1e2ec7171e",
"build/prefab/lib/mac_x86_64_server/debug/libballisticaplus.a": "1659535e95e3047fda529543e265ac97", "build/prefab/lib/mac_x86_64_server/debug/libballisticaplus.a": "1659535e95e3047fda529543e265ac97",
"build/prefab/lib/mac_x86_64_server/release/libballisticaplus.a": "3e5c5fd0a09f55ba7b05ce1e2ec7171e", "build/prefab/lib/mac_x86_64_server/release/libballisticaplus.a": "3e5c5fd0a09f55ba7b05ce1e2ec7171e",
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "3193670862ed84af2f6bbf3dc7265137", "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "6b6aae30362b1e9aaf3f1a8daae0b0b4",
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "5e45916a6cfb40a5667c691e507ea81d", "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "25db08ee2b4c79ca631e517b622c741d",
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "419fba17d012361c3ca8174c44dffdb2", "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "2ea419644782c4c52d1fa784d0ced86d",
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "d895b4afb3bb74dd1c94595a126a2c24", "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "c40627a46ee127997153df041e47eda5",
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "56a67ab9520c07bc4be68162e78534b3", "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "fff81b29e2d86031ec25c4a672a243e7",
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "40f942e6da490173c0e17fdf23e786e8", "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "2a87e2f53c658d0be3918476cd8a04ee",
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "3242b64140d0b0d6f7af09825d9489e0", "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "1e91536979b318b9a8325ab0e871ecec",
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "5d41c8b29dc4e585b878c100e01e8af4", "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "c6506399a93ef93e8322425f78e2e6b0",
"src/assets/ba_data/python/babase/_mgen/__init__.py": "f885fed7f2ed98ff2ba271f9dbe3391c", "src/assets/ba_data/python/babase/_mgen/__init__.py": "f885fed7f2ed98ff2ba271f9dbe3391c",
"src/assets/ba_data/python/babase/_mgen/enums.py": "cb299985623bbcc86015cb103a424ae6", "src/assets/ba_data/python/babase/_mgen/enums.py": "cb299985623bbcc86015cb103a424ae6",
"src/ballistica/base/mgen/pyembed/binding_base.inc": "efa61468cf098f77cc6a234461d8b86d", "src/ballistica/base/mgen/pyembed/binding_base.inc": "efa61468cf098f77cc6a234461d8b86d",

View File

@ -1,4 +1,4 @@
### 1.7.37 (build 21976, api 9, 2024-08-30) ### 1.7.37 (build 21977, api 9, 2024-08-30)
- 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.
@ -8,6 +8,7 @@
- Soundtrack customization no longer requires pro. - Soundtrack customization no longer requires pro.
- 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.
- 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

@ -399,7 +399,6 @@
"ba_data/python/bauiv1lib/__pycache__/resourcetypeinfo.cpython-312.opt-1.pyc", "ba_data/python/bauiv1lib/__pycache__/resourcetypeinfo.cpython-312.opt-1.pyc",
"ba_data/python/bauiv1lib/__pycache__/sendinfo.cpython-312.opt-1.pyc", "ba_data/python/bauiv1lib/__pycache__/sendinfo.cpython-312.opt-1.pyc",
"ba_data/python/bauiv1lib/__pycache__/serverdialog.cpython-312.opt-1.pyc", "ba_data/python/bauiv1lib/__pycache__/serverdialog.cpython-312.opt-1.pyc",
"ba_data/python/bauiv1lib/__pycache__/specialoffer.cpython-312.opt-1.pyc",
"ba_data/python/bauiv1lib/__pycache__/tabs.cpython-312.opt-1.pyc", "ba_data/python/bauiv1lib/__pycache__/tabs.cpython-312.opt-1.pyc",
"ba_data/python/bauiv1lib/__pycache__/teamnamescolors.cpython-312.opt-1.pyc", "ba_data/python/bauiv1lib/__pycache__/teamnamescolors.cpython-312.opt-1.pyc",
"ba_data/python/bauiv1lib/__pycache__/tournamententry.cpython-312.opt-1.pyc", "ba_data/python/bauiv1lib/__pycache__/tournamententry.cpython-312.opt-1.pyc",
@ -558,7 +557,6 @@
"ba_data/python/bauiv1lib/soundtrack/edit.py", "ba_data/python/bauiv1lib/soundtrack/edit.py",
"ba_data/python/bauiv1lib/soundtrack/entrytypeselect.py", "ba_data/python/bauiv1lib/soundtrack/entrytypeselect.py",
"ba_data/python/bauiv1lib/soundtrack/macmusicapp.py", "ba_data/python/bauiv1lib/soundtrack/macmusicapp.py",
"ba_data/python/bauiv1lib/specialoffer.py",
"ba_data/python/bauiv1lib/store/__init__.py", "ba_data/python/bauiv1lib/store/__init__.py",
"ba_data/python/bauiv1lib/store/__pycache__/__init__.cpython-312.opt-1.pyc", "ba_data/python/bauiv1lib/store/__pycache__/__init__.cpython-312.opt-1.pyc",
"ba_data/python/bauiv1lib/store/__pycache__/browser.cpython-312.opt-1.pyc", "ba_data/python/bauiv1lib/store/__pycache__/browser.cpython-312.opt-1.pyc",

View File

@ -425,7 +425,6 @@ SCRIPT_TARGETS_PY_PUBLIC = \
$(BUILD_DIR)/ba_data/python/bauiv1lib/soundtrack/edit.py \ $(BUILD_DIR)/ba_data/python/bauiv1lib/soundtrack/edit.py \
$(BUILD_DIR)/ba_data/python/bauiv1lib/soundtrack/entrytypeselect.py \ $(BUILD_DIR)/ba_data/python/bauiv1lib/soundtrack/entrytypeselect.py \
$(BUILD_DIR)/ba_data/python/bauiv1lib/soundtrack/macmusicapp.py \ $(BUILD_DIR)/ba_data/python/bauiv1lib/soundtrack/macmusicapp.py \
$(BUILD_DIR)/ba_data/python/bauiv1lib/specialoffer.py \
$(BUILD_DIR)/ba_data/python/bauiv1lib/store/__init__.py \ $(BUILD_DIR)/ba_data/python/bauiv1lib/store/__init__.py \
$(BUILD_DIR)/ba_data/python/bauiv1lib/store/browser.py \ $(BUILD_DIR)/ba_data/python/bauiv1lib/store/browser.py \
$(BUILD_DIR)/ba_data/python/bauiv1lib/store/button.py \ $(BUILD_DIR)/ba_data/python/bauiv1lib/store/button.py \
@ -704,7 +703,6 @@ SCRIPT_TARGETS_PYC_PUBLIC = \
$(BUILD_DIR)/ba_data/python/bauiv1lib/soundtrack/__pycache__/edit.cpython-312.opt-1.pyc \ $(BUILD_DIR)/ba_data/python/bauiv1lib/soundtrack/__pycache__/edit.cpython-312.opt-1.pyc \
$(BUILD_DIR)/ba_data/python/bauiv1lib/soundtrack/__pycache__/entrytypeselect.cpython-312.opt-1.pyc \ $(BUILD_DIR)/ba_data/python/bauiv1lib/soundtrack/__pycache__/entrytypeselect.cpython-312.opt-1.pyc \
$(BUILD_DIR)/ba_data/python/bauiv1lib/soundtrack/__pycache__/macmusicapp.cpython-312.opt-1.pyc \ $(BUILD_DIR)/ba_data/python/bauiv1lib/soundtrack/__pycache__/macmusicapp.cpython-312.opt-1.pyc \
$(BUILD_DIR)/ba_data/python/bauiv1lib/__pycache__/specialoffer.cpython-312.opt-1.pyc \
$(BUILD_DIR)/ba_data/python/bauiv1lib/store/__pycache__/__init__.cpython-312.opt-1.pyc \ $(BUILD_DIR)/ba_data/python/bauiv1lib/store/__pycache__/__init__.cpython-312.opt-1.pyc \
$(BUILD_DIR)/ba_data/python/bauiv1lib/store/__pycache__/browser.cpython-312.opt-1.pyc \ $(BUILD_DIR)/ba_data/python/bauiv1lib/store/__pycache__/browser.cpython-312.opt-1.pyc \
$(BUILD_DIR)/ba_data/python/bauiv1lib/store/__pycache__/button.cpython-312.opt-1.pyc \ $(BUILD_DIR)/ba_data/python/bauiv1lib/store/__pycache__/button.cpython-312.opt-1.pyc \

View File

@ -216,24 +216,6 @@ class ClassicAppSubsystem(babase.AppSubsystem):
cfg['launchCount'] = launch_count cfg['launchCount'] = launch_count
cfg.commit() cfg.commit()
# Run a test in a few seconds to see if we should pop up an existing
# pending special offer.
def check_special_offer() -> None:
assert plus is not None
from bauiv1lib.specialoffer import show_offer
if (
'pendingSpecialOffer' in cfg
and plus.get_v1_account_public_login_id()
== cfg['pendingSpecialOffer']['a']
):
self.special_offer = cfg['pendingSpecialOffer']['o']
show_offer()
if babase.app.env.gui:
babase.apptimer(3.0, check_special_offer)
# If there's a leftover log file, attempt to upload it to the # If there's a leftover log file, attempt to upload it to the
# master-server and/or get rid of it. # master-server and/or get rid of it.
babase.handle_leftover_v1_cloud_log_file() babase.handle_leftover_v1_cloud_log_file()
@ -832,7 +814,7 @@ class ClassicAppSubsystem(babase.AppSubsystem):
app = bauiv1.app app = bauiv1.app
env = app.env env = app.env
with bascenev1.ContextRef.empty(): with bascenev1.ContextRef.empty():
from bauiv1lib import specialoffer # from bauiv1lib import specialoffer
assert app.classic is not None assert app.classic is not None
if app.env.headless: if app.env.headless:
@ -927,11 +909,11 @@ class ClassicAppSubsystem(babase.AppSubsystem):
# (we may not have heard back from the server) # (we may not have heard back from the server)
# ..if that doesn't work they'll just have to wait # ..if that doesn't work they'll just have to wait
# until the next opportunity. # until the next opportunity.
if not specialoffer.show_offer(): # if not specialoffer.show_offer():
def try_again() -> None: # def try_again() -> None:
if not specialoffer.show_offer(): # if not specialoffer.show_offer():
# Try one last time.. # # Try one last time..
bauiv1.apptimer(2.0, specialoffer.show_offer) # bauiv1.apptimer(2.0, specialoffer.show_offer)
bauiv1.apptimer(2.0, try_again) # bauiv1.apptimer(2.0, try_again)

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 = 21976 TARGET_BALLISTICA_BUILD = 21977
TARGET_BALLISTICA_VERSION = '1.7.37' TARGET_BALLISTICA_VERSION = '1.7.37'

View File

@ -207,20 +207,22 @@ class CoopScoreScreen(bs.Activity[bs.Player, bs.Team]):
) )
def _ui_menu(self) -> None: def _ui_menu(self) -> None:
from bauiv1lib import specialoffer # from bauiv1lib import specialoffer
# if specialoffer.show_offer():
# return
if specialoffer.show_offer():
return
bui.containerwidget(edit=self._root_ui, transition='out_left') bui.containerwidget(edit=self._root_ui, transition='out_left')
with self.context: with self.context:
bs.timer(0.1, bs.Call(bs.WeakCall(self.session.end))) bs.timer(0.1, bs.Call(bs.WeakCall(self.session.end)))
def _ui_restart(self) -> None: def _ui_restart(self) -> None:
from bauiv1lib.tournamententry import TournamentEntryWindow from bauiv1lib.tournamententry import TournamentEntryWindow
from bauiv1lib import specialoffer
if specialoffer.show_offer(): # from bauiv1lib import specialoffer
return
# if specialoffer.show_offer():
# return
# If we're in a tournament and it looks like there's no time left, # If we're in a tournament and it looks like there's no time left,
# disallow. # disallow.
@ -268,10 +270,10 @@ class CoopScoreScreen(bs.Activity[bs.Player, bs.Team]):
self.end({'outcome': 'restart'}) self.end({'outcome': 'restart'})
def _ui_next(self) -> None: def _ui_next(self) -> None:
from bauiv1lib.specialoffer import show_offer # from bauiv1lib.specialoffer import show_offer
if show_offer(): # if show_offer():
return # return
# If we didn't just complete this level but are choosing to play the # If we didn't just complete this level but are choosing to play the
# next one, set it as current (this won't happen otherwise). # next one, set it as current (this won't happen otherwise).

View File

@ -1,569 +0,0 @@
# Released under the MIT License. See LICENSE for details.
#
"""UI for presenting sales/etc."""
from __future__ import annotations
import copy
import logging
from typing import TYPE_CHECKING
import bauiv1 as bui
if TYPE_CHECKING:
from typing import Any
class SpecialOfferWindow(bui.Window):
"""Window for presenting sales/etc."""
def __init__(self, offer: dict[str, Any], transition: str = 'in_right'):
# pylint: disable=too-many-statements
# pylint: disable=too-many-branches
# pylint: disable=too-many-locals
from babase import SpecialChar
from bauiv1lib.store import item as storeitemui
plus = bui.app.plus
assert plus is not None
assert bui.app.classic is not None
store = bui.app.classic.store
self._cancel_delay = offer.get('cancelDelay', 0)
# First thing: if we're offering pro or an IAP, see if we have a
# price for it.
# If not, abort and go into zombie mode (the user should never see
# us that way).
real_price: str | None
# Misnomer: 'pro' actually means offer 'pro_sale'.
if offer['item'] in ['pro', 'pro_fullprice']:
real_price = plus.get_price(
'pro' if offer['item'] == 'pro_fullprice' else 'pro_sale'
)
if real_price is None and bui.app.env.debug:
print('NOTE: Faking prices for debug build.')
real_price = '$1.23'
zombie = real_price is None
elif isinstance(offer['price'], str):
# (a string price implies IAP id)
real_price = plus.get_price(offer['price'])
if real_price is None and bui.app.env.debug:
print('NOTE: Faking price for debug build.')
real_price = '$1.23'
zombie = real_price is None
else:
real_price = None
zombie = False
if real_price is None:
real_price = '?'
if offer['item'] in ['pro', 'pro_fullprice']:
self._offer_item = 'pro'
else:
self._offer_item = offer['item']
# If we wanted a real price but didn't find one, go zombie.
if zombie:
return
# This can pop up suddenly, so lets block input for 1 second.
bui.lock_all_input()
bui.apptimer(1.0, bui.unlock_all_input)
bui.getsound('ding').play()
bui.apptimer(0.3, bui.getsound('ooh').play)
self._offer = copy.deepcopy(offer)
self._width = 580
self._height = 590
uiscale = bui.app.ui_v1.uiscale
super().__init__(
root_widget=bui.containerwidget(
size=(self._width, self._height),
transition=transition,
scale=(
1.2
if uiscale is bui.UIScale.SMALL
else 1.15 if uiscale is bui.UIScale.MEDIUM else 1.0
),
stack_offset=(
(0, -15) if uiscale is bui.UIScale.SMALL else (0, 0)
),
)
)
self._is_bundle_sale = False
try:
if offer['item'] in ['pro', 'pro_fullprice']:
original_price_str = plus.get_price('pro')
if original_price_str is None:
original_price_str = '?'
new_price_str = plus.get_price('pro_sale')
if new_price_str is None:
new_price_str = '?'
percent_off_text = ''
else:
# If the offer includes bonus tickets, it's a bundle-sale.
if (
'bonusTickets' in offer
and offer['bonusTickets'] is not None
):
self._is_bundle_sale = True
original_price = plus.get_v1_account_misc_read_val(
'price.' + self._offer_item, 9999
)
# For pure ticket prices we can show a percent-off.
if isinstance(offer['price'], int):
new_price = offer['price']
tchar = bui.charstr(SpecialChar.TICKET)
original_price_str = tchar + str(original_price)
new_price_str = tchar + str(new_price)
percent_off = int(
round(
100.0 - (float(new_price) / original_price) * 100.0
)
)
percent_off_text = ' ' + bui.Lstr(
resource='store.salePercentText'
).evaluate().replace('${PERCENT}', str(percent_off))
else:
original_price_str = new_price_str = '?'
percent_off_text = ''
except Exception:
logging.exception('Error setting up special-offer: %s.', offer)
original_price_str = new_price_str = '?'
percent_off_text = ''
# If its a bundle sale, change the title.
if self._is_bundle_sale:
sale_text = bui.Lstr(
resource='store.saleBundleText',
fallback_resource='store.saleText',
).evaluate()
else:
# For full pro we say 'Upgrade?' since its not really a sale.
if offer['item'] == 'pro_fullprice':
sale_text = bui.Lstr(
resource='store.upgradeQuestionText',
fallback_resource='store.saleExclaimText',
).evaluate()
else:
sale_text = bui.Lstr(
resource='store.saleExclaimText',
fallback_resource='store.saleText',
).evaluate()
self._title_text = bui.textwidget(
parent=self._root_widget,
position=(self._width * 0.5, self._height - 40),
size=(0, 0),
text=sale_text
+ (
(' ' + bui.Lstr(resource='store.oneTimeOnlyText').evaluate())
if self._offer['oneTimeOnly']
else ''
)
+ percent_off_text,
h_align='center',
v_align='center',
maxwidth=self._width * 0.9 - 220,
scale=1.4,
color=(0.3, 1, 0.3),
)
self._flash_on = False
self._flashing_timer: bui.AppTimer | None = bui.AppTimer(
0.05, bui.WeakCall(self._flash_cycle), repeat=True
)
bui.apptimer(0.6, bui.WeakCall(self._stop_flashing))
size = store.get_store_item_display_size(self._offer_item)
display: dict[str, Any] = {}
storeitemui.instantiate_store_item_display(
self._offer_item,
display,
parent_widget=self._root_widget,
b_pos=(
self._width * 0.5
- size[0] * 0.5
+ 10
- ((size[0] * 0.5 + 30) if self._is_bundle_sale else 0),
self._height * 0.5
- size[1] * 0.5
+ 20
+ (20 if self._is_bundle_sale else 0),
),
b_width=size[0],
b_height=size[1],
button=not self._is_bundle_sale,
)
# Wire up the parts we need.
if self._is_bundle_sale:
self._plus_text = bui.textwidget(
parent=self._root_widget,
position=(self._width * 0.5, self._height * 0.5 + 50),
size=(0, 0),
text='+',
h_align='center',
v_align='center',
maxwidth=self._width * 0.9,
scale=1.4,
color=(0.5, 0.5, 0.5),
)
self._plus_tickets = bui.textwidget(
parent=self._root_widget,
position=(self._width * 0.5 + 120, self._height * 0.5 + 50),
size=(0, 0),
text=bui.charstr(SpecialChar.TICKET_BACKING)
+ str(offer['bonusTickets']),
h_align='center',
v_align='center',
maxwidth=self._width * 0.9,
scale=2.5,
color=(0.2, 1, 0.2),
)
self._price_text = bui.textwidget(
parent=self._root_widget,
position=(self._width * 0.5, 150),
size=(0, 0),
text=real_price,
h_align='center',
v_align='center',
maxwidth=self._width * 0.9,
scale=1.4,
color=(0.2, 1, 0.2),
)
# Total-value if they supplied it.
total_worth_item = offer.get('valueItem', None)
if total_worth_item is not None:
price = plus.get_price(total_worth_item)
total_worth_price = (
store.get_clean_price(price) if price is not None else None
)
if total_worth_price is not None:
total_worth_text = bui.Lstr(
resource='store.totalWorthText',
subs=[('${TOTAL_WORTH}', total_worth_price)],
)
self._total_worth_text = bui.textwidget(
parent=self._root_widget,
text=total_worth_text,
position=(self._width * 0.5, 210),
scale=0.9,
maxwidth=self._width * 0.7,
size=(0, 0),
h_align='center',
v_align='center',
shadow=1.0,
flatness=1.0,
color=(0.3, 1, 1),
)
elif offer['item'] == 'pro_fullprice':
# for full-price pro we simply show full price
bui.textwidget(edit=display['price_widget'], text=real_price)
bui.buttonwidget(
edit=display['button'], on_activate_call=self._purchase
)
else:
# Show old/new prices otherwise (for pro sale).
bui.buttonwidget(
edit=display['button'], on_activate_call=self._purchase
)
bui.imagewidget(edit=display['price_slash_widget'], opacity=1.0)
bui.textwidget(
edit=display['price_widget_left'], text=original_price_str
)
bui.textwidget(
edit=display['price_widget_right'], text=new_price_str
)
# Add ticket button only if this is ticket-purchasable.
# if isinstance(offer.get('price'), int):
# self._get_tickets_button = bui.buttonwidget(
# parent=self._root_widget,
# position=(self._width - 125, self._height - 68),
# size=(90, 55),
# scale=1.0,
# button_type='square',
# color=(0.7, 0.5, 0.85),
# textcolor=(0.2, 1, 0.2),
# autoselect=True,
# label=bui.Lstr(resource='getTicketsWindow.titleText'),
# on_activate_call=self._on_get_more_tickets_press,
# )
# self._ticket_text_update_timer = bui.AppTimer(
# 1.0, bui.WeakCall(self._update_tickets_text), repeat=True
# )
# self._update_tickets_text()
self._update_timer = bui.AppTimer(
1.0, bui.WeakCall(self._update), repeat=True
)
self._cancel_button = bui.buttonwidget(
parent=self._root_widget,
position=(
(50, 40)
if self._is_bundle_sale
else (self._width * 0.5 - 75, 40)
),
size=(150, 60),
scale=1.0,
on_activate_call=self._cancel,
autoselect=True,
label=bui.Lstr(resource='noThanksText'),
)
self._cancel_countdown_text = bui.textwidget(
parent=self._root_widget,
text='',
position=(
(50 + 150 + 20, 40 + 27)
if self._is_bundle_sale
else (self._width * 0.5 - 75 + 150 + 20, 40 + 27)
),
scale=1.1,
size=(0, 0),
h_align='left',
v_align='center',
shadow=1.0,
flatness=1.0,
color=(0.6, 0.5, 0.5),
)
self._update_cancel_button_graphics()
if self._is_bundle_sale:
self._purchase_button = bui.buttonwidget(
parent=self._root_widget,
position=(self._width - 200, 40),
size=(150, 60),
scale=1.0,
on_activate_call=self._purchase,
autoselect=True,
label=bui.Lstr(resource='store.purchaseText'),
)
bui.containerwidget(
edit=self._root_widget,
cancel_button=self._cancel_button,
start_button=(
self._purchase_button if self._is_bundle_sale else None
),
selected_child=(
self._purchase_button
if self._is_bundle_sale
else display['button']
),
)
def _stop_flashing(self) -> None:
self._flashing_timer = None
bui.textwidget(edit=self._title_text, color=(0.3, 1, 0.3))
def _flash_cycle(self) -> None:
if not self._root_widget:
return
self._flash_on = not self._flash_on
bui.textwidget(
edit=self._title_text,
color=(0.3, 1, 0.3) if self._flash_on else (1, 0.5, 0),
)
def _update_cancel_button_graphics(self) -> None:
bui.buttonwidget(
edit=self._cancel_button,
color=(
(0.5, 0.5, 0.5) if self._cancel_delay > 0 else (0.7, 0.4, 0.34)
),
textcolor=(
(0.5, 0.5, 0.5) if self._cancel_delay > 0 else (0.9, 0.9, 1.0)
),
)
bui.textwidget(
edit=self._cancel_countdown_text,
text=str(self._cancel_delay) if self._cancel_delay > 0 else '',
)
def _update(self) -> None:
plus = bui.app.plus
assert plus is not None
# If we've got seconds left on our countdown, update it.
if self._cancel_delay > 0:
self._cancel_delay = max(0, self._cancel_delay - 1)
self._update_cancel_button_graphics()
can_die = False
# We go away if we see that our target item is owned.
if self._offer_item == 'pro':
assert bui.app.classic is not None
if bui.app.classic.accounts.have_pro():
can_die = True
else:
if plus.get_purchased(self._offer_item):
can_die = True
if can_die:
self._transition_out('out_left')
def _transition_out(self, transition: str = 'out_left') -> None:
# Also clear any pending-special-offer we've stored at this point.
cfg = bui.app.config
if 'pendingSpecialOffer' in cfg:
del cfg['pendingSpecialOffer']
cfg.commit()
bui.containerwidget(edit=self._root_widget, transition=transition)
# def _update_tickets_text(self) -> None:
# from babase import SpecialChar
# plus = bui.app.plus
# assert plus is not None
# if not self._root_widget:
# return
# sval: str | bui.Lstr
# if plus.get_v1_account_state() == 'signed_in':
# sval = bui.charstr(SpecialChar.TICKET) + str(
# plus.get_v1_account_ticket_count()
# )
# else:
# sval = bui.Lstr(resource='getTicketsWindow.titleText')
# bui.buttonwidget(edit=self._get_tickets_button, label=sval)
# def _on_get_more_tickets_press(self) -> None:
# from bauiv1lib import account
# from bauiv1lib import gettickets
# plus = bui.app.plus
# assert plus is not None
# if plus.get_v1_account_state() != 'signed_in':
# account.show_sign_in_prompt()
# return
# gettickets.GetTicketsWindow(modal=True).get_root_widget()
def _purchase(self) -> None:
# from bauiv1lib import gettickets
from bauiv1lib import confirm
plus = bui.app.plus
assert plus is not None
assert bui.app.classic is not None
store = bui.app.classic.store
if self._offer['item'] == 'pro':
plus.purchase('pro_sale')
elif self._offer['item'] == 'pro_fullprice':
plus.purchase('pro')
elif self._is_bundle_sale:
# With bundle sales, the price is the name of the IAP.
plus.purchase(self._offer['price'])
else:
ticket_count: int | None
try:
ticket_count = plus.get_v1_account_ticket_count()
except Exception:
ticket_count = None
if ticket_count is not None and ticket_count < self._offer['price']:
# gettickets.show_get_tickets_prompt()
bui.getsound('error').play()
return
def do_it() -> None:
assert plus is not None
plus.in_game_purchase(
'offer:' + str(self._offer['id']), self._offer['price']
)
bui.getsound('swish').play()
confirm.ConfirmWindow(
bui.Lstr(
resource='store.purchaseConfirmText',
subs=[
(
'${ITEM}',
store.get_store_item_name_translated(
self._offer['item']
),
)
],
),
width=400,
height=120,
action=do_it,
ok_text=bui.Lstr(
resource='store.purchaseText', fallback_resource='okText'
),
)
def _cancel(self) -> None:
if self._cancel_delay > 0:
bui.getsound('error').play()
return
self._transition_out('out_right')
def show_offer() -> bool:
"""(internal)"""
try:
from bauiv1lib import feedback
plus = bui.app.plus
assert plus is not None
app = bui.app
if app.classic is None:
raise RuntimeError(
'Classic feature-set is required to show offers.'
)
# Space things out a bit so we don't hit the poor user with an
# ad and then an in-game offer.
has_been_long_enough_since_ad = True
if app.classic.ads.last_ad_completion_time is not None and (
bui.apptime() - app.classic.ads.last_ad_completion_time < 30.0
):
has_been_long_enough_since_ad = False
if (
app.classic.special_offer is not None
and has_been_long_enough_since_ad
):
# Special case: for pro offers, store this in our prefs so
# we can re-show it if the user kills us (set phasers to
# 'NAG'!!!).
if app.classic.special_offer.get('item') == 'pro_fullprice':
cfg = app.config
cfg['pendingSpecialOffer'] = {
'a': plus.get_v1_account_public_login_id(),
'o': app.classic.special_offer,
}
cfg.commit()
if app.classic.special_offer['item'] == 'rating':
# Go with a native thing if we've got one.
if bui.native_review_request_supported():
bui.native_review_request()
else:
if app.ui_v1.available:
feedback.ask_for_rating()
else:
if app.ui_v1.available:
SpecialOfferWindow(app.classic.special_offer)
app.classic.special_offer = None
return True
except Exception:
logging.exception('Error showing offer.')
return False

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 = 21976; const int kEngineBuildNumber = 21977;
const char* kEngineVersion = "1.7.37"; const char* kEngineVersion = "1.7.37";
const int kEngineApiVersion = 9; const int kEngineApiVersion = 9;