mirror of
https://github.com/RYDE-WORK/ballistica.git
synced 2026-01-19 13:25:31 +08:00
better tourney results inbox messages
This commit is contained in:
parent
206e3d7f4b
commit
9de17896d1
94
.efrocachemap
generated
94
.efrocachemap
generated
@ -432,43 +432,43 @@
|
||||
"build/assets/ba_data/audio/zoeOw.ogg": "b2d705c31c9dcc1efdc71394764c3beb",
|
||||
"build/assets/ba_data/audio/zoePickup01.ogg": "e9366dc2d2b8ab8b0c4e2c14c02d0789",
|
||||
"build/assets/ba_data/audio/zoeScream01.ogg": "903e0e45ee9b3373e9d9ce20c814374e",
|
||||
"build/assets/ba_data/data/langdata.json": "dbbd8f26d2f85c0b649d461e991b80cb",
|
||||
"build/assets/ba_data/data/languages/arabic.json": "3c22e7b6d7b09a812a2e28b35c9e9241",
|
||||
"build/assets/ba_data/data/langdata.json": "4c8242df36a1b589035beb4711cbf772",
|
||||
"build/assets/ba_data/data/languages/arabic.json": "397dfd469ef7c744cbb472cd19b73f1f",
|
||||
"build/assets/ba_data/data/languages/belarussian.json": "0b60a9d4496d1213c2d0b647d346ce30",
|
||||
"build/assets/ba_data/data/languages/chinese.json": "fc45d2838b834889c06920ae7c2102fa",
|
||||
"build/assets/ba_data/data/languages/chinesetraditional.json": "904b35b656c53f9830e406565edd5120",
|
||||
"build/assets/ba_data/data/languages/chinese.json": "168b529f2d55d714886be57f162f6842",
|
||||
"build/assets/ba_data/data/languages/chinesetraditional.json": "32f53581b80ce723edbe8aa7956e6727",
|
||||
"build/assets/ba_data/data/languages/croatian.json": "e131a87cf5783e0fbb3d211a927efe1a",
|
||||
"build/assets/ba_data/data/languages/czech.json": "d18b7d1c6bf51fc81af4084ef0e69e3e",
|
||||
"build/assets/ba_data/data/languages/czech.json": "3418bee44e69be13b7f72996abe96921",
|
||||
"build/assets/ba_data/data/languages/danish.json": "8e57db30c5250df2abff14a822f83ea7",
|
||||
"build/assets/ba_data/data/languages/dutch.json": "4085dec5af362cf068b494524ced3872",
|
||||
"build/assets/ba_data/data/languages/dutch.json": "4ba5bbcc0fecddd0aac6ee2c165d1e40",
|
||||
"build/assets/ba_data/data/languages/english.json": "527d106870b0690cc39a80b88e60ab7a",
|
||||
"build/assets/ba_data/data/languages/esperanto.json": "0e397cfa5f3fb8cef5f4a64f21cda880",
|
||||
"build/assets/ba_data/data/languages/filipino.json": "3d9269a90a2fee164d0a7513c4f130a3",
|
||||
"build/assets/ba_data/data/languages/filipino.json": "1894fc331dcad7ce9cf4c180843f548f",
|
||||
"build/assets/ba_data/data/languages/french.json": "6d20655730b1017ef187fd828b91d43c",
|
||||
"build/assets/ba_data/data/languages/german.json": "b92ec951b5a0ce4f73677051ca59a06b",
|
||||
"build/assets/ba_data/data/languages/german.json": "bc656f1ada467161c23546f48d0dacc5",
|
||||
"build/assets/ba_data/data/languages/gibberish.json": "2569fe1b2f686670f825e2faaa8c5dc3",
|
||||
"build/assets/ba_data/data/languages/greek.json": "d28d1092fbb00ed857cbd53124c0dc78",
|
||||
"build/assets/ba_data/data/languages/hindi.json": "567e6976b3c72f891431ad7fcc62ab16",
|
||||
"build/assets/ba_data/data/languages/hungarian.json": "9d88004a98f0fbe2ea72edd5e0b3002e",
|
||||
"build/assets/ba_data/data/languages/hungarian.json": "af801baffb2c06460635dfb04c34bb3e",
|
||||
"build/assets/ba_data/data/languages/indonesian.json": "607ba358179185f032096ea1978e4448",
|
||||
"build/assets/ba_data/data/languages/italian.json": "eabad2faba952c426876bc07e1490d09",
|
||||
"build/assets/ba_data/data/languages/korean.json": "4e3524327a0174250aff5e1ef4c0c597",
|
||||
"build/assets/ba_data/data/languages/italian.json": "254d4d3962fda17fe127636fa6221851",
|
||||
"build/assets/ba_data/data/languages/korean.json": "360760d72832863e1a3451b0a514cb08",
|
||||
"build/assets/ba_data/data/languages/malay.json": "0212e18e54efa202c17505376e5b82fb",
|
||||
"build/assets/ba_data/data/languages/persian.json": "859a60de6226fdf9fc24b68b7f6782b6",
|
||||
"build/assets/ba_data/data/languages/piratespeak.json": "7c7e3b72b87c1bcd5b04c9f64d912f0c",
|
||||
"build/assets/ba_data/data/languages/polish.json": "941eb816c7db9e04d6a3b8f28a64e2e8",
|
||||
"build/assets/ba_data/data/languages/portuguese.json": "b4463a05d65515f6812e1177c60ac666",
|
||||
"build/assets/ba_data/data/languages/romanian.json": "5ae206fe0b71c4015b02b86da8931c8f",
|
||||
"build/assets/ba_data/data/languages/russian.json": "fc64ed6b6356ea11385ee5c20748425a",
|
||||
"build/assets/ba_data/data/languages/persian.json": "517217e679c768fff4ffec7f8000ab77",
|
||||
"build/assets/ba_data/data/languages/piratespeak.json": "be23decfaf220b3aa3de3cf35e59b420",
|
||||
"build/assets/ba_data/data/languages/polish.json": "993b612c5854fc42a78726ed09c65251",
|
||||
"build/assets/ba_data/data/languages/portuguese.json": "f034d8099298b56792d4e0e41c5c34a0",
|
||||
"build/assets/ba_data/data/languages/romanian.json": "b04345d8c7631d657a69c73eb7be755a",
|
||||
"build/assets/ba_data/data/languages/russian.json": "eca8fe1ef8343aee559e49c49805b850",
|
||||
"build/assets/ba_data/data/languages/serbian.json": "623fa4129a1154c2f32ed7867e56ff6a",
|
||||
"build/assets/ba_data/data/languages/slovak.json": "c11c29708b3742cdc2a92b4fa0d6d29f",
|
||||
"build/assets/ba_data/data/languages/spanish.json": "f8ab976d219e579546bb98b6d7fd12ce",
|
||||
"build/assets/ba_data/data/languages/swedish.json": "3b179e7333183c70adb0811246b09959",
|
||||
"build/assets/ba_data/data/languages/tamil.json": "ead39b864228696a9b0d19344bc4b5ec",
|
||||
"build/assets/ba_data/data/languages/thai.json": "383540a1e9c7c131ac579f51afc87471",
|
||||
"build/assets/ba_data/data/languages/turkish.json": "ccec3224e41bee03f798d9c1a7d23342",
|
||||
"build/assets/ba_data/data/languages/turkish.json": "1415bdb746551f0a24f0e675304dfe07",
|
||||
"build/assets/ba_data/data/languages/ukrainian.json": "6063d27c9d6ed013b2b64ff452433621",
|
||||
"build/assets/ba_data/data/languages/venetian.json": "abebcc38ca2655578e65428cc0dd3c45",
|
||||
"build/assets/ba_data/data/languages/venetian.json": "e0666c6a1db1792d895fcb250e59861b",
|
||||
"build/assets/ba_data/data/languages/vietnamese.json": "59f6686890ceac2b0ac92597751a18ca",
|
||||
"build/assets/ba_data/data/maps/big_g.json": "1dd301d490643088a435ce75df971054",
|
||||
"build/assets/ba_data/data/maps/bridgit.json": "6aea74805f4880cc11237c5734a24422",
|
||||
@ -1333,10 +1333,10 @@
|
||||
"build/assets/ba_data/textures/buttonSquare.dds": "48e117e4a57a1d99ebf0e38dd414a95b",
|
||||
"build/assets/ba_data/textures/buttonSquare.ktx": "936f04a43f99f692071c7e9567cc2a3d",
|
||||
"build/assets/ba_data/textures/buttonSquare.pvr": "b53fe9f1725e0d28bc974f6ef1623fb0",
|
||||
"build/assets/ba_data/textures/buttonSquareWide.dds": "5ab9ff791eae959d49f7ac1018f395a9",
|
||||
"build/assets/ba_data/textures/buttonSquareWide.ktx": "043bbadbe5adff0236d2841fcaeadb87",
|
||||
"build/assets/ba_data/textures/buttonSquareWide.pvr": "ca3773bfeacc8dcf42387a6da6ef0807",
|
||||
"build/assets/ba_data/textures/buttonSquareWide_preview.png": "a5a02ed8a9a0b4d0043fcf21fc0f5f8a",
|
||||
"build/assets/ba_data/textures/buttonSquareWide.dds": "879ecc705072338a427f25fdbf759792",
|
||||
"build/assets/ba_data/textures/buttonSquareWide.ktx": "98e3b5d628823ffac2add60aa63c0274",
|
||||
"build/assets/ba_data/textures/buttonSquareWide.pvr": "f5ea38658215153ef97bba12ce113923",
|
||||
"build/assets/ba_data/textures/buttonSquareWide_preview.png": "543a1f28b538ada0f63c998f2c75e518",
|
||||
"build/assets/ba_data/textures/buttonSquare_preview.png": "a9abe7bbf392caf8141adf81fc63f4f8",
|
||||
"build/assets/ba_data/textures/chTitleChar1.dds": "d8c615a51d900da15b8aba5ce35296bf",
|
||||
"build/assets/ba_data/textures/chTitleChar1.ktx": "44384ea28c9fe01440deb1fc80c7224a",
|
||||
@ -4126,22 +4126,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": "d0d676371cecc9fff81f2b23fa6e7275",
|
||||
"build/prefab/full/linux_arm64_gui/release/ballisticakit": "1a8c30616d66c2ab31879d44c355a436",
|
||||
"build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "b7e5a81d1170d4e932d06c48e4500fe6",
|
||||
"build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "e28fcdb70262585d0b3ae62f75d8e487",
|
||||
"build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "714db737373c55db0126046e3a5998cf",
|
||||
"build/prefab/full/linux_x86_64_gui/release/ballisticakit": "eb601b6b70a673fa8b5f67e766bf2a5e",
|
||||
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "618d617773fce1dc2cc0a7dcc48722e2",
|
||||
"build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "3a95038a0d6ec21e53585613d5736f64",
|
||||
"build/prefab/full/mac_arm64_gui/debug/ballisticakit": "5b3e194acd4d65030362258c19c5c378",
|
||||
"build/prefab/full/mac_arm64_gui/release/ballisticakit": "5d8bcc750c247f14fe44bd0a8c432e36",
|
||||
"build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "c31c365f0353760437328dc05badf43a",
|
||||
"build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "9dbcec2283230c23e21e7a607153d322",
|
||||
"build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "25b1790251a2190bbb8b036cf764b11f",
|
||||
"build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "4d08c824bff1dccf9b9fe5f5af011023",
|
||||
"build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "2b93477aa54b233ce0e65805eac1c160",
|
||||
"build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "321b48eeb777a3955b3afd250e99c4c5",
|
||||
"build/prefab/full/linux_arm64_gui/debug/ballisticakit": "1ffc1f5dcda65363be124baa30006ccd",
|
||||
"build/prefab/full/linux_arm64_gui/release/ballisticakit": "4cc5de1993654275f1d5156af47581a1",
|
||||
"build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "15fd8eb2457aa3a925f723ef657f384c",
|
||||
"build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "1c4bb442f9a71ee616a85ff404ee4a1d",
|
||||
"build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "6c50ad81231ef51d23c09033babfef16",
|
||||
"build/prefab/full/linux_x86_64_gui/release/ballisticakit": "abbd6b5cb2708d1b45e748d4383794d4",
|
||||
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "35a616d3ef72a4867a36da69d0b997c7",
|
||||
"build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "c261940da039b1e32eb0137a6e2bdfa8",
|
||||
"build/prefab/full/mac_arm64_gui/debug/ballisticakit": "951b3624f3ea80423f00cae72be2854c",
|
||||
"build/prefab/full/mac_arm64_gui/release/ballisticakit": "5079d46536257fb5d751461fde6eac50",
|
||||
"build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "17113f9727ada85f564042267a861f4b",
|
||||
"build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "822261f0c05dc5de3c68f9d76f8fd969",
|
||||
"build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "e63a924dde0304441f96a8304855754b",
|
||||
"build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "2bf917a51df7eb8f322d7d7cb5523458",
|
||||
"build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "95943c9107f7d3756bcf88a03a1673d1",
|
||||
"build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "194d951ddd839028b2c6efabdf53019f",
|
||||
"build/prefab/lib/linux_arm64_gui/debug/libballisticaplus.a": "1c375e8003442dd3d059bc0baa260e61",
|
||||
"build/prefab/lib/linux_arm64_gui/release/libballisticaplus.a": "40daac4bbc8990d5140f97e792bc4fb1",
|
||||
"build/prefab/lib/linux_arm64_server/debug/libballisticaplus.a": "1c375e8003442dd3d059bc0baa260e61",
|
||||
@ -4154,14 +4154,14 @@
|
||||
"build/prefab/lib/mac_arm64_gui/release/libballisticaplus.a": "36bb6f32ab12e2a46b82155a93b2e527",
|
||||
"build/prefab/lib/mac_arm64_server/debug/libballisticaplus.a": "51884d81e2d7bdeb6b59a72f0247c8e1",
|
||||
"build/prefab/lib/mac_arm64_server/release/libballisticaplus.a": "36bb6f32ab12e2a46b82155a93b2e527",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "b73abcca68eebe3067b6fe13db2d6545",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "ef9b111ceb3bb8566ae0c0d6579c06a3",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "426c27616a8c706e27ea94b308cc4f98",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "a1c5a7fa4b717ec9edf2cd030ff189ef",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "9a4debdbef814405208292bdeb7bee18",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "dc38927a539aa85ce720e085ee28490d",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "1256eedc2b351c1264e55a90f37efca9",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "ae14008d451581c06702334f94b50d4d",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "0cd1427bb99690616b493a59e7d567d9",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "8b472a65a2407291dde5c54bb1c24df1",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "c97c08a508bd57b325cc8817d12af73f",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "082957f5ee4f2e5d50d62384bda60895",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "4d8bf5c5937ed8c6e4f5e775366590cb",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "11909c454caaa9d50f3ed70869964743",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "4a9492a2cfa1d944ea5618eb2ac9cb7b",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "e1aeaf29546c0a357214c68fb2f0399c",
|
||||
"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",
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
### 1.7.37 (build 22184, api 9, 2025-01-13)
|
||||
### 1.7.37 (build 22189, api 9, 2025-01-14)
|
||||
- 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.
|
||||
|
||||
@ -79,6 +79,7 @@
|
||||
"ba_data/python/baclassic/__pycache__/_benchmark.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/baclassic/__pycache__/_chest.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/baclassic/__pycache__/_clienteffect.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/baclassic/__pycache__/_displayitem.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/baclassic/__pycache__/_input.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/baclassic/__pycache__/_music.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/baclassic/__pycache__/_net.cpython-312.opt-1.pyc",
|
||||
@ -97,6 +98,7 @@
|
||||
"ba_data/python/baclassic/_benchmark.py",
|
||||
"ba_data/python/baclassic/_chest.py",
|
||||
"ba_data/python/baclassic/_clienteffect.py",
|
||||
"ba_data/python/baclassic/_displayitem.py",
|
||||
"ba_data/python/baclassic/_input.py",
|
||||
"ba_data/python/baclassic/_music.py",
|
||||
"ba_data/python/baclassic/_net.py",
|
||||
|
||||
@ -208,6 +208,7 @@ SCRIPT_TARGETS_PY_PUBLIC = \
|
||||
$(BUILD_DIR)/ba_data/python/baclassic/_benchmark.py \
|
||||
$(BUILD_DIR)/ba_data/python/baclassic/_chest.py \
|
||||
$(BUILD_DIR)/ba_data/python/baclassic/_clienteffect.py \
|
||||
$(BUILD_DIR)/ba_data/python/baclassic/_displayitem.py \
|
||||
$(BUILD_DIR)/ba_data/python/baclassic/_input.py \
|
||||
$(BUILD_DIR)/ba_data/python/baclassic/_music.py \
|
||||
$(BUILD_DIR)/ba_data/python/baclassic/_net.py \
|
||||
@ -490,6 +491,7 @@ SCRIPT_TARGETS_PYC_PUBLIC = \
|
||||
$(BUILD_DIR)/ba_data/python/baclassic/__pycache__/_benchmark.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/baclassic/__pycache__/_chest.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/baclassic/__pycache__/_clienteffect.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/baclassic/__pycache__/_displayitem.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/baclassic/__pycache__/_input.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/baclassic/__pycache__/_music.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/baclassic/__pycache__/_net.cpython-312.opt-1.pyc \
|
||||
|
||||
@ -41,8 +41,8 @@ def is_browser_likely_available() -> bool:
|
||||
|
||||
category: General Utility Functions
|
||||
|
||||
If this returns False you may want to avoid calling babase.show_url()
|
||||
with any lengthy addresses. (ba.show_url() will display an address
|
||||
If this returns False you may want to avoid calling babase.open_url()
|
||||
with any lengthy addresses. (babase.open_url() will display an address
|
||||
as a string in a window if unable to bring up a browser, but that
|
||||
is only useful for simple URLs.)
|
||||
"""
|
||||
|
||||
@ -176,6 +176,7 @@ class _WeakCall:
|
||||
'Warning: callable passed to babase.WeakCall() is not'
|
||||
' weak-referencable (%s); use functools.partial instead'
|
||||
' to avoid this warning.',
|
||||
args[0],
|
||||
stack_info=True,
|
||||
)
|
||||
type(self)._did_invalid_call_warning = True
|
||||
|
||||
@ -27,6 +27,7 @@ from baclassic._chest import (
|
||||
CHEST_APPEARANCE_DISPLAY_INFO_DEFAULT,
|
||||
CHEST_APPEARANCE_DISPLAY_INFOS,
|
||||
)
|
||||
from baclassic._displayitem import show_display_item
|
||||
|
||||
__all__ = [
|
||||
'ChestAppearanceDisplayInfo',
|
||||
@ -36,6 +37,7 @@ __all__ = [
|
||||
'ClassicAppSubsystem',
|
||||
'Achievement',
|
||||
'AchievementSubsystem',
|
||||
'show_display_item',
|
||||
]
|
||||
|
||||
# We want stuff here to show up as packagename.Foo instead of
|
||||
|
||||
109
src/assets/ba_data/python/baclassic/_displayitem.py
Normal file
109
src/assets/ba_data/python/baclassic/_displayitem.py
Normal file
@ -0,0 +1,109 @@
|
||||
# Released under the MIT License. See LICENSE for details.
|
||||
#
|
||||
"""Display-item related functionality."""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from efro.util import pairs_from_flat
|
||||
import bacommon.bs
|
||||
import bauiv1
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
pass
|
||||
|
||||
|
||||
def show_display_item(
|
||||
itemwrapper: bacommon.bs.DisplayItemWrapper,
|
||||
parent: bauiv1.Widget,
|
||||
pos: tuple[float, float],
|
||||
width: float,
|
||||
) -> None:
|
||||
"""Create ui to depict a display-item."""
|
||||
|
||||
height = width * 0.666
|
||||
|
||||
# Silent no-op if our parent ui is dead.
|
||||
if not parent:
|
||||
return
|
||||
|
||||
img: str | None = None
|
||||
img_y_offs = 0.0
|
||||
text_y_offs = 0.0
|
||||
show_text = True
|
||||
|
||||
if isinstance(itemwrapper.item, bacommon.bs.TicketsDisplayItem):
|
||||
img = 'tickets'
|
||||
img_y_offs = width * 0.11
|
||||
text_y_offs = width * -0.15
|
||||
elif isinstance(itemwrapper.item, bacommon.bs.TokensDisplayItem):
|
||||
img = 'coin'
|
||||
img_y_offs = width * 0.11
|
||||
text_y_offs = width * -0.15
|
||||
elif isinstance(itemwrapper.item, bacommon.bs.ChestDisplayItem):
|
||||
from baclassic._chest import (
|
||||
CHEST_APPEARANCE_DISPLAY_INFOS,
|
||||
CHEST_APPEARANCE_DISPLAY_INFO_DEFAULT,
|
||||
)
|
||||
|
||||
img = None
|
||||
show_text = False
|
||||
c_info = CHEST_APPEARANCE_DISPLAY_INFOS.get(
|
||||
itemwrapper.item.appearance, CHEST_APPEARANCE_DISPLAY_INFO_DEFAULT
|
||||
)
|
||||
c_size = width * 0.85
|
||||
bauiv1.imagewidget(
|
||||
parent=parent,
|
||||
position=(pos[0] - c_size * 0.5, pos[1] - c_size * 0.5),
|
||||
color=c_info.color,
|
||||
size=(c_size, c_size),
|
||||
texture=bauiv1.gettexture(c_info.texclosed),
|
||||
tint_texture=bauiv1.gettexture(c_info.texclosedtint),
|
||||
tint_color=c_info.tint,
|
||||
tint2_color=c_info.tint2,
|
||||
)
|
||||
|
||||
# Enable this for testing spacing.
|
||||
if bool(False):
|
||||
bauiv1.imagewidget(
|
||||
parent=parent,
|
||||
position=(
|
||||
pos[0] - width * 0.5,
|
||||
pos[1] - height * 0.5,
|
||||
),
|
||||
size=(width, height),
|
||||
texture=bauiv1.gettexture('white'),
|
||||
color=(0, 1, 0),
|
||||
opacity=0.1,
|
||||
)
|
||||
|
||||
imgsize = width * 0.33
|
||||
if img is not None:
|
||||
bauiv1.imagewidget(
|
||||
parent=parent,
|
||||
position=(
|
||||
pos[0] - imgsize * 0.5,
|
||||
pos[1] + img_y_offs - imgsize * 0.5,
|
||||
),
|
||||
size=(imgsize, imgsize),
|
||||
texture=bauiv1.gettexture(img),
|
||||
)
|
||||
if show_text:
|
||||
subs = itemwrapper.description_subs
|
||||
if subs is None:
|
||||
subs = []
|
||||
bauiv1.textwidget(
|
||||
parent=parent,
|
||||
position=(pos[0], pos[1] + text_y_offs),
|
||||
scale=width * 0.006,
|
||||
size=(0, 0),
|
||||
text=bauiv1.Lstr(
|
||||
translate=('serverResponses', itemwrapper.description),
|
||||
subs=pairs_from_flat(subs),
|
||||
),
|
||||
maxwidth=width * 0.9,
|
||||
color=(0.0, 1.0, 0.0),
|
||||
h_align='center',
|
||||
v_align='center',
|
||||
)
|
||||
@ -53,7 +53,7 @@ if TYPE_CHECKING:
|
||||
|
||||
# Build number and version of the ballistica binary we expect to be
|
||||
# using.
|
||||
TARGET_BALLISTICA_BUILD = 22184
|
||||
TARGET_BALLISTICA_BUILD = 22189
|
||||
TARGET_BALLISTICA_VERSION = '1.7.37'
|
||||
|
||||
|
||||
|
||||
@ -88,7 +88,7 @@ class AccountViewerWindow(PopupWindow):
|
||||
scale=0.6,
|
||||
text=bui.Lstr(resource='playerInfoText'),
|
||||
maxwidth=200,
|
||||
color=(0.7, 0.7, 0.7, 0.7),
|
||||
color=bui.app.ui_v1.title_color,
|
||||
)
|
||||
|
||||
self._scrollwidget = bui.scrollwidget(
|
||||
@ -97,6 +97,7 @@ class AccountViewerWindow(PopupWindow):
|
||||
position=(30, 30),
|
||||
capture_arrows=True,
|
||||
simple_culling_v=10,
|
||||
border_opacity=0.4,
|
||||
)
|
||||
bui.widget(edit=self._scrollwidget, autoselect=True)
|
||||
|
||||
|
||||
@ -20,7 +20,7 @@ class AchievementsWindow(bui.MainWindow):
|
||||
# pylint: disable=too-many-locals
|
||||
assert bui.app.classic is not None
|
||||
uiscale = bui.app.ui_v1.uiscale
|
||||
self._width = 600 if uiscale is bui.UIScale.SMALL else 450
|
||||
self._width = 600 if uiscale is bui.UIScale.SMALL else 500
|
||||
self._height = (
|
||||
380
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
@ -102,11 +102,11 @@ class AchievementsWindow(bui.MainWindow):
|
||||
parent=self._root_widget,
|
||||
size=(
|
||||
self._width - 60,
|
||||
self._height - (150 if uiscale is bui.UIScale.SMALL else 70),
|
||||
self._height - (150 if uiscale is bui.UIScale.SMALL else 80),
|
||||
),
|
||||
position=(
|
||||
30,
|
||||
(110 if uiscale is bui.UIScale.SMALL else 30) + yoffs,
|
||||
(110 if uiscale is bui.UIScale.SMALL else 35) + yoffs,
|
||||
),
|
||||
capture_arrows=True,
|
||||
simple_culling_v=10,
|
||||
|
||||
@ -9,6 +9,7 @@ import math
|
||||
import random
|
||||
from typing import override, TYPE_CHECKING
|
||||
|
||||
from efro.util import strict_partial
|
||||
import bacommon.bs
|
||||
import bauiv1 as bui
|
||||
|
||||
@ -29,8 +30,6 @@ class ChestWindow(bui.MainWindow):
|
||||
transition: str | None = 'in_right',
|
||||
origin_widget: bui.Widget | None = None,
|
||||
):
|
||||
# print('ChestWindow()')
|
||||
|
||||
self._index = index
|
||||
|
||||
assert bui.app.classic is not None
|
||||
@ -514,7 +513,6 @@ class ChestWindow(bui.MainWindow):
|
||||
)
|
||||
|
||||
self._show_odds(initial_highlighted_row=-1)
|
||||
# bui.textwidget(edit=self._infotext, text='')
|
||||
|
||||
def _highlight_odds_row(self, row: int, extra: bool = False) -> None:
|
||||
|
||||
@ -702,8 +700,6 @@ class ChestWindow(bui.MainWindow):
|
||||
|
||||
# Convey that something is in progress.
|
||||
if self._open_now_button:
|
||||
# bui.buttonwidget(edit=self._open_now_button,
|
||||
# color=(0.4, 1.0, 0.4))
|
||||
bui.spinnerwidget(edit=self._open_now_spinner, visible=True)
|
||||
for twidget in self._open_now_texts:
|
||||
bui.textwidget(edit=twidget, color=(1, 1, 1, 0.2))
|
||||
@ -788,7 +784,7 @@ class ChestWindow(bui.MainWindow):
|
||||
self._reset()
|
||||
msg = (
|
||||
'This slot can hold a treasure chest.\n\n'
|
||||
'Earn chests by beating campaing levels,\n'
|
||||
'Earn chests by playing campaign levels,\n'
|
||||
'placing in tournaments, and completing\n'
|
||||
'achievements.'
|
||||
)
|
||||
@ -799,12 +795,22 @@ class ChestWindow(bui.MainWindow):
|
||||
) -> None:
|
||||
# pylint: disable=too-many-locals
|
||||
|
||||
from baclassic import show_display_item
|
||||
|
||||
# No-op if our ui is dead.
|
||||
if not self._root_widget:
|
||||
return
|
||||
|
||||
assert response.contents is not None
|
||||
|
||||
# Insert test items for testing.
|
||||
if bool(False):
|
||||
response.contents += [
|
||||
bacommon.bs.DisplayItemWrapper.for_display_item(
|
||||
bacommon.bs.TestDisplayItem()
|
||||
)
|
||||
]
|
||||
|
||||
tincr = 0.4
|
||||
tendoffs = tincr * 4.0
|
||||
toffs = 0.0
|
||||
@ -861,7 +867,7 @@ class ChestWindow(bui.MainWindow):
|
||||
),
|
||||
)
|
||||
|
||||
xspacing = 150
|
||||
xspacing = 100
|
||||
xoffs = -0.5 * (len(response.contents) - 1) * xspacing
|
||||
bui.apptimer(
|
||||
toffs - 0.2, lambda: bui.getsound('corkPop2').play(volume=4.0)
|
||||
@ -898,14 +904,25 @@ class ChestWindow(bui.MainWindow):
|
||||
toffsopen = toffs
|
||||
bui.apptimer(toffs, bui.WeakCall(self._show_chest_opening))
|
||||
toffs += tincr * 1.0
|
||||
width = xspacing * 0.75
|
||||
for obj in response.contents:
|
||||
width = xspacing * 0.95
|
||||
|
||||
for item in response.contents:
|
||||
toffs += tincr
|
||||
bui.apptimer(
|
||||
toffs - 0.1, lambda: bui.getsound('cashRegister').play()
|
||||
)
|
||||
bui.apptimer(
|
||||
toffs, bui.WeakCall(self._show_chest_item, obj, xoffs, width)
|
||||
toffs,
|
||||
strict_partial(
|
||||
show_display_item,
|
||||
item,
|
||||
self._root_widget,
|
||||
pos=(
|
||||
self._width * 0.5 + xoffs,
|
||||
self._height - 250.0 + self._yoffs,
|
||||
),
|
||||
width=width,
|
||||
),
|
||||
)
|
||||
xoffs += xspacing
|
||||
toffs += tincr
|
||||
@ -1003,61 +1020,6 @@ class ChestWindow(bui.MainWindow):
|
||||
initial_highlighted_extra=True,
|
||||
)
|
||||
|
||||
def _show_chest_item(
|
||||
self,
|
||||
itemwrapper: bacommon.bs.DisplayItemWrapper,
|
||||
xoffs: float,
|
||||
width: float,
|
||||
) -> None:
|
||||
# No-op if our ui is dead.
|
||||
if not self._root_widget:
|
||||
return
|
||||
|
||||
img: str | None = None
|
||||
if isinstance(itemwrapper.item, bacommon.bs.TicketsDisplayItem):
|
||||
img = 'tickets'
|
||||
elif isinstance(itemwrapper.item, bacommon.bs.TokensDisplayItem):
|
||||
img = 'coin'
|
||||
|
||||
# Translate the wrapper description and apply any subs.
|
||||
descfin = bui.Lstr(
|
||||
translate=('serverResponses', itemwrapper.description)
|
||||
).evaluate()
|
||||
subs = (
|
||||
[]
|
||||
if itemwrapper.description_subs is None
|
||||
else itemwrapper.description_subs
|
||||
)
|
||||
assert len(subs) % 2 == 0 # Should always be even.
|
||||
for j in range(0, len(subs) - 1, 2):
|
||||
descfin = descfin.replace(subs[j], subs[j + 1])
|
||||
|
||||
imgsize = 34
|
||||
if img is not None:
|
||||
bui.imagewidget(
|
||||
parent=self._root_widget,
|
||||
position=(
|
||||
self._width * 0.5 + xoffs - imgsize * 0.5,
|
||||
self._height - 252 + 14.0 + self._yoffs - imgsize * 0.5,
|
||||
),
|
||||
size=(imgsize, imgsize),
|
||||
texture=bui.gettexture(img),
|
||||
)
|
||||
bui.textwidget(
|
||||
parent=self._root_widget,
|
||||
position=(
|
||||
self._width * 0.5 + xoffs,
|
||||
self._height - 252 - 14.0 + self._yoffs,
|
||||
),
|
||||
scale=0.65,
|
||||
size=(0, 0),
|
||||
text=f'+ {descfin}',
|
||||
maxwidth=width,
|
||||
color=(0.0, 1.0, 0.0),
|
||||
h_align='center',
|
||||
v_align='center',
|
||||
)
|
||||
|
||||
def _show_done_button(self) -> None:
|
||||
# No-op if our ui is dead.
|
||||
if not self._root_widget:
|
||||
|
||||
@ -275,7 +275,7 @@ class CoopBrowserWindow(bui.MainWindow):
|
||||
simple_culling_v=10.0,
|
||||
claims_left_right=True,
|
||||
selection_loops_to_parent=True,
|
||||
border_opacity=0.3 if uiscale is bui.UIScale.SMALL else 1.0,
|
||||
border_opacity=0.4,
|
||||
)
|
||||
|
||||
if uiscale is bui.UIScale.SMALL:
|
||||
|
||||
@ -627,6 +627,10 @@ class TournamentButton:
|
||||
max_players = bui.app.classic.accounts.tournament_info[
|
||||
self.tournament_id
|
||||
]['maxPlayers']
|
||||
|
||||
print('GOT GAME', game)
|
||||
print('GOT ID', self.tournament_id)
|
||||
print('GOT PLAYERS', max_players)
|
||||
txt = bui.Lstr(
|
||||
value='${A} ${B}',
|
||||
subs=[
|
||||
|
||||
@ -1,25 +1,35 @@
|
||||
# Released under the MIT License. See LICENSE for details.
|
||||
#
|
||||
# pylint: disable=too-many-lines
|
||||
"""Provides a popup window to view achievements."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import weakref
|
||||
from functools import partial
|
||||
from dataclasses import dataclass
|
||||
from typing import override, assert_never
|
||||
from typing import override, assert_never, TYPE_CHECKING
|
||||
|
||||
from efro.util import strict_partial, pairs_from_flat
|
||||
from efro.error import CommunicationError
|
||||
import bacommon.bs
|
||||
import bauiv1 as bui
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Callable
|
||||
|
||||
|
||||
class _Section:
|
||||
def get_height(self) -> float:
|
||||
"""Return section height."""
|
||||
raise NotImplementedError()
|
||||
|
||||
def draw(self, subcontainer: bui.Widget, y: float) -> None:
|
||||
"""Draw the section."""
|
||||
def get_button_row(self) -> list[bui.Widget]:
|
||||
"""Return rows of selectable controls."""
|
||||
return []
|
||||
|
||||
def emit(self, subcontainer: bui.Widget, y: float) -> None:
|
||||
"""Emit the section."""
|
||||
|
||||
|
||||
class _TextSection(_Section):
|
||||
@ -27,9 +37,8 @@ class _TextSection(_Section):
|
||||
def __init__(
|
||||
self,
|
||||
sub_width: float,
|
||||
text: str,
|
||||
text: bui.Lstr | str,
|
||||
*,
|
||||
subs: list[str],
|
||||
spacing_top: float = 0.0,
|
||||
spacing_bottom: float = 0.0,
|
||||
scale: float = 0.6,
|
||||
@ -40,23 +49,22 @@ class _TextSection(_Section):
|
||||
self.spacing_bottom = spacing_bottom
|
||||
self.color = color
|
||||
|
||||
self.textfin = bui.Lstr(translate=('serverResponses', text)).evaluate()
|
||||
assert len(subs) % 2 == 0 # Should always be even.
|
||||
for j in range(0, len(subs) - 1, 2):
|
||||
self.textfin = self.textfin.replace(subs[j], subs[j + 1])
|
||||
# We need to bake this down since we plug its final size into
|
||||
# our math.
|
||||
self.textbaked = text.evaluate() if isinstance(text, bui.Lstr) else text
|
||||
|
||||
# Calc scale to fit width and then see what height we need at
|
||||
# that scale.
|
||||
t_width = max(
|
||||
10.0,
|
||||
bui.get_string_width(self.textfin, suppress_warning=True) * scale,
|
||||
bui.get_string_width(self.textbaked, suppress_warning=True) * scale,
|
||||
)
|
||||
self.text_scale = scale * min(1.0, (sub_width * 0.9) / t_width)
|
||||
|
||||
self.text_height = (
|
||||
0.0
|
||||
if not self.textfin
|
||||
else bui.get_string_height(self.textfin, suppress_warning=True)
|
||||
if not self.textbaked
|
||||
else bui.get_string_height(self.textbaked, suppress_warning=True)
|
||||
) * self.text_scale
|
||||
|
||||
self.full_height = self.text_height + spacing_top + spacing_bottom
|
||||
@ -66,25 +74,137 @@ class _TextSection(_Section):
|
||||
return self.full_height
|
||||
|
||||
@override
|
||||
def draw(self, subcontainer: bui.Widget, y: float) -> None:
|
||||
def emit(self, subcontainer: bui.Widget, y: float) -> None:
|
||||
bui.textwidget(
|
||||
parent=subcontainer,
|
||||
position=(
|
||||
self.sub_width * 0.5,
|
||||
y - self.spacing_top - self.text_height * 0.5,
|
||||
# y - self.height * 0.5 - 23.0,
|
||||
),
|
||||
color=self.color,
|
||||
scale=self.text_scale,
|
||||
flatness=1.0,
|
||||
shadow=0.0,
|
||||
text=self.textfin,
|
||||
text=self.textbaked,
|
||||
size=(0, 0),
|
||||
h_align='center',
|
||||
v_align='center',
|
||||
)
|
||||
|
||||
|
||||
class _ButtonSection(_Section):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
sub_width: float,
|
||||
label: bui.Lstr | str,
|
||||
*,
|
||||
color: tuple[float, float, float],
|
||||
label_color: tuple[float, float, float],
|
||||
call: Callable[[_ButtonSection], None],
|
||||
spacing_top: float = 0.0,
|
||||
spacing_bottom: float = 0.0,
|
||||
) -> None:
|
||||
self.sub_width = sub_width
|
||||
self.spacing_top = spacing_top
|
||||
self.spacing_bottom = spacing_bottom
|
||||
self.color = color
|
||||
self.label_color = label_color
|
||||
self.button: bui.Widget | None = None
|
||||
self.call = call
|
||||
self.labelfin = label
|
||||
self.button_width = 130
|
||||
self.button_height = 30
|
||||
self.full_height = self.button_height + spacing_top + spacing_bottom
|
||||
|
||||
@override
|
||||
def get_height(self) -> float:
|
||||
return self.full_height
|
||||
|
||||
@staticmethod
|
||||
def weak_call(section: weakref.ref[_ButtonSection]) -> None:
|
||||
"""Call button section call if section still exists."""
|
||||
section_strong = section()
|
||||
if section_strong is None:
|
||||
return
|
||||
|
||||
section_strong.call(section_strong)
|
||||
|
||||
@override
|
||||
def emit(self, subcontainer: bui.Widget, y: float) -> None:
|
||||
self.button = bui.buttonwidget(
|
||||
parent=subcontainer,
|
||||
position=(
|
||||
self.sub_width * 0.5 - self.button_width * 0.5,
|
||||
y - self.spacing_top - self.button_height,
|
||||
),
|
||||
autoselect=True,
|
||||
label=self.labelfin,
|
||||
textcolor=self.label_color,
|
||||
text_scale=0.55,
|
||||
size=(self.button_width, self.button_height),
|
||||
color=self.color,
|
||||
on_activate_call=strict_partial(self.weak_call, weakref.ref(self)),
|
||||
)
|
||||
bui.widget(edit=self.button, depth_range=(0.1, 1.0))
|
||||
|
||||
@override
|
||||
def get_button_row(self) -> list[bui.Widget]:
|
||||
"""Return rows of selectable controls."""
|
||||
assert self.button is not None
|
||||
return [self.button]
|
||||
|
||||
|
||||
class _DisplayItemsSection(_Section):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
sub_width: float,
|
||||
items: list[bacommon.bs.DisplayItemWrapper],
|
||||
width: float = 100.0,
|
||||
*,
|
||||
spacing_top: float = 0.0,
|
||||
spacing_bottom: float = 0.0,
|
||||
) -> None:
|
||||
self.display_item_width = width
|
||||
|
||||
# FIXME - ask for this somewhere in case it changes.
|
||||
self.display_item_height = self.display_item_width * 0.666
|
||||
self.items = items
|
||||
self.sub_width = sub_width
|
||||
self.spacing_top = spacing_top
|
||||
self.spacing_bottom = spacing_bottom
|
||||
self.full_height = (
|
||||
self.display_item_height + spacing_top + spacing_bottom
|
||||
)
|
||||
|
||||
@override
|
||||
def get_height(self) -> float:
|
||||
return self.full_height
|
||||
|
||||
@override
|
||||
def emit(self, subcontainer: bui.Widget, y: float) -> None:
|
||||
# pylint: disable=cyclic-import
|
||||
from baclassic import show_display_item
|
||||
|
||||
xspacing = 1.1 * self.display_item_width
|
||||
total_width = (
|
||||
0 if not self.items else ((len(self.items) - 1) * xspacing)
|
||||
)
|
||||
x = -0.5 * total_width
|
||||
for item in self.items:
|
||||
show_display_item(
|
||||
item,
|
||||
subcontainer,
|
||||
pos=(
|
||||
self.sub_width * 0.5 + x,
|
||||
y - self.spacing_top - self.display_item_height * 0.5,
|
||||
),
|
||||
width=self.display_item_width,
|
||||
)
|
||||
x += xspacing
|
||||
|
||||
|
||||
@dataclass
|
||||
class _EntryDisplay:
|
||||
interaction_style: bacommon.bs.BasicClientUI.InteractionStyle
|
||||
@ -99,7 +219,6 @@ class _EntryDisplay:
|
||||
button_spinner_positive: bui.Widget | None = None
|
||||
button_negative: bui.Widget | None = None
|
||||
button_spinner_negative: bui.Widget | None = None
|
||||
# message_text: bui.Widget | None = None
|
||||
processing_complete: bool = False
|
||||
|
||||
|
||||
@ -498,7 +617,7 @@ class InboxWindow(bui.MainWindow):
|
||||
button_label_negative: bacommon.bs.BasicClientUI.ButtonLabel
|
||||
|
||||
sections: list[_Section] = []
|
||||
total_height = 90.0
|
||||
total_height = 80.0
|
||||
|
||||
# Display only entries where we recognize all style/label
|
||||
# values and ui component types.
|
||||
@ -514,14 +633,18 @@ class InboxWindow(bui.MainWindow):
|
||||
idcls = bacommon.bs.BasicClientUIComponentTypeID
|
||||
for component in wrapper.ui.components:
|
||||
ctypeid = component.get_type_id()
|
||||
section: _Section
|
||||
|
||||
if ctypeid is idcls.TEXT:
|
||||
assert isinstance(
|
||||
component, bacommon.bs.BasicClientUIComponentText
|
||||
)
|
||||
section = _TextSection(
|
||||
sub_width=sub_width,
|
||||
text=component.text,
|
||||
subs=component.subs,
|
||||
text=bui.Lstr(
|
||||
translate=('serverResponses', component.text),
|
||||
subs=pairs_from_flat(component.subs),
|
||||
),
|
||||
color=component.color,
|
||||
scale=component.scale,
|
||||
spacing_top=component.spacing_top,
|
||||
@ -530,8 +653,209 @@ class InboxWindow(bui.MainWindow):
|
||||
total_height += section.get_height()
|
||||
sections.append(section)
|
||||
|
||||
elif ctypeid is idcls.LINK:
|
||||
assert isinstance(
|
||||
component, bacommon.bs.BasicClientUIComponentLink
|
||||
)
|
||||
|
||||
def _do_open_url(url: str, sec: _ButtonSection) -> None:
|
||||
del sec # Unused.
|
||||
bui.open_url(url)
|
||||
|
||||
section = _ButtonSection(
|
||||
sub_width=sub_width,
|
||||
label=bui.Lstr(
|
||||
translate=('serverResponses', component.label),
|
||||
subs=pairs_from_flat(component.subs),
|
||||
),
|
||||
color=color,
|
||||
call=partial(_do_open_url, component.url),
|
||||
label_color=(0.5, 0.7, 0.6),
|
||||
spacing_top=component.spacing_top,
|
||||
spacing_bottom=component.spacing_bottom,
|
||||
)
|
||||
total_height += section.get_height()
|
||||
sections.append(section)
|
||||
|
||||
elif ctypeid is idcls.DISPLAY_ITEMS:
|
||||
assert isinstance(
|
||||
component,
|
||||
bacommon.bs.BasicClientUIDisplayItems,
|
||||
)
|
||||
section = _DisplayItemsSection(
|
||||
sub_width=sub_width,
|
||||
items=component.items,
|
||||
width=component.width,
|
||||
spacing_top=component.spacing_top,
|
||||
spacing_bottom=component.spacing_bottom,
|
||||
)
|
||||
total_height += section.get_height()
|
||||
sections.append(section)
|
||||
|
||||
elif ctypeid is idcls.BS_CLASSIC_TOURNEY_RESULT:
|
||||
from bascenev1 import get_trophy_string
|
||||
|
||||
assert isinstance(
|
||||
component,
|
||||
bacommon.bs.BasicClientUIBsClassicTourneyResult,
|
||||
)
|
||||
campaignname, levelname = component.game.split(':')
|
||||
assert bui.app.classic is not None
|
||||
campaign = bui.app.classic.getcampaign(campaignname)
|
||||
|
||||
tourney_name = bui.Lstr(
|
||||
value='${A} ${B}',
|
||||
subs=[
|
||||
(
|
||||
'${A}',
|
||||
campaign.getlevel(levelname).displayname,
|
||||
),
|
||||
(
|
||||
'${B}',
|
||||
bui.Lstr(
|
||||
resource='playerCountAbbreviatedText',
|
||||
subs=[
|
||||
('${COUNT}', str(component.players))
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
if component.trophy is not None:
|
||||
trophy_prefix = (
|
||||
get_trophy_string(component.trophy) + ' '
|
||||
)
|
||||
else:
|
||||
trophy_prefix = ''
|
||||
|
||||
section = _TextSection(
|
||||
sub_width=sub_width,
|
||||
# text=bui.Lstr(
|
||||
# translate=(
|
||||
# 'serverResponses',
|
||||
# 'You placed #${RANK}' ' in a tournament!',
|
||||
# # 'You placed in a tournament!',
|
||||
# ),
|
||||
# subs=[('${RANK}', str(component.rank))],
|
||||
# ),
|
||||
text=bui.Lstr(
|
||||
value='${P}${V}',
|
||||
subs=[
|
||||
('${P}', trophy_prefix),
|
||||
(
|
||||
'${V}',
|
||||
bui.Lstr(
|
||||
translate=(
|
||||
'serverResponses',
|
||||
'You placed #${RANK}'
|
||||
' in a tournament!',
|
||||
# 'You placed in a tournament!',
|
||||
),
|
||||
subs=[
|
||||
('${RANK}', str(component.rank))
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
color=(1.0, 1.0, 1.0, 1.0),
|
||||
scale=0.6,
|
||||
)
|
||||
total_height += section.get_height()
|
||||
sections.append(section)
|
||||
|
||||
section = _TextSection(
|
||||
sub_width=sub_width,
|
||||
# text=bui.Lstr(
|
||||
# value='${P}${V}',
|
||||
# subs=[
|
||||
# ('${P}', trophy_prefix),
|
||||
# ('${V}', tourney_name),
|
||||
# ],
|
||||
# ),
|
||||
text=tourney_name,
|
||||
spacing_top=5,
|
||||
color=(0.7, 0.7, 1.0, 1.0),
|
||||
scale=0.7,
|
||||
)
|
||||
total_height += section.get_height()
|
||||
sections.append(section)
|
||||
|
||||
# rank_trophy_str = f'#{component.rank}'
|
||||
# if component.trophy is not None:
|
||||
# rank_trophy_str = get_trophy_string(
|
||||
# component.trophy
|
||||
# )
|
||||
# section = _TextSection(
|
||||
# sub_width=sub_width,
|
||||
# text=rank_trophy_str,
|
||||
# spacing_top=10,
|
||||
# scale=1.0,
|
||||
# )
|
||||
# total_height += section.get_height()
|
||||
# sections.append(section)
|
||||
|
||||
def _do_tourney_scores(
|
||||
tournament_id: str, sec: _ButtonSection
|
||||
) -> None:
|
||||
from bauiv1lib.tournamentscores import (
|
||||
TournamentScoresWindow,
|
||||
)
|
||||
|
||||
assert sec.button is not None
|
||||
_ = (
|
||||
TournamentScoresWindow(
|
||||
tournament_id=tournament_id,
|
||||
position=(
|
||||
sec.button
|
||||
).get_screen_space_center(),
|
||||
),
|
||||
)
|
||||
|
||||
section = _ButtonSection(
|
||||
sub_width=sub_width,
|
||||
label=bui.Lstr(
|
||||
translate=('serverResponses', 'Final Standings')
|
||||
),
|
||||
color=color,
|
||||
call=partial(
|
||||
_do_tourney_scores, component.tournament_id
|
||||
),
|
||||
label_color=(0.5, 0.7, 0.6),
|
||||
spacing_top=7.0,
|
||||
)
|
||||
total_height += section.get_height()
|
||||
sections.append(section)
|
||||
|
||||
section = _TextSection(
|
||||
sub_width=sub_width,
|
||||
text=bui.Lstr(
|
||||
translate=(
|
||||
'serverResponses',
|
||||
'Your prize:',
|
||||
)
|
||||
),
|
||||
spacing_top=6,
|
||||
color=(1.0, 1.0, 1.0, 0.4),
|
||||
scale=0.35,
|
||||
)
|
||||
total_height += section.get_height()
|
||||
sections.append(section)
|
||||
|
||||
section = _DisplayItemsSection(
|
||||
sub_width=sub_width,
|
||||
items=component.prizes,
|
||||
width=70.0,
|
||||
spacing_top=0.0,
|
||||
spacing_bottom=0.0,
|
||||
)
|
||||
total_height += section.get_height()
|
||||
sections.append(section)
|
||||
|
||||
elif ctypeid is idcls.UNKNOWN:
|
||||
raise RuntimeError('Should not get here.')
|
||||
|
||||
else:
|
||||
# Make sure we handle all types.
|
||||
assert_never(ctypeid)
|
||||
@ -550,8 +874,9 @@ class InboxWindow(bui.MainWindow):
|
||||
|
||||
section = _TextSection(
|
||||
sub_width=sub_width,
|
||||
text='You must update the app to view this.',
|
||||
subs=[],
|
||||
text=bui.Lstr(
|
||||
value='You must update the app to view this.'
|
||||
),
|
||||
)
|
||||
total_height += section.get_height()
|
||||
sections.append(section)
|
||||
@ -611,7 +936,11 @@ class InboxWindow(bui.MainWindow):
|
||||
|
||||
# Section contents.
|
||||
for sec in entry_display.sections:
|
||||
sec.draw(subcontainer, ysection)
|
||||
sec.emit(subcontainer, ysection)
|
||||
# Wire up any widgets created by this section.
|
||||
sec_button_row = sec.get_button_row()
|
||||
if sec_button_row:
|
||||
buttonrows.append(sec_button_row)
|
||||
ysection -= sec.get_height()
|
||||
|
||||
buttonrow: list[bui.Widget] = []
|
||||
@ -633,6 +962,7 @@ class InboxWindow(bui.MainWindow):
|
||||
entry_display.button_positive = btn = bui.buttonwidget(
|
||||
parent=subcontainer,
|
||||
position=bpos,
|
||||
autoselect=True,
|
||||
size=(bwidth, bheight),
|
||||
label=bui.app.classic.basic_client_ui_button_label_str(
|
||||
entry_display.button_label_positive
|
||||
@ -663,6 +993,7 @@ class InboxWindow(bui.MainWindow):
|
||||
entry_display.button_negative = btn2 = bui.buttonwidget(
|
||||
parent=subcontainer,
|
||||
position=bpos,
|
||||
autoselect=True,
|
||||
size=(bwidth, bheight),
|
||||
label=bui.app.classic.basic_client_ui_button_label_str(
|
||||
entry_display.button_label_negative
|
||||
@ -712,11 +1043,16 @@ class InboxWindow(bui.MainWindow):
|
||||
bui.widget(
|
||||
edit=button,
|
||||
up_widget=above_widget,
|
||||
down_widget=(
|
||||
button if below_widget is None else below_widget
|
||||
),
|
||||
down_widget=below_widget,
|
||||
# down_widget=(
|
||||
# button if below_widget is None else below_widget
|
||||
# ),
|
||||
right_widget=buttons[max(j - 1, 0)],
|
||||
left_widget=buttons[min(j + 1, len(buttons) - 1)],
|
||||
)
|
||||
|
||||
above_widget = buttons[0]
|
||||
|
||||
|
||||
def _get_bs_classic_tourney_results_sections() -> list[_Section]:
|
||||
return []
|
||||
|
||||
@ -126,6 +126,7 @@ class PlaylistAddGameWindow(bui.MainWindow):
|
||||
position=(x_inset + 61, v - scroll_height),
|
||||
size=(self._scroll_width, scroll_height),
|
||||
highlight=False,
|
||||
border_opacity=0.4,
|
||||
)
|
||||
bui.widget(
|
||||
edit=self._scrollwidget,
|
||||
|
||||
@ -142,9 +142,9 @@ class PlaylistBrowserWindow(bui.MainWindow):
|
||||
size=(self._scroll_width, self._scroll_height),
|
||||
position=(
|
||||
(self._width - self._scroll_width) * 0.5,
|
||||
65 + scroll_offs,
|
||||
65 + scroll_offs + (0 if uiscale is bui.UIScale.SMALL else -5),
|
||||
),
|
||||
border_opacity=0.4 if uiscale is bui.UIScale.SMALL else 1.0,
|
||||
border_opacity=0.4,
|
||||
)
|
||||
bui.containerwidget(edit=self._scrollwidget, claims_left_right=True)
|
||||
self._subcontainer: bui.Widget | None = None
|
||||
|
||||
@ -274,6 +274,7 @@ class PlaylistCustomizeBrowserWindow(bui.MainWindow):
|
||||
position=(140 + x_inset, v - self._scroll_height),
|
||||
size=(self._width - (180 + 2 * x_inset), self._scroll_height + 10),
|
||||
highlight=False,
|
||||
border_opacity=0.4,
|
||||
)
|
||||
if self._back_button is not None:
|
||||
bui.widget(edit=self._back_button, right_widget=scrollwidget)
|
||||
|
||||
@ -232,6 +232,7 @@ class PlaylistEditWindow(bui.MainWindow):
|
||||
highlight=False,
|
||||
on_select_call=bui.Call(self._set_ui_selection, 'gameList'),
|
||||
size=(self._scroll_width, (scroll_height - 15)),
|
||||
border_opacity=0.4,
|
||||
)
|
||||
bui.widget(
|
||||
edit=scrollwidget,
|
||||
|
||||
@ -206,6 +206,7 @@ class PlaylistEditGameWindow(bui.MainWindow):
|
||||
highlight=False,
|
||||
claims_left_right=True,
|
||||
selection_loops_to_parent=True,
|
||||
border_opacity=0.4,
|
||||
)
|
||||
self._subcontainer = bui.containerwidget(
|
||||
parent=self._scrollwidget,
|
||||
|
||||
@ -111,6 +111,7 @@ class PlaylistMapSelectWindow(bui.MainWindow):
|
||||
parent=self._root_widget,
|
||||
position=(40 + x_inset, v - self._scroll_height),
|
||||
size=(self._scroll_width, self._scroll_height),
|
||||
border_opacity=0.4,
|
||||
)
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, selected_child=self._scrollwidget
|
||||
|
||||
@ -30,7 +30,7 @@ class ResourceTypeInfoWindow(PopupWindow):
|
||||
)
|
||||
self._transitioning_out = False
|
||||
self._width = 570
|
||||
self._height = 350
|
||||
self._height = 400
|
||||
bg_color = (0.5, 0.4, 0.6)
|
||||
super().__init__(
|
||||
size=(self._width, self._height),
|
||||
@ -56,6 +56,7 @@ class ResourceTypeInfoWindow(PopupWindow):
|
||||
yoffs = self._height - 145
|
||||
|
||||
if resource_type == 'tickets':
|
||||
yoffs -= 20
|
||||
rdesc = (
|
||||
'Tickets can be used to unlock characters,\n'
|
||||
'maps, minigames, and more in the store.\n'
|
||||
@ -70,8 +71,8 @@ class ResourceTypeInfoWindow(PopupWindow):
|
||||
'and for other game and account features.\n'
|
||||
'\n'
|
||||
'You can win tokens in the game or buy them\n'
|
||||
'in packs. Or buy a Gold Pass to get infinite\n'
|
||||
'tokens forever and never hear of them again.'
|
||||
'in packs. Or buy a Gold Pass for infinite\n'
|
||||
'tokens and never hear about them again.'
|
||||
)
|
||||
texname = 'coin'
|
||||
elif resource_type == 'trophies':
|
||||
|
||||
@ -93,7 +93,7 @@ class AllSettingsWindow(bui.MainWindow):
|
||||
all_buttons_width = 4.0 * bwidth + 3.0 * margin
|
||||
|
||||
x = width * 0.5 - all_buttons_width * 0.5
|
||||
y = height + yoffs - 320.0
|
||||
y = height + yoffs - 335.0
|
||||
|
||||
def _button(
|
||||
position: tuple[float, float],
|
||||
|
||||
@ -146,7 +146,8 @@ class TournamentEntryWindow(PopupWindow):
|
||||
scale=0.6,
|
||||
text=bui.Lstr(resource='tournamentEntryText'),
|
||||
maxwidth=180,
|
||||
color=(1, 1, 1, 0.4),
|
||||
# color=(1, 1, 1, 0.4),
|
||||
color=bui.app.ui_v1.title_color,
|
||||
)
|
||||
|
||||
btn = self._pay_with_tickets_button = bui.buttonwidget(
|
||||
|
||||
@ -22,33 +22,20 @@ class TournamentScoresWindow(PopupWindow):
|
||||
self,
|
||||
tournament_id: str,
|
||||
*,
|
||||
tournament_activity: bs.GameActivity | None = None,
|
||||
position: tuple[float, float] = (0.0, 0.0),
|
||||
scale: float | None = None,
|
||||
offset: tuple[float, float] = (0.0, 0.0),
|
||||
tint_color: Sequence[float] = (1.0, 1.0, 1.0),
|
||||
tint2_color: Sequence[float] = (1.0, 1.0, 1.0),
|
||||
selected_character: str | None = None,
|
||||
on_close_call: Callable[[], Any] | None = None,
|
||||
):
|
||||
plus = bui.app.plus
|
||||
assert plus is not None
|
||||
|
||||
del tournament_activity # unused arg
|
||||
del tint_color # unused arg
|
||||
del tint2_color # unused arg
|
||||
del selected_character # unused arg
|
||||
self._tournament_id = tournament_id
|
||||
self._subcontainer: bui.Widget | None = None
|
||||
self._on_close_call = on_close_call
|
||||
assert bui.app.classic is not None
|
||||
uiscale = bui.app.ui_v1.uiscale
|
||||
if scale is None:
|
||||
scale = (
|
||||
2.3
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 1.65 if uiscale is bui.UIScale.MEDIUM else 1.23
|
||||
)
|
||||
scale = (
|
||||
2.3
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 1.65 if uiscale is bui.UIScale.MEDIUM else 1.23
|
||||
)
|
||||
self._transitioning_out = False
|
||||
|
||||
self._width = 400
|
||||
@ -60,13 +47,12 @@ class TournamentScoresWindow(PopupWindow):
|
||||
|
||||
bg_color = (0.5, 0.4, 0.6)
|
||||
|
||||
# creates our _root_widget
|
||||
# Creates our _root_widget.
|
||||
super().__init__(
|
||||
position=position,
|
||||
size=(self._width, self._height),
|
||||
scale=scale,
|
||||
bg_color=bg_color,
|
||||
offset=offset,
|
||||
)
|
||||
|
||||
self._cancel_button = bui.buttonwidget(
|
||||
@ -91,7 +77,7 @@ class TournamentScoresWindow(PopupWindow):
|
||||
scale=0.6,
|
||||
text=bui.Lstr(resource='tournamentStandingsText'),
|
||||
maxwidth=200,
|
||||
color=(1, 1, 1, 0.4),
|
||||
color=bui.app.ui_v1.title_color,
|
||||
)
|
||||
|
||||
self._scrollwidget = bui.scrollwidget(
|
||||
@ -100,16 +86,18 @@ class TournamentScoresWindow(PopupWindow):
|
||||
position=(30, 30),
|
||||
highlight=False,
|
||||
simple_culling_v=10,
|
||||
border_opacity=0.4,
|
||||
)
|
||||
bui.widget(edit=self._scrollwidget, autoselect=True)
|
||||
|
||||
self._loading_spinner = bui.spinnerwidget(
|
||||
parent=self.root_widget,
|
||||
position=(self._width * 0.5, self._height * 0.5),
|
||||
)
|
||||
self._loading_text = bui.textwidget(
|
||||
parent=self._scrollwidget,
|
||||
scale=0.5,
|
||||
text=bui.Lstr(
|
||||
value='${A}...',
|
||||
subs=[('${A}', bui.Lstr(resource='loadingText'))],
|
||||
),
|
||||
text='',
|
||||
size=(self._width - 60, 100),
|
||||
h_align='center',
|
||||
v_align='center',
|
||||
@ -132,10 +120,12 @@ class TournamentScoresWindow(PopupWindow):
|
||||
self, data: dict[str, Any] | None
|
||||
) -> None:
|
||||
if data is not None:
|
||||
# this used to be the whole payload
|
||||
# This used to be the whole payload.
|
||||
data_t: list[dict[str, Any]] = data['t']
|
||||
# kill our loading text if we've got scores.. otherwise just
|
||||
# replace it with 'no scores yet'
|
||||
|
||||
# Kill our loading text if we've got scores; otherwise just
|
||||
# replace it with 'no scores yet'.
|
||||
bui.spinnerwidget(edit=self._loading_spinner, visible=False)
|
||||
if data_t[0]['scores']:
|
||||
self._loading_text.delete()
|
||||
else:
|
||||
@ -219,7 +209,8 @@ class TournamentScoresWindow(PopupWindow):
|
||||
def _show_player_info(self, entry: Any, textwidget: bui.Widget) -> None:
|
||||
from bauiv1lib.account.viewer import AccountViewerWindow
|
||||
|
||||
# for the moment we only work if a single player-info is present..
|
||||
# For the moment we only work if a single player-info is
|
||||
# present.
|
||||
if len(entry[2]) != 1:
|
||||
bui.getsound('error').play()
|
||||
return
|
||||
@ -238,8 +229,6 @@ class TournamentScoresWindow(PopupWindow):
|
||||
if not self._transitioning_out:
|
||||
self._transitioning_out = True
|
||||
bui.containerwidget(edit=self.root_widget, transition='out_scale')
|
||||
if self._on_close_call is not None:
|
||||
self._on_close_call()
|
||||
|
||||
@override
|
||||
def on_popup_cancel(self) -> None:
|
||||
|
||||
@ -535,7 +535,7 @@ static auto PyGetStringHeight(PyObject* self, PyObject* args, PyObject* keywds)
|
||||
#if BA_DEBUG_BUILD
|
||||
if (g_base->assets->CompileResourceString(s) != s) {
|
||||
BA_LOG_PYTHON_TRACE(
|
||||
"resource-string passed to get_string_height; this should be avoided");
|
||||
"Resource-string passed to get_string_height; this should be avoided.");
|
||||
}
|
||||
#endif
|
||||
assert(g_base->graphics);
|
||||
|
||||
@ -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 = 22184;
|
||||
const int kEngineBuildNumber = 22189;
|
||||
const char* kEngineVersion = "1.7.37";
|
||||
const int kEngineApiVersion = 9;
|
||||
|
||||
|
||||
@ -778,9 +778,10 @@ void HScrollWidget::Draw(base::RenderPass* pass, bool draw_transparent) {
|
||||
if (draw_transparent && IsHierarchySelected()
|
||||
&& g_base->ui->ShouldHighlightWidgets() && highlight_
|
||||
&& border_opacity_ > 0.0f) {
|
||||
float m = 0.8f
|
||||
+ std::abs(sinf(static_cast<float>(current_time_ms) * 0.006467f))
|
||||
* 0.2f * border_opacity_;
|
||||
float m = (0.8f
|
||||
+ std::abs(sinf(static_cast<float>(current_time_ms) * 0.006467f))
|
||||
* 0.2f)
|
||||
* border_opacity_;
|
||||
|
||||
if (glow_dirty_) {
|
||||
float r2 = l + width();
|
||||
|
||||
@ -836,9 +836,10 @@ void ScrollWidget::Draw(base::RenderPass* pass, bool draw_transparent) {
|
||||
// If selected, do glow at depth 0.9 - 1.0.
|
||||
if (draw_transparent && IsHierarchySelected()
|
||||
&& g_base->ui->ShouldHighlightWidgets() && highlight_) {
|
||||
float m = 0.8f
|
||||
+ std::abs(sinf(static_cast<float>(current_time) * 0.006467f))
|
||||
* 0.2f * border_opacity_;
|
||||
float m =
|
||||
(0.8f
|
||||
+ std::abs(sinf(static_cast<float>(current_time) * 0.006467f)) * 0.2f)
|
||||
* border_opacity_;
|
||||
if (glow_dirty_) {
|
||||
float r2 = l + width();
|
||||
float l2 = l;
|
||||
|
||||
@ -9,6 +9,7 @@ from enum import Enum
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Annotated, override, assert_never
|
||||
|
||||
from efro.util import pairs_to_flat
|
||||
from efro.dataclassio import ioprepped, IOAttrs, IOMultiType
|
||||
from efro.message import Message, Response
|
||||
|
||||
@ -102,6 +103,8 @@ class DisplayItemTypeID(Enum):
|
||||
UNKNOWN = 'u'
|
||||
TICKETS = 't'
|
||||
TOKENS = 'k'
|
||||
TEST = 's'
|
||||
CHEST = 'c'
|
||||
|
||||
|
||||
class DisplayItem(IOMultiType[DisplayItemTypeID]):
|
||||
@ -123,19 +126,21 @@ class DisplayItem(IOMultiType[DisplayItemTypeID]):
|
||||
def get_type(cls, type_id: DisplayItemTypeID) -> type[DisplayItem]:
|
||||
"""Return the subclass for each of our type-ids."""
|
||||
# pylint: disable=cyclic-import
|
||||
out: type[DisplayItem]
|
||||
|
||||
t = DisplayItemTypeID
|
||||
if type_id is t.UNKNOWN:
|
||||
out = UnknownDisplayItem
|
||||
elif type_id is t.TICKETS:
|
||||
out = TicketsDisplayItem
|
||||
elif type_id is t.TOKENS:
|
||||
out = TokensDisplayItem
|
||||
else:
|
||||
# Important to make sure we provide all types.
|
||||
assert_never(type_id)
|
||||
return out
|
||||
return UnknownDisplayItem
|
||||
if type_id is t.TICKETS:
|
||||
return TicketsDisplayItem
|
||||
if type_id is t.TOKENS:
|
||||
return TokensDisplayItem
|
||||
if type_id is t.TEST:
|
||||
return TestDisplayItem
|
||||
if type_id is t.CHEST:
|
||||
return ChestDisplayItem
|
||||
|
||||
# Important to make sure we provide all types.
|
||||
assert_never(type_id)
|
||||
|
||||
def get_description(self) -> tuple[str, list[tuple[str, str]]]:
|
||||
"""Return a string description and subs for the item.
|
||||
@ -211,6 +216,38 @@ class TokensDisplayItem(DisplayItem):
|
||||
return '${C} Tokens', [('${C}', str(self.count))]
|
||||
|
||||
|
||||
@ioprepped
|
||||
@dataclass
|
||||
class TestDisplayItem(DisplayItem):
|
||||
"""Fills usable space for a display-item - good for calibration."""
|
||||
|
||||
@override
|
||||
@classmethod
|
||||
def get_type_id(cls) -> DisplayItemTypeID:
|
||||
return DisplayItemTypeID.TEST
|
||||
|
||||
@override
|
||||
def get_description(self) -> tuple[str, list[tuple[str, str]]]:
|
||||
return 'Test Display Item Here', []
|
||||
|
||||
|
||||
@ioprepped
|
||||
@dataclass
|
||||
class ChestDisplayItem(DisplayItem):
|
||||
"""Display a chest."""
|
||||
|
||||
appearance: Annotated[ClassicChestAppearance, IOAttrs('a')]
|
||||
|
||||
@override
|
||||
@classmethod
|
||||
def get_type_id(cls) -> DisplayItemTypeID:
|
||||
return DisplayItemTypeID.CHEST
|
||||
|
||||
@override
|
||||
def get_description(self) -> tuple[str, list[tuple[str, str]]]:
|
||||
return '${TYPE} Chest', [('${TYPE}', self.appearance.name.capitalize())]
|
||||
|
||||
|
||||
@ioprepped
|
||||
@dataclass
|
||||
class DisplayItemWrapper:
|
||||
@ -224,9 +261,7 @@ class DisplayItemWrapper:
|
||||
def for_display_item(cls, item: DisplayItem) -> DisplayItemWrapper:
|
||||
"""Convenience method to wrap a DisplayItem."""
|
||||
desc, subs = item.get_description()
|
||||
# Flatten subs to single list.
|
||||
flat_subs = [item for pair in subs for item in pair]
|
||||
return DisplayItemWrapper(item, desc, flat_subs)
|
||||
return DisplayItemWrapper(item, desc, pairs_to_flat(subs))
|
||||
|
||||
|
||||
@ioprepped
|
||||
@ -263,10 +298,10 @@ class ChestInfoResponse(Response):
|
||||
IOAttrs('a', enum_fallback=ClassicChestAppearance.UNKNOWN),
|
||||
]
|
||||
|
||||
# How much to unlock *now*.
|
||||
# How much it costs to unlock *now*.
|
||||
unlock_tokens: Annotated[int, IOAttrs('tk')]
|
||||
|
||||
# When unlocks on its own.
|
||||
# When it unlocks on its own.
|
||||
unlock_time: Annotated[datetime.datetime, IOAttrs('t')]
|
||||
|
||||
# Possible prizes we contain.
|
||||
@ -396,6 +431,9 @@ class BasicClientUIComponentTypeID(Enum):
|
||||
|
||||
UNKNOWN = 'u'
|
||||
TEXT = 't'
|
||||
LINK = 'l'
|
||||
BS_CLASSIC_TOURNEY_RESULT = 'ct'
|
||||
DISPLAY_ITEMS = 'di'
|
||||
|
||||
|
||||
class BasicClientUIComponent(IOMultiType[BasicClientUIComponentTypeID]):
|
||||
@ -422,8 +460,12 @@ class BasicClientUIComponent(IOMultiType[BasicClientUIComponentTypeID]):
|
||||
return BasicClientUIComponentUnknown
|
||||
if type_id is t.TEXT:
|
||||
return BasicClientUIComponentText
|
||||
# if type_id is t.SCREEN_MESSAGE:
|
||||
# return BasicClientUIComponentScreenMessage
|
||||
if type_id is t.LINK:
|
||||
return BasicClientUIComponentLink
|
||||
if type_id is t.BS_CLASSIC_TOURNEY_RESULT:
|
||||
return BasicClientUIBsClassicTourneyResult
|
||||
if type_id is t.DISPLAY_ITEMS:
|
||||
return BasicClientUIDisplayItems
|
||||
|
||||
# Important to make sure we provide all types.
|
||||
assert_never(type_id)
|
||||
@ -464,12 +506,7 @@ class BasicClientUIComponentText(BasicClientUIComponent):
|
||||
scale: Annotated[float, IOAttrs('sc', store_default=False)] = 1.0
|
||||
color: Annotated[
|
||||
tuple[float, float, float, float], IOAttrs('c', store_default=False)
|
||||
] = (
|
||||
1.0,
|
||||
1.0,
|
||||
1.0,
|
||||
1.0,
|
||||
)
|
||||
] = (1.0, 1.0, 1.0, 1.0)
|
||||
spacing_top: Annotated[float, IOAttrs('st', store_default=False)] = 0.0
|
||||
spacing_bottom: Annotated[float, IOAttrs('sb', store_default=False)] = 0.0
|
||||
|
||||
@ -479,6 +516,59 @@ class BasicClientUIComponentText(BasicClientUIComponent):
|
||||
return BasicClientUIComponentTypeID.TEXT
|
||||
|
||||
|
||||
@ioprepped
|
||||
@dataclass
|
||||
class BasicClientUIComponentLink(BasicClientUIComponent):
|
||||
"""Show a link in the inbox message."""
|
||||
|
||||
url: Annotated[str, IOAttrs('u')]
|
||||
label: Annotated[str, IOAttrs('l')]
|
||||
subs: Annotated[list[str], IOAttrs('s', store_default=False)] = field(
|
||||
default_factory=list
|
||||
)
|
||||
spacing_top: Annotated[float, IOAttrs('st', store_default=False)] = 0.0
|
||||
spacing_bottom: Annotated[float, IOAttrs('sb', store_default=False)] = 0.0
|
||||
|
||||
@override
|
||||
@classmethod
|
||||
def get_type_id(cls) -> BasicClientUIComponentTypeID:
|
||||
return BasicClientUIComponentTypeID.LINK
|
||||
|
||||
|
||||
@ioprepped
|
||||
@dataclass
|
||||
class BasicClientUIBsClassicTourneyResult(BasicClientUIComponent):
|
||||
"""Show info about a classic tourney."""
|
||||
|
||||
tournament_id: Annotated[str, IOAttrs('t')]
|
||||
game: Annotated[str, IOAttrs('g')]
|
||||
players: Annotated[int, IOAttrs('p')]
|
||||
rank: Annotated[int, IOAttrs('r')]
|
||||
trophy: Annotated[str | None, IOAttrs('tr')]
|
||||
prizes: Annotated[list[DisplayItemWrapper], IOAttrs('pr')]
|
||||
|
||||
@override
|
||||
@classmethod
|
||||
def get_type_id(cls) -> BasicClientUIComponentTypeID:
|
||||
return BasicClientUIComponentTypeID.BS_CLASSIC_TOURNEY_RESULT
|
||||
|
||||
|
||||
@ioprepped
|
||||
@dataclass
|
||||
class BasicClientUIDisplayItems(BasicClientUIComponent):
|
||||
"""Show some display-items."""
|
||||
|
||||
items: Annotated[list[DisplayItemWrapper], IOAttrs('d')]
|
||||
width: Annotated[float, IOAttrs('w')] = 100.0
|
||||
spacing_top: Annotated[float, IOAttrs('st', store_default=False)] = 0.0
|
||||
spacing_bottom: Annotated[float, IOAttrs('sb', store_default=False)] = 0.0
|
||||
|
||||
@override
|
||||
@classmethod
|
||||
def get_type_id(cls) -> BasicClientUIComponentTypeID:
|
||||
return BasicClientUIComponentTypeID.DISPLAY_ITEMS
|
||||
|
||||
|
||||
@ioprepped
|
||||
@dataclass
|
||||
class BasicClientUI(ClientUI):
|
||||
@ -642,9 +732,6 @@ class ClientEffectScreenMessage(ClientEffect):
|
||||
"""Display a screen-message."""
|
||||
|
||||
message: Annotated[str, IOAttrs('m')]
|
||||
|
||||
# Note: Firestore can't store arrays of arrays so we flatten it to a
|
||||
# single dimension.
|
||||
subs: Annotated[list[str], IOAttrs('s')]
|
||||
color: Annotated[tuple[float, float, float], IOAttrs('c')] = (1.0, 1.0, 1.0)
|
||||
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
# Released under the MIT License. See LICENSE for details.
|
||||
#
|
||||
# pylint: disable=too-many-lines
|
||||
"""Small handy bits of functionality."""
|
||||
|
||||
from __future__ import annotations
|
||||
@ -15,7 +16,7 @@ from typing import TYPE_CHECKING, cast, TypeVar, Generic, overload, ParamSpec
|
||||
|
||||
if TYPE_CHECKING:
|
||||
import asyncio
|
||||
from typing import Any, Callable, Literal
|
||||
from typing import Any, Callable, Literal, Sequence
|
||||
|
||||
T = TypeVar('T')
|
||||
ValT = TypeVar('ValT')
|
||||
@ -983,6 +984,21 @@ def extract_arg(
|
||||
return val
|
||||
|
||||
|
||||
def pairs_to_flat(pairs: Sequence[tuple[T, T]]) -> list[T]:
|
||||
"""Given a sequence of same-typed pairs, flattens to a list."""
|
||||
return [item for pair in pairs for item in pair]
|
||||
|
||||
|
||||
def pairs_from_flat(flat: Sequence[T]) -> list[tuple[T, T]]:
|
||||
"""Given a flat even numbered sequence, returns pairs."""
|
||||
if len(flat) % 2 != 0:
|
||||
raise ValueError('Provided sequence has an odd number of elements.')
|
||||
out: list[tuple[T, T]] = []
|
||||
for i in range(0, len(flat) - 1, 2):
|
||||
out.append((flat[i], flat[i + 1]))
|
||||
return out
|
||||
|
||||
|
||||
def weighted_choice(*args: tuple[T, float]) -> T:
|
||||
"""Given object/weight pairs as args, returns a random object.
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user