mirror of
https://github.com/RYDE-WORK/ballistica.git
synced 2026-01-27 17:33:13 +08:00
removed pro and bundle nag screens
This commit is contained in:
parent
64c6613c23
commit
5b778890cf
56
.efrocachemap
generated
56
.efrocachemap
generated
@ -4096,26 +4096,26 @@
|
||||
"build/assets/windows/Win32/ucrtbased.dll": "2def5335207d41b21b9823f6805997f1",
|
||||
"build/assets/windows/Win32/vc_redist.x86.exe": "b08a55e2e77623fe657bea24f223a3ae",
|
||||
"build/assets/windows/Win32/vcruntime140d.dll": "865b2af4d1e26a1a8073c89acb06e599",
|
||||
"build/prefab/full/linux_arm64_gui/debug/ballisticakit": "512c99d6d32d3f7ca27de9d00b3f6bee",
|
||||
"build/prefab/full/linux_arm64_gui/release/ballisticakit": "407a6d564f35c7db571702ef6996adc1",
|
||||
"build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "03c278694182a2a7cd6e39d7cf0cdde8",
|
||||
"build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "8c0f3132135f6a392b31dccce44ecc72",
|
||||
"build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "399783ec75c825a7c0ceffb6b66546a6",
|
||||
"build/prefab/full/linux_x86_64_gui/release/ballisticakit": "7d5f43f891ddbc0e68e1e4b924717941",
|
||||
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "97b462045118ca81436452c19e50ead3",
|
||||
"build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "daedf2d4f2c7012f9f1146ef5e675a51",
|
||||
"build/prefab/full/mac_arm64_gui/debug/ballisticakit": "ef571b31a6175b391c70cde46587afc6",
|
||||
"build/prefab/full/mac_arm64_gui/release/ballisticakit": "fcbe9cb15740f5569d32daaef838bae3",
|
||||
"build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "06d8ed9ca06ed1fb12437708b117621f",
|
||||
"build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "eff858f25a173f090731401c42fcfad7",
|
||||
"build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "21401c4a1bb13c6a50fbcc2413a34bc6",
|
||||
"build/prefab/full/mac_x86_64_gui/release/ballisticakit": "a5f6bf1f1a675a60b43674cbe06ee740",
|
||||
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "4965d74db093926f890d37a2d2bcb0cf",
|
||||
"build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "527d364caa4c68cb3a5e70575a834333",
|
||||
"build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "f3e69ff8d4928b52fb301c911d6e01cb",
|
||||
"build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "82dd100621de502523d9feca94de7fc5",
|
||||
"build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "6c66e68c95330200d339ec5a44706491",
|
||||
"build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "f6903fb7071440ee807963cf34fd220f",
|
||||
"build/prefab/full/linux_arm64_gui/debug/ballisticakit": "d6246c930e7e2d2d9a6aff6788f33b69",
|
||||
"build/prefab/full/linux_arm64_gui/release/ballisticakit": "001c67c4d4d33e20755399e0b2ed1593",
|
||||
"build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "6f6bfaf19daf6e866f4fecbc889b8854",
|
||||
"build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "ebc7449903d7868c631c504aed10f371",
|
||||
"build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "91f03e7dbfc0d7eb75568704f681fba5",
|
||||
"build/prefab/full/linux_x86_64_gui/release/ballisticakit": "0b32b6eb05df0a7e23e55ff2e7235a8f",
|
||||
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "4ed4b63cc506815f759412a295bfe088",
|
||||
"build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "1890731fb8a2fb43c4cde72af9d7a4e6",
|
||||
"build/prefab/full/mac_arm64_gui/debug/ballisticakit": "1a4764a504dcb20591ac3472c48db8d9",
|
||||
"build/prefab/full/mac_arm64_gui/release/ballisticakit": "9bfd6234aac4ffd7d7601a40017a73be",
|
||||
"build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "941f8fb79d54522ca5df97a735c3babe",
|
||||
"build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "290a3d9840efc5e88532e13b76b3ae6b",
|
||||
"build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "621a6684b54b0a9101f808209bcca1ee",
|
||||
"build/prefab/full/mac_x86_64_gui/release/ballisticakit": "43c8b0b29e5fb257e4cde0f7fce1c680",
|
||||
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "9a30c6b88ffc11bdf6765780616d8ba1",
|
||||
"build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "8a8f63850fc296b060a994f4e001d74f",
|
||||
"build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "2864e9ae1d2d566def85f1cdf6e863fe",
|
||||
"build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "dc0db7ca99661a896634fc05187a5c75",
|
||||
"build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "f56bb0fafe0a45cecdcd06a10a6924c9",
|
||||
"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/release/libballisticaplus.a": "fa659b5d6119acba6570c92ce4d35ae2",
|
||||
"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_server/debug/libballisticaplus.a": "1659535e95e3047fda529543e265ac97",
|
||||
"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.pdb": "5e45916a6cfb40a5667c691e507ea81d",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "419fba17d012361c3ca8174c44dffdb2",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "d895b4afb3bb74dd1c94595a126a2c24",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "56a67ab9520c07bc4be68162e78534b3",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "40f942e6da490173c0e17fdf23e786e8",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "3242b64140d0b0d6f7af09825d9489e0",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "5d41c8b29dc4e585b878c100e01e8af4",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "6b6aae30362b1e9aaf3f1a8daae0b0b4",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "25db08ee2b4c79ca631e517b622c741d",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "2ea419644782c4c52d1fa784d0ced86d",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "c40627a46ee127997153df041e47eda5",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "fff81b29e2d86031ec25c4a672a243e7",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "2a87e2f53c658d0be3918476cd8a04ee",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "1e91536979b318b9a8325ab0e871ecec",
|
||||
"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/enums.py": "cb299985623bbcc86015cb103a424ae6",
|
||||
"src/ballistica/base/mgen/pyembed/binding_base.inc": "efa61468cf098f77cc6a234461d8b86d",
|
||||
|
||||
@ -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
|
||||
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.
|
||||
@ -8,6 +8,7 @@
|
||||
- Soundtrack customization no longer requires pro.
|
||||
- Campaign hard mode 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
|
||||
several years. This includes a number of handy things such as consistent
|
||||
buttons and widgets for league status, currencies, inventory, and the store.
|
||||
|
||||
@ -399,7 +399,6 @@
|
||||
"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__/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__/teamnamescolors.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/entrytypeselect.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/__pycache__/__init__.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/bauiv1lib/store/__pycache__/browser.cpython-312.opt-1.pyc",
|
||||
|
||||
@ -425,7 +425,6 @@ SCRIPT_TARGETS_PY_PUBLIC = \
|
||||
$(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/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/browser.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__/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/__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__/browser.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/store/__pycache__/button.cpython-312.opt-1.pyc \
|
||||
|
||||
@ -216,24 +216,6 @@ class ClassicAppSubsystem(babase.AppSubsystem):
|
||||
cfg['launchCount'] = launch_count
|
||||
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
|
||||
# master-server and/or get rid of it.
|
||||
babase.handle_leftover_v1_cloud_log_file()
|
||||
@ -832,7 +814,7 @@ class ClassicAppSubsystem(babase.AppSubsystem):
|
||||
app = bauiv1.app
|
||||
env = app.env
|
||||
with bascenev1.ContextRef.empty():
|
||||
from bauiv1lib import specialoffer
|
||||
# from bauiv1lib import specialoffer
|
||||
|
||||
assert app.classic is not None
|
||||
if app.env.headless:
|
||||
@ -927,11 +909,11 @@ class ClassicAppSubsystem(babase.AppSubsystem):
|
||||
# (we may not have heard back from the server)
|
||||
# ..if that doesn't work they'll just have to wait
|
||||
# until the next opportunity.
|
||||
if not specialoffer.show_offer():
|
||||
# if not specialoffer.show_offer():
|
||||
|
||||
def try_again() -> None:
|
||||
if not specialoffer.show_offer():
|
||||
# Try one last time..
|
||||
bauiv1.apptimer(2.0, specialoffer.show_offer)
|
||||
# def try_again() -> None:
|
||||
# if not specialoffer.show_offer():
|
||||
# # Try one last time..
|
||||
# bauiv1.apptimer(2.0, specialoffer.show_offer)
|
||||
|
||||
bauiv1.apptimer(2.0, try_again)
|
||||
# bauiv1.apptimer(2.0, try_again)
|
||||
|
||||
@ -52,7 +52,7 @@ if TYPE_CHECKING:
|
||||
|
||||
# Build number and version of the ballistica binary we expect to be
|
||||
# using.
|
||||
TARGET_BALLISTICA_BUILD = 21976
|
||||
TARGET_BALLISTICA_BUILD = 21977
|
||||
TARGET_BALLISTICA_VERSION = '1.7.37'
|
||||
|
||||
|
||||
|
||||
@ -207,20 +207,22 @@ class CoopScoreScreen(bs.Activity[bs.Player, bs.Team]):
|
||||
)
|
||||
|
||||
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')
|
||||
with self.context:
|
||||
bs.timer(0.1, bs.Call(bs.WeakCall(self.session.end)))
|
||||
|
||||
def _ui_restart(self) -> None:
|
||||
from bauiv1lib.tournamententry import TournamentEntryWindow
|
||||
from bauiv1lib import specialoffer
|
||||
|
||||
if specialoffer.show_offer():
|
||||
return
|
||||
# from bauiv1lib import specialoffer
|
||||
|
||||
# if specialoffer.show_offer():
|
||||
# return
|
||||
|
||||
# If we're in a tournament and it looks like there's no time left,
|
||||
# disallow.
|
||||
@ -268,10 +270,10 @@ class CoopScoreScreen(bs.Activity[bs.Player, bs.Team]):
|
||||
self.end({'outcome': 'restart'})
|
||||
|
||||
def _ui_next(self) -> None:
|
||||
from bauiv1lib.specialoffer import show_offer
|
||||
# from bauiv1lib.specialoffer import show_offer
|
||||
|
||||
if show_offer():
|
||||
return
|
||||
# if show_offer():
|
||||
# return
|
||||
|
||||
# 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).
|
||||
|
||||
@ -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
|
||||
@ -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 = 21976;
|
||||
const int kEngineBuildNumber = 21977;
|
||||
const char* kEngineVersion = "1.7.37";
|
||||
const int kEngineApiVersion = 9;
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user