mirror of
https://github.com/RYDE-WORK/ballistica.git
synced 2026-02-01 20:33:46 +08:00
Merge branch 'master' of https://github.com/SoK05/ballistica-sok
This commit is contained in:
commit
277c5f14ca
145
.efrocachemap
generated
145
.efrocachemap
generated
@ -421,42 +421,42 @@
|
||||
"build/assets/ba_data/audio/zoeOw.ogg": "74befe45a8417e95b6a2233c51992a26",
|
||||
"build/assets/ba_data/audio/zoePickup01.ogg": "48ab8cddfcde36a750856f3f81dd20c8",
|
||||
"build/assets/ba_data/audio/zoeScream01.ogg": "2b468aedfa8741090247f04eb9e6df55",
|
||||
"build/assets/ba_data/data/langdata.json": "bb60812044af0a8d1bdefee759ff2522",
|
||||
"build/assets/ba_data/data/langdata.json": "66f05313ffa9880373066332cff4594c",
|
||||
"build/assets/ba_data/data/languages/arabic.json": "0db32e21b6d5337ccca478381744aa88",
|
||||
"build/assets/ba_data/data/languages/belarussian.json": "a112dfca3e188387516788bd8229c5b0",
|
||||
"build/assets/ba_data/data/languages/chinese.json": "93f3ca9f90d86dc7c8d0923f5f11ef46",
|
||||
"build/assets/ba_data/data/languages/belarussian.json": "09954e550d13d3d9cb5a635a1d32a151",
|
||||
"build/assets/ba_data/data/languages/chinese.json": "bb51b5aa614830c561e8fe2542a9ab8a",
|
||||
"build/assets/ba_data/data/languages/chinesetraditional.json": "319565f8a15667488f48dbce59278e39",
|
||||
"build/assets/ba_data/data/languages/croatian.json": "766532c67af5bd0144c2d63cab0516fa",
|
||||
"build/assets/ba_data/data/languages/czech.json": "c9d518a324870066b987b8f412881dd3",
|
||||
"build/assets/ba_data/data/languages/danish.json": "3fd69080783d5c9dcc0af737f02b6f1e",
|
||||
"build/assets/ba_data/data/languages/dutch.json": "5cbf1a68a9d93dee00dbc27f834d878a",
|
||||
"build/assets/ba_data/data/languages/english.json": "1c4037fea1066d39d6eced419f314f35",
|
||||
"build/assets/ba_data/data/languages/croatian.json": "e671b9d0c012be1a30f9c15eb1b81860",
|
||||
"build/assets/ba_data/data/languages/czech.json": "15be4fd59895135bad0265f79b362d5b",
|
||||
"build/assets/ba_data/data/languages/danish.json": "8e57db30c5250df2abff14a822f83ea7",
|
||||
"build/assets/ba_data/data/languages/dutch.json": "b0900d572c9141897d53d6574c471343",
|
||||
"build/assets/ba_data/data/languages/english.json": "6501b04faba1d81e26725dfa19b15667",
|
||||
"build/assets/ba_data/data/languages/esperanto.json": "0e397cfa5f3fb8cef5f4a64f21cda880",
|
||||
"build/assets/ba_data/data/languages/filipino.json": "0031cbb8eb6a638a94fb43c5d892346c",
|
||||
"build/assets/ba_data/data/languages/french.json": "8bc35eb4b20a0b30c3348bcc9a3844a6",
|
||||
"build/assets/ba_data/data/languages/filipino.json": "fe3f1efcb47efaa23524300d21728933",
|
||||
"build/assets/ba_data/data/languages/french.json": "917e4174d6f0eb7f00c27fd79cfbb924",
|
||||
"build/assets/ba_data/data/languages/german.json": "450fa41ae264f29a5d1af22143d0d0ad",
|
||||
"build/assets/ba_data/data/languages/gibberish.json": "b461539243e8efe3137137b886256ba7",
|
||||
"build/assets/ba_data/data/languages/gibberish.json": "0c1c4ac59d82a58c4b89328d44510d72",
|
||||
"build/assets/ba_data/data/languages/greek.json": "287c0ec437b38772284ef9d3e4fb2fc3",
|
||||
"build/assets/ba_data/data/languages/hindi.json": "8848f6b0caec0fcf9d85bc6e683809ec",
|
||||
"build/assets/ba_data/data/languages/hindi.json": "90f54663e15d85a163f1848a8e9d8d07",
|
||||
"build/assets/ba_data/data/languages/hungarian.json": "796a290a8c44a1e7635208c2ff5fdc6e",
|
||||
"build/assets/ba_data/data/languages/indonesian.json": "408fb026e84c24a8dd7a43cb2b794541",
|
||||
"build/assets/ba_data/data/languages/italian.json": "f550810b6866ea9bcf1985b7228f8cff",
|
||||
"build/assets/ba_data/data/languages/korean.json": "03fd99d5e1155e81053fc028f69df982",
|
||||
"build/assets/ba_data/data/languages/indonesian.json": "9103845242b572aa8ba48e24f81ddb68",
|
||||
"build/assets/ba_data/data/languages/italian.json": "fc6440be9ba1846172cf5e11df617c05",
|
||||
"build/assets/ba_data/data/languages/korean.json": "4e3524327a0174250aff5e1ef4c0c597",
|
||||
"build/assets/ba_data/data/languages/malay.json": "832562ce997fc70704b9234c95fb2e38",
|
||||
"build/assets/ba_data/data/languages/persian.json": "9728d631cf7d9ad3b209ae1244bb59c0",
|
||||
"build/assets/ba_data/data/languages/polish.json": "3a90b2d9e2c59305580c96f8098fc839",
|
||||
"build/assets/ba_data/data/languages/portuguese.json": "0274cb9a4b7d2bd49c8eb8120144a1bf",
|
||||
"build/assets/ba_data/data/languages/romanian.json": "aeebdd54f65939c2facc6ac50c117826",
|
||||
"build/assets/ba_data/data/languages/russian.json": "30d5f3d2415088e1fb6558fcd6ccfa98",
|
||||
"build/assets/ba_data/data/languages/persian.json": "c4144aebf2900fc655860de891d16f83",
|
||||
"build/assets/ba_data/data/languages/polish.json": "9d22c6643c097c4cb268d0d6b6319cd4",
|
||||
"build/assets/ba_data/data/languages/portuguese.json": "b52164747c6308fc9d054eb6c0ff3c54",
|
||||
"build/assets/ba_data/data/languages/romanian.json": "b3e46efd6f869dbd78014570e037c290",
|
||||
"build/assets/ba_data/data/languages/russian.json": "0590f49889616b5279be569dea926e17",
|
||||
"build/assets/ba_data/data/languages/serbian.json": "d7452dd72ac0e51680cb39b5ebaa1c69",
|
||||
"build/assets/ba_data/data/languages/slovak.json": "27962d53dc3f7dd4e877cd40faafeeef",
|
||||
"build/assets/ba_data/data/languages/spanish.json": "08d9b39a519743da9a715c2524c3b6ca",
|
||||
"build/assets/ba_data/data/languages/slovak.json": "c00fb27cf982ffad5a4370ad3b16bd21",
|
||||
"build/assets/ba_data/data/languages/spanish.json": "b2edb923fdca973a16f0efb1acc26a97",
|
||||
"build/assets/ba_data/data/languages/swedish.json": "5142a96597d17d8344be96a603da64ac",
|
||||
"build/assets/ba_data/data/languages/tamil.json": "b4de1a2851afe4869c82e9acd94cd89c",
|
||||
"build/assets/ba_data/data/languages/thai.json": "77755219bbf5fb7eea0d6b226684f403",
|
||||
"build/assets/ba_data/data/languages/turkish.json": "2be25c89ca754341f27750e0d595f31e",
|
||||
"build/assets/ba_data/data/languages/ukrainian.json": "b54a38e93deebafa5706ba2d1f626892",
|
||||
"build/assets/ba_data/data/languages/venetian.json": "8e9714d98a85e428ce3543fc49188a46",
|
||||
"build/assets/ba_data/data/languages/tamil.json": "b9fcc523639f55e05c7f4e7914f3321a",
|
||||
"build/assets/ba_data/data/languages/thai.json": "1d665629361f302693dead39de8fa945",
|
||||
"build/assets/ba_data/data/languages/turkish.json": "db71f3776072b7a15ef37b1bb1245795",
|
||||
"build/assets/ba_data/data/languages/ukrainian.json": "3d75d21205c82db34fb1a1b014592747",
|
||||
"build/assets/ba_data/data/languages/venetian.json": "f896fc3df13a42f1bef8813ca80b1a09",
|
||||
"build/assets/ba_data/data/languages/vietnamese.json": "921cd1e50f60fe3e101f246e172750ba",
|
||||
"build/assets/ba_data/data/maps/big_g.json": "1dd301d490643088a435ce75df971054",
|
||||
"build/assets/ba_data/data/maps/bridgit.json": "6aea74805f4880cc11237c5734a24422",
|
||||
@ -950,7 +950,7 @@
|
||||
"build/assets/ba_data/python-site-packages/certifi/__main__.py": "ef02e73f8581609df189a9f61aca365b",
|
||||
"build/assets/ba_data/python-site-packages/certifi/cacert.pem": "4422aed09ab445f7290df7d72a301a47",
|
||||
"build/assets/ba_data/python-site-packages/certifi/core.py": "1b505388f1475fabd1b60031f985271c",
|
||||
"build/assets/ba_data/python-site-packages/typing_extensions.py": "2d974cad17a71505d86513d1322976a5",
|
||||
"build/assets/ba_data/python-site-packages/typing_extensions.py": "188320d92e530be7ea345d3ce3be38de",
|
||||
"build/assets/ba_data/python-site-packages/yaml/__init__.py": "2b747e5772c203377222afc888ac6b71",
|
||||
"build/assets/ba_data/python-site-packages/yaml/composer.py": "cef871e1f5f99ba2a7c44941b70afb06",
|
||||
"build/assets/ba_data/python-site-packages/yaml/constructor.py": "8a15e361e34b79491c81553bb3534062",
|
||||
@ -3521,6 +3521,7 @@
|
||||
"build/assets/pylib-apple/zoneinfo/_common.py": "5b52bdac4156dcbac96743fa99468bf2",
|
||||
"build/assets/pylib-apple/zoneinfo/_tzpath.py": "f021e91036bd38590f2ce643b59dc881",
|
||||
"build/assets/pylib-apple/zoneinfo/_zoneinfo.py": "d000d61aa8998d0076c37f96cf40ca69",
|
||||
"build/assets/sphinx/template/conf.py": "f095d5b0fd30c3776e9ee1256c9c035b",
|
||||
"build/assets/windows/Win32/DLLs/_asyncio.pyd": "36024ca5f0f257dd4edfe1a3e92c1a07",
|
||||
"build/assets/windows/Win32/DLLs/_asyncio_d.pyd": "a809fe3d7f3b6931e5f127821d0d30b6",
|
||||
"build/assets/windows/Win32/DLLs/_bz2.pyd": "cf535d3d0a020f0ae5ff20336a56ba3b",
|
||||
@ -4060,50 +4061,50 @@
|
||||
"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": "cd19dfdf480de6e73949db674e1b02d2",
|
||||
"build/prefab/full/linux_arm64_gui/release/ballisticakit": "8c08cdda59e731a3830624000de5ca7f",
|
||||
"build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "14685eca62b8540cc2a268883d0ebc5d",
|
||||
"build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "f81876d7827a10be412306c52b03fa08",
|
||||
"build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "b8370845743ebba86ed6eaa6ee1d79d5",
|
||||
"build/prefab/full/linux_x86_64_gui/release/ballisticakit": "cdf04825dedae8fb2c26502ec2a505db",
|
||||
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "4036493f98646b58de8bf425bee227cb",
|
||||
"build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "1cf36c63f68ecaa954fb9c48a132725e",
|
||||
"build/prefab/full/mac_arm64_gui/debug/ballisticakit": "b757a940c5157197a0138e12e308f859",
|
||||
"build/prefab/full/mac_arm64_gui/release/ballisticakit": "92a07f83fceeddf3b29cfe2ead57f7e3",
|
||||
"build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "90002c085c66be4af378d4b3fc8e0260",
|
||||
"build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "eeb363d0d48e68f5f2ac2e536a26aeeb",
|
||||
"build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "e119b480fc7e542f33ceb16e8c04585f",
|
||||
"build/prefab/full/mac_x86_64_gui/release/ballisticakit": "6e657aa09d052765ed891789ec60dfb2",
|
||||
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "2d4eab8ea8399defd1afdbe548216e9c",
|
||||
"build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "b03bb9d5d1eb695a11843f64f24906ef",
|
||||
"build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "163fbc40b479ef1db1c753f7beb73c0f",
|
||||
"build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "37291abd76871f4556348f77e12dd363",
|
||||
"build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "acca6904f2f2f952ecae99922c602b9d",
|
||||
"build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "3c2dfd9cf26e77a0b803ed43c85df113",
|
||||
"build/prefab/lib/linux_arm64_gui/debug/libballisticaplus.a": "3af5cf00e5eb30d55030e8705b83353a",
|
||||
"build/prefab/lib/linux_arm64_gui/release/libballisticaplus.a": "be337c05f72235b5b486277bb1a9c259",
|
||||
"build/prefab/lib/linux_arm64_server/debug/libballisticaplus.a": "3af5cf00e5eb30d55030e8705b83353a",
|
||||
"build/prefab/lib/linux_arm64_server/release/libballisticaplus.a": "be337c05f72235b5b486277bb1a9c259",
|
||||
"build/prefab/lib/linux_x86_64_gui/debug/libballisticaplus.a": "17c7d0041bc7c84077bf6692b16e3988",
|
||||
"build/prefab/lib/linux_x86_64_gui/release/libballisticaplus.a": "4affbfea91e8a33ab62da763ffc07ddd",
|
||||
"build/prefab/lib/linux_x86_64_server/debug/libballisticaplus.a": "17c7d0041bc7c84077bf6692b16e3988",
|
||||
"build/prefab/lib/linux_x86_64_server/release/libballisticaplus.a": "4affbfea91e8a33ab62da763ffc07ddd",
|
||||
"build/prefab/lib/mac_arm64_gui/debug/libballisticaplus.a": "58656b49d34e6c650983fbf79b5c41ae",
|
||||
"build/prefab/lib/mac_arm64_gui/release/libballisticaplus.a": "3ce5652e0ff5d277e256f517dec4eb61",
|
||||
"build/prefab/lib/mac_arm64_server/debug/libballisticaplus.a": "58656b49d34e6c650983fbf79b5c41ae",
|
||||
"build/prefab/lib/mac_arm64_server/release/libballisticaplus.a": "3ce5652e0ff5d277e256f517dec4eb61",
|
||||
"build/prefab/lib/mac_x86_64_gui/debug/libballisticaplus.a": "b94fff3a719003c1d8f5dd16dffdb3fc",
|
||||
"build/prefab/lib/mac_x86_64_gui/release/libballisticaplus.a": "5d68e1957febe6053815bbee3f068e76",
|
||||
"build/prefab/lib/mac_x86_64_server/debug/libballisticaplus.a": "85bbca447ca8a1d0fad984afc6f0700a",
|
||||
"build/prefab/lib/mac_x86_64_server/release/libballisticaplus.a": "5d68e1957febe6053815bbee3f068e76",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "7f2ed141a475e051d3350d571ef6cb0c",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "93fb764531ae16a30d4886eb183c3681",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "750cd7ef428f4faf65ccbeff50c21f8e",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "104cf85df9f1f7ffbf4de5997f7c6879",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "af85fb387d755b152c42f8dfb0891ad7",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "01ce8e0619b342e4cc2cc5f18f81a727",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "f8aae2e04f95f4cfb863791da36ff931",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "66252d58a1be97db8523bd0bf8098a16",
|
||||
"build/prefab/full/linux_arm64_gui/debug/ballisticakit": "b8ca5252d3d8f2865e486756bd460118",
|
||||
"build/prefab/full/linux_arm64_gui/release/ballisticakit": "005367a629683ecb9c54bc98fb7a94c6",
|
||||
"build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "6a90b3bdefbb2d55a5b9c454784e8b16",
|
||||
"build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "c3d831d36d5c81aa850872d33761c4be",
|
||||
"build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "5dfa9f0125be245e37d754981b28b8c0",
|
||||
"build/prefab/full/linux_x86_64_gui/release/ballisticakit": "7c687fc514f115d6cc368468dd697a91",
|
||||
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "6ed08dcb724be490cab50db9155e1120",
|
||||
"build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "14b0f978f221664c531bfa72310def53",
|
||||
"build/prefab/full/mac_arm64_gui/debug/ballisticakit": "8ef9c34296da8dda3346b04160f024dc",
|
||||
"build/prefab/full/mac_arm64_gui/release/ballisticakit": "94465074121d8a252fb13d16f5cc1bff",
|
||||
"build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "780d95b4e1812798804f20023663409d",
|
||||
"build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "740ede02d02dae029d17d8a109ee699b",
|
||||
"build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "489e797842a70426313b7731ab1048de",
|
||||
"build/prefab/full/mac_x86_64_gui/release/ballisticakit": "62c118fd9da045125073ad121369901c",
|
||||
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "cf39062a56888d50e031a66c9dfed789",
|
||||
"build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "27d6ce4966f64b840b726093572c6f2f",
|
||||
"build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "5806a280206f9dfabf99e39aa9abc337",
|
||||
"build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "c83e9c27279efb373a8a57c0590678d9",
|
||||
"build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "ea1dd66fcdfb58fdf2b8aab87b88b70d",
|
||||
"build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "9c947d5febb2fd91d30336f88a49738d",
|
||||
"build/prefab/lib/linux_arm64_gui/debug/libballisticaplus.a": "d9865523059d8cf11b2bef4b9da9a8c9",
|
||||
"build/prefab/lib/linux_arm64_gui/release/libballisticaplus.a": "56d6440f62c271c4ce9ef520400395a3",
|
||||
"build/prefab/lib/linux_arm64_server/debug/libballisticaplus.a": "d9865523059d8cf11b2bef4b9da9a8c9",
|
||||
"build/prefab/lib/linux_arm64_server/release/libballisticaplus.a": "56d6440f62c271c4ce9ef520400395a3",
|
||||
"build/prefab/lib/linux_x86_64_gui/debug/libballisticaplus.a": "390a90cf4af1c55662c61ec19f9481bb",
|
||||
"build/prefab/lib/linux_x86_64_gui/release/libballisticaplus.a": "e55895a55cc40f79be9e2e8095e8adf2",
|
||||
"build/prefab/lib/linux_x86_64_server/debug/libballisticaplus.a": "390a90cf4af1c55662c61ec19f9481bb",
|
||||
"build/prefab/lib/linux_x86_64_server/release/libballisticaplus.a": "e55895a55cc40f79be9e2e8095e8adf2",
|
||||
"build/prefab/lib/mac_arm64_gui/debug/libballisticaplus.a": "9846a6a3dd3685417fe834b91be8ac74",
|
||||
"build/prefab/lib/mac_arm64_gui/release/libballisticaplus.a": "68087f1bac1513e92cabdb59c637e759",
|
||||
"build/prefab/lib/mac_arm64_server/debug/libballisticaplus.a": "9846a6a3dd3685417fe834b91be8ac74",
|
||||
"build/prefab/lib/mac_arm64_server/release/libballisticaplus.a": "68087f1bac1513e92cabdb59c637e759",
|
||||
"build/prefab/lib/mac_x86_64_gui/debug/libballisticaplus.a": "72a7370f23c76ed8018999b78d88a545",
|
||||
"build/prefab/lib/mac_x86_64_gui/release/libballisticaplus.a": "c2cf0dc227e41a826c913d12e117c316",
|
||||
"build/prefab/lib/mac_x86_64_server/debug/libballisticaplus.a": "fbdc80e41c5883b4a893d2f0786e377f",
|
||||
"build/prefab/lib/mac_x86_64_server/release/libballisticaplus.a": "c2cf0dc227e41a826c913d12e117c316",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "8c0e9e61d1fd181880283b3c1ca23fd5",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "5a79b4cf27ce798d23741d46043de014",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "f4d46d65ce5924b7348e86a5a0a96cdb",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "d9a76fea59cf167073297139a3b30791",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "890a94f1091f9eba729991eac95fe523",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "bb57e51c4dba3dbccc86ad177b4c1a0d",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "e331ee4c1374a73f2325f86ac98f7f53",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "a1b03a030785baa7d65bfafcf1a1839f",
|
||||
"src/assets/ba_data/python/babase/_mgen/__init__.py": "f885fed7f2ed98ff2ba271f9dbe3391c",
|
||||
"src/assets/ba_data/python/babase/_mgen/enums.py": "b611c090513a21e2fe90e56582724e9d",
|
||||
"src/ballistica/base/mgen/pyembed/binding_base.inc": "72bfed2cce8ff19741989dec28302f3f",
|
||||
|
||||
15
.github/ISSUE_TEMPLATE/bug_report.md
vendored
15
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@ -9,7 +9,7 @@ assignees: ''
|
||||
|
||||
### Description
|
||||
Describe the bug. Do not forget to fill the title.
|
||||
Make sure you're running game without any modifications (unless you want to report an api bug).
|
||||
Make sure you're running game without any modifications.
|
||||
|
||||
### Steps to reproduce
|
||||
1. Launch BombSquad
|
||||
@ -18,16 +18,17 @@ Make sure you're running game without any modifications (unless you want to repo
|
||||
4. Bug!
|
||||
|
||||
### Expected behavior
|
||||
Describe what you think should happen.
|
||||
Describe what you think should happen if it's not obvious.
|
||||
|
||||
### Machine
|
||||
**Platform**: Windows 10 / Ubuntu 20.04 LTS / AOSP 8.1 / etc.
|
||||
**BombSquad version**: [1.5.27](https://github.com/efroemling/ballistica/releases/tag/v1.5.27)
|
||||
**Commit**: [2642488](https://github.com/efroemling/ballistica/commit/2642488a51b250752169738f5aeeccaafa2bc8de)
|
||||
Select what do you want to use: release version or commit. Please use a hyperlink.
|
||||
**Platform**: Windows 11 / Ubuntu 22.04 LTS / Android 12 / MyToasterOS 7.3 / ... \
|
||||
**BombSquad version**: [1.7.32](https://github.com/efroemling/ballistica/tree/v1.7.32) \
|
||||
**Commit**: https://github.com/efroemling/ballistica/tree/978f32f9f098bd0ff1dc64b496ec31cf493ded09
|
||||
|
||||
You may specify BombSquad version you're running or refer to the latest commit.
|
||||
|
||||
### Screenshots
|
||||
Put some screenshots here if needed.
|
||||
|
||||
### Extra
|
||||
Put some extra information here. For example, describe your assumptions about the cause of the bug.
|
||||
You may put some extra information here. For example, describe your assumptions about the cause of the bug.
|
||||
|
||||
52
.github/workflows/cd.yml
vendored
52
.github/workflows/cd.yml
vendored
@ -14,6 +14,9 @@ jobs:
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.11'
|
||||
# Remove this once we upgrade to 3.12.
|
||||
- name: Install typing_extensions (temp)
|
||||
run: python3.11 -m pip install typing_extensions
|
||||
- name: Install pip requirements
|
||||
run: tools/pcommand install_pip_reqs
|
||||
- name: Make the build
|
||||
@ -31,6 +34,9 @@ jobs:
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.11'
|
||||
# Remove this once we upgrade to 3.12.
|
||||
- name: Install typing_extensions (temp)
|
||||
run: python3.11 -m pip install typing_extensions
|
||||
- name: Install pip requirements
|
||||
run: tools/pcommand install_pip_reqs
|
||||
- name: Make the build
|
||||
@ -48,6 +54,9 @@ jobs:
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.11'
|
||||
# Remove this once we upgrade to 3.12.
|
||||
- name: Install typing_extensions (temp)
|
||||
run: python3.11 -m pip install typing_extensions
|
||||
- name: Install pip requirements
|
||||
run: tools/pcommand install_pip_reqs
|
||||
- name: Make the build
|
||||
@ -65,6 +74,9 @@ jobs:
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.11'
|
||||
# Remove this once we upgrade to 3.12.
|
||||
- name: Install typing_extensions (temp)
|
||||
run: python3.11 -m pip install typing_extensions
|
||||
- name: Install pip requirements
|
||||
run: tools/pcommand install_pip_reqs
|
||||
- name: Make the build
|
||||
@ -82,6 +94,9 @@ jobs:
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.11'
|
||||
# Remove this once we upgrade to 3.12.
|
||||
- name: Install typing_extensions (temp)
|
||||
run: python3.11 -m pip install typing_extensions
|
||||
- name: Install pip requirements
|
||||
run: tools/pcommand install_pip_reqs
|
||||
- name: Make the build
|
||||
@ -99,6 +114,9 @@ jobs:
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.11'
|
||||
# Remove this once we upgrade to 3.12.
|
||||
- name: Install typing_extensions (temp)
|
||||
run: python3.11 -m pip install typing_extensions
|
||||
- name: Install pip requirements
|
||||
run: tools/pcommand install_pip_reqs
|
||||
- name: Make the build
|
||||
@ -116,6 +134,9 @@ jobs:
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.11'
|
||||
# Remove this once we upgrade to 3.12.
|
||||
- name: Install typing_extensions (temp)
|
||||
run: python3.11 -m pip install typing_extensions
|
||||
- name: Install pip requirements
|
||||
run: tools/pcommand install_pip_reqs
|
||||
- name: Make the build
|
||||
@ -133,6 +154,9 @@ jobs:
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.11'
|
||||
# Remove this once we upgrade to 3.12.
|
||||
- name: Install typing_extensions (temp)
|
||||
run: python3.11 -m pip install typing_extensions
|
||||
- name: Install pip requirements
|
||||
run: tools/pcommand install_pip_reqs
|
||||
- name: Make the build
|
||||
@ -150,6 +174,9 @@ jobs:
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.11'
|
||||
# Remove this once we upgrade to 3.12.
|
||||
- name: Install typing_extensions (temp)
|
||||
run: python3.11 -m pip install typing_extensions
|
||||
- name: Install pip requirements
|
||||
run: tools/pcommand install_pip_reqs
|
||||
- name: Make the build
|
||||
@ -167,6 +194,9 @@ jobs:
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.11'
|
||||
# Remove this once we upgrade to 3.12.
|
||||
- name: Install typing_extensions (temp)
|
||||
run: python3.11 -m pip install typing_extensions
|
||||
- name: Install pip requirements
|
||||
run: tools/pcommand install_pip_reqs
|
||||
- name: Make the build
|
||||
@ -176,3 +206,25 @@ jobs:
|
||||
with:
|
||||
name: windows_x86_server_(debug)
|
||||
path: build/prefab/full/windows_x86_server
|
||||
make_sphinx_docs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.11'
|
||||
# Remove this once we upgrade to 3.12.
|
||||
- name: Install typing_extensions (temp)
|
||||
run: python3.11 -m pip install typing_extensions
|
||||
- name: Install sphinx
|
||||
run: python3.11 -m pip install sphinx furo
|
||||
- name: Install pip requirements
|
||||
run: tools/pcommand install_pip_reqs
|
||||
- name: Make the build
|
||||
run: make docs-sphinx
|
||||
- name: Upload the build
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: sphinx_html_docs
|
||||
path: build/sphinx
|
||||
12
.github/workflows/ci.yml
vendored
12
.github/workflows/ci.yml
vendored
@ -21,6 +21,9 @@ jobs:
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.11'
|
||||
# Remove this once we upgrade to 3.12.
|
||||
- name: Install typing_extensions (temp)
|
||||
run: python3.11 -m pip install typing_extensions
|
||||
- name: Install dependencies
|
||||
run: tools/pcommand install_pip_reqs
|
||||
- name: Run checks
|
||||
@ -35,6 +38,9 @@ jobs:
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.11'
|
||||
# Remove this once we upgrade to 3.12.
|
||||
- name: Install typing_extensions (temp)
|
||||
run: python3.11 -m pip install typing_extensions
|
||||
- name: Install dependencies
|
||||
run: tools/pcommand install_pip_reqs
|
||||
- name: Assemble monolithic server build
|
||||
@ -53,6 +59,9 @@ jobs:
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.11'
|
||||
# Remove this once we upgrade to 3.12.
|
||||
- name: Install typing_extensions (temp)
|
||||
run: python3.11 -m pip install typing_extensions
|
||||
- name: Install dependencies
|
||||
run: tools/pcommand install_pip_reqs
|
||||
- name: Build spinoff project with only core featureset
|
||||
@ -71,6 +80,9 @@ jobs:
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.11'
|
||||
# Remove this once we upgrade to 3.12.
|
||||
- name: Install typing_extensions (temp)
|
||||
run: python3.11 -m pip install typing_extensions
|
||||
- name: Install dependencies
|
||||
run: tools/pcommand install_pip_reqs
|
||||
- name: Create poo feature-set
|
||||
|
||||
37
CHANGELOG.md
37
CHANGELOG.md
@ -1,4 +1,4 @@
|
||||
### 1.7.33 (build 21757, api 8, 2024-01-06)
|
||||
### 1.7.33 (build 21775, api 8, 2024-03-12)
|
||||
- Stress test input-devices are now a bit smarter; they won't press any buttons
|
||||
while UIs are up (this could cause lots of chaos if it happened).
|
||||
- Added a 'Show Demos When Idle' option in advanced settings. If enabled, the
|
||||
@ -11,7 +11,32 @@
|
||||
- Players now get points for killing bots with their own bombs by catching it
|
||||
and throwing it back at them. This is actually old logic but was disabled due
|
||||
to a logic flaw, but should be fixed now. (Thanks VinniTR!)
|
||||
|
||||
- Updated the 'Settings->Advanced->Enter Code' functionality to talk to the V2
|
||||
master server (V1 is still used as a fallback).
|
||||
- Adopted the `@override` decorator in all Python code and set up Mypy to
|
||||
enforce its usage. Currently `override` comes from `typing_extensions` module
|
||||
but when we upgrade to Python 3.12 soon it will come from the standard
|
||||
`typing` module. This decorator should be familiar to users of other
|
||||
languages; I feel it helps keep logic more understandable and should help us
|
||||
catch problems where a base class changes or removes a method and child
|
||||
classes forget to adapt to the change.
|
||||
- Custom spaz "curse_time" values now work properly. (Thanks Temp!)
|
||||
- Implemented `efro.dataclassio.IOMultiType` which will make my life a lot
|
||||
easier.
|
||||
- Punches no longer physically affect powerup boxes which should make it easier
|
||||
to grab the powerup (Thanks VinniTR!).
|
||||
- The 'Manual' party tab now supports entering IPv6 addresses (Thanks
|
||||
brostos!).
|
||||
- Fixes a bug where Meteor Shower could make the game-end bell sound twice
|
||||
(Thanks 3alTemp!).
|
||||
- Leaving the game or dying while touching your team's flag will no longer
|
||||
recover & return it indefinitely in a teams game of Capture the Flag. (Thanks
|
||||
3alTemp!)
|
||||
- Added a server config setting for max players (not max clients) (Thanks
|
||||
EraOSBeta!)
|
||||
- Added a UI for customizing Series Length in Teams and Points-to-Win in FFA
|
||||
(Thanks EraOSBeta!)
|
||||
|
||||
### 1.7.32 (build 21741, api 8, 2023-12-20)
|
||||
- Fixed a screen message that no one will ever see (Thanks vishal332008?...)
|
||||
- Plugins window now displays 'No Plugins Installed' when no plugins are present (Thanks vishal332008!)
|
||||
@ -54,7 +79,7 @@
|
||||
intended. Now, however, such commands get scheduled to a current
|
||||
'ui-operation' and then run *almost* immediately, which should prevent such
|
||||
situations. Please holler if you run into any UI weirdness at this point.
|
||||
|
||||
|
||||
### 1.7.30 (build 21697, api 8, 2023-12-08)
|
||||
- Continued work on the big 1.7.28 update.
|
||||
- Got the Android version back up and running. There's been lots of cleanup and
|
||||
@ -331,7 +356,7 @@
|
||||
- Added a 'glow_type' arg to `bauiv1.textwidget()` to adjust the glow used when
|
||||
the text is selected. The default is 'gradient' but there is now a 'uniform'
|
||||
option which may look better in some circumstances.
|
||||
|
||||
|
||||
### 1.7.27 (build 21282, api 8, 2023-08-30)
|
||||
|
||||
- Fixed a rare crash that could occur if the app shuts down while a background
|
||||
@ -452,7 +477,7 @@
|
||||
Visual Studio Code (and potentially other editors), so am seeing if it is
|
||||
worth officially supporting in addition to or as a replacement for Mypy. See
|
||||
`tools/pcommand pyright`
|
||||
|
||||
|
||||
### 1.7.24 (build 21199, api 8, 2023-07-27)
|
||||
|
||||
- Fixed an issue where respawn icons could disappear in epic mode (Thanks for
|
||||
@ -507,7 +532,7 @@
|
||||
can be useful for core engine code to directly and clearly point out problems
|
||||
that cannot be recovered from (Exceptions in such cases can tend to be
|
||||
'handled' which leads to a broken or crashing app).
|
||||
|
||||
|
||||
### 1.7.23 (build 21178, api 8, 2023-07-19)
|
||||
|
||||
- Network security improvements. (Thanks Dliwk!)
|
||||
|
||||
@ -37,12 +37,12 @@
|
||||
- Added feature
|
||||
|
||||
### Vishal332008
|
||||
- Bug Fixer
|
||||
- QoL and Bug Fixer
|
||||
- Modder
|
||||
|
||||
### Era0S
|
||||
- Community Suggestions Implementer
|
||||
- Bug Fixer
|
||||
- QoL and Bug Fixer
|
||||
- Modder
|
||||
|
||||
### VinniTR
|
||||
@ -55,6 +55,12 @@
|
||||
- Modder
|
||||
- BSE Heartbeat mechanic port
|
||||
|
||||
### Temp
|
||||
- Modder
|
||||
- CTF Flag Bug Fix
|
||||
### Temp (3alTemp)
|
||||
- Original idea for customizable series length on GUI builds
|
||||
- Modder & Bug Fixer
|
||||
|
||||
### brostos
|
||||
- Added support for joining using ipv6 address
|
||||
|
||||
### Loup Garou
|
||||
- Added sphinx documentation generation
|
||||
13
Makefile
13
Makefile
@ -49,7 +49,7 @@ endif
|
||||
# Prereq targets that should be safe to run anytime; even if project-files
|
||||
# are out of date.
|
||||
PREREQS_SAFE = .cache/checkenv $(PCOMMANDBATCHBIN) .dir-locals.el .mypy.ini \
|
||||
.pyrightconfig.json .pycheckers .pylintrc .style.yapf .clang-format \
|
||||
.pyrightconfig.json .pylintrc .style.yapf .clang-format \
|
||||
ballisticakit-cmake/.clang-format .editorconfig
|
||||
|
||||
# Prereq targets that may break if the project needs updating should go here.
|
||||
@ -183,6 +183,14 @@ docs:
|
||||
docs-pdoc:
|
||||
@$(PCOMMAND) gen_docs_pdoc
|
||||
|
||||
docs-sphinx:
|
||||
$(MAKE) dummymodules
|
||||
@$(PCOMMAND) gen_docs_sphinx
|
||||
|
||||
docs-sphinx-clean:
|
||||
rm -rf .cache/sphinx
|
||||
rm -rf build/sphinx
|
||||
|
||||
pcommandbatch_speed_test: prereqs
|
||||
@$(PCOMMAND) pcommandbatch_speed_test $(PCOMMANDBATCH)
|
||||
|
||||
@ -1216,9 +1224,6 @@ ENV_SRC = $(PCOMMAND) tools/batools/build.py
|
||||
.pyrightconfig.json: config/toolconfigsrc/pyrightconfig.yaml $(TOOL_CFG_SRC)
|
||||
@$(TOOL_CFG_INST) $< $@
|
||||
|
||||
.pycheckers: config/toolconfigsrc/pycheckers $(TOOL_CFG_SRC)
|
||||
@$(TOOL_CFG_INST) $< $@
|
||||
|
||||
# Set this to 1 to skip environment checks.
|
||||
SKIP_ENV_CHECKS ?= 0
|
||||
|
||||
|
||||
3
ballisticakit-cmake/.idea/misc.xml
generated
3
ballisticakit-cmake/.idea/misc.xml
generated
@ -49,9 +49,6 @@
|
||||
<file path="$PROJECT_DIR$/../src/external/python-android-debug" />
|
||||
<file path="$PROJECT_DIR$/../src/external/python-apple" />
|
||||
<file path="$PROJECT_DIR$/../src/external/python-apple-debug" />
|
||||
<file path="$PROJECT_DIR$/../src/external/sdl-1.2.14_ef" />
|
||||
<file path="$PROJECT_DIR$/../src/external/sdl2-ef_android" />
|
||||
<file path="$PROJECT_DIR$/../src/external/sdl2-ef_ios" />
|
||||
<file path="$PROJECT_DIR$/../src/external/tremor" />
|
||||
<file path="$PROJECT_DIR$/../src/external/windows" />
|
||||
<file path="$PROJECT_DIR$/../src/meta" />
|
||||
|
||||
@ -278,6 +278,7 @@ ctx.filter_file_extensions = {
|
||||
'.xcsettings',
|
||||
'.xcstrings',
|
||||
'.filters',
|
||||
'.rst',
|
||||
}
|
||||
|
||||
# ELSE files with these extensions will NOT be filtered.
|
||||
|
||||
@ -4487,6 +4487,8 @@
|
||||
"pylib-apple/zoneinfo/_common.py",
|
||||
"pylib-apple/zoneinfo/_tzpath.py",
|
||||
"pylib-apple/zoneinfo/_zoneinfo.py",
|
||||
"sphinx/template/__pycache__/conf.cpython-311.opt-1.pyc",
|
||||
"sphinx/template/conf.py",
|
||||
"windows/Win32/DLLs/_asyncio.pyd",
|
||||
"windows/Win32/DLLs/_asyncio_d.pyd",
|
||||
"windows/Win32/DLLs/_bz2.pyd",
|
||||
|
||||
@ -13,7 +13,6 @@
|
||||
"ba_data/python/babase/__pycache__/_apputils.cpython-311.opt-1.pyc",
|
||||
"ba_data/python/babase/__pycache__/_assetmanager.cpython-311.opt-1.pyc",
|
||||
"ba_data/python/babase/__pycache__/_asyncio.cpython-311.opt-1.pyc",
|
||||
"ba_data/python/babase/__pycache__/_cloud.cpython-311.opt-1.pyc",
|
||||
"ba_data/python/babase/__pycache__/_devconsole.cpython-311.opt-1.pyc",
|
||||
"ba_data/python/babase/__pycache__/_emptyappmode.cpython-311.opt-1.pyc",
|
||||
"ba_data/python/babase/__pycache__/_env.cpython-311.opt-1.pyc",
|
||||
@ -42,7 +41,6 @@
|
||||
"ba_data/python/babase/_apputils.py",
|
||||
"ba_data/python/babase/_assetmanager.py",
|
||||
"ba_data/python/babase/_asyncio.py",
|
||||
"ba_data/python/babase/_cloud.py",
|
||||
"ba_data/python/babase/_devconsole.py",
|
||||
"ba_data/python/babase/_emptyappmode.py",
|
||||
"ba_data/python/babase/_env.py",
|
||||
@ -121,8 +119,10 @@
|
||||
"ba_data/python/baenv.py",
|
||||
"ba_data/python/baplus/__init__.py",
|
||||
"ba_data/python/baplus/__pycache__/__init__.cpython-311.opt-1.pyc",
|
||||
"ba_data/python/baplus/__pycache__/_cloud.cpython-311.opt-1.pyc",
|
||||
"ba_data/python/baplus/__pycache__/_hooks.cpython-311.opt-1.pyc",
|
||||
"ba_data/python/baplus/__pycache__/_subsystem.cpython-311.opt-1.pyc",
|
||||
"ba_data/python/baplus/_cloud.py",
|
||||
"ba_data/python/baplus/_hooks.py",
|
||||
"ba_data/python/baplus/_subsystem.py",
|
||||
"ba_data/python/bascenev1/__init__.py",
|
||||
|
||||
@ -171,7 +171,6 @@ SCRIPT_TARGETS_PY_PUBLIC = \
|
||||
$(BUILD_DIR)/ba_data/python/babase/_apputils.py \
|
||||
$(BUILD_DIR)/ba_data/python/babase/_assetmanager.py \
|
||||
$(BUILD_DIR)/ba_data/python/babase/_asyncio.py \
|
||||
$(BUILD_DIR)/ba_data/python/babase/_cloud.py \
|
||||
$(BUILD_DIR)/ba_data/python/babase/_devconsole.py \
|
||||
$(BUILD_DIR)/ba_data/python/babase/_emptyappmode.py \
|
||||
$(BUILD_DIR)/ba_data/python/babase/_env.py \
|
||||
@ -210,6 +209,7 @@ SCRIPT_TARGETS_PY_PUBLIC = \
|
||||
$(BUILD_DIR)/ba_data/python/baclassic/osmusic.py \
|
||||
$(BUILD_DIR)/ba_data/python/baenv.py \
|
||||
$(BUILD_DIR)/ba_data/python/baplus/__init__.py \
|
||||
$(BUILD_DIR)/ba_data/python/baplus/_cloud.py \
|
||||
$(BUILD_DIR)/ba_data/python/baplus/_hooks.py \
|
||||
$(BUILD_DIR)/ba_data/python/baplus/_subsystem.py \
|
||||
$(BUILD_DIR)/ba_data/python/bascenev1/__init__.py \
|
||||
@ -446,7 +446,6 @@ SCRIPT_TARGETS_PYC_PUBLIC = \
|
||||
$(BUILD_DIR)/ba_data/python/babase/__pycache__/_apputils.cpython-311.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/babase/__pycache__/_assetmanager.cpython-311.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/babase/__pycache__/_asyncio.cpython-311.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/babase/__pycache__/_cloud.cpython-311.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/babase/__pycache__/_devconsole.cpython-311.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/babase/__pycache__/_emptyappmode.cpython-311.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/babase/__pycache__/_env.cpython-311.opt-1.pyc \
|
||||
@ -485,6 +484,7 @@ SCRIPT_TARGETS_PYC_PUBLIC = \
|
||||
$(BUILD_DIR)/ba_data/python/baclassic/__pycache__/osmusic.cpython-311.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/__pycache__/baenv.cpython-311.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/baplus/__pycache__/__init__.cpython-311.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/baplus/__pycache__/_cloud.cpython-311.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/baplus/__pycache__/_hooks.cpython-311.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/baplus/__pycache__/_subsystem.cpython-311.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/bascenev1/__pycache__/__init__.cpython-311.opt-1.pyc \
|
||||
@ -2742,7 +2742,8 @@ SCRIPT_TARGETS_PY_PRIVATE_COMMON = \
|
||||
$(BUILD_DIR)/ba_data/python-site-packages/yaml/resolver.py \
|
||||
$(BUILD_DIR)/ba_data/python-site-packages/yaml/scanner.py \
|
||||
$(BUILD_DIR)/ba_data/python-site-packages/yaml/serializer.py \
|
||||
$(BUILD_DIR)/ba_data/python-site-packages/yaml/tokens.py
|
||||
$(BUILD_DIR)/ba_data/python-site-packages/yaml/tokens.py \
|
||||
$(BUILD_DIR)/sphinx/template/conf.py
|
||||
|
||||
SCRIPT_TARGETS_PYC_PRIVATE_COMMON = \
|
||||
$(BUILD_DIR)/ba_data/python-site-packages/_yaml/__pycache__/__init__.cpython-311.opt-1.pyc \
|
||||
@ -2766,7 +2767,8 @@ SCRIPT_TARGETS_PYC_PRIVATE_COMMON = \
|
||||
$(BUILD_DIR)/ba_data/python-site-packages/yaml/__pycache__/resolver.cpython-311.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python-site-packages/yaml/__pycache__/scanner.cpython-311.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python-site-packages/yaml/__pycache__/serializer.cpython-311.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python-site-packages/yaml/__pycache__/tokens.cpython-311.opt-1.pyc
|
||||
$(BUILD_DIR)/ba_data/python-site-packages/yaml/__pycache__/tokens.cpython-311.opt-1.pyc \
|
||||
$(BUILD_DIR)/sphinx/template/__pycache__/conf.cpython-311.opt-1.pyc
|
||||
|
||||
# Rule to copy src asset scripts to dst.
|
||||
# (and make non-writable so I'm less likely to accidentally edit them there)
|
||||
|
||||
@ -118,7 +118,6 @@ from babase._apputils import (
|
||||
get_remote_app_name,
|
||||
AppHealthMonitor,
|
||||
)
|
||||
from babase._cloud import CloudSubsystem
|
||||
from babase._devconsole import (
|
||||
DevConsoleTab,
|
||||
DevConsoleTabEntry,
|
||||
@ -213,7 +212,6 @@ __all__ = [
|
||||
'clipboard_has_text',
|
||||
'clipboard_is_supported',
|
||||
'clipboard_set_text',
|
||||
'CloudSubsystem',
|
||||
'commit_app_config',
|
||||
'ContextCall',
|
||||
'ContextError',
|
||||
|
||||
@ -1,15 +1,17 @@
|
||||
# Released under the MIT License. See LICENSE for details.
|
||||
#
|
||||
# pylint: disable=too-many-lines
|
||||
"""Functionality related to the high level state of the app."""
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import logging
|
||||
from enum import Enum
|
||||
from typing import TYPE_CHECKING
|
||||
from typing import TYPE_CHECKING, TypeVar
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
from functools import cached_property
|
||||
|
||||
from typing_extensions import override
|
||||
from efro.call import tpartial
|
||||
|
||||
import _babase
|
||||
@ -26,7 +28,7 @@ from babase._devconsole import DevConsoleSubsystem
|
||||
|
||||
if TYPE_CHECKING:
|
||||
import asyncio
|
||||
from typing import Any, Callable, Coroutine
|
||||
from typing import Any, Callable, Coroutine, Generator, Awaitable
|
||||
from concurrent.futures import Future
|
||||
|
||||
import babase
|
||||
@ -42,6 +44,8 @@ if TYPE_CHECKING:
|
||||
|
||||
# __FEATURESET_APP_SUBSYSTEM_IMPORTS_END__
|
||||
|
||||
T = TypeVar('T')
|
||||
|
||||
|
||||
class App:
|
||||
"""A class for high level app functionality and state.
|
||||
@ -124,6 +128,7 @@ class App:
|
||||
statically in a spinoff project.
|
||||
"""
|
||||
|
||||
@override
|
||||
def app_mode_for_intent(
|
||||
self, intent: AppIntent
|
||||
) -> type[AppMode] | None:
|
||||
@ -199,7 +204,8 @@ class App:
|
||||
self._called_on_running = False
|
||||
self._subsystem_registration_ended = False
|
||||
self._pending_apply_app_config = False
|
||||
self._aioloop: asyncio.AbstractEventLoop | None = None
|
||||
self._asyncio_loop: asyncio.AbstractEventLoop | None = None
|
||||
self._asyncio_tasks: set[asyncio.Task] = set()
|
||||
self._asyncio_timer: babase.AppTimer | None = None
|
||||
self._config: babase.AppConfig | None = None
|
||||
self._pending_intent: AppIntent | None = None
|
||||
@ -239,18 +245,68 @@ class App:
|
||||
return _babase.app_is_active()
|
||||
|
||||
@property
|
||||
def aioloop(self) -> asyncio.AbstractEventLoop:
|
||||
def asyncio_loop(self) -> asyncio.AbstractEventLoop:
|
||||
"""The logic thread's asyncio event loop.
|
||||
|
||||
This allow async tasks to be run in the logic thread.
|
||||
|
||||
Generally you should call App.create_async_task() to schedule
|
||||
async code to run instead of using this directly. That will
|
||||
handle retaining the task and logging errors automatically.
|
||||
Only schedule tasks onto asyncio_loop yourself when you intend
|
||||
to hold on to the returned task and await its results. Releasing
|
||||
the task reference can lead to subtle bugs such as unreported
|
||||
errors and garbage-collected tasks disappearing before their
|
||||
work is done.
|
||||
|
||||
Note that, at this time, the asyncio loop is encapsulated
|
||||
and explicitly stepped by the engine's logic thread loop and
|
||||
thus things like asyncio.get_running_loop() will not return this
|
||||
loop from most places in the logic thread; only from within a
|
||||
task explicitly created in this loop.
|
||||
thus things like asyncio.get_running_loop() will unintuitively
|
||||
*not* return this loop from most places in the logic thread;
|
||||
only from within a task explicitly created in this loop.
|
||||
Hopefully this situation will be improved in the future with a
|
||||
unified event loop.
|
||||
"""
|
||||
assert self._aioloop is not None
|
||||
return self._aioloop
|
||||
assert _babase.in_logic_thread()
|
||||
assert self._asyncio_loop is not None
|
||||
return self._asyncio_loop
|
||||
|
||||
def create_async_task(
|
||||
self,
|
||||
coro: Generator[Any, Any, T] | Coroutine[Any, Any, T],
|
||||
*,
|
||||
name: str | None = None,
|
||||
) -> None:
|
||||
"""Create a fully managed async task.
|
||||
|
||||
This will automatically retain and release a reference to the task
|
||||
and log any exceptions that occur in it. If you need to await a task
|
||||
or otherwise need more control, schedule a task directly using
|
||||
App.asyncio_loop.
|
||||
"""
|
||||
assert _babase.in_logic_thread()
|
||||
# Hold a strong reference to the task until it is done.
|
||||
# Otherwise it is possible for it to be garbage collected and
|
||||
# disappear midway if the caller does not hold on to the
|
||||
# returned task, which seems like a great way to introduce
|
||||
# hard-to-track bugs.
|
||||
task = self.asyncio_loop.create_task(coro, name=name)
|
||||
self._asyncio_tasks.add(task)
|
||||
task.add_done_callback(self._on_task_done)
|
||||
# return task
|
||||
|
||||
def _on_task_done(self, task: asyncio.Task) -> None:
|
||||
# Report any errors that occurred.
|
||||
try:
|
||||
exc = task.exception()
|
||||
if exc is not None:
|
||||
logging.error(
|
||||
"Error in async task '%s'.", task.get_name(), exc_info=exc
|
||||
)
|
||||
except Exception:
|
||||
logging.exception('Error reporting async task error.')
|
||||
|
||||
self._asyncio_tasks.remove(task)
|
||||
|
||||
@property
|
||||
def config(self) -> babase.AppConfig:
|
||||
@ -594,7 +650,7 @@ class App:
|
||||
|
||||
_env.on_app_state_initing()
|
||||
|
||||
self._aioloop = _asyncio.setup_asyncio()
|
||||
self._asyncio_loop = _asyncio.setup_asyncio()
|
||||
self.health_monitor = AppHealthMonitor()
|
||||
|
||||
# __FEATURESET_APP_SUBSYSTEM_CREATE_BEGIN__
|
||||
@ -874,8 +930,8 @@ class App:
|
||||
)
|
||||
|
||||
# Now kick off any async shutdown task(s).
|
||||
assert self._aioloop is not None
|
||||
self._shutdown_task = self._aioloop.create_task(self._shutdown())
|
||||
assert self._asyncio_loop is not None
|
||||
self._shutdown_task = self._asyncio_loop.create_task(self._shutdown())
|
||||
|
||||
def _on_shutdown_complete(self) -> None:
|
||||
"""(internal)"""
|
||||
|
||||
@ -40,16 +40,16 @@ class AppSubsystem:
|
||||
"""Called when the app reaches the running state."""
|
||||
|
||||
def on_app_suspend(self) -> None:
|
||||
"""Called when the app enters the paused state."""
|
||||
"""Called when the app enters the suspended state."""
|
||||
|
||||
def on_app_unsuspend(self) -> None:
|
||||
"""Called when the app exits the paused state."""
|
||||
"""Called when the app exits the suspended state."""
|
||||
|
||||
def on_app_shutdown(self) -> None:
|
||||
"""Called when the app is shutting down."""
|
||||
"""Called when the app begins shutting down."""
|
||||
|
||||
def on_app_shutdown_complete(self) -> None:
|
||||
"""Called when the app is done shutting down."""
|
||||
"""Called when the app completes shutting down."""
|
||||
|
||||
def do_apply_app_config(self) -> None:
|
||||
"""Called when the app config should be applied."""
|
||||
|
||||
@ -10,9 +10,11 @@ from threading import Thread
|
||||
from dataclasses import dataclass
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from typing_extensions import override
|
||||
from efro.call import tpartial
|
||||
from efro.log import LogLevel
|
||||
from efro.dataclassio import ioprepped, dataclass_to_json, dataclass_from_json
|
||||
|
||||
import _babase
|
||||
from babase._appsubsystem import AppSubsystem
|
||||
|
||||
@ -386,6 +388,7 @@ class AppHealthMonitor(AppSubsystem):
|
||||
self._response = False
|
||||
self._first_check = True
|
||||
|
||||
@override
|
||||
def on_app_loading(self) -> None:
|
||||
# If any traceback dumps happened last run, log and clear them.
|
||||
log_dumped_app_state(from_previous_run=True)
|
||||
@ -449,10 +452,12 @@ class AppHealthMonitor(AppSubsystem):
|
||||
|
||||
self._first_check = False
|
||||
|
||||
@override
|
||||
def on_app_suspend(self) -> None:
|
||||
assert _babase.in_logic_thread()
|
||||
self._running = False
|
||||
|
||||
@override
|
||||
def on_app_unsuspend(self) -> None:
|
||||
assert _babase.in_logic_thread()
|
||||
self._running = True
|
||||
|
||||
@ -8,6 +8,8 @@ from typing import TYPE_CHECKING
|
||||
from dataclasses import dataclass
|
||||
import logging
|
||||
|
||||
from typing_extensions import override
|
||||
|
||||
import _babase
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@ -96,6 +98,7 @@ class DevConsoleTab:
|
||||
class DevConsoleTabPython(DevConsoleTab):
|
||||
"""The Python dev-console tab."""
|
||||
|
||||
@override
|
||||
def refresh(self) -> None:
|
||||
self.python_terminal()
|
||||
|
||||
@ -103,6 +106,7 @@ class DevConsoleTabPython(DevConsoleTab):
|
||||
class DevConsoleTabTest(DevConsoleTab):
|
||||
"""Test dev-console tab."""
|
||||
|
||||
@override
|
||||
def refresh(self) -> None:
|
||||
import random
|
||||
|
||||
|
||||
@ -5,6 +5,7 @@ from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from typing_extensions import override
|
||||
from bacommon.app import AppExperience
|
||||
|
||||
import _babase
|
||||
@ -18,15 +19,18 @@ if TYPE_CHECKING:
|
||||
class EmptyAppMode(AppMode):
|
||||
"""An empty app mode that can be used as a fallback/etc."""
|
||||
|
||||
@override
|
||||
@classmethod
|
||||
def get_app_experience(cls) -> AppExperience:
|
||||
return AppExperience.EMPTY
|
||||
|
||||
@override
|
||||
@classmethod
|
||||
def _supports_intent(cls, intent: AppIntent) -> bool:
|
||||
# We support default and exec intents currently.
|
||||
return isinstance(intent, AppIntentExec | AppIntentDefault)
|
||||
|
||||
@override
|
||||
def handle_intent(self, intent: AppIntent) -> None:
|
||||
if isinstance(intent, AppIntentExec):
|
||||
_babase.empty_app_mode_handle_intent_exec(intent.code)
|
||||
@ -34,10 +38,12 @@ class EmptyAppMode(AppMode):
|
||||
assert isinstance(intent, AppIntentDefault)
|
||||
_babase.empty_app_mode_handle_intent_default()
|
||||
|
||||
@override
|
||||
def on_activate(self) -> None:
|
||||
# Let the native layer do its thing.
|
||||
_babase.on_empty_app_mode_activate()
|
||||
|
||||
@override
|
||||
def on_deactivate(self) -> None:
|
||||
# Let the native layer do its thing.
|
||||
_babase.on_empty_app_mode_deactivate()
|
||||
|
||||
@ -9,6 +9,7 @@ import logging
|
||||
import warnings
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from typing_extensions import override
|
||||
from efro.log import LogLevel
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@ -216,6 +217,7 @@ def _feed_logs_to_babase(log_handler: LogHandler) -> None:
|
||||
class _CustomHelper:
|
||||
"""Replacement 'help' that behaves better for our setup."""
|
||||
|
||||
@override
|
||||
def __repr__(self) -> str:
|
||||
return 'Type help(object) for help about object.'
|
||||
|
||||
|
||||
@ -10,6 +10,7 @@ import logging
|
||||
import inspect
|
||||
from typing import TYPE_CHECKING, TypeVar, Protocol, NewType
|
||||
|
||||
from typing_extensions import override
|
||||
from efro.terminal import Clr
|
||||
|
||||
import _babase
|
||||
@ -178,6 +179,7 @@ class _WeakCall:
|
||||
def __call__(self, *args_extra: Any) -> Any:
|
||||
return self._call(*self._args + args_extra, **self._keywds)
|
||||
|
||||
@override
|
||||
def __str__(self) -> str:
|
||||
return (
|
||||
'<ba.WeakCall object; _call='
|
||||
@ -224,6 +226,7 @@ class _Call:
|
||||
def __call__(self, *args_extra: Any) -> Any:
|
||||
return self._call(*self._args + args_extra, **self._keywds)
|
||||
|
||||
@override
|
||||
def __str__(self) -> str:
|
||||
return (
|
||||
'<ba.Call object; _call='
|
||||
@ -268,6 +271,7 @@ class WeakMethod:
|
||||
return None
|
||||
return self._func(*((obj,) + args), **keywds)
|
||||
|
||||
@override
|
||||
def __str__(self) -> str:
|
||||
return '<ba.WeakMethod object; call=' + str(self._func) + '>'
|
||||
|
||||
|
||||
@ -8,6 +8,8 @@ import json
|
||||
import logging
|
||||
from typing import TYPE_CHECKING, overload
|
||||
|
||||
from typing_extensions import override
|
||||
|
||||
import _babase
|
||||
from babase._appsubsystem import AppSubsystem
|
||||
|
||||
@ -217,6 +219,7 @@ class LanguageSubsystem(AppSubsystem):
|
||||
color=(0, 1, 0),
|
||||
)
|
||||
|
||||
@override
|
||||
def do_apply_app_config(self) -> None:
|
||||
assert _babase.in_logic_thread()
|
||||
assert isinstance(_babase.app.config, dict)
|
||||
@ -598,9 +601,11 @@ class Lstr:
|
||||
_error.print_exception('_get_json failed for', self.args)
|
||||
return 'JSON_ERR'
|
||||
|
||||
@override
|
||||
def __str__(self) -> str:
|
||||
return '<ba.Lstr: ' + self._get_json() + '>'
|
||||
|
||||
@override
|
||||
def __repr__(self) -> str:
|
||||
return '<ba.Lstr: ' + self._get_json() + '>'
|
||||
|
||||
@ -648,5 +653,6 @@ class AttrDict(dict):
|
||||
assert not isinstance(val, bytes)
|
||||
return val
|
||||
|
||||
@override
|
||||
def __setattr__(self, attr: str, value: Any) -> None:
|
||||
raise AttributeError()
|
||||
|
||||
@ -9,6 +9,7 @@ import logging
|
||||
from dataclasses import dataclass
|
||||
from typing import TYPE_CHECKING, final
|
||||
|
||||
from typing_extensions import override
|
||||
from bacommon.login import LoginType
|
||||
|
||||
import _babase
|
||||
@ -353,6 +354,7 @@ class LoginAdapterNative(LoginAdapter):
|
||||
self._sign_in_attempt_num = 123
|
||||
self._sign_in_attempts: dict[int, Callable[[str | None], None]] = {}
|
||||
|
||||
@override
|
||||
def get_sign_in_token(
|
||||
self, completion_cb: Callable[[str | None], None]
|
||||
) -> None:
|
||||
@ -363,6 +365,7 @@ class LoginAdapterNative(LoginAdapter):
|
||||
self.login_type.value, attempt_id
|
||||
)
|
||||
|
||||
@override
|
||||
def on_back_end_active_change(self, active: bool) -> None:
|
||||
_babase.login_adapter_back_end_active_change(
|
||||
self.login_type.value, active
|
||||
|
||||
@ -26,7 +26,7 @@ EXPORT_CLASS_NAME_SHORTCUTS: dict[str, str] = {
|
||||
'plugin': 'babase.Plugin',
|
||||
# DEPRECATED as of 12/2023. Currently am warning if finding these
|
||||
# but should take this out eventually.
|
||||
'keyboard': 'babase.Keyboard',
|
||||
'keyboard': 'bauiv1.Keyboard',
|
||||
}
|
||||
|
||||
T = TypeVar('T')
|
||||
@ -288,14 +288,12 @@ class DirectoryScan:
|
||||
) -> None:
|
||||
"""Scan provided path and add module entries to provided list."""
|
||||
try:
|
||||
# Special case: let's save some time and skip the whole 'babase'
|
||||
# package since we know it doesn't contain any meta tags.
|
||||
fullpath = Path(path, subpath)
|
||||
# Note: skipping hidden dirs (starting with '.').
|
||||
entries = [
|
||||
(path, Path(subpath, name))
|
||||
for name in os.listdir(fullpath)
|
||||
# Actually scratch that for now; trying to avoid special cases.
|
||||
# if name != 'babase'
|
||||
if not name.startswith('.')
|
||||
]
|
||||
except PermissionError:
|
||||
# Expected sometimes.
|
||||
|
||||
@ -8,6 +8,8 @@ import logging
|
||||
import importlib.util
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from typing_extensions import override
|
||||
|
||||
import _babase
|
||||
from babase._appsubsystem import AppSubsystem
|
||||
|
||||
@ -158,6 +160,7 @@ class PluginSubsystem(AppSubsystem):
|
||||
if config_changed:
|
||||
_babase.app.config.commit()
|
||||
|
||||
@override
|
||||
def on_app_running(self) -> None:
|
||||
# Load up our plugins and go ahead and call their on_app_running
|
||||
# calls.
|
||||
@ -170,6 +173,7 @@ class PluginSubsystem(AppSubsystem):
|
||||
|
||||
_error.print_exception('Error in plugin on_app_running()')
|
||||
|
||||
@override
|
||||
def on_app_suspend(self) -> None:
|
||||
for plugin in self.active_plugins:
|
||||
try:
|
||||
@ -179,6 +183,7 @@ class PluginSubsystem(AppSubsystem):
|
||||
|
||||
_error.print_exception('Error in plugin on_app_suspend()')
|
||||
|
||||
@override
|
||||
def on_app_unsuspend(self) -> None:
|
||||
for plugin in self.active_plugins:
|
||||
try:
|
||||
@ -188,6 +193,7 @@ class PluginSubsystem(AppSubsystem):
|
||||
|
||||
_error.print_exception('Error in plugin on_app_unsuspend()')
|
||||
|
||||
@override
|
||||
def on_app_shutdown(self) -> None:
|
||||
for plugin in self.active_plugins:
|
||||
try:
|
||||
@ -197,6 +203,7 @@ class PluginSubsystem(AppSubsystem):
|
||||
|
||||
_error.print_exception('Error in plugin on_app_shutdown()')
|
||||
|
||||
@override
|
||||
def on_app_shutdown_complete(self) -> None:
|
||||
for plugin in self.active_plugins:
|
||||
try:
|
||||
|
||||
@ -5,6 +5,8 @@ from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from typing_extensions import override
|
||||
|
||||
from babase._stringedit import StringEditAdapter
|
||||
import _babase
|
||||
|
||||
@ -24,9 +26,11 @@ class DevConsoleStringEditAdapter(StringEditAdapter):
|
||||
description, initial_text, max_length, screen_space_center
|
||||
)
|
||||
|
||||
@override
|
||||
def _do_apply(self, new_text: str) -> None:
|
||||
_babase.set_dev_console_input_text(new_text)
|
||||
_babase.dev_console_input_adapter_finish()
|
||||
|
||||
@override
|
||||
def _do_cancel(self) -> None:
|
||||
_babase.dev_console_input_adapter_finish()
|
||||
|
||||
@ -136,7 +136,9 @@ def create_user_system_scripts() -> None:
|
||||
path = f'{env.python_directory_user}/sys/{env.version}'
|
||||
pathtmp = path + '_tmp'
|
||||
if os.path.exists(path):
|
||||
shutil.rmtree(path)
|
||||
print('Delete Existing User Scripts and try again.')
|
||||
_babase.screenmessage('Delete Existing User Scripts and try again.')
|
||||
return
|
||||
if os.path.exists(pathtmp):
|
||||
shutil.rmtree(pathtmp)
|
||||
|
||||
@ -159,6 +161,7 @@ def create_user_system_scripts() -> None:
|
||||
f"'\nRestart {_babase.appname()} to use them."
|
||||
f' (use babase.quit() to exit the game)'
|
||||
)
|
||||
_babase.screenmessage('Created User System Scripts')
|
||||
if app.classic is not None and app.classic.platform == 'android':
|
||||
print(
|
||||
'Note: the new files may not be visible via '
|
||||
@ -183,6 +186,7 @@ def delete_user_system_scripts() -> None:
|
||||
f'Restart {_babase.appname()} to use internal'
|
||||
f' scripts. (use babase.quit() to exit the game)'
|
||||
)
|
||||
_babase.screenmessage('Deleted User System Scripts')
|
||||
else:
|
||||
print(f"User system scripts not found at '{path}'.")
|
||||
|
||||
|
||||
@ -152,9 +152,9 @@ class AccountV1Subsystem:
|
||||
"""(internal)"""
|
||||
|
||||
for entry in info:
|
||||
cache_entry = self.tournament_info[
|
||||
entry['tournamentID']
|
||||
] = copy.deepcopy(entry)
|
||||
cache_entry = self.tournament_info[entry['tournamentID']] = (
|
||||
copy.deepcopy(entry)
|
||||
)
|
||||
|
||||
# Also store the time we received this, so we can adjust
|
||||
# time-remaining values/etc.
|
||||
|
||||
@ -75,9 +75,9 @@ class AchievementSubsystem:
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.achievements: list[Achievement] = []
|
||||
self.achievements_to_display: (
|
||||
list[tuple[baclassic.Achievement, bool]]
|
||||
) = []
|
||||
self.achievements_to_display: list[
|
||||
tuple[baclassic.Achievement, bool]
|
||||
] = []
|
||||
self.achievement_display_timer: bascenev1.BaseTimer | None = None
|
||||
self.last_achievement_display_time: float = 0.0
|
||||
self.achievement_completion_banner_slots: set[int] = set()
|
||||
|
||||
@ -229,9 +229,7 @@ class AdsSubsystem:
|
||||
await asyncio.sleep(1.0)
|
||||
payload.run(fallback=True)
|
||||
|
||||
_fallback_task = babase.app.aioloop.create_task(
|
||||
add_fallback_task()
|
||||
)
|
||||
babase.app.create_async_task(add_fallback_task())
|
||||
self.show_ad('between_game', on_completion_call=payload.run)
|
||||
else:
|
||||
babase.pushcall(call) # Just run the callback without the ad.
|
||||
|
||||
@ -7,6 +7,7 @@ import random
|
||||
from dataclasses import dataclass
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from typing_extensions import override
|
||||
import babase
|
||||
import bascenev1
|
||||
import _baclassic
|
||||
@ -43,6 +44,7 @@ def run_cpu_benchmark() -> None:
|
||||
cfg['Graphics Quality'] = self._old_quality
|
||||
cfg.apply()
|
||||
|
||||
@override
|
||||
def on_player_request(self, player: bascenev1.SessionPlayer) -> bool:
|
||||
return False
|
||||
|
||||
|
||||
@ -9,6 +9,7 @@ import threading
|
||||
from enum import Enum
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from typing_extensions import override
|
||||
import babase
|
||||
import bascenev1
|
||||
|
||||
@ -68,6 +69,7 @@ class MasterServerV1CallThread(threading.Thread):
|
||||
with self._context:
|
||||
self._callback(arg)
|
||||
|
||||
@override
|
||||
def run(self) -> None:
|
||||
# pylint: disable=consider-using-with
|
||||
# pylint: disable=too-many-branches
|
||||
|
||||
@ -310,9 +310,7 @@ class ServerController:
|
||||
typename = (
|
||||
'teams'
|
||||
if result['playlistType'] == 'Team Tournament'
|
||||
else 'ffa'
|
||||
if result['playlistType'] == 'Free-for-All'
|
||||
else '??'
|
||||
else 'ffa' if result['playlistType'] == 'Free-for-All' else '??'
|
||||
)
|
||||
plistname = result['playlistName']
|
||||
print(f'{Clr.SBLU}Got playlist: "{plistname}" ({typename}).{Clr.RST}')
|
||||
@ -390,14 +388,14 @@ class ServerController:
|
||||
|
||||
if sessiontype is bascenev1.FreeForAllSession:
|
||||
appcfg['Free-for-All Playlist Selection'] = self._playlist_name
|
||||
appcfg[
|
||||
'Free-for-All Playlist Randomize'
|
||||
] = self._config.playlist_shuffle
|
||||
appcfg['Free-for-All Playlist Randomize'] = (
|
||||
self._config.playlist_shuffle
|
||||
)
|
||||
elif sessiontype is bascenev1.DualTeamSession:
|
||||
appcfg['Team Tournament Playlist Selection'] = self._playlist_name
|
||||
appcfg[
|
||||
'Team Tournament Playlist Randomize'
|
||||
] = self._config.playlist_shuffle
|
||||
appcfg['Team Tournament Playlist Randomize'] = (
|
||||
self._config.playlist_shuffle
|
||||
)
|
||||
elif sessiontype is bascenev1.CoopSession:
|
||||
classic.coop_session_args = {
|
||||
'campaign': self._config.coop_campaign,
|
||||
@ -406,6 +404,10 @@ class ServerController:
|
||||
else:
|
||||
raise RuntimeError(f'Unknown session type {sessiontype}')
|
||||
|
||||
appcfg['Teams Series Length'] = self._config.teams_series_length
|
||||
appcfg['FFA Series Length'] = self._config.ffa_series_length
|
||||
|
||||
# deprecated, left here in order to not break mods
|
||||
classic.teams_series_length = self._config.teams_series_length
|
||||
classic.ffa_series_length = self._config.ffa_series_length
|
||||
|
||||
@ -427,6 +429,10 @@ class ServerController:
|
||||
self._config.player_rejoin_cooldown
|
||||
)
|
||||
|
||||
bascenev1.set_max_players_override(
|
||||
self._config.session_max_players_override
|
||||
)
|
||||
|
||||
# And here.. we.. go.
|
||||
if self._config.stress_test_players is not None:
|
||||
# Special case: run a stress test.
|
||||
|
||||
@ -8,6 +8,7 @@ import random
|
||||
import logging
|
||||
import weakref
|
||||
|
||||
from typing_extensions import override
|
||||
from efro.dataclassio import dataclass_from_dict
|
||||
import babase
|
||||
import bauiv1
|
||||
@ -102,8 +103,8 @@ class ClassicSubsystem(babase.AppSubsystem):
|
||||
self.maps: dict[str, type[bascenev1.Map]] = {}
|
||||
|
||||
# Gameplay.
|
||||
self.teams_series_length = 7
|
||||
self.ffa_series_length = 24
|
||||
self.teams_series_length = 7 # deprecated, left for old mods
|
||||
self.ffa_series_length = 24 # deprecated, left for old mods
|
||||
self.coop_session_args: dict = {}
|
||||
|
||||
# UI.
|
||||
@ -149,6 +150,7 @@ class ClassicSubsystem(babase.AppSubsystem):
|
||||
assert isinstance(self._env['legacy_user_agent_string'], str)
|
||||
return self._env['legacy_user_agent_string']
|
||||
|
||||
@override
|
||||
def on_app_loading(self) -> None:
|
||||
from bascenev1lib.actor import spazappearance
|
||||
from bascenev1lib import maps as stdmaps
|
||||
@ -230,13 +232,16 @@ class ClassicSubsystem(babase.AppSubsystem):
|
||||
|
||||
self.accounts.on_app_loading()
|
||||
|
||||
@override
|
||||
def on_app_suspend(self) -> None:
|
||||
self.accounts.on_app_suspend()
|
||||
|
||||
@override
|
||||
def on_app_unsuspend(self) -> None:
|
||||
self.accounts.on_app_unsuspend()
|
||||
self.music.on_app_unsuspend()
|
||||
|
||||
@override
|
||||
def on_app_shutdown(self) -> None:
|
||||
self.music.on_app_shutdown()
|
||||
|
||||
|
||||
@ -35,9 +35,11 @@ def get_tournament_prize_strings(entry: dict[str, Any]) -> list[str]:
|
||||
prval = (
|
||||
''
|
||||
if rng is None
|
||||
else ('#' + str(rng[0]))
|
||||
if (rng[0] == rng[1])
|
||||
else ('#' + str(rng[0]) + '-' + str(rng[1]))
|
||||
else (
|
||||
('#' + str(rng[0]))
|
||||
if (rng[0] == rng[1])
|
||||
else ('#' + str(rng[0]) + '-' + str(rng[1]))
|
||||
)
|
||||
)
|
||||
pvval = ''
|
||||
if trophy_type is not None:
|
||||
|
||||
@ -8,6 +8,7 @@ import threading
|
||||
from collections import deque
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from typing_extensions import override
|
||||
import babase
|
||||
|
||||
from baclassic._music import MusicPlayer
|
||||
@ -27,6 +28,7 @@ class MacMusicAppMusicPlayer(MusicPlayer):
|
||||
self._thread = _MacMusicAppThread()
|
||||
self._thread.start()
|
||||
|
||||
@override
|
||||
def on_select_entry(
|
||||
self,
|
||||
callback: Callable[[Any], None],
|
||||
@ -40,6 +42,7 @@ class MacMusicAppMusicPlayer(MusicPlayer):
|
||||
callback, current_entry, selection_target_name
|
||||
)
|
||||
|
||||
@override
|
||||
def on_set_volume(self, volume: float) -> None:
|
||||
self._thread.set_volume(volume)
|
||||
|
||||
@ -47,6 +50,7 @@ class MacMusicAppMusicPlayer(MusicPlayer):
|
||||
"""Asynchronously fetch the list of available iTunes playlists."""
|
||||
self._thread.get_playlists(callback)
|
||||
|
||||
@override
|
||||
def on_play(self, entry: Any) -> None:
|
||||
assert babase.app.classic is not None
|
||||
music = babase.app.classic.music
|
||||
@ -59,9 +63,11 @@ class MacMusicAppMusicPlayer(MusicPlayer):
|
||||
entry_type,
|
||||
)
|
||||
|
||||
@override
|
||||
def on_stop(self) -> None:
|
||||
self._thread.play_playlist(None)
|
||||
|
||||
@override
|
||||
def on_app_shutdown(self) -> None:
|
||||
self._thread.shutdown()
|
||||
|
||||
@ -77,6 +83,7 @@ class _MacMusicAppThread(threading.Thread):
|
||||
self._current_playlist: str | None = None
|
||||
self._orig_volume: int | None = None
|
||||
|
||||
@override
|
||||
def run(self) -> None:
|
||||
"""Run the Music.app thread."""
|
||||
babase.set_thread_name('BA_MacMusicAppThread')
|
||||
|
||||
@ -9,6 +9,7 @@ import logging
|
||||
import threading
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from typing_extensions import override
|
||||
import babase
|
||||
|
||||
from baclassic._music import MusicPlayer
|
||||
@ -33,6 +34,7 @@ class OSMusicPlayer(MusicPlayer):
|
||||
# FIXME: should ask the C++ layer for these; just hard-coding for now.
|
||||
return ['mp3', 'ogg', 'm4a', 'wav', 'flac', 'mid']
|
||||
|
||||
@override
|
||||
def on_select_entry(
|
||||
self,
|
||||
callback: Callable[[Any], None],
|
||||
@ -48,9 +50,11 @@ class OSMusicPlayer(MusicPlayer):
|
||||
callback, current_entry, selection_target_name
|
||||
)
|
||||
|
||||
@override
|
||||
def on_set_volume(self, volume: float) -> None:
|
||||
babase.music_player_set_volume(volume)
|
||||
|
||||
@override
|
||||
def on_play(self, entry: Any) -> None:
|
||||
assert babase.app.classic is not None
|
||||
music = babase.app.classic.music
|
||||
@ -99,11 +103,13 @@ class OSMusicPlayer(MusicPlayer):
|
||||
self._actually_playing = True
|
||||
babase.music_player_play(result)
|
||||
|
||||
@override
|
||||
def on_stop(self) -> None:
|
||||
self._want_to_play = False
|
||||
self._actually_playing = False
|
||||
babase.music_player_stop()
|
||||
|
||||
@override
|
||||
def on_app_shutdown(self) -> None:
|
||||
babase.music_player_shutdown()
|
||||
|
||||
@ -120,6 +126,7 @@ class _PickFolderSongThread(threading.Thread):
|
||||
self._callback = callback
|
||||
self._path = path
|
||||
|
||||
@override
|
||||
def run(self) -> None:
|
||||
do_log_error = True
|
||||
try:
|
||||
|
||||
@ -52,7 +52,7 @@ if TYPE_CHECKING:
|
||||
|
||||
# Build number and version of the ballistica binary we expect to be
|
||||
# using.
|
||||
TARGET_BALLISTICA_BUILD = 21757
|
||||
TARGET_BALLISTICA_BUILD = 21775
|
||||
TARGET_BALLISTICA_VERSION = '1.7.33'
|
||||
|
||||
|
||||
@ -264,6 +264,10 @@ def _calc_data_dir(data_dir: str | None) -> str:
|
||||
def _setup_logging() -> LogHandler:
|
||||
from efro.log import setup_logging, LogLevel
|
||||
|
||||
# TODO: should set this up with individual loggers under a top level
|
||||
# 'ba' logger, and at that point we can kill off the
|
||||
# suppress_non_root_debug option since we'll only ever need to set
|
||||
# 'ba' to DEBUG at most.
|
||||
log_handler = setup_logging(
|
||||
log_path=None,
|
||||
level=LogLevel.DEBUG,
|
||||
@ -287,9 +291,9 @@ def _setup_certs(contains_python_dist: bool) -> None:
|
||||
import certifi
|
||||
|
||||
# Let both OpenSSL and requests (if present) know to use this.
|
||||
os.environ['SSL_CERT_FILE'] = os.environ[
|
||||
'REQUESTS_CA_BUNDLE'
|
||||
] = certifi.where()
|
||||
os.environ['SSL_CERT_FILE'] = os.environ['REQUESTS_CA_BUNDLE'] = (
|
||||
certifi.where()
|
||||
)
|
||||
|
||||
|
||||
def _setup_paths(
|
||||
|
||||
@ -16,9 +16,11 @@ from __future__ import annotations
|
||||
|
||||
import logging
|
||||
|
||||
from baplus._cloud import CloudSubsystem
|
||||
from baplus._subsystem import PlusSubsystem
|
||||
|
||||
__all__ = [
|
||||
'CloudSubsystem',
|
||||
'PlusSubsystem',
|
||||
]
|
||||
|
||||
|
||||
@ -7,8 +7,7 @@ from __future__ import annotations
|
||||
import logging
|
||||
from typing import TYPE_CHECKING, overload
|
||||
|
||||
import _babase
|
||||
from babase._appsubsystem import AppSubsystem
|
||||
import babase
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Callable, Any
|
||||
@ -23,7 +22,7 @@ DEBUG_LOG = False
|
||||
# internal protocols.
|
||||
|
||||
|
||||
class CloudSubsystem(AppSubsystem):
|
||||
class CloudSubsystem(babase.AppSubsystem):
|
||||
"""Manages communication with cloud components."""
|
||||
|
||||
@property
|
||||
@ -44,7 +43,7 @@ class CloudSubsystem(AppSubsystem):
|
||||
if DEBUG_LOG:
|
||||
logging.debug('CloudSubsystem: Connectivity is now %s.', connected)
|
||||
|
||||
plus = _babase.app.plus
|
||||
plus = babase.app.plus
|
||||
assert plus is not None
|
||||
|
||||
# Inform things that use this.
|
||||
@ -58,8 +57,7 @@ class CloudSubsystem(AppSubsystem):
|
||||
on_response: Callable[
|
||||
[bacommon.cloud.LoginProxyRequestResponse | Exception], None
|
||||
],
|
||||
) -> None:
|
||||
...
|
||||
) -> None: ...
|
||||
|
||||
@overload
|
||||
def send_message_cb(
|
||||
@ -68,24 +66,21 @@ class CloudSubsystem(AppSubsystem):
|
||||
on_response: Callable[
|
||||
[bacommon.cloud.LoginProxyStateQueryResponse | Exception], None
|
||||
],
|
||||
) -> None:
|
||||
...
|
||||
) -> None: ...
|
||||
|
||||
@overload
|
||||
def send_message_cb(
|
||||
self,
|
||||
msg: bacommon.cloud.LoginProxyCompleteMessage,
|
||||
on_response: Callable[[None | Exception], None],
|
||||
) -> None:
|
||||
...
|
||||
) -> None: ...
|
||||
|
||||
@overload
|
||||
def send_message_cb(
|
||||
self,
|
||||
msg: bacommon.cloud.PingMessage,
|
||||
on_response: Callable[[bacommon.cloud.PingResponse | Exception], None],
|
||||
) -> None:
|
||||
...
|
||||
) -> None: ...
|
||||
|
||||
@overload
|
||||
def send_message_cb(
|
||||
@ -94,8 +89,7 @@ class CloudSubsystem(AppSubsystem):
|
||||
on_response: Callable[
|
||||
[bacommon.cloud.SignInResponse | Exception], None
|
||||
],
|
||||
) -> None:
|
||||
...
|
||||
) -> None: ...
|
||||
|
||||
@overload
|
||||
def send_message_cb(
|
||||
@ -104,8 +98,7 @@ class CloudSubsystem(AppSubsystem):
|
||||
on_response: Callable[
|
||||
[bacommon.cloud.ManageAccountResponse | Exception], None
|
||||
],
|
||||
) -> None:
|
||||
...
|
||||
) -> None: ...
|
||||
|
||||
def send_message_cb(
|
||||
self,
|
||||
@ -117,12 +110,11 @@ class CloudSubsystem(AppSubsystem):
|
||||
The provided on_response call will be run in the logic thread
|
||||
and passed either the response or the error that occurred.
|
||||
"""
|
||||
from babase._general import Call
|
||||
|
||||
del msg # Unused.
|
||||
|
||||
_babase.pushcall(
|
||||
Call(
|
||||
babase.pushcall(
|
||||
babase.Call(
|
||||
on_response,
|
||||
RuntimeError('Cloud functionality is not available.'),
|
||||
)
|
||||
@ -131,20 +123,17 @@ class CloudSubsystem(AppSubsystem):
|
||||
@overload
|
||||
def send_message(
|
||||
self, msg: bacommon.cloud.WorkspaceFetchMessage
|
||||
) -> bacommon.cloud.WorkspaceFetchResponse:
|
||||
...
|
||||
) -> bacommon.cloud.WorkspaceFetchResponse: ...
|
||||
|
||||
@overload
|
||||
def send_message(
|
||||
self, msg: bacommon.cloud.MerchAvailabilityMessage
|
||||
) -> bacommon.cloud.MerchAvailabilityResponse:
|
||||
...
|
||||
) -> bacommon.cloud.MerchAvailabilityResponse: ...
|
||||
|
||||
@overload
|
||||
def send_message(
|
||||
self, msg: bacommon.cloud.TestMessage
|
||||
) -> bacommon.cloud.TestResponse:
|
||||
...
|
||||
) -> bacommon.cloud.TestResponse: ...
|
||||
|
||||
def send_message(self, msg: Message) -> Response | None:
|
||||
"""Synchronously send a message to the cloud.
|
||||
@ -153,6 +142,23 @@ class CloudSubsystem(AppSubsystem):
|
||||
"""
|
||||
raise RuntimeError('Cloud functionality is not available.')
|
||||
|
||||
@overload
|
||||
async def send_message_async(
|
||||
self, msg: bacommon.cloud.PromoCodeMessage
|
||||
) -> bacommon.cloud.PromoCodeResponse: ...
|
||||
|
||||
@overload
|
||||
async def send_message_async(
|
||||
self, msg: bacommon.cloud.TestMessage
|
||||
) -> bacommon.cloud.TestResponse: ...
|
||||
|
||||
async def send_message_async(self, msg: Message) -> Response | None:
|
||||
"""Synchronously send a message to the cloud.
|
||||
|
||||
Must be called from the logic thread.
|
||||
"""
|
||||
raise RuntimeError('Cloud functionality is not available.')
|
||||
|
||||
|
||||
def cloud_console_exec(code: str) -> None:
|
||||
"""Called by the cloud console to run code in the logic thread."""
|
||||
@ -188,7 +194,7 @@ def cloud_console_exec(code: str) -> None:
|
||||
except Exception:
|
||||
import traceback
|
||||
|
||||
apptime = _babase.apptime()
|
||||
apptime = babase.apptime()
|
||||
print(f'Exec error at time {apptime:.2f}.', file=sys.stderr)
|
||||
traceback.print_exc()
|
||||
|
||||
@ -5,13 +5,17 @@ from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import _baplus
|
||||
from typing_extensions import override
|
||||
from babase import AppSubsystem
|
||||
|
||||
import _baplus
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Callable, Any
|
||||
|
||||
from babase import CloudSubsystem, AccountV2Subsystem
|
||||
from babase import AccountV2Subsystem
|
||||
|
||||
from baplus._cloud import CloudSubsystem
|
||||
|
||||
|
||||
class PlusSubsystem(AppSubsystem):
|
||||
@ -32,6 +36,7 @@ class PlusSubsystem(AppSubsystem):
|
||||
accounts: AccountV2Subsystem
|
||||
cloud: CloudSubsystem
|
||||
|
||||
@override
|
||||
def on_app_loading(self) -> None:
|
||||
_baplus.on_app_loading()
|
||||
self.accounts.on_app_loading()
|
||||
|
||||
@ -231,7 +231,11 @@ from bascenev1._settings import (
|
||||
IntSetting,
|
||||
Setting,
|
||||
)
|
||||
from bascenev1._session import Session, set_player_rejoin_cooldown
|
||||
from bascenev1._session import (
|
||||
Session,
|
||||
set_player_rejoin_cooldown,
|
||||
set_max_players_override,
|
||||
)
|
||||
from bascenev1._stats import PlayerScoredMessage, PlayerRecord, Stats
|
||||
from bascenev1._team import SessionTeam, Team, EmptyTeam
|
||||
from bascenev1._teamgame import TeamGameActivity
|
||||
@ -426,6 +430,7 @@ __all__ = [
|
||||
'set_public_party_queue_enabled',
|
||||
'set_public_party_stats_url',
|
||||
'set_player_rejoin_cooldown',
|
||||
'set_max_players_override',
|
||||
'set_replay_speed_exponent',
|
||||
'set_touchscreen_editing',
|
||||
'setmusic',
|
||||
|
||||
@ -5,6 +5,7 @@ from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from typing_extensions import override
|
||||
import babase
|
||||
|
||||
import _bascenev1
|
||||
@ -34,11 +35,13 @@ class EndSessionActivity(Activity[EmptyPlayer, EmptyTeam]):
|
||||
self.inherits_vr_camera_offset = True
|
||||
self.inherits_vr_overlay_center = True
|
||||
|
||||
@override
|
||||
def on_transition_in(self) -> None:
|
||||
super().on_transition_in()
|
||||
babase.fade_screen(False)
|
||||
babase.lock_all_input()
|
||||
|
||||
@override
|
||||
def on_begin(self) -> None:
|
||||
# pylint: disable=cyclic-import
|
||||
|
||||
@ -77,6 +80,7 @@ class JoinActivity(Activity[EmptyPlayer, EmptyTeam]):
|
||||
self._tips_text: bascenev1.Actor | None = None
|
||||
self._join_info: JoinInfo | None = None
|
||||
|
||||
@override
|
||||
def on_transition_in(self) -> None:
|
||||
# pylint: disable=cyclic-import
|
||||
from bascenev1lib.actor.tipstext import TipsText
|
||||
@ -110,6 +114,7 @@ class TransitionActivity(Activity[EmptyPlayer, EmptyTeam]):
|
||||
super().__init__(settings)
|
||||
self._background: bascenev1.Actor | None = None
|
||||
|
||||
@override
|
||||
def on_transition_in(self) -> None:
|
||||
# pylint: disable=cyclic-import
|
||||
from bascenev1lib.actor.background import Background
|
||||
@ -119,6 +124,7 @@ class TransitionActivity(Activity[EmptyPlayer, EmptyTeam]):
|
||||
fade_time=0.5, start_faded=False, show_logo=False
|
||||
)
|
||||
|
||||
@override
|
||||
def on_begin(self) -> None:
|
||||
super().on_begin()
|
||||
|
||||
@ -152,6 +158,7 @@ class ScoreScreenActivity(Activity[EmptyPlayer, EmptyTeam]):
|
||||
self._custom_continue_message: babase.Lstr | None = None
|
||||
self._server_transitioning: bool | None = None
|
||||
|
||||
@override
|
||||
def on_player_join(self, player: EmptyPlayer) -> None:
|
||||
super().on_player_join(player)
|
||||
time_till_assign = max(
|
||||
@ -164,6 +171,7 @@ class ScoreScreenActivity(Activity[EmptyPlayer, EmptyTeam]):
|
||||
time_till_assign, babase.WeakCall(self._safe_assign, player)
|
||||
)
|
||||
|
||||
@override
|
||||
def on_transition_in(self) -> None:
|
||||
from bascenev1lib.actor.tipstext import TipsText
|
||||
from bascenev1lib.actor.background import Background
|
||||
@ -176,6 +184,7 @@ class ScoreScreenActivity(Activity[EmptyPlayer, EmptyTeam]):
|
||||
self._tips_text = TipsText()
|
||||
setmusic(self.default_music)
|
||||
|
||||
@override
|
||||
def on_begin(self) -> None:
|
||||
# pylint: disable=cyclic-import
|
||||
from bascenev1lib.actor.text import Text
|
||||
@ -194,9 +203,11 @@ class ScoreScreenActivity(Activity[EmptyPlayer, EmptyTeam]):
|
||||
sval = babase.Lstr(resource='pressAnyButtonText')
|
||||
|
||||
Text(
|
||||
self._custom_continue_message
|
||||
if self._custom_continue_message is not None
|
||||
else sval,
|
||||
(
|
||||
self._custom_continue_message
|
||||
if self._custom_continue_message is not None
|
||||
else sval
|
||||
),
|
||||
v_attach=Text.VAttach.BOTTOM,
|
||||
h_align=Text.HAlign.CENTER,
|
||||
flash=True,
|
||||
|
||||
@ -198,12 +198,14 @@ class Actor:
|
||||
# Overloads to convey our exact return type depending on 'doraise' value.
|
||||
|
||||
@overload
|
||||
def getactivity(self, doraise: Literal[True] = True) -> bascenev1.Activity:
|
||||
...
|
||||
def getactivity(
|
||||
self, doraise: Literal[True] = True
|
||||
) -> bascenev1.Activity: ...
|
||||
|
||||
@overload
|
||||
def getactivity(self, doraise: Literal[False]) -> bascenev1.Activity | None:
|
||||
...
|
||||
def getactivity(
|
||||
self, doraise: Literal[False]
|
||||
) -> bascenev1.Activity | None: ...
|
||||
|
||||
def getactivity(self, doraise: bool = True) -> bascenev1.Activity | None:
|
||||
"""Return the bascenev1.Activity this Actor is associated with.
|
||||
|
||||
@ -5,6 +5,7 @@ from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from typing_extensions import override
|
||||
from bacommon.app import AppExperience
|
||||
from babase import (
|
||||
app,
|
||||
@ -23,15 +24,18 @@ if TYPE_CHECKING:
|
||||
class SceneV1AppMode(AppMode):
|
||||
"""Our app-mode."""
|
||||
|
||||
@override
|
||||
@classmethod
|
||||
def get_app_experience(cls) -> AppExperience:
|
||||
return AppExperience.MELEE
|
||||
|
||||
@override
|
||||
@classmethod
|
||||
def _supports_intent(cls, intent: AppIntent) -> bool:
|
||||
# We support default and exec intents currently.
|
||||
return isinstance(intent, AppIntentExec | AppIntentDefault)
|
||||
|
||||
@override
|
||||
def handle_intent(self, intent: AppIntent) -> None:
|
||||
if isinstance(intent, AppIntentExec):
|
||||
_bascenev1.handle_app_intent_exec(intent.code)
|
||||
@ -39,14 +43,17 @@ class SceneV1AppMode(AppMode):
|
||||
assert isinstance(intent, AppIntentDefault)
|
||||
_bascenev1.handle_app_intent_default()
|
||||
|
||||
@override
|
||||
def on_activate(self) -> None:
|
||||
# Let the native layer do its thing.
|
||||
_bascenev1.on_app_mode_activate()
|
||||
|
||||
@override
|
||||
def on_deactivate(self) -> None:
|
||||
# Let the native layer do its thing.
|
||||
_bascenev1.on_app_mode_deactivate()
|
||||
|
||||
@override
|
||||
def on_app_active_changed(self) -> None:
|
||||
# If we've gone inactive, bring up the main menu, which has the
|
||||
# side effect of pausing the action (when possible).
|
||||
|
||||
@ -6,6 +6,7 @@ from __future__ import annotations
|
||||
import logging
|
||||
from typing import TYPE_CHECKING, TypeVar
|
||||
|
||||
from typing_extensions import override
|
||||
import babase
|
||||
|
||||
import _bascenev1
|
||||
@ -31,6 +32,7 @@ class CoopGameActivity(GameActivity[PlayerT, TeamT]):
|
||||
# We can assume our session is a CoopSession.
|
||||
session: bascenev1.CoopSession
|
||||
|
||||
@override
|
||||
@classmethod
|
||||
def supports_session_type(
|
||||
cls, sessiontype: type[bascenev1.Session]
|
||||
@ -49,6 +51,7 @@ class CoopGameActivity(GameActivity[PlayerT, TeamT]):
|
||||
self._life_warning_beep_timer: bascenev1.Timer | None = None
|
||||
self._warn_beeps_sound = _bascenev1.getsound('warnBeeps')
|
||||
|
||||
@override
|
||||
def on_begin(self) -> None:
|
||||
super().on_begin()
|
||||
|
||||
@ -139,6 +142,7 @@ class CoopGameActivity(GameActivity[PlayerT, TeamT]):
|
||||
)
|
||||
vval -= 55
|
||||
|
||||
@override
|
||||
def spawn_player_spaz(
|
||||
self,
|
||||
player: PlayerT,
|
||||
|
||||
@ -5,6 +5,7 @@ from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from typing_extensions import override
|
||||
import babase
|
||||
|
||||
import _bascenev1
|
||||
@ -97,6 +98,7 @@ class CoopSession(Session):
|
||||
"""Get the game instance currently being played."""
|
||||
return self._current_game_instance
|
||||
|
||||
@override
|
||||
def should_allow_mid_activity_joins(
|
||||
self, activity: bascenev1.Activity
|
||||
) -> bool:
|
||||
@ -174,9 +176,11 @@ class CoopSession(Session):
|
||||
|
||||
self._tutorial_activity = _bascenev1.newactivity(TutorialActivity)
|
||||
|
||||
@override
|
||||
def get_custom_menu_entries(self) -> list[dict[str, Any]]:
|
||||
return self._custom_menu_ui
|
||||
|
||||
@override
|
||||
def on_player_leave(self, sessionplayer: bascenev1.SessionPlayer) -> None:
|
||||
super().on_player_leave(sessionplayer)
|
||||
|
||||
@ -256,6 +260,7 @@ class CoopSession(Session):
|
||||
activity.end(results={'outcome': 'restart'}, force=True)
|
||||
|
||||
# noinspection PyUnresolvedReferences
|
||||
@override
|
||||
def on_activity_end(
|
||||
self, activity: bascenev1.Activity, results: Any
|
||||
) -> None:
|
||||
|
||||
@ -7,6 +7,7 @@ from __future__ import annotations
|
||||
import weakref
|
||||
from typing import Generic, TypeVar, TYPE_CHECKING
|
||||
|
||||
from typing_extensions import override
|
||||
import babase
|
||||
|
||||
import _bascenev1
|
||||
@ -313,6 +314,7 @@ class AssetPackage(DependencyComponent):
|
||||
self.package_id = entry.config
|
||||
print(f'LOADING ASSET PACKAGE {self.package_id}')
|
||||
|
||||
@override
|
||||
@classmethod
|
||||
def dep_is_present(cls, config: Any = None) -> bool:
|
||||
assert isinstance(config, str)
|
||||
|
||||
@ -5,6 +5,7 @@ from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from typing_extensions import override
|
||||
import babase
|
||||
|
||||
import _bascenev1
|
||||
@ -32,6 +33,7 @@ class DualTeamSession(MultiTeamSession):
|
||||
babase.increment_analytics_count('Teams session start')
|
||||
super().__init__()
|
||||
|
||||
@override
|
||||
def _switch_to_score_screen(self, results: bascenev1.GameResults) -> None:
|
||||
# pylint: disable=cyclic-import
|
||||
from bascenev1lib.activity.multiteamvictory import (
|
||||
|
||||
@ -6,6 +6,7 @@ from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from typing_extensions import override
|
||||
import babase
|
||||
|
||||
import _bascenev1
|
||||
@ -53,6 +54,7 @@ class FreeForAllSession(MultiTeamSession):
|
||||
babase.increment_analytics_count('Free-for-all session start')
|
||||
super().__init__()
|
||||
|
||||
@override
|
||||
def _switch_to_score_screen(self, results: bascenev1.GameResults) -> None:
|
||||
# pylint: disable=cyclic-import
|
||||
from efro.util import asserttype
|
||||
|
||||
@ -9,6 +9,7 @@ import random
|
||||
import logging
|
||||
from typing import TYPE_CHECKING, TypeVar
|
||||
|
||||
from typing_extensions import override
|
||||
import babase
|
||||
|
||||
import _bascenev1
|
||||
@ -377,6 +378,7 @@ class GameActivity(Activity[PlayerT, TeamT]):
|
||||
"""
|
||||
return ''
|
||||
|
||||
@override
|
||||
def on_transition_in(self) -> None:
|
||||
super().on_transition_in()
|
||||
|
||||
@ -488,6 +490,7 @@ class GameActivity(Activity[PlayerT, TeamT]):
|
||||
|
||||
self.end_game()
|
||||
|
||||
@override
|
||||
def on_begin(self) -> None:
|
||||
super().on_begin()
|
||||
|
||||
@ -536,12 +539,14 @@ class GameActivity(Activity[PlayerT, TeamT]):
|
||||
max(5, data_t[0]['timeRemaining'])
|
||||
)
|
||||
|
||||
@override
|
||||
def on_player_join(self, player: PlayerT) -> None:
|
||||
super().on_player_join(player)
|
||||
|
||||
# By default, just spawn a dude.
|
||||
self.spawn_player(player)
|
||||
|
||||
@override
|
||||
def handlemessage(self, msg: Any) -> Any:
|
||||
if isinstance(msg, PlayerDiedMessage):
|
||||
# pylint: disable=cyclic-import
|
||||
@ -835,6 +840,7 @@ class GameActivity(Activity[PlayerT, TeamT]):
|
||||
animate(combine, 'input3', {0: 0, 1.0: 1, 4.0: 1, 5.0: 0})
|
||||
_bascenev1.timer(5.0, tnode.delete)
|
||||
|
||||
@override
|
||||
def end(
|
||||
self, results: Any = None, delay: float = 0.0, force: bool = False
|
||||
) -> None:
|
||||
|
||||
@ -42,9 +42,9 @@ class GameResults:
|
||||
self._scores: dict[
|
||||
int, tuple[weakref.ref[bascenev1.SessionTeam], int | None]
|
||||
] = {}
|
||||
self._sessionteams: list[
|
||||
weakref.ref[bascenev1.SessionTeam]
|
||||
] | None = None
|
||||
self._sessionteams: list[weakref.ref[bascenev1.SessionTeam]] | None = (
|
||||
None
|
||||
)
|
||||
self._playerinfos: list[bascenev1.PlayerInfo] | None = None
|
||||
self._lower_is_better: bool | None = None
|
||||
self._score_label: str | None = None
|
||||
|
||||
@ -7,6 +7,7 @@ import copy
|
||||
import weakref
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from typing_extensions import override
|
||||
import babase
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@ -38,6 +39,7 @@ class Level:
|
||||
self._index: int | None = None
|
||||
self._score_version_string: str | None = None
|
||||
|
||||
@override
|
||||
def __repr__(self) -> str:
|
||||
cls = type(self)
|
||||
return f"<{cls.__module__}.{cls.__name__} '{self._name}'>"
|
||||
@ -71,9 +73,11 @@ class Level:
|
||||
return babase.Lstr(
|
||||
translate=(
|
||||
'coopLevelNames',
|
||||
self._displayname
|
||||
if self._displayname is not None
|
||||
else self._name,
|
||||
(
|
||||
self._displayname
|
||||
if self._displayname is not None
|
||||
else self._name
|
||||
),
|
||||
),
|
||||
subs=[
|
||||
('${GAME}', self._gametype.get_display_string(self._settings))
|
||||
|
||||
@ -6,6 +6,7 @@ from __future__ import annotations
|
||||
import random
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from typing_extensions import override
|
||||
import babase
|
||||
|
||||
import _bascenev1
|
||||
@ -255,9 +256,7 @@ class Map(Actor):
|
||||
return (
|
||||
None
|
||||
if val is None
|
||||
else babase.vec3validate(val)
|
||||
if __debug__
|
||||
else val
|
||||
else babase.vec3validate(val) if __debug__ else val
|
||||
)
|
||||
|
||||
def get_def_points(self, name: str) -> list[Sequence[float]]:
|
||||
@ -333,8 +332,7 @@ class Map(Actor):
|
||||
closest_player_dist = 9999.0
|
||||
for ppt in player_pts:
|
||||
dist = (ppt - testpt).length()
|
||||
if dist < closest_player_dist:
|
||||
closest_player_dist = dist
|
||||
closest_player_dist = min(dist, closest_player_dist)
|
||||
if closest_player_dist > farthestpt_dist:
|
||||
farthestpt_dist = closest_player_dist
|
||||
farthestpt = testpt
|
||||
@ -353,9 +351,11 @@ class Map(Actor):
|
||||
return self.flag_points_default[:3]
|
||||
return self.flag_points[team_index % len(self.flag_points)][:3]
|
||||
|
||||
@override
|
||||
def exists(self) -> bool:
|
||||
return bool(self.node)
|
||||
|
||||
@override
|
||||
def handlemessage(self, msg: Any) -> Any:
|
||||
from bascenev1 import _messages
|
||||
|
||||
|
||||
@ -8,7 +8,9 @@ import random
|
||||
import logging
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from typing_extensions import override
|
||||
import babase
|
||||
|
||||
import _bascenev1
|
||||
from bascenev1._session import Session
|
||||
|
||||
@ -65,8 +67,8 @@ class MultiTeamSession(Session):
|
||||
max_players=self.get_max_players(),
|
||||
)
|
||||
|
||||
self._series_length: int = classic.teams_series_length
|
||||
self._ffa_series_length: int = classic.ffa_series_length
|
||||
self._series_length: int = int(cfg.get('Teams Series Length', 7))
|
||||
self._ffa_series_length: int = int(cfg.get('FFA Series Length', 24))
|
||||
|
||||
show_tutorial = cfg.get('Show Tutorial', True)
|
||||
|
||||
@ -160,6 +162,7 @@ class MultiTeamSession(Session):
|
||||
"""Returns which game in the series is currently being played."""
|
||||
return self._game_number
|
||||
|
||||
@override
|
||||
def on_team_join(self, team: bascenev1.SessionTeam) -> None:
|
||||
team.customdata['previous_score'] = team.customdata['score'] = 0
|
||||
|
||||
@ -178,6 +181,7 @@ class MultiTeamSession(Session):
|
||||
self._next_game_spec['settings'],
|
||||
)
|
||||
|
||||
@override
|
||||
def on_activity_end(
|
||||
self, activity: bascenev1.Activity, results: Any
|
||||
) -> None:
|
||||
|
||||
@ -6,6 +6,8 @@ from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from typing_extensions import override
|
||||
|
||||
from bascenev1._messages import DieMessage
|
||||
from bascenev1._actor import Actor
|
||||
|
||||
@ -28,6 +30,7 @@ class NodeActor(Actor):
|
||||
super().__init__()
|
||||
self.node = node
|
||||
|
||||
@override
|
||||
def handlemessage(self, msg: Any) -> Any:
|
||||
if isinstance(msg, DieMessage):
|
||||
if self.node:
|
||||
@ -35,5 +38,6 @@ class NodeActor(Actor):
|
||||
return None
|
||||
return super().handlemessage(msg)
|
||||
|
||||
@override
|
||||
def exists(self) -> bool:
|
||||
return bool(self.node)
|
||||
|
||||
@ -89,18 +89,18 @@ def filter_playlist(
|
||||
'bs_king_of_the_hill.KingOfTheHillGame',
|
||||
'bastd.game.kingofthehill.KingOfTheHillGame',
|
||||
):
|
||||
entry[
|
||||
'type'
|
||||
] = 'bascenev1lib.game.kingofthehill.KingOfTheHillGame'
|
||||
entry['type'] = (
|
||||
'bascenev1lib.game.kingofthehill.KingOfTheHillGame'
|
||||
)
|
||||
if entry['type'] in (
|
||||
'Capture_the_Flag.CTFGame',
|
||||
'bsCaptureTheFlag.CTFGame',
|
||||
'bs_capture_the_flag.CTFGame',
|
||||
'bastd.game.capturetheflag.CaptureTheFlagGame',
|
||||
):
|
||||
entry[
|
||||
'type'
|
||||
] = 'bascenev1lib.game.capturetheflag.CaptureTheFlagGame'
|
||||
entry['type'] = (
|
||||
'bascenev1lib.game.capturetheflag.CaptureTheFlagGame'
|
||||
)
|
||||
if entry['type'] in (
|
||||
'Death_Match.DeathMatchGame',
|
||||
'bsDeathMatch.DeathMatchGame',
|
||||
@ -163,25 +163,25 @@ def filter_playlist(
|
||||
'bs_easter_egg_hunt.EasterEggHuntGame',
|
||||
'bastd.game.easteregghunt.EasterEggHuntGame',
|
||||
):
|
||||
entry[
|
||||
'type'
|
||||
] = 'bascenev1lib.game.easteregghunt.EasterEggHuntGame'
|
||||
entry['type'] = (
|
||||
'bascenev1lib.game.easteregghunt.EasterEggHuntGame'
|
||||
)
|
||||
if entry['type'] in (
|
||||
'bsMeteorShower.MeteorShowerGame',
|
||||
'bs_meteor_shower.MeteorShowerGame',
|
||||
'bastd.game.meteorshower.MeteorShowerGame',
|
||||
):
|
||||
entry[
|
||||
'type'
|
||||
] = 'bascenev1lib.game.meteorshower.MeteorShowerGame'
|
||||
entry['type'] = (
|
||||
'bascenev1lib.game.meteorshower.MeteorShowerGame'
|
||||
)
|
||||
if entry['type'] in (
|
||||
'bsTargetPractice.TargetPracticeGame',
|
||||
'bs_target_practice.TargetPracticeGame',
|
||||
'bastd.game.targetpractice.TargetPracticeGame',
|
||||
):
|
||||
entry[
|
||||
'type'
|
||||
] = 'bascenev1lib.game.targetpractice.TargetPracticeGame'
|
||||
entry['type'] = (
|
||||
'bascenev1lib.game.targetpractice.TargetPracticeGame'
|
||||
)
|
||||
|
||||
gameclass = babase.getclass(entry['type'], GameActivity)
|
||||
|
||||
|
||||
@ -23,6 +23,9 @@ if TYPE_CHECKING:
|
||||
# such as skipping respawn waits.
|
||||
_g_player_rejoin_cooldown: float = 0.0
|
||||
|
||||
# overrides the session's decision of max_players
|
||||
_max_players_override: int | None = None
|
||||
|
||||
|
||||
def set_player_rejoin_cooldown(cooldown: float) -> None:
|
||||
"""Set the cooldown for individual players rejoining after leaving."""
|
||||
@ -30,6 +33,12 @@ def set_player_rejoin_cooldown(cooldown: float) -> None:
|
||||
_g_player_rejoin_cooldown = max(0.0, cooldown)
|
||||
|
||||
|
||||
def set_max_players_override(max_players: int | None) -> None:
|
||||
"""Set the override for how many players can join a session"""
|
||||
global _max_players_override # pylint: disable=global-statement
|
||||
_max_players_override = max_players
|
||||
|
||||
|
||||
class Session:
|
||||
"""Defines a high level series of bascenev1.Activity-es.
|
||||
|
||||
@ -161,7 +170,11 @@ class Session:
|
||||
self.sessionteams = []
|
||||
self.sessionplayers = []
|
||||
self.min_players = min_players
|
||||
self.max_players = max_players
|
||||
self.max_players = (
|
||||
max_players
|
||||
if _max_players_override is None
|
||||
else _max_players_override
|
||||
)
|
||||
|
||||
self.customdata = {}
|
||||
self._in_set_activity = False
|
||||
@ -255,7 +268,7 @@ class Session:
|
||||
babase.app.classic is not None
|
||||
and babase.app.classic.stress_test_update_timer is None
|
||||
):
|
||||
if len(self.sessionplayers) >= self.max_players:
|
||||
if len(self.sessionplayers) >= self.max_players >= 0:
|
||||
# Print a rejection message *only* to the client trying to
|
||||
# join (prevents spamming everyone else in the game).
|
||||
_bascenev1.getsound('error').play()
|
||||
|
||||
@ -7,6 +7,7 @@ from __future__ import annotations
|
||||
import logging
|
||||
from typing import TYPE_CHECKING, TypeVar
|
||||
|
||||
from typing_extensions import override
|
||||
import babase
|
||||
|
||||
import _bascenev1
|
||||
@ -35,6 +36,7 @@ class TeamGameActivity(GameActivity[PlayerT, TeamT]):
|
||||
bascenev1.Player has their own bascenev1.Team)
|
||||
"""
|
||||
|
||||
@override
|
||||
@classmethod
|
||||
def supports_session_type(
|
||||
cls, sessiontype: type[bascenev1.Session]
|
||||
@ -57,6 +59,7 @@ class TeamGameActivity(GameActivity[PlayerT, TeamT]):
|
||||
if isinstance(self.session, FreeForAllSession):
|
||||
self.show_kill_points = False
|
||||
|
||||
@override
|
||||
def on_transition_in(self) -> None:
|
||||
# pylint: disable=cyclic-import
|
||||
from bascenev1._coopsession import CoopSession
|
||||
@ -85,6 +88,7 @@ class TeamGameActivity(GameActivity[PlayerT, TeamT]):
|
||||
).autoretain()
|
||||
setattr(self.session, attrname, True)
|
||||
|
||||
@override
|
||||
def on_begin(self) -> None:
|
||||
super().on_begin()
|
||||
try:
|
||||
@ -104,6 +108,7 @@ class TeamGameActivity(GameActivity[PlayerT, TeamT]):
|
||||
except Exception:
|
||||
logging.exception('Error in on_begin.')
|
||||
|
||||
@override
|
||||
def spawn_player_spaz(
|
||||
self,
|
||||
player: PlayerT,
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing_extensions import override
|
||||
import bascenev1 as bs
|
||||
|
||||
|
||||
@ -18,6 +19,7 @@ class CoopJoinActivity(bs.JoinActivity):
|
||||
session = self.session
|
||||
assert isinstance(session, bs.CoopSession)
|
||||
|
||||
@override
|
||||
def on_transition_in(self) -> None:
|
||||
from bascenev1lib.actor.controlsguide import ControlsGuide
|
||||
from bascenev1lib.actor.text import Text
|
||||
|
||||
@ -9,6 +9,7 @@ import random
|
||||
import logging
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from typing_extensions import override
|
||||
from bacommon.login import LoginType
|
||||
import bascenev1 as bs
|
||||
import bauiv1 as bui
|
||||
@ -186,6 +187,7 @@ class CoopScoreScreen(bs.Activity[bs.Player, bs.Team]):
|
||||
|
||||
self._victory: bool = settings['outcome'] == 'victory'
|
||||
|
||||
@override
|
||||
def __del__(self) -> None:
|
||||
super().__del__()
|
||||
|
||||
@ -194,6 +196,7 @@ class CoopScoreScreen(bs.Activity[bs.Player, bs.Team]):
|
||||
with bui.ContextRef.empty():
|
||||
bui.containerwidget(edit=self._root_ui, transition='out_left')
|
||||
|
||||
@override
|
||||
def on_transition_in(self) -> None:
|
||||
from bascenev1lib.actor import background # FIXME NO BSSTD
|
||||
|
||||
@ -392,11 +395,15 @@ class CoopScoreScreen(bs.Activity[bs.Player, bs.Team]):
|
||||
color=(0.45, 0.4, 0.5),
|
||||
position=(160, v_offs + 480),
|
||||
size=(350, 62),
|
||||
label=bui.Lstr(resource='tournamentStandingsText')
|
||||
if self.session.tournament_id is not None
|
||||
else bui.Lstr(resource='worldsBestScoresText')
|
||||
if self._score_type == 'points'
|
||||
else bui.Lstr(resource='worldsBestTimesText'),
|
||||
label=(
|
||||
bui.Lstr(resource='tournamentStandingsText')
|
||||
if self.session.tournament_id is not None
|
||||
else (
|
||||
bui.Lstr(resource='worldsBestScoresText')
|
||||
if self._score_type == 'points'
|
||||
else bui.Lstr(resource='worldsBestTimesText')
|
||||
)
|
||||
),
|
||||
autoselect=True,
|
||||
on_activate_call=bui.WeakCall(self._ui_worlds_best),
|
||||
transition_delay=delay + 1.9,
|
||||
@ -512,9 +519,11 @@ class CoopScoreScreen(bs.Activity[bs.Player, bs.Team]):
|
||||
|
||||
bui.containerwidget(
|
||||
edit=rootc,
|
||||
selected_child=next_button
|
||||
if (self._newly_complete and self._victory and show_next_button)
|
||||
else restart_button,
|
||||
selected_child=(
|
||||
next_button
|
||||
if (self._newly_complete and self._victory and show_next_button)
|
||||
else restart_button
|
||||
),
|
||||
on_cancel_call=menu_button.activate,
|
||||
)
|
||||
|
||||
@ -574,6 +583,7 @@ class CoopScoreScreen(bs.Activity[bs.Player, bs.Team]):
|
||||
self._player_press,
|
||||
)
|
||||
|
||||
@override
|
||||
def on_player_join(self, player: bs.Player) -> None:
|
||||
super().on_player_join(player)
|
||||
|
||||
@ -585,6 +595,7 @@ class CoopScoreScreen(bs.Activity[bs.Player, bs.Team]):
|
||||
|
||||
bs.timer(time_till_assign, bs.WeakCall(self._safe_assign, player))
|
||||
|
||||
@override
|
||||
def on_begin(self) -> None:
|
||||
# FIXME: Clean this up.
|
||||
# pylint: disable=too-many-statements
|
||||
@ -639,14 +650,16 @@ class CoopScoreScreen(bs.Activity[bs.Player, bs.Team]):
|
||||
and not (env.demo or env.arcade)
|
||||
):
|
||||
Text(
|
||||
bs.Lstr(
|
||||
value='${A}:\n',
|
||||
subs=[('${A}', bs.Lstr(resource='levelUnlockedText'))],
|
||||
)
|
||||
if self._newly_complete
|
||||
else bs.Lstr(
|
||||
value='${A}:\n',
|
||||
subs=[('${A}', bs.Lstr(resource='nextLevelText'))],
|
||||
(
|
||||
bs.Lstr(
|
||||
value='${A}:\n',
|
||||
subs=[('${A}', bs.Lstr(resource='levelUnlockedText'))],
|
||||
)
|
||||
if self._newly_complete
|
||||
else bs.Lstr(
|
||||
value='${A}:\n',
|
||||
subs=[('${A}', bs.Lstr(resource='nextLevelText'))],
|
||||
)
|
||||
),
|
||||
transition=Text.Transition.IN_RIGHT,
|
||||
transition_delay=5.2,
|
||||
@ -855,11 +868,15 @@ class CoopScoreScreen(bs.Activity[bs.Player, bs.Team]):
|
||||
ts_h_offs = 210
|
||||
v_offs = 40
|
||||
txt = Text(
|
||||
bs.Lstr(resource='tournamentStandingsText')
|
||||
if self.session.tournament_id is not None
|
||||
else bs.Lstr(resource='worldsBestScoresText')
|
||||
if self._score_type == 'points'
|
||||
else bs.Lstr(resource='worldsBestTimesText'),
|
||||
(
|
||||
bs.Lstr(resource='tournamentStandingsText')
|
||||
if self.session.tournament_id is not None
|
||||
else (
|
||||
bs.Lstr(resource='worldsBestScoresText')
|
||||
if self._score_type == 'points'
|
||||
else bs.Lstr(resource='worldsBestTimesText')
|
||||
)
|
||||
),
|
||||
maxwidth=210,
|
||||
position=(ts_h_offs - 10, ts_height / 2 + 25 + v_offs + 20),
|
||||
transition=Text.Transition.IN_LEFT,
|
||||
@ -877,9 +894,11 @@ class CoopScoreScreen(bs.Activity[bs.Player, bs.Team]):
|
||||
ts_h_offs = -480
|
||||
v_offs = 40
|
||||
Text(
|
||||
bs.Lstr(resource='yourBestScoresText')
|
||||
if self._score_type == 'points'
|
||||
else bs.Lstr(resource='yourBestTimesText'),
|
||||
(
|
||||
bs.Lstr(resource='yourBestScoresText')
|
||||
if self._score_type == 'points'
|
||||
else bs.Lstr(resource='yourBestTimesText')
|
||||
),
|
||||
maxwidth=210,
|
||||
position=(ts_h_offs - 10, ts_height / 2 + 25 + v_offs + 20),
|
||||
transition=Text.Transition.IN_RIGHT,
|
||||
@ -943,9 +962,11 @@ class CoopScoreScreen(bs.Activity[bs.Player, bs.Team]):
|
||||
tdelay1 = times[i][0]
|
||||
tdelay2 = times[i][1]
|
||||
Text(
|
||||
str(display_scores[i][0])
|
||||
if self._score_type == 'points'
|
||||
else bs.timestring((display_scores[i][0] * 10) / 1000.0),
|
||||
(
|
||||
str(display_scores[i][0])
|
||||
if self._score_type == 'points'
|
||||
else bs.timestring((display_scores[i][0] * 10) / 1000.0)
|
||||
),
|
||||
position=(
|
||||
ts_h_offs + 20 + h_offs_extra,
|
||||
v_offs_extra
|
||||
@ -1122,9 +1143,11 @@ class CoopScoreScreen(bs.Activity[bs.Player, bs.Team]):
|
||||
tdelay2 = times[i][1]
|
||||
if name_str != '-':
|
||||
Text(
|
||||
str(score)
|
||||
if self._score_type == 'points'
|
||||
else bs.timestring((score * 10) / 1000.0),
|
||||
(
|
||||
str(score)
|
||||
if self._score_type == 'points'
|
||||
else bs.timestring((score * 10) / 1000.0)
|
||||
),
|
||||
position=(
|
||||
ts_h_offs + 20 + h_offs_extra,
|
||||
v_offs_extra
|
||||
@ -1308,9 +1331,11 @@ class CoopScoreScreen(bs.Activity[bs.Player, bs.Team]):
|
||||
|
||||
if name_str != '-':
|
||||
Text(
|
||||
str(score)
|
||||
if self._score_type == 'points'
|
||||
else bs.timestring((score * 10) / 1000.0),
|
||||
(
|
||||
str(score)
|
||||
if self._score_type == 'points'
|
||||
else bs.timestring((score * 10) / 1000.0)
|
||||
),
|
||||
position=(
|
||||
ts_h_offs + 20 + h_offs_extra,
|
||||
ts_height / 2
|
||||
@ -1684,17 +1709,22 @@ class CoopScoreScreen(bs.Activity[bs.Player, bs.Team]):
|
||||
)
|
||||
if not self._newly_complete:
|
||||
Text(
|
||||
bs.Lstr(
|
||||
value='${A}${B}',
|
||||
subs=[
|
||||
('${A}', bs.Lstr(resource='newPersonalBestText')),
|
||||
('${B}', was_string),
|
||||
],
|
||||
)
|
||||
if new_best
|
||||
else bs.Lstr(
|
||||
resource='bestRatingText',
|
||||
subs=[('${RATING}', str(best_rank))],
|
||||
(
|
||||
bs.Lstr(
|
||||
value='${A}${B}',
|
||||
subs=[
|
||||
(
|
||||
'${A}',
|
||||
bs.Lstr(resource='newPersonalBestText'),
|
||||
),
|
||||
('${B}', was_string),
|
||||
],
|
||||
)
|
||||
if new_best
|
||||
else bs.Lstr(
|
||||
resource='bestRatingText',
|
||||
subs=[('${RATING}', str(best_rank))],
|
||||
)
|
||||
),
|
||||
position=(0, -165),
|
||||
color=(1, 1, 1, 0.7),
|
||||
@ -1768,14 +1798,16 @@ class CoopScoreScreen(bs.Activity[bs.Player, bs.Team]):
|
||||
jitter=1.0,
|
||||
).autoretain()
|
||||
Text(
|
||||
bs.Lstr(
|
||||
value='${A}:',
|
||||
subs=[('${A}', bs.Lstr(resource='finalScoreText'))],
|
||||
)
|
||||
if self._score_type == 'points'
|
||||
else bs.Lstr(
|
||||
value='${A}:',
|
||||
subs=[('${A}', bs.Lstr(resource='finalTimeText'))],
|
||||
(
|
||||
bs.Lstr(
|
||||
value='${A}:',
|
||||
subs=[('${A}', bs.Lstr(resource='finalScoreText'))],
|
||||
)
|
||||
if self._score_type == 'points'
|
||||
else bs.Lstr(
|
||||
value='${A}:',
|
||||
subs=[('${A}', bs.Lstr(resource='finalTimeText'))],
|
||||
)
|
||||
),
|
||||
maxwidth=300,
|
||||
position=(0, 200),
|
||||
|
||||
@ -4,7 +4,9 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing_extensions import override
|
||||
import bascenev1 as bs
|
||||
|
||||
from bascenev1lib.activity.multiteamscore import MultiTeamScoreScreenActivity
|
||||
from bascenev1lib.actor.zoomtext import ZoomText
|
||||
|
||||
@ -14,6 +16,7 @@ class DrawScoreScreenActivity(MultiTeamScoreScreenActivity):
|
||||
|
||||
default_music = None # Awkward silence...
|
||||
|
||||
@override
|
||||
def on_begin(self) -> None:
|
||||
bs.set_analytics_screen('Draw Score Screen')
|
||||
super().on_begin()
|
||||
|
||||
@ -4,7 +4,9 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing_extensions import override
|
||||
import bascenev1 as bs
|
||||
|
||||
from bascenev1lib.activity.multiteamscore import MultiTeamScoreScreenActivity
|
||||
from bascenev1lib.actor.zoomtext import ZoomText
|
||||
|
||||
@ -17,6 +19,7 @@ class TeamVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
|
||||
self._winner: bs.SessionTeam = settings['winner']
|
||||
assert isinstance(self._winner, bs.SessionTeam)
|
||||
|
||||
@override
|
||||
def on_begin(self) -> None:
|
||||
bs.set_analytics_screen('Teams Score Screen')
|
||||
super().on_begin()
|
||||
|
||||
@ -6,9 +6,11 @@ from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from bascenev1lib.activity.multiteamscore import MultiTeamScoreScreenActivity
|
||||
from typing_extensions import override
|
||||
import bascenev1 as bs
|
||||
|
||||
from bascenev1lib.activity.multiteamscore import MultiTeamScoreScreenActivity
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any
|
||||
|
||||
@ -23,6 +25,7 @@ class FreeForAllVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
|
||||
self.transition_time = 0.5
|
||||
self._cymbal_sound = bs.getsound('cymbal')
|
||||
|
||||
@override
|
||||
def on_begin(self) -> None:
|
||||
# pylint: disable=too-many-locals
|
||||
# pylint: disable=too-many-statements
|
||||
|
||||
@ -4,7 +4,9 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing_extensions import override
|
||||
import bascenev1 as bs
|
||||
|
||||
from bascenev1lib.actor.text import Text
|
||||
|
||||
|
||||
@ -15,6 +17,7 @@ class MultiTeamJoinActivity(bs.JoinActivity):
|
||||
super().__init__(settings)
|
||||
self._next_up_text: Text | None = None
|
||||
|
||||
@override
|
||||
def on_transition_in(self) -> None:
|
||||
from bascenev1lib.actor.controlsguide import ControlsGuide
|
||||
|
||||
|
||||
@ -3,7 +3,9 @@
|
||||
"""Functionality related to teams mode score screen."""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing_extensions import override
|
||||
import bascenev1 as bs
|
||||
|
||||
from bascenev1lib.actor.text import Text
|
||||
from bascenev1lib.actor.image import Image
|
||||
|
||||
@ -18,6 +20,7 @@ class MultiTeamScoreScreenActivity(bs.ScoreScreenActivity):
|
||||
|
||||
self._show_up_next: bool = True
|
||||
|
||||
@override
|
||||
def on_begin(self) -> None:
|
||||
super().on_begin()
|
||||
session = self.session
|
||||
@ -196,9 +199,9 @@ class MultiTeamScoreScreenActivity(bs.ScoreScreenActivity):
|
||||
ts_v_offset + (voffs + 15) * scale,
|
||||
),
|
||||
scale=scale,
|
||||
color=(1.0, 0.9, 0.5, 1.0)
|
||||
if highlight
|
||||
else (0.5, 0.5, 0.6, 0.5),
|
||||
color=(
|
||||
(1.0, 0.9, 0.5, 1.0) if highlight else (0.5, 0.5, 0.6, 0.5)
|
||||
),
|
||||
h_align=Text.HAlign.RIGHT,
|
||||
v_align=Text.VAlign.CENTER,
|
||||
maxwidth=maxwidth,
|
||||
|
||||
@ -4,7 +4,9 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing_extensions import override
|
||||
import bascenev1 as bs
|
||||
|
||||
from bascenev1lib.activity.multiteamscore import MultiTeamScoreScreenActivity
|
||||
|
||||
|
||||
@ -22,6 +24,7 @@ class TeamSeriesVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
|
||||
self._tips_text = None
|
||||
self._default_show_tips = False
|
||||
|
||||
@override
|
||||
def on_begin(self) -> None:
|
||||
# pylint: disable=too-many-branches
|
||||
# pylint: disable=too-many-locals
|
||||
@ -371,9 +374,11 @@ class TeamSeriesVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
|
||||
tdelay -= 4 * t_incr
|
||||
v_offs -= 40
|
||||
Text(
|
||||
str(prec.team.customdata['score'])
|
||||
if self._is_ffa
|
||||
else str(prec.score),
|
||||
(
|
||||
str(prec.team.customdata['score'])
|
||||
if self._is_ffa
|
||||
else str(prec.score)
|
||||
),
|
||||
color=(0.5, 0.5, 0.5, 1.0),
|
||||
position=(ts_h_offs + 230, ts_height / 2 + v_offs),
|
||||
h_align=Text.HAlign.RIGHT,
|
||||
|
||||
@ -9,6 +9,7 @@ import weakref
|
||||
import logging
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from typing_extensions import override
|
||||
import bascenev1 as bs
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@ -104,6 +105,7 @@ class Background(bs.Actor):
|
||||
timeval += random.random() * 0.1
|
||||
bs.animate(cmb, 'input1', keys, loop=True)
|
||||
|
||||
@override
|
||||
def __del__(self) -> None:
|
||||
# Normal actors don't get sent DieMessages when their
|
||||
# activity is shutting down, but we still need to do so
|
||||
@ -138,6 +140,7 @@ class Background(bs.Actor):
|
||||
)
|
||||
bs.timer(self.fade_time + 0.1, self.node.delete)
|
||||
|
||||
@override
|
||||
def handlemessage(self, msg: Any) -> Any:
|
||||
assert not self.expired
|
||||
if isinstance(msg, bs.DieMessage):
|
||||
|
||||
@ -10,7 +10,9 @@ from __future__ import annotations
|
||||
import random
|
||||
from typing import TYPE_CHECKING, TypeVar
|
||||
|
||||
from typing_extensions import override
|
||||
import bascenev1 as bs
|
||||
|
||||
from bascenev1lib.gameutils import SharedObjects
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@ -661,6 +663,7 @@ class Blast(bs.Actor):
|
||||
|
||||
bs.timer(0.4, _extra_debris_sound)
|
||||
|
||||
@override
|
||||
def handlemessage(self, msg: Any) -> Any:
|
||||
assert not self.expired
|
||||
|
||||
@ -935,6 +938,7 @@ class Bomb(bs.Actor):
|
||||
else None
|
||||
)
|
||||
|
||||
@override
|
||||
def on_expire(self) -> None:
|
||||
super().on_expire()
|
||||
|
||||
@ -1140,6 +1144,7 @@ class Bomb(bs.Actor):
|
||||
if msg.srcnode:
|
||||
pass
|
||||
|
||||
@override
|
||||
def handlemessage(self, msg: Any) -> Any:
|
||||
if isinstance(msg, ExplodeMessage):
|
||||
self.explode()
|
||||
|
||||
@ -6,6 +6,7 @@ from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from typing_extensions import override
|
||||
import bascenev1 as bs
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@ -455,9 +456,11 @@ class ControlsGuide(bs.Actor):
|
||||
(
|
||||
'${B}',
|
||||
bs.Lstr(
|
||||
resource='holdAnyKeyText'
|
||||
if all_keyboards
|
||||
else 'holdAnyButtonText'
|
||||
resource=(
|
||||
'holdAnyKeyText'
|
||||
if all_keyboards
|
||||
else 'holdAnyButtonText'
|
||||
)
|
||||
),
|
||||
),
|
||||
],
|
||||
@ -547,9 +550,11 @@ class ControlsGuide(bs.Actor):
|
||||
self._update_timer = None
|
||||
self._dead = True
|
||||
|
||||
@override
|
||||
def exists(self) -> bool:
|
||||
return not self._dead
|
||||
|
||||
@override
|
||||
def handlemessage(self, msg: Any) -> Any:
|
||||
assert not self.expired
|
||||
if isinstance(msg, bs.DieMessage):
|
||||
|
||||
@ -7,9 +7,11 @@ from __future__ import annotations
|
||||
from dataclasses import dataclass
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from bascenev1lib.gameutils import SharedObjects
|
||||
from typing_extensions import override
|
||||
import bascenev1 as bs
|
||||
|
||||
from bascenev1lib.gameutils import SharedObjects
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any, Sequence
|
||||
|
||||
@ -328,6 +330,7 @@ class Flag(bs.Actor):
|
||||
1.0, bs.WeakCall(self._hide_score_text)
|
||||
)
|
||||
|
||||
@override
|
||||
def handlemessage(self, msg: Any) -> Any:
|
||||
assert not self.expired
|
||||
if isinstance(msg, bs.DieMessage):
|
||||
|
||||
@ -7,6 +7,7 @@ from __future__ import annotations
|
||||
from enum import Enum
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from typing_extensions import override
|
||||
import bascenev1 as bs
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@ -165,6 +166,7 @@ class Image(bs.Actor):
|
||||
bs.WeakCall(self.handlemessage, bs.DieMessage()),
|
||||
)
|
||||
|
||||
@override
|
||||
def handlemessage(self, msg: Any) -> Any:
|
||||
assert not self.expired
|
||||
if isinstance(msg, bs.DieMessage):
|
||||
|
||||
@ -6,6 +6,7 @@ from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from typing_extensions import override
|
||||
import bascenev1 as bs
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@ -72,6 +73,7 @@ class OnScreenCountdown(bs.Actor):
|
||||
)
|
||||
self._timer = bs.Timer(1.0, self._update, repeat=True)
|
||||
|
||||
@override
|
||||
def on_expire(self) -> None:
|
||||
super().on_expire()
|
||||
|
||||
|
||||
@ -6,6 +6,7 @@ from __future__ import annotations
|
||||
from typing import TYPE_CHECKING
|
||||
import logging
|
||||
|
||||
from typing_extensions import override
|
||||
import bascenev1 as bs
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@ -93,6 +94,7 @@ class OnScreenTimer(bs.Actor):
|
||||
"""Shortcut for start time in seconds."""
|
||||
return self.getstarttime()
|
||||
|
||||
@override
|
||||
def handlemessage(self, msg: Any) -> Any:
|
||||
# if we're asked to die, just kill our node/timer
|
||||
if isinstance(msg, bs.DieMessage):
|
||||
|
||||
@ -6,7 +6,9 @@ from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, TypeVar, overload
|
||||
|
||||
from typing_extensions import override
|
||||
import bascenev1 as bs
|
||||
|
||||
from bascenev1lib.actor.spaz import Spaz
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@ -77,14 +79,12 @@ class PlayerSpaz(Spaz):
|
||||
@overload
|
||||
def getplayer(
|
||||
self, playertype: type[PlayerT], doraise: Literal[False] = False
|
||||
) -> PlayerT | None:
|
||||
...
|
||||
) -> PlayerT | None: ...
|
||||
|
||||
@overload
|
||||
def getplayer(
|
||||
self, playertype: type[PlayerT], doraise: Literal[True]
|
||||
) -> PlayerT:
|
||||
...
|
||||
) -> PlayerT: ...
|
||||
|
||||
def getplayer(
|
||||
self, playertype: type[PlayerT], doraise: bool = False
|
||||
@ -183,6 +183,7 @@ class PlayerSpaz(Spaz):
|
||||
' non-connected player'
|
||||
)
|
||||
|
||||
@override
|
||||
def handlemessage(self, msg: Any) -> Any:
|
||||
# FIXME: Tidy this up.
|
||||
# pylint: disable=too-many-branches
|
||||
|
||||
@ -7,6 +7,7 @@ from __future__ import annotations
|
||||
import random
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from typing_extensions import override
|
||||
import bascenev1 as bs
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@ -118,6 +119,7 @@ class PopupText(bs.Actor):
|
||||
lifespan, bs.WeakCall(self.handlemessage, bs.DieMessage())
|
||||
)
|
||||
|
||||
@override
|
||||
def handlemessage(self, msg: Any) -> Any:
|
||||
assert not self.expired
|
||||
if isinstance(msg, bs.DieMessage):
|
||||
|
||||
@ -7,7 +7,9 @@ from __future__ import annotations
|
||||
import random
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from typing_extensions import override
|
||||
import bascenev1 as bs
|
||||
|
||||
from bascenev1lib.gameutils import SharedObjects
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@ -278,6 +280,7 @@ class PowerupBox(bs.Actor):
|
||||
if self.node:
|
||||
self.node.flashing = True
|
||||
|
||||
@override
|
||||
def handlemessage(self, msg: Any) -> Any:
|
||||
assert not self.expired
|
||||
|
||||
|
||||
@ -9,11 +9,13 @@ import random
|
||||
import logging
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from typing_extensions import override
|
||||
import bascenev1 as bs
|
||||
|
||||
from bascenev1lib.actor.bomb import Bomb, Blast
|
||||
from bascenev1lib.actor.powerupbox import PowerupBoxFactory
|
||||
from bascenev1lib.actor.powerupbox import PowerupBoxFactory, PowerupBox
|
||||
from bascenev1lib.actor.spazfactory import SpazFactory
|
||||
from bascenev1lib.gameutils import SharedObjects
|
||||
import bascenev1 as bs
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any, Sequence, Callable
|
||||
@ -228,9 +230,11 @@ class Spaz(bs.Actor):
|
||||
self.punch_callback: Callable[[Spaz], Any] | None = None
|
||||
self.pick_up_powerup_callback: Callable[[Spaz], Any] | None = None
|
||||
|
||||
@override
|
||||
def exists(self) -> bool:
|
||||
return bool(self.node)
|
||||
|
||||
@override
|
||||
def on_expire(self) -> None:
|
||||
super().on_expire()
|
||||
|
||||
@ -249,6 +253,7 @@ class Spaz(bs.Actor):
|
||||
assert not self.expired
|
||||
self._dropped_bomb_callbacks.append(call)
|
||||
|
||||
@override
|
||||
def is_alive(self) -> bool:
|
||||
"""
|
||||
Method override; returns whether ol' spaz is still kickin'.
|
||||
@ -624,7 +629,8 @@ class Spaz(bs.Actor):
|
||||
1000.0 * (tval + self.curse_time)
|
||||
)
|
||||
self._curse_timer = bs.Timer(
|
||||
5.0, bs.WeakCall(self.handlemessage, CurseExplodeMessage())
|
||||
self.curse_time,
|
||||
bs.WeakCall(self.handlemessage, CurseExplodeMessage()),
|
||||
)
|
||||
|
||||
def equip_boxing_gloves(self) -> None:
|
||||
@ -694,6 +700,7 @@ class Spaz(bs.Actor):
|
||||
else:
|
||||
self.shield_decay_timer = None
|
||||
|
||||
@override
|
||||
def handlemessage(self, msg: Any) -> Any:
|
||||
# pylint: disable=too-many-return-statements
|
||||
# pylint: disable=too-many-statements
|
||||
@ -1221,6 +1228,10 @@ class Spaz(bs.Actor):
|
||||
return None
|
||||
node = bs.getcollision().opposingnode
|
||||
|
||||
# Don't want to physically affect powerups.
|
||||
if node.getdelegate(PowerupBox):
|
||||
return None
|
||||
|
||||
# Only allow one hit per node per punch.
|
||||
if node and (node not in self._punched_nodes):
|
||||
punch_momentum_angular = (
|
||||
|
||||
@ -10,6 +10,7 @@ import weakref
|
||||
import logging
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from typing_extensions import override
|
||||
import bascenev1 as bs
|
||||
from bascenev1lib.actor.spaz import Spaz
|
||||
|
||||
@ -489,6 +490,7 @@ class SpazBot(Spaz):
|
||||
self.on_punch_press()
|
||||
self.on_punch_release()
|
||||
|
||||
@override
|
||||
def on_punched(self, damage: int) -> None:
|
||||
"""
|
||||
Method override; sends bs.SpazBotPunchedMessage
|
||||
@ -496,6 +498,7 @@ class SpazBot(Spaz):
|
||||
"""
|
||||
bs.getactivity().handlemessage(SpazBotPunchedMessage(self, damage))
|
||||
|
||||
@override
|
||||
def on_expire(self) -> None:
|
||||
super().on_expire()
|
||||
|
||||
@ -503,6 +506,7 @@ class SpazBot(Spaz):
|
||||
# no chance of them keeping activities or other things alive.
|
||||
self.update_callback = None
|
||||
|
||||
@override
|
||||
def handlemessage(self, msg: Any) -> Any:
|
||||
# pylint: disable=too-many-branches
|
||||
assert not self.expired
|
||||
|
||||
@ -7,6 +7,7 @@ from __future__ import annotations
|
||||
from enum import Enum
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from typing_extensions import override
|
||||
import bascenev1 as bs
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@ -221,6 +222,7 @@ class Text(bs.Actor):
|
||||
bs.WeakCall(self.handlemessage, bs.DieMessage()),
|
||||
)
|
||||
|
||||
@override
|
||||
def handlemessage(self, msg: Any) -> Any:
|
||||
assert not self.expired
|
||||
if isinstance(msg, bs.DieMessage):
|
||||
|
||||
@ -6,6 +6,7 @@ from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from typing_extensions import override
|
||||
import bascenev1 as bs
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@ -72,9 +73,11 @@ class TipsText(bs.Actor):
|
||||
next_tip = bs.Lstr(
|
||||
translate=(
|
||||
'tips',
|
||||
bs.app.classic.get_next_tip()
|
||||
if bs.app.classic is not None
|
||||
else '',
|
||||
(
|
||||
bs.app.classic.get_next_tip()
|
||||
if bs.app.classic is not None
|
||||
else ''
|
||||
),
|
||||
),
|
||||
subs=[('${REMOTE_APP_NAME}', get_remote_app_name())],
|
||||
)
|
||||
@ -95,6 +98,7 @@ class TipsText(bs.Actor):
|
||||
)
|
||||
self.node.text = next_tip
|
||||
|
||||
@override
|
||||
def handlemessage(self, msg: Any) -> Any:
|
||||
assert not self.expired
|
||||
if isinstance(msg, bs.DieMessage):
|
||||
|
||||
@ -8,6 +8,7 @@ import random
|
||||
import logging
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from typing_extensions import override
|
||||
import bascenev1 as bs
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@ -158,6 +159,7 @@ class ZoomText(bs.Actor):
|
||||
if lifespan is not None:
|
||||
bs.timer(lifespan, bs.WeakCall(self.handlemessage, bs.DieMessage()))
|
||||
|
||||
@override
|
||||
def handlemessage(self, msg: Any) -> Any:
|
||||
assert not self.expired
|
||||
if isinstance(msg, bs.DieMessage):
|
||||
|
||||
@ -10,11 +10,13 @@ from __future__ import annotations
|
||||
import random
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from typing_extensions import override
|
||||
import bascenev1 as bs
|
||||
|
||||
from bascenev1lib.actor.playerspaz import PlayerSpaz
|
||||
from bascenev1lib.actor.flag import Flag
|
||||
from bascenev1lib.actor.scoreboard import Scoreboard
|
||||
from bascenev1lib.gameutils import SharedObjects
|
||||
import bascenev1 as bs
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any, Sequence
|
||||
@ -71,10 +73,12 @@ class AssaultGame(bs.TeamGameActivity[Player, Team]):
|
||||
bs.BoolSetting('Epic Mode', default=False),
|
||||
]
|
||||
|
||||
@override
|
||||
@classmethod
|
||||
def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool:
|
||||
return issubclass(sessiontype, bs.DualTeamSession)
|
||||
|
||||
@override
|
||||
@classmethod
|
||||
def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]:
|
||||
assert bs.app.classic is not None
|
||||
@ -96,16 +100,19 @@ class AssaultGame(bs.TeamGameActivity[Player, Team]):
|
||||
bs.MusicType.EPIC if self._epic_mode else bs.MusicType.FORWARD_MARCH
|
||||
)
|
||||
|
||||
@override
|
||||
def get_instance_description(self) -> str | Sequence:
|
||||
if self._score_to_win == 1:
|
||||
return 'Touch the enemy flag.'
|
||||
return 'Touch the enemy flag ${ARG1} times.', self._score_to_win
|
||||
|
||||
@override
|
||||
def get_instance_description_short(self) -> str | Sequence:
|
||||
if self._score_to_win == 1:
|
||||
return 'touch 1 flag'
|
||||
return 'touch ${ARG1} flags', self._score_to_win
|
||||
|
||||
@override
|
||||
def create_team(self, sessionteam: bs.SessionTeam) -> Team:
|
||||
shared = SharedObjects.get()
|
||||
base_pos = self.map.get_flag_position(sessionteam.id)
|
||||
@ -151,16 +158,19 @@ class AssaultGame(bs.TeamGameActivity[Player, Team]):
|
||||
|
||||
return team
|
||||
|
||||
@override
|
||||
def on_team_join(self, team: Team) -> None:
|
||||
# Can't do this in create_team because the team's color/etc. have
|
||||
# not been wired up yet at that point.
|
||||
self._update_scoreboard()
|
||||
|
||||
@override
|
||||
def on_begin(self) -> None:
|
||||
super().on_begin()
|
||||
self.setup_standard_time_limit(self._time_limit)
|
||||
self.setup_standard_powerup_drops()
|
||||
|
||||
@override
|
||||
def handlemessage(self, msg: Any) -> Any:
|
||||
if isinstance(msg, bs.PlayerDiedMessage):
|
||||
super().handlemessage(msg) # Augment standard.
|
||||
@ -249,6 +259,7 @@ class AssaultGame(bs.TeamGameActivity[Player, Team]):
|
||||
if player_team.score >= self._score_to_win:
|
||||
self.end_game()
|
||||
|
||||
@override
|
||||
def end_game(self) -> None:
|
||||
results = bs.GameResults()
|
||||
for team in self.teams:
|
||||
|
||||
@ -10,6 +10,9 @@ from __future__ import annotations
|
||||
import logging
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from typing_extensions import override
|
||||
import bascenev1 as bs
|
||||
|
||||
from bascenev1lib.actor.playerspaz import PlayerSpaz
|
||||
from bascenev1lib.actor.scoreboard import Scoreboard
|
||||
from bascenev1lib.actor.flag import (
|
||||
@ -19,7 +22,6 @@ from bascenev1lib.actor.flag import (
|
||||
FlagDroppedMessage,
|
||||
FlagDiedMessage,
|
||||
)
|
||||
import bascenev1 as bs
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any, Sequence
|
||||
@ -141,10 +143,12 @@ class CaptureTheFlagGame(bs.TeamGameActivity[Player, Team]):
|
||||
bs.BoolSetting('Epic Mode', default=False),
|
||||
]
|
||||
|
||||
@override
|
||||
@classmethod
|
||||
def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool:
|
||||
return issubclass(sessiontype, bs.DualTeamSession)
|
||||
|
||||
@override
|
||||
@classmethod
|
||||
def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]:
|
||||
assert bs.app.classic is not None
|
||||
@ -173,16 +177,19 @@ class CaptureTheFlagGame(bs.TeamGameActivity[Player, Team]):
|
||||
bs.MusicType.EPIC if self._epic_mode else bs.MusicType.FLAG_CATCHER
|
||||
)
|
||||
|
||||
@override
|
||||
def get_instance_description(self) -> str | Sequence:
|
||||
if self._score_to_win == 1:
|
||||
return 'Steal the enemy flag.'
|
||||
return 'Steal the enemy flag ${ARG1} times.', self._score_to_win
|
||||
|
||||
@override
|
||||
def get_instance_description_short(self) -> str | Sequence:
|
||||
if self._score_to_win == 1:
|
||||
return 'return 1 flag'
|
||||
return 'return ${ARG1} flags', self._score_to_win
|
||||
|
||||
@override
|
||||
def create_team(self, sessionteam: bs.SessionTeam) -> Team:
|
||||
# Create our team instance and its initial values.
|
||||
|
||||
@ -272,12 +279,14 @@ class CaptureTheFlagGame(bs.TeamGameActivity[Player, Team]):
|
||||
|
||||
return team
|
||||
|
||||
@override
|
||||
def on_team_join(self, team: Team) -> None:
|
||||
# Can't do this in create_team because the team's color/etc. have
|
||||
# not been wired up yet at that point.
|
||||
self._spawn_flag_for_team(team)
|
||||
self._update_scoreboard()
|
||||
|
||||
@override
|
||||
def on_begin(self) -> None:
|
||||
super().on_begin()
|
||||
self.setup_standard_time_limit(self._time_limit)
|
||||
@ -406,6 +415,7 @@ class CaptureTheFlagGame(bs.TeamGameActivity[Player, Team]):
|
||||
if team.score >= self._score_to_win:
|
||||
self.end_game()
|
||||
|
||||
@override
|
||||
def end_game(self) -> None:
|
||||
results = bs.GameResults()
|
||||
for team in self.teams:
|
||||
@ -519,6 +529,30 @@ class CaptureTheFlagGame(bs.TeamGameActivity[Player, Team]):
|
||||
if team.flag_return_touches < 0:
|
||||
logging.exception('CTF flag_return_touches < 0')
|
||||
|
||||
def _handle_death_flag_capture(self, player: Player) -> None:
|
||||
"""Handles flag values when a player dies or leaves the game."""
|
||||
# Don't do anything if the player hasn't touched the flag at all.
|
||||
if not player.touching_own_flag:
|
||||
return
|
||||
|
||||
team = player.team
|
||||
# For each "point" our player has touched theflag (Could be multiple),
|
||||
# deduct one from both our player and
|
||||
# the flag's return touches variable.
|
||||
for _ in range(player.touching_own_flag):
|
||||
# Deduct
|
||||
player.touching_own_flag -= 1
|
||||
team.flag_return_touches -= 1
|
||||
# Update our flag's timer accordingly
|
||||
# (Prevents immediate resets in case
|
||||
# there might be more people touching it).
|
||||
if team.flag_return_touches == 0:
|
||||
team.touch_return_timer = None
|
||||
team.touch_return_timer_ticking = None
|
||||
# Safety check, just to be sure!
|
||||
if team.flag_return_touches < 0:
|
||||
logging.exception('CTF flag_return_touches < 0')
|
||||
|
||||
def _flash_base(self, team: Team, length: float = 2.0) -> None:
|
||||
light = bs.newnode(
|
||||
'light',
|
||||
@ -532,6 +566,7 @@ class CaptureTheFlagGame(bs.TeamGameActivity[Player, Team]):
|
||||
bs.animate(light, 'intensity', {0.0: 0, 0.25: 2.0, 0.5: 0}, loop=True)
|
||||
bs.timer(length, light.delete)
|
||||
|
||||
@override
|
||||
def spawn_player_spaz(
|
||||
self,
|
||||
player: Player,
|
||||
@ -576,9 +611,11 @@ class CaptureTheFlagGame(bs.TeamGameActivity[Player, Team]):
|
||||
team, team.score, self._score_to_win
|
||||
)
|
||||
|
||||
@override
|
||||
def handlemessage(self, msg: Any) -> Any:
|
||||
if isinstance(msg, bs.PlayerDiedMessage):
|
||||
super().handlemessage(msg) # Augment standard behavior.
|
||||
self._handle_death_flag_capture(msg.getplayer(Player))
|
||||
self.respawn_player(msg.getplayer(Player))
|
||||
|
||||
elif isinstance(msg, FlagDiedMessage):
|
||||
@ -605,3 +642,8 @@ class CaptureTheFlagGame(bs.TeamGameActivity[Player, Team]):
|
||||
|
||||
else:
|
||||
super().handlemessage(msg)
|
||||
|
||||
@override
|
||||
def on_player_leave(self, player: Player) -> None:
|
||||
"""Prevents leaving players from capturing their flag."""
|
||||
self._handle_death_flag_capture(player)
|
||||
|
||||
@ -10,11 +10,13 @@ from __future__ import annotations
|
||||
import logging
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from typing_extensions import override
|
||||
import bascenev1 as bs
|
||||
|
||||
from bascenev1lib.actor.flag import Flag
|
||||
from bascenev1lib.actor.playerspaz import PlayerSpaz
|
||||
from bascenev1lib.actor.scoreboard import Scoreboard
|
||||
from bascenev1lib.gameutils import SharedObjects
|
||||
import bascenev1 as bs
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any, Sequence
|
||||
@ -83,6 +85,7 @@ class ChosenOneGame(bs.TeamGameActivity[Player, Team]):
|
||||
]
|
||||
scoreconfig = bs.ScoreConfig(label='Time Held')
|
||||
|
||||
@override
|
||||
@classmethod
|
||||
def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]:
|
||||
assert bs.app.classic is not None
|
||||
@ -121,20 +124,25 @@ class ChosenOneGame(bs.TeamGameActivity[Player, Team]):
|
||||
bs.MusicType.EPIC if self._epic_mode else bs.MusicType.CHOSEN_ONE
|
||||
)
|
||||
|
||||
@override
|
||||
def get_instance_description(self) -> str | Sequence:
|
||||
return 'There can be only one.'
|
||||
|
||||
@override
|
||||
def create_team(self, sessionteam: bs.SessionTeam) -> Team:
|
||||
return Team(time_remaining=self._chosen_one_time)
|
||||
|
||||
@override
|
||||
def on_team_join(self, team: Team) -> None:
|
||||
self._update_scoreboard()
|
||||
|
||||
@override
|
||||
def on_player_leave(self, player: Player) -> None:
|
||||
super().on_player_leave(player)
|
||||
if self._get_chosen_one_player() is player:
|
||||
self._set_chosen_one_player(None)
|
||||
|
||||
@override
|
||||
def on_begin(self) -> None:
|
||||
super().on_begin()
|
||||
shared = SharedObjects.get()
|
||||
@ -251,6 +259,7 @@ class ChosenOneGame(bs.TeamGameActivity[Player, Team]):
|
||||
logging.error('got nonexistent player as chosen one in _tick')
|
||||
self._set_chosen_one_player(None)
|
||||
|
||||
@override
|
||||
def end_game(self) -> None:
|
||||
results = bs.GameResults()
|
||||
for team in self.teams:
|
||||
@ -335,6 +344,7 @@ class ChosenOneGame(bs.TeamGameActivity[Player, Team]):
|
||||
'position', light.node, 'position'
|
||||
)
|
||||
|
||||
@override
|
||||
def handlemessage(self, msg: Any) -> Any:
|
||||
if isinstance(msg, bs.PlayerDiedMessage):
|
||||
# Augment standard behavior.
|
||||
|
||||
@ -10,12 +10,14 @@ from __future__ import annotations
|
||||
import random
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from typing_extensions import override
|
||||
import bascenev1 as bs
|
||||
|
||||
from bascenev1lib.actor.flag import Flag
|
||||
from bascenev1lib.actor.scoreboard import Scoreboard
|
||||
from bascenev1lib.actor.playerspaz import PlayerSpaz
|
||||
from bascenev1lib.gameutils import SharedObjects
|
||||
from bascenev1lib.actor.respawnicon import RespawnIcon
|
||||
import bascenev1 as bs
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any, Sequence
|
||||
@ -108,10 +110,12 @@ class ConquestGame(bs.TeamGameActivity[Player, Team]):
|
||||
bs.BoolSetting('Epic Mode', default=False),
|
||||
]
|
||||
|
||||
@override
|
||||
@classmethod
|
||||
def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool:
|
||||
return issubclass(sessiontype, bs.DualTeamSession)
|
||||
|
||||
@override
|
||||
@classmethod
|
||||
def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]:
|
||||
assert bs.app.classic is not None
|
||||
@ -143,16 +147,20 @@ class ConquestGame(bs.TeamGameActivity[Player, Team]):
|
||||
),
|
||||
)
|
||||
|
||||
@override
|
||||
def get_instance_description(self) -> str | Sequence:
|
||||
return 'Secure all ${ARG1} flags.', len(self.map.flag_points)
|
||||
|
||||
@override
|
||||
def get_instance_description_short(self) -> str | Sequence:
|
||||
return 'secure all ${ARG1} flags', len(self.map.flag_points)
|
||||
|
||||
@override
|
||||
def on_team_join(self, team: Team) -> None:
|
||||
if self.has_begun():
|
||||
self._update_scores()
|
||||
|
||||
@override
|
||||
def on_player_join(self, player: Player) -> None:
|
||||
player.respawn_timer = None
|
||||
|
||||
@ -160,6 +168,7 @@ class ConquestGame(bs.TeamGameActivity[Player, Team]):
|
||||
if player.team.flags_held > 0:
|
||||
self.spawn_player(player)
|
||||
|
||||
@override
|
||||
def on_begin(self) -> None:
|
||||
super().on_begin()
|
||||
self.setup_standard_time_limit(self._time_limit)
|
||||
@ -221,6 +230,7 @@ class ConquestGame(bs.TeamGameActivity[Player, Team]):
|
||||
team, team.flags_held, len(self._flags)
|
||||
)
|
||||
|
||||
@override
|
||||
def end_game(self) -> None:
|
||||
results = bs.GameResults()
|
||||
for team in self.teams:
|
||||
@ -272,6 +282,7 @@ class ConquestGame(bs.TeamGameActivity[Player, Team]):
|
||||
):
|
||||
self.spawn_player(otherplayer)
|
||||
|
||||
@override
|
||||
def handlemessage(self, msg: Any) -> Any:
|
||||
if isinstance(msg, bs.PlayerDiedMessage):
|
||||
# Augment standard behavior.
|
||||
@ -287,6 +298,7 @@ class ConquestGame(bs.TeamGameActivity[Player, Team]):
|
||||
else:
|
||||
super().handlemessage(msg)
|
||||
|
||||
@override
|
||||
def spawn_player(self, player: Player) -> bs.Actor:
|
||||
# We spawn players at different places based on what flags are held.
|
||||
return self.spawn_player_spaz(
|
||||
|
||||
@ -9,9 +9,11 @@ from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from typing_extensions import override
|
||||
import bascenev1 as bs
|
||||
|
||||
from bascenev1lib.actor.playerspaz import PlayerSpaz
|
||||
from bascenev1lib.actor.scoreboard import Scoreboard
|
||||
import bascenev1 as bs
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any, Sequence
|
||||
@ -38,6 +40,7 @@ class DeathMatchGame(bs.TeamGameActivity[Player, Team]):
|
||||
# Print messages when players die since it matters here.
|
||||
announce_player_deaths = True
|
||||
|
||||
@override
|
||||
@classmethod
|
||||
def get_available_settings(
|
||||
cls, sessiontype: type[bs.Session]
|
||||
@ -87,12 +90,14 @@ class DeathMatchGame(bs.TeamGameActivity[Player, Team]):
|
||||
|
||||
return settings
|
||||
|
||||
@override
|
||||
@classmethod
|
||||
def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool:
|
||||
return issubclass(sessiontype, bs.DualTeamSession) or issubclass(
|
||||
sessiontype, bs.FreeForAllSession
|
||||
)
|
||||
|
||||
@override
|
||||
@classmethod
|
||||
def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]:
|
||||
assert bs.app.classic is not None
|
||||
@ -116,16 +121,20 @@ class DeathMatchGame(bs.TeamGameActivity[Player, Team]):
|
||||
bs.MusicType.EPIC if self._epic_mode else bs.MusicType.TO_THE_DEATH
|
||||
)
|
||||
|
||||
@override
|
||||
def get_instance_description(self) -> str | Sequence:
|
||||
return 'Crush ${ARG1} of your enemies.', self._score_to_win
|
||||
|
||||
@override
|
||||
def get_instance_description_short(self) -> str | Sequence:
|
||||
return 'kill ${ARG1} enemies', self._score_to_win
|
||||
|
||||
@override
|
||||
def on_team_join(self, team: Team) -> None:
|
||||
if self.has_begun():
|
||||
self._update_scoreboard()
|
||||
|
||||
@override
|
||||
def on_begin(self) -> None:
|
||||
super().on_begin()
|
||||
self.setup_standard_time_limit(self._time_limit)
|
||||
@ -137,6 +146,7 @@ class DeathMatchGame(bs.TeamGameActivity[Player, Team]):
|
||||
)
|
||||
self._update_scoreboard()
|
||||
|
||||
@override
|
||||
def handlemessage(self, msg: Any) -> Any:
|
||||
if isinstance(msg, bs.PlayerDiedMessage):
|
||||
# Augment standard behavior.
|
||||
@ -197,6 +207,7 @@ class DeathMatchGame(bs.TeamGameActivity[Player, Team]):
|
||||
team, team.score, self._score_to_win
|
||||
)
|
||||
|
||||
@override
|
||||
def end_game(self) -> None:
|
||||
results = bs.GameResults()
|
||||
for team in self.teams:
|
||||
|
||||
@ -10,6 +10,9 @@ from __future__ import annotations
|
||||
import random
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from typing_extensions import override
|
||||
import bascenev1 as bs
|
||||
|
||||
from bascenev1lib.actor.bomb import Bomb
|
||||
from bascenev1lib.actor.playerspaz import PlayerSpaz
|
||||
from bascenev1lib.actor.spazbot import SpazBotSet, BouncyBot, SpazBotDiedMessage
|
||||
@ -17,7 +20,6 @@ from bascenev1lib.actor.onscreencountdown import OnScreenCountdown
|
||||
from bascenev1lib.actor.scoreboard import Scoreboard
|
||||
from bascenev1lib.actor.respawnicon import RespawnIcon
|
||||
from bascenev1lib.gameutils import SharedObjects
|
||||
import bascenev1 as bs
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any
|
||||
@ -51,11 +53,13 @@ class EasterEggHuntGame(bs.TeamGameActivity[Player, Team]):
|
||||
scoreconfig = bs.ScoreConfig(label='Score', scoretype=bs.ScoreType.POINTS)
|
||||
|
||||
# We're currently hard-coded for one map.
|
||||
@override
|
||||
@classmethod
|
||||
def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]:
|
||||
return ['Tower D']
|
||||
|
||||
# We support teams, free-for-all, and co-op sessions.
|
||||
@override
|
||||
@classmethod
|
||||
def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool:
|
||||
return (
|
||||
@ -93,11 +97,13 @@ class EasterEggHuntGame(bs.TeamGameActivity[Player, Team]):
|
||||
bs.MusicType.EPIC if self._epic_mode else bs.MusicType.FORWARD_MARCH
|
||||
)
|
||||
|
||||
@override
|
||||
def on_team_join(self, team: Team) -> None:
|
||||
if self.has_begun():
|
||||
self._update_scoreboard()
|
||||
|
||||
# Called when our game actually starts.
|
||||
@override
|
||||
def on_begin(self) -> None:
|
||||
from bascenev1lib.maps import TowerD
|
||||
|
||||
@ -118,6 +124,7 @@ class EasterEggHuntGame(bs.TeamGameActivity[Player, Team]):
|
||||
self._spawn_evil_bunny()
|
||||
|
||||
# Overriding the default character spawning.
|
||||
@override
|
||||
def spawn_player(self, player: Player) -> bs.Actor:
|
||||
spaz = self.spawn_player_spaz(player)
|
||||
spaz.connect_controls_to_player()
|
||||
@ -191,6 +198,7 @@ class EasterEggHuntGame(bs.TeamGameActivity[Player, Team]):
|
||||
self._eggs.append(Egg(position=(xpos, ypos, zpos)))
|
||||
|
||||
# Various high-level game events come through this method.
|
||||
@override
|
||||
def handlemessage(self, msg: Any) -> Any:
|
||||
# Respawn dead players.
|
||||
if isinstance(msg, bs.PlayerDiedMessage):
|
||||
@ -231,6 +239,7 @@ class EasterEggHuntGame(bs.TeamGameActivity[Player, Team]):
|
||||
for team in self.teams:
|
||||
self._scoreboard.set_team_value(team, team.score)
|
||||
|
||||
@override
|
||||
def end_game(self) -> None:
|
||||
results = bs.GameResults()
|
||||
for team in self.teams:
|
||||
@ -271,9 +280,11 @@ class Egg(bs.Actor):
|
||||
},
|
||||
)
|
||||
|
||||
@override
|
||||
def exists(self) -> bool:
|
||||
return bool(self.node)
|
||||
|
||||
@override
|
||||
def handlemessage(self, msg: Any) -> Any:
|
||||
if isinstance(msg, bs.DieMessage):
|
||||
if self.node:
|
||||
|
||||
@ -10,9 +10,11 @@ from __future__ import annotations
|
||||
import logging
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from typing_extensions import override
|
||||
import bascenev1 as bs
|
||||
|
||||
from bascenev1lib.actor.spazfactory import SpazFactory
|
||||
from bascenev1lib.actor.scoreboard import Scoreboard
|
||||
import bascenev1 as bs
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any, Sequence
|
||||
@ -157,6 +159,7 @@ class Icon(bs.Actor):
|
||||
if lives == 0:
|
||||
bs.timer(0.6, self.update_for_lives)
|
||||
|
||||
@override
|
||||
def handlemessage(self, msg: Any) -> Any:
|
||||
if isinstance(msg, bs.DieMessage):
|
||||
self.node.delete()
|
||||
@ -194,6 +197,7 @@ class EliminationGame(bs.TeamGameActivity[Player, Team]):
|
||||
|
||||
allow_mid_activity_joins = False
|
||||
|
||||
@override
|
||||
@classmethod
|
||||
def get_available_settings(
|
||||
cls, sessiontype: type[bs.Session]
|
||||
@ -238,12 +242,14 @@ class EliminationGame(bs.TeamGameActivity[Player, Team]):
|
||||
)
|
||||
return settings
|
||||
|
||||
@override
|
||||
@classmethod
|
||||
def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool:
|
||||
return issubclass(sessiontype, bs.DualTeamSession) or issubclass(
|
||||
sessiontype, bs.FreeForAllSession
|
||||
)
|
||||
|
||||
@override
|
||||
@classmethod
|
||||
def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]:
|
||||
assert bs.app.classic is not None
|
||||
@ -269,6 +275,7 @@ class EliminationGame(bs.TeamGameActivity[Player, Team]):
|
||||
bs.MusicType.EPIC if self._epic_mode else bs.MusicType.SURVIVAL
|
||||
)
|
||||
|
||||
@override
|
||||
def get_instance_description(self) -> str | Sequence:
|
||||
return (
|
||||
'Last team standing wins.'
|
||||
@ -276,6 +283,7 @@ class EliminationGame(bs.TeamGameActivity[Player, Team]):
|
||||
else 'Last one standing wins.'
|
||||
)
|
||||
|
||||
@override
|
||||
def get_instance_description_short(self) -> str | Sequence:
|
||||
return (
|
||||
'last team standing wins'
|
||||
@ -283,6 +291,7 @@ class EliminationGame(bs.TeamGameActivity[Player, Team]):
|
||||
else 'last one standing wins'
|
||||
)
|
||||
|
||||
@override
|
||||
def on_player_join(self, player: Player) -> None:
|
||||
player.lives = self._lives_per_player
|
||||
|
||||
@ -299,6 +308,7 @@ class EliminationGame(bs.TeamGameActivity[Player, Team]):
|
||||
if self.has_begun():
|
||||
self._update_icons()
|
||||
|
||||
@override
|
||||
def on_begin(self) -> None:
|
||||
super().on_begin()
|
||||
self._start_time = bs.time()
|
||||
@ -469,6 +479,7 @@ class EliminationGame(bs.TeamGameActivity[Player, Team]):
|
||||
return points[-1][1]
|
||||
return None
|
||||
|
||||
@override
|
||||
def spawn_player(self, player: Player) -> bs.Actor:
|
||||
actor = self.spawn_player_spaz(player, self._get_spawn_point(player))
|
||||
if not self._solo_mode:
|
||||
@ -495,6 +506,7 @@ class EliminationGame(bs.TeamGameActivity[Player, Team]):
|
||||
position=player.node.position,
|
||||
).autoretain()
|
||||
|
||||
@override
|
||||
def on_player_leave(self, player: Player) -> None:
|
||||
super().on_player_leave(player)
|
||||
player.icons = []
|
||||
@ -518,6 +530,7 @@ class EliminationGame(bs.TeamGameActivity[Player, Team]):
|
||||
def _get_total_team_lives(self, team: Team) -> int:
|
||||
return sum(player.lives for player in team.players)
|
||||
|
||||
@override
|
||||
def handlemessage(self, msg: Any) -> Any:
|
||||
if isinstance(msg, bs.PlayerDiedMessage):
|
||||
# Augment standard behavior.
|
||||
@ -588,6 +601,7 @@ class EliminationGame(bs.TeamGameActivity[Player, Team]):
|
||||
and any(player.lives > 0 for player in team.players)
|
||||
]
|
||||
|
||||
@override
|
||||
def end_game(self) -> None:
|
||||
if self.has_ended():
|
||||
return
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
# Released under the MIT License. See LICENSE for details.
|
||||
#
|
||||
# pylint: disable=too-many-lines
|
||||
"""Implements football games (both co-op and teams varieties)."""
|
||||
|
||||
# ba_meta require api 8
|
||||
@ -12,6 +13,9 @@ import random
|
||||
import logging
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from typing_extensions import override
|
||||
import bascenev1 as bs
|
||||
|
||||
from bascenev1lib.actor.bomb import TNTSpawner
|
||||
from bascenev1lib.actor.playerspaz import PlayerSpaz
|
||||
from bascenev1lib.actor.scoreboard import Scoreboard
|
||||
@ -39,7 +43,6 @@ from bascenev1lib.actor.spazbot import (
|
||||
StickyBot,
|
||||
ExplodeyBot,
|
||||
)
|
||||
import bascenev1 as bs
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any, Sequence
|
||||
@ -128,11 +131,13 @@ class FootballTeamGame(bs.TeamGameActivity[Player, Team]):
|
||||
bs.BoolSetting('Epic Mode', default=False),
|
||||
]
|
||||
|
||||
@override
|
||||
@classmethod
|
||||
def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool:
|
||||
# We only support two-team play.
|
||||
return issubclass(sessiontype, bs.DualTeamSession)
|
||||
|
||||
@override
|
||||
@classmethod
|
||||
def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]:
|
||||
assert bs.app.classic is not None
|
||||
@ -170,6 +175,7 @@ class FootballTeamGame(bs.TeamGameActivity[Player, Team]):
|
||||
bs.MusicType.EPIC if self._epic_mode else bs.MusicType.FOOTBALL
|
||||
)
|
||||
|
||||
@override
|
||||
def get_instance_description(self) -> str | Sequence:
|
||||
touchdowns = self._score_to_win / 7
|
||||
|
||||
@ -181,6 +187,7 @@ class FootballTeamGame(bs.TeamGameActivity[Player, Team]):
|
||||
return 'Score ${ARG1} touchdowns.', touchdowns
|
||||
return 'Score a touchdown.'
|
||||
|
||||
@override
|
||||
def get_instance_description_short(self) -> str | Sequence:
|
||||
touchdowns = self._score_to_win / 7
|
||||
touchdowns = math.ceil(touchdowns)
|
||||
@ -188,6 +195,7 @@ class FootballTeamGame(bs.TeamGameActivity[Player, Team]):
|
||||
return 'score ${ARG1} touchdowns', touchdowns
|
||||
return 'score a touchdown'
|
||||
|
||||
@override
|
||||
def on_begin(self) -> None:
|
||||
super().on_begin()
|
||||
self.setup_standard_time_limit(self._time_limit)
|
||||
@ -224,6 +232,7 @@ class FootballTeamGame(bs.TeamGameActivity[Player, Team]):
|
||||
self._update_scoreboard()
|
||||
self._chant_sound.play()
|
||||
|
||||
@override
|
||||
def on_team_join(self, team: Team) -> None:
|
||||
self._update_scoreboard()
|
||||
|
||||
@ -285,6 +294,7 @@ class FootballTeamGame(bs.TeamGameActivity[Player, Team]):
|
||||
bs.cameraflash(duration=10.0)
|
||||
self._update_scoreboard()
|
||||
|
||||
@override
|
||||
def end_game(self) -> None:
|
||||
results = bs.GameResults()
|
||||
for team in self.teams:
|
||||
@ -298,6 +308,7 @@ class FootballTeamGame(bs.TeamGameActivity[Player, Team]):
|
||||
team, team.score, self._score_to_win
|
||||
)
|
||||
|
||||
@override
|
||||
def handlemessage(self, msg: Any) -> Any:
|
||||
if isinstance(msg, FlagPickedUpMessage):
|
||||
assert isinstance(msg.flag, FootballFlag)
|
||||
@ -379,9 +390,11 @@ class FootballCoopGame(bs.CoopGameActivity[Player, Team]):
|
||||
default_music = bs.MusicType.FOOTBALL
|
||||
|
||||
# FIXME: Need to update co-op games to use getscoreconfig.
|
||||
@override
|
||||
def get_score_type(self) -> str:
|
||||
return 'time'
|
||||
|
||||
@override
|
||||
def get_instance_description(self) -> str | Sequence:
|
||||
touchdowns = self._score_to_win / 7
|
||||
touchdowns = math.ceil(touchdowns)
|
||||
@ -389,6 +402,7 @@ class FootballCoopGame(bs.CoopGameActivity[Player, Team]):
|
||||
return 'Score ${ARG1} touchdowns.', touchdowns
|
||||
return 'Score a touchdown.'
|
||||
|
||||
@override
|
||||
def get_instance_description_short(self) -> str | Sequence:
|
||||
touchdowns = self._score_to_win / 7
|
||||
touchdowns = math.ceil(touchdowns)
|
||||
@ -444,6 +458,7 @@ class FootballCoopGame(bs.CoopGameActivity[Player, Team]):
|
||||
self._flag_respawn_light: bs.Actor | None = None
|
||||
self._flag: FootballFlag | None = None
|
||||
|
||||
@override
|
||||
def on_transition_in(self) -> None:
|
||||
super().on_transition_in()
|
||||
self._scoreboard = Scoreboard()
|
||||
@ -480,6 +495,7 @@ class FootballCoopGame(bs.CoopGameActivity[Player, Team]):
|
||||
)
|
||||
self._chant_sound.play()
|
||||
|
||||
@override
|
||||
def on_begin(self) -> None:
|
||||
# FIXME: Split this up a bit.
|
||||
# pylint: disable=too-many-statements
|
||||
@ -795,11 +811,13 @@ class FootballCoopGame(bs.CoopGameActivity[Player, Team]):
|
||||
if i == 0:
|
||||
bs.cameraflash(duration=10.0)
|
||||
|
||||
@override
|
||||
def end_game(self) -> None:
|
||||
bs.setmusic(None)
|
||||
self._bots.final_celebrate()
|
||||
bs.timer(0.001, bs.Call(self.do_end, 'defeat'))
|
||||
|
||||
@override
|
||||
def on_continue(self) -> None:
|
||||
# Subtract one touchdown from the bots and get them moving again.
|
||||
assert self._bot_team is not None
|
||||
@ -897,6 +915,7 @@ class FootballCoopGame(bs.CoopGameActivity[Player, Team]):
|
||||
},
|
||||
)
|
||||
|
||||
@override
|
||||
def handlemessage(self, msg: Any) -> Any:
|
||||
"""handle high-level game messages"""
|
||||
if isinstance(msg, bs.PlayerDiedMessage):
|
||||
@ -959,6 +978,7 @@ class FootballCoopGame(bs.CoopGameActivity[Player, Team]):
|
||||
del player # Unused.
|
||||
self._player_has_punched = True
|
||||
|
||||
@override
|
||||
def spawn_player(self, player: Player) -> bs.Actor:
|
||||
spaz = self.spawn_player_spaz(
|
||||
player, position=self.map.get_start_position(player.team.id)
|
||||
|
||||
@ -9,11 +9,13 @@ from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from typing_extensions import override
|
||||
import bascenev1 as bs
|
||||
|
||||
from bascenev1lib.actor.playerspaz import PlayerSpaz
|
||||
from bascenev1lib.actor.scoreboard import Scoreboard
|
||||
from bascenev1lib.actor.powerupbox import PowerupBoxFactory
|
||||
from bascenev1lib.gameutils import SharedObjects
|
||||
import bascenev1 as bs
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any, Sequence
|
||||
@ -58,6 +60,7 @@ class Puck(bs.Actor):
|
||||
)
|
||||
bs.animate(self.node, 'mesh_scale', {0: 0, 0.2: 1.3, 0.26: 1})
|
||||
|
||||
@override
|
||||
def handlemessage(self, msg: Any) -> Any:
|
||||
if isinstance(msg, bs.DieMessage):
|
||||
if self.node:
|
||||
@ -152,10 +155,12 @@ class HockeyGame(bs.TeamGameActivity[Player, Team]):
|
||||
bs.BoolSetting('Epic Mode', default=False),
|
||||
]
|
||||
|
||||
@override
|
||||
@classmethod
|
||||
def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool:
|
||||
return issubclass(sessiontype, bs.DualTeamSession)
|
||||
|
||||
@override
|
||||
@classmethod
|
||||
def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]:
|
||||
assert bs.app.classic is not None
|
||||
@ -231,16 +236,19 @@ class HockeyGame(bs.TeamGameActivity[Player, Team]):
|
||||
bs.MusicType.EPIC if self._epic_mode else bs.MusicType.HOCKEY
|
||||
)
|
||||
|
||||
@override
|
||||
def get_instance_description(self) -> str | Sequence:
|
||||
if self._score_to_win == 1:
|
||||
return 'Score a goal.'
|
||||
return 'Score ${ARG1} goals.', self._score_to_win
|
||||
|
||||
@override
|
||||
def get_instance_description_short(self) -> str | Sequence:
|
||||
if self._score_to_win == 1:
|
||||
return 'score a goal'
|
||||
return 'score ${ARG1} goals', self._score_to_win
|
||||
|
||||
@override
|
||||
def on_begin(self) -> None:
|
||||
super().on_begin()
|
||||
|
||||
@ -281,6 +289,7 @@ class HockeyGame(bs.TeamGameActivity[Player, Team]):
|
||||
self._update_scoreboard()
|
||||
self._chant_sound.play()
|
||||
|
||||
@override
|
||||
def on_team_join(self, team: Team) -> None:
|
||||
self._update_scoreboard()
|
||||
|
||||
@ -364,6 +373,7 @@ class HockeyGame(bs.TeamGameActivity[Player, Team]):
|
||||
bs.cameraflash(duration=10.0)
|
||||
self._update_scoreboard()
|
||||
|
||||
@override
|
||||
def end_game(self) -> None:
|
||||
results = bs.GameResults()
|
||||
for team in self.teams:
|
||||
@ -375,6 +385,7 @@ class HockeyGame(bs.TeamGameActivity[Player, Team]):
|
||||
for team in self.teams:
|
||||
self._scoreboard.set_team_value(team, team.score, winscore)
|
||||
|
||||
@override
|
||||
def handlemessage(self, msg: Any) -> Any:
|
||||
# Respawn dead players if they're still in the game.
|
||||
if isinstance(msg, bs.PlayerDiedMessage):
|
||||
|
||||
@ -11,6 +11,9 @@ import logging
|
||||
from enum import Enum
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from typing_extensions import override
|
||||
import bascenev1 as bs
|
||||
|
||||
from bascenev1lib.actor.playerspaz import PlayerSpaz
|
||||
from bascenev1lib.actor.scoreboard import Scoreboard
|
||||
from bascenev1lib.actor.flag import (
|
||||
@ -19,7 +22,6 @@ from bascenev1lib.actor.flag import (
|
||||
FlagDiedMessage,
|
||||
FlagPickedUpMessage,
|
||||
)
|
||||
import bascenev1 as bs
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any, Sequence
|
||||
@ -86,12 +88,14 @@ class KeepAwayGame(bs.TeamGameActivity[Player, Team]):
|
||||
]
|
||||
scoreconfig = bs.ScoreConfig(label='Time Held')
|
||||
|
||||
@override
|
||||
@classmethod
|
||||
def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool:
|
||||
return issubclass(sessiontype, bs.DualTeamSession) or issubclass(
|
||||
sessiontype, bs.FreeForAllSession
|
||||
)
|
||||
|
||||
@override
|
||||
@classmethod
|
||||
def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]:
|
||||
assert bs.app.classic is not None
|
||||
@ -129,18 +133,23 @@ class KeepAwayGame(bs.TeamGameActivity[Player, Team]):
|
||||
bs.MusicType.EPIC if self._epic_mode else bs.MusicType.KEEP_AWAY
|
||||
)
|
||||
|
||||
@override
|
||||
def get_instance_description(self) -> str | Sequence:
|
||||
return 'Carry the flag for ${ARG1} seconds.', self._hold_time
|
||||
|
||||
@override
|
||||
def get_instance_description_short(self) -> str | Sequence:
|
||||
return 'carry the flag for ${ARG1} seconds', self._hold_time
|
||||
|
||||
@override
|
||||
def create_team(self, sessionteam: bs.SessionTeam) -> Team:
|
||||
return Team(timeremaining=self._hold_time)
|
||||
|
||||
@override
|
||||
def on_team_join(self, team: Team) -> None:
|
||||
self._update_scoreboard()
|
||||
|
||||
@override
|
||||
def on_begin(self) -> None:
|
||||
super().on_begin()
|
||||
self.setup_standard_time_limit(self._time_limit)
|
||||
@ -181,6 +190,7 @@ class KeepAwayGame(bs.TeamGameActivity[Player, Team]):
|
||||
if scoreteam.timeremaining <= 0:
|
||||
self.end_game()
|
||||
|
||||
@override
|
||||
def end_game(self) -> None:
|
||||
results = bs.GameResults()
|
||||
for team in self.teams:
|
||||
@ -268,6 +278,7 @@ class KeepAwayGame(bs.TeamGameActivity[Player, Team]):
|
||||
team, team.timeremaining, self._hold_time, countdown=True
|
||||
)
|
||||
|
||||
@override
|
||||
def handlemessage(self, msg: Any) -> Any:
|
||||
if isinstance(msg, bs.PlayerDiedMessage):
|
||||
# Augment standard behavior.
|
||||
|
||||
@ -11,11 +11,13 @@ import weakref
|
||||
from enum import Enum
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from typing_extensions import override
|
||||
import bascenev1 as bs
|
||||
|
||||
from bascenev1lib.actor.flag import Flag
|
||||
from bascenev1lib.actor.playerspaz import PlayerSpaz
|
||||
from bascenev1lib.actor.scoreboard import Scoreboard
|
||||
from bascenev1lib.gameutils import SharedObjects
|
||||
import bascenev1 as bs
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any, Sequence
|
||||
@ -84,10 +86,12 @@ class KingOfTheHillGame(bs.TeamGameActivity[Player, Team]):
|
||||
]
|
||||
scoreconfig = bs.ScoreConfig(label='Time Held')
|
||||
|
||||
@override
|
||||
@classmethod
|
||||
def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool:
|
||||
return issubclass(sessiontype, bs.MultiTeamSession)
|
||||
|
||||
@override
|
||||
@classmethod
|
||||
def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]:
|
||||
assert bs.app.classic is not None
|
||||
@ -144,15 +148,19 @@ class KingOfTheHillGame(bs.TeamGameActivity[Player, Team]):
|
||||
bs.MusicType.EPIC if self._epic_mode else bs.MusicType.SCARY
|
||||
)
|
||||
|
||||
@override
|
||||
def get_instance_description(self) -> str | Sequence:
|
||||
return 'Secure the flag for ${ARG1} seconds.', self._hold_time
|
||||
|
||||
@override
|
||||
def get_instance_description_short(self) -> str | Sequence:
|
||||
return 'secure the flag for ${ARG1} seconds', self._hold_time
|
||||
|
||||
@override
|
||||
def create_team(self, sessionteam: bs.SessionTeam) -> Team:
|
||||
return Team(time_remaining=self._hold_time)
|
||||
|
||||
@override
|
||||
def on_begin(self) -> None:
|
||||
super().on_begin()
|
||||
shared = SharedObjects.get()
|
||||
@ -223,6 +231,7 @@ class KingOfTheHillGame(bs.TeamGameActivity[Player, Team]):
|
||||
if scoring_team.time_remaining <= 0:
|
||||
self.end_game()
|
||||
|
||||
@override
|
||||
def end_game(self) -> None:
|
||||
results = bs.GameResults()
|
||||
for team in self.teams:
|
||||
@ -283,6 +292,7 @@ class KingOfTheHillGame(bs.TeamGameActivity[Player, Team]):
|
||||
team, team.time_remaining, self._hold_time, countdown=True
|
||||
)
|
||||
|
||||
@override
|
||||
def handlemessage(self, msg: Any) -> Any:
|
||||
if isinstance(msg, bs.PlayerDiedMessage):
|
||||
super().handlemessage(msg) # Augment default.
|
||||
|
||||
@ -10,9 +10,11 @@ from __future__ import annotations
|
||||
import random
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from typing_extensions import override
|
||||
import bascenev1 as bs
|
||||
|
||||
from bascenev1lib.actor.bomb import Bomb
|
||||
from bascenev1lib.actor.onscreentimer import OnScreenTimer
|
||||
import bascenev1 as bs
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any, Sequence
|
||||
@ -49,11 +51,13 @@ class MeteorShowerGame(bs.TeamGameActivity[Player, Team]):
|
||||
allow_mid_activity_joins = False
|
||||
|
||||
# We're currently hard-coded for one map.
|
||||
@override
|
||||
@classmethod
|
||||
def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]:
|
||||
return ['Rampage']
|
||||
|
||||
# We support teams, free-for-all, and co-op sessions.
|
||||
@override
|
||||
@classmethod
|
||||
def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool:
|
||||
return (
|
||||
@ -69,6 +73,7 @@ class MeteorShowerGame(bs.TeamGameActivity[Player, Team]):
|
||||
self._last_player_death_time: float | None = None
|
||||
self._meteor_time = 2.0
|
||||
self._timer: OnScreenTimer | None = None
|
||||
self._ended: bool = False
|
||||
|
||||
# Some base class overrides:
|
||||
self.default_music = (
|
||||
@ -77,6 +82,7 @@ class MeteorShowerGame(bs.TeamGameActivity[Player, Team]):
|
||||
if self._epic_mode:
|
||||
self.slow_motion = True
|
||||
|
||||
@override
|
||||
def on_begin(self) -> None:
|
||||
super().on_begin()
|
||||
|
||||
@ -100,6 +106,7 @@ class MeteorShowerGame(bs.TeamGameActivity[Player, Team]):
|
||||
# Check for immediate end (if we've only got 1 player, etc).
|
||||
bs.timer(5.0, self._check_end_game)
|
||||
|
||||
@override
|
||||
def on_player_leave(self, player: Player) -> None:
|
||||
# Augment default behavior.
|
||||
super().on_player_leave(player)
|
||||
@ -108,6 +115,7 @@ class MeteorShowerGame(bs.TeamGameActivity[Player, Team]):
|
||||
self._check_end_game()
|
||||
|
||||
# overriding the default character spawning..
|
||||
@override
|
||||
def spawn_player(self, player: Player) -> bs.Actor:
|
||||
spaz = self.spawn_player_spaz(player)
|
||||
|
||||
@ -122,6 +130,7 @@ class MeteorShowerGame(bs.TeamGameActivity[Player, Team]):
|
||||
return spaz
|
||||
|
||||
# Various high-level game events come through this method.
|
||||
@override
|
||||
def handlemessage(self, msg: Any) -> Any:
|
||||
if isinstance(msg, bs.PlayerDiedMessage):
|
||||
# Augment standard behavior.
|
||||
@ -153,6 +162,10 @@ class MeteorShowerGame(bs.TeamGameActivity[Player, Team]):
|
||||
return None
|
||||
|
||||
def _check_end_game(self) -> None:
|
||||
# We don't want to end this activity more than once.
|
||||
if self._ended:
|
||||
return
|
||||
|
||||
living_team_count = 0
|
||||
for team in self.teams:
|
||||
for player in team.players:
|
||||
@ -213,6 +226,7 @@ class MeteorShowerGame(bs.TeamGameActivity[Player, Team]):
|
||||
def _decrement_meteor_time(self) -> None:
|
||||
self._meteor_time = max(0.01, self._meteor_time * 0.9)
|
||||
|
||||
@override
|
||||
def end_game(self) -> None:
|
||||
cur_time = bs.time()
|
||||
assert self._timer is not None
|
||||
@ -261,4 +275,5 @@ class MeteorShowerGame(bs.TeamGameActivity[Player, Team]):
|
||||
# Submit the score value in milliseconds.
|
||||
results.set_team_score(team, int(1000.0 * longest_life))
|
||||
|
||||
self._ended = True
|
||||
self.end(results=results)
|
||||
|
||||
@ -10,13 +10,15 @@ from __future__ import annotations
|
||||
import random
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from typing_extensions import override
|
||||
import bascenev1 as bs
|
||||
|
||||
from bascenev1lib.actor.spazbot import (
|
||||
SpazBotSet,
|
||||
ChargerBot,
|
||||
SpazBotDiedMessage,
|
||||
)
|
||||
from bascenev1lib.actor.onscreentimer import OnScreenTimer
|
||||
import bascenev1 as bs
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any
|
||||
@ -44,6 +46,7 @@ class NinjaFightGame(bs.TeamGameActivity[Player, Team]):
|
||||
)
|
||||
default_music = bs.MusicType.TO_THE_DEATH
|
||||
|
||||
@override
|
||||
@classmethod
|
||||
def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]:
|
||||
# For now we're hard-coding spawn positions and whatnot
|
||||
@ -51,6 +54,7 @@ class NinjaFightGame(bs.TeamGameActivity[Player, Team]):
|
||||
# a specific map.
|
||||
return ['Courtyard']
|
||||
|
||||
@override
|
||||
@classmethod
|
||||
def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool:
|
||||
# We currently support Co-Op only.
|
||||
@ -67,6 +71,7 @@ class NinjaFightGame(bs.TeamGameActivity[Player, Team]):
|
||||
self._preset = str(settings['preset'])
|
||||
|
||||
# Called when our game actually begins.
|
||||
@override
|
||||
def on_begin(self) -> None:
|
||||
super().on_begin()
|
||||
is_pro = self._preset == 'pro'
|
||||
@ -123,6 +128,7 @@ class NinjaFightGame(bs.TeamGameActivity[Player, Team]):
|
||||
)
|
||||
|
||||
# Called for each spawning player.
|
||||
@override
|
||||
def spawn_player(self, player: Player) -> bs.Actor:
|
||||
# Let's spawn close to the center.
|
||||
spawn_center = (0, 3, -2)
|
||||
@ -144,6 +150,7 @@ class NinjaFightGame(bs.TeamGameActivity[Player, Team]):
|
||||
self.end_game()
|
||||
|
||||
# Called for miscellaneous messages.
|
||||
@override
|
||||
def handlemessage(self, msg: Any) -> Any:
|
||||
# A player has died.
|
||||
if isinstance(msg, bs.PlayerDiedMessage):
|
||||
@ -166,6 +173,7 @@ class NinjaFightGame(bs.TeamGameActivity[Player, Team]):
|
||||
# When this is called, we should fill out results and end the game
|
||||
# *regardless* of whether is has been won. (this may be called due
|
||||
# to a tournament ending or other external reason).
|
||||
@override
|
||||
def end_game(self) -> None:
|
||||
# Stop our on-screen timer so players can see what they got.
|
||||
assert self._timer is not None
|
||||
|
||||
@ -17,6 +17,9 @@ from enum import Enum, unique
|
||||
from dataclasses import dataclass
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from typing_extensions import override
|
||||
import bascenev1 as bs
|
||||
|
||||
from bascenev1lib.actor.popuptext import PopupText
|
||||
from bascenev1lib.actor.bomb import TNTSpawner
|
||||
from bascenev1lib.actor.playerspaz import PlayerSpazHurtMessage
|
||||
@ -45,7 +48,6 @@ from bascenev1lib.actor.spazbot import (
|
||||
BrawlerBotPro,
|
||||
BomberBotProShielded,
|
||||
)
|
||||
import bascenev1 as bs
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any, Sequence
|
||||
@ -222,6 +224,7 @@ class OnslaughtGame(bs.CoopGameActivity[Player, Team]):
|
||||
self._land_mine_kills = 0
|
||||
self._tnt_kills = 0
|
||||
|
||||
@override
|
||||
def on_transition_in(self) -> None:
|
||||
super().on_transition_in()
|
||||
customdata = bs.getsession().customdata
|
||||
@ -286,6 +289,7 @@ class OnslaughtGame(bs.CoopGameActivity[Player, Team]):
|
||||
label=bs.Lstr(resource='scoreText'), score_split=0.5
|
||||
)
|
||||
|
||||
@override
|
||||
def on_begin(self) -> None:
|
||||
super().on_begin()
|
||||
player_count = len(self.players)
|
||||
@ -330,29 +334,37 @@ class OnslaughtGame(bs.CoopGameActivity[Player, Team]):
|
||||
Wave(
|
||||
base_angle=130,
|
||||
entries=[
|
||||
Spawn(BrawlerBotLite, spacing=5)
|
||||
if player_count > 1
|
||||
else None,
|
||||
(
|
||||
Spawn(BrawlerBotLite, spacing=5)
|
||||
if player_count > 1
|
||||
else None
|
||||
),
|
||||
Spawn(BrawlerBotLite, spacing=5),
|
||||
Spacing(30),
|
||||
Spawn(BomberBotLite, spacing=5)
|
||||
if player_count > 3
|
||||
else None,
|
||||
(
|
||||
Spawn(BomberBotLite, spacing=5)
|
||||
if player_count > 3
|
||||
else None
|
||||
),
|
||||
Spawn(BomberBotLite, spacing=5),
|
||||
Spacing(30),
|
||||
Spawn(BrawlerBotLite, spacing=5),
|
||||
Spawn(BrawlerBotLite, spacing=5)
|
||||
if player_count > 2
|
||||
else None,
|
||||
(
|
||||
Spawn(BrawlerBotLite, spacing=5)
|
||||
if player_count > 2
|
||||
else None
|
||||
),
|
||||
],
|
||||
),
|
||||
Wave(
|
||||
base_angle=195,
|
||||
entries=[
|
||||
Spawn(TriggerBot, spacing=90),
|
||||
Spawn(TriggerBot, spacing=90)
|
||||
if player_count > 1
|
||||
else None,
|
||||
(
|
||||
Spawn(TriggerBot, spacing=90)
|
||||
if player_count > 1
|
||||
else None
|
||||
),
|
||||
],
|
||||
),
|
||||
]
|
||||
@ -363,9 +375,11 @@ class OnslaughtGame(bs.CoopGameActivity[Player, Team]):
|
||||
self._waves = [
|
||||
Wave(
|
||||
entries=[
|
||||
Spawn(ChargerBot, Point.LEFT_UPPER_MORE)
|
||||
if player_count > 2
|
||||
else None,
|
||||
(
|
||||
Spawn(ChargerBot, Point.LEFT_UPPER_MORE)
|
||||
if player_count > 2
|
||||
else None
|
||||
),
|
||||
Spawn(ChargerBot, Point.LEFT_UPPER),
|
||||
]
|
||||
),
|
||||
@ -373,36 +387,50 @@ class OnslaughtGame(bs.CoopGameActivity[Player, Team]):
|
||||
entries=[
|
||||
Spawn(BomberBotStaticLite, Point.TURRET_TOP_RIGHT),
|
||||
Spawn(BrawlerBotLite, Point.RIGHT_UPPER),
|
||||
Spawn(BrawlerBotLite, Point.RIGHT_LOWER)
|
||||
if player_count > 1
|
||||
else None,
|
||||
Spawn(BomberBotStaticLite, Point.TURRET_BOTTOM_RIGHT)
|
||||
if player_count > 2
|
||||
else None,
|
||||
(
|
||||
Spawn(BrawlerBotLite, Point.RIGHT_LOWER)
|
||||
if player_count > 1
|
||||
else None
|
||||
),
|
||||
(
|
||||
Spawn(
|
||||
BomberBotStaticLite, Point.TURRET_BOTTOM_RIGHT
|
||||
)
|
||||
if player_count > 2
|
||||
else None
|
||||
),
|
||||
]
|
||||
),
|
||||
Wave(
|
||||
entries=[
|
||||
Spawn(BomberBotStaticLite, Point.TURRET_BOTTOM_LEFT),
|
||||
Spawn(TriggerBot, Point.LEFT),
|
||||
Spawn(TriggerBot, Point.LEFT_LOWER)
|
||||
if player_count > 1
|
||||
else None,
|
||||
Spawn(TriggerBot, Point.LEFT_UPPER)
|
||||
if player_count > 2
|
||||
else None,
|
||||
(
|
||||
Spawn(TriggerBot, Point.LEFT_LOWER)
|
||||
if player_count > 1
|
||||
else None
|
||||
),
|
||||
(
|
||||
Spawn(TriggerBot, Point.LEFT_UPPER)
|
||||
if player_count > 2
|
||||
else None
|
||||
),
|
||||
]
|
||||
),
|
||||
Wave(
|
||||
entries=[
|
||||
Spawn(BrawlerBotLite, Point.TOP_RIGHT),
|
||||
Spawn(BrawlerBot, Point.TOP_HALF_RIGHT)
|
||||
if player_count > 1
|
||||
else None,
|
||||
(
|
||||
Spawn(BrawlerBot, Point.TOP_HALF_RIGHT)
|
||||
if player_count > 1
|
||||
else None
|
||||
),
|
||||
Spawn(BrawlerBotLite, Point.TOP_LEFT),
|
||||
Spawn(BrawlerBotLite, Point.TOP_HALF_LEFT)
|
||||
if player_count > 2
|
||||
else None,
|
||||
(
|
||||
Spawn(BrawlerBotLite, Point.TOP_HALF_LEFT)
|
||||
if player_count > 2
|
||||
else None
|
||||
),
|
||||
Spawn(BrawlerBot, Point.TOP),
|
||||
Spawn(BomberBotStaticLite, Point.TURRET_TOP_MIDDLE),
|
||||
]
|
||||
@ -412,12 +440,16 @@ class OnslaughtGame(bs.CoopGameActivity[Player, Team]):
|
||||
Spawn(TriggerBotStatic, Point.TURRET_BOTTOM_LEFT),
|
||||
Spawn(TriggerBotStatic, Point.TURRET_BOTTOM_RIGHT),
|
||||
Spawn(TriggerBot, Point.BOTTOM),
|
||||
Spawn(TriggerBot, Point.BOTTOM_HALF_RIGHT)
|
||||
if player_count > 1
|
||||
else None,
|
||||
Spawn(TriggerBot, Point.BOTTOM_HALF_LEFT)
|
||||
if player_count > 2
|
||||
else None,
|
||||
(
|
||||
Spawn(TriggerBot, Point.BOTTOM_HALF_RIGHT)
|
||||
if player_count > 1
|
||||
else None
|
||||
),
|
||||
(
|
||||
Spawn(TriggerBot, Point.BOTTOM_HALF_LEFT)
|
||||
if player_count > 2
|
||||
else None
|
||||
),
|
||||
]
|
||||
),
|
||||
Wave(
|
||||
@ -425,12 +457,16 @@ class OnslaughtGame(bs.CoopGameActivity[Player, Team]):
|
||||
Spawn(BomberBotStaticLite, Point.TURRET_TOP_LEFT),
|
||||
Spawn(BomberBotStaticLite, Point.TURRET_TOP_RIGHT),
|
||||
Spawn(ChargerBot, Point.BOTTOM),
|
||||
Spawn(ChargerBot, Point.BOTTOM_HALF_LEFT)
|
||||
if player_count > 1
|
||||
else None,
|
||||
Spawn(ChargerBot, Point.BOTTOM_HALF_RIGHT)
|
||||
if player_count > 2
|
||||
else None,
|
||||
(
|
||||
Spawn(ChargerBot, Point.BOTTOM_HALF_LEFT)
|
||||
if player_count > 1
|
||||
else None
|
||||
),
|
||||
(
|
||||
Spawn(ChargerBot, Point.BOTTOM_HALF_RIGHT)
|
||||
if player_count > 2
|
||||
else None
|
||||
),
|
||||
]
|
||||
),
|
||||
]
|
||||
@ -442,44 +478,62 @@ class OnslaughtGame(bs.CoopGameActivity[Player, Team]):
|
||||
Wave(
|
||||
base_angle=-50,
|
||||
entries=[
|
||||
Spawn(BrawlerBot, spacing=12)
|
||||
if player_count > 3
|
||||
else None,
|
||||
(
|
||||
Spawn(BrawlerBot, spacing=12)
|
||||
if player_count > 3
|
||||
else None
|
||||
),
|
||||
Spawn(BrawlerBot, spacing=12),
|
||||
Spawn(BomberBot, spacing=6),
|
||||
Spawn(BomberBot, spacing=6)
|
||||
if self._preset is Preset.PRO
|
||||
else None,
|
||||
Spawn(BomberBot, spacing=6)
|
||||
if player_count > 1
|
||||
else None,
|
||||
(
|
||||
Spawn(BomberBot, spacing=6)
|
||||
if self._preset is Preset.PRO
|
||||
else None
|
||||
),
|
||||
(
|
||||
Spawn(BomberBot, spacing=6)
|
||||
if player_count > 1
|
||||
else None
|
||||
),
|
||||
Spawn(BrawlerBot, spacing=12),
|
||||
Spawn(BrawlerBot, spacing=12)
|
||||
if player_count > 2
|
||||
else None,
|
||||
(
|
||||
Spawn(BrawlerBot, spacing=12)
|
||||
if player_count > 2
|
||||
else None
|
||||
),
|
||||
],
|
||||
),
|
||||
Wave(
|
||||
base_angle=180,
|
||||
entries=[
|
||||
Spawn(BrawlerBot, spacing=6)
|
||||
if player_count > 3
|
||||
else None,
|
||||
Spawn(BrawlerBot, spacing=6)
|
||||
if self._preset is Preset.PRO
|
||||
else None,
|
||||
(
|
||||
Spawn(BrawlerBot, spacing=6)
|
||||
if player_count > 3
|
||||
else None
|
||||
),
|
||||
(
|
||||
Spawn(BrawlerBot, spacing=6)
|
||||
if self._preset is Preset.PRO
|
||||
else None
|
||||
),
|
||||
Spawn(BrawlerBot, spacing=6),
|
||||
Spawn(ChargerBot, spacing=45),
|
||||
Spawn(ChargerBot, spacing=45)
|
||||
if player_count > 1
|
||||
else None,
|
||||
(
|
||||
Spawn(ChargerBot, spacing=45)
|
||||
if player_count > 1
|
||||
else None
|
||||
),
|
||||
Spawn(BrawlerBot, spacing=6),
|
||||
Spawn(BrawlerBot, spacing=6)
|
||||
if self._preset is Preset.PRO
|
||||
else None,
|
||||
Spawn(BrawlerBot, spacing=6)
|
||||
if player_count > 2
|
||||
else None,
|
||||
(
|
||||
Spawn(BrawlerBot, spacing=6)
|
||||
if self._preset is Preset.PRO
|
||||
else None
|
||||
),
|
||||
(
|
||||
Spawn(BrawlerBot, spacing=6)
|
||||
if player_count > 2
|
||||
else None
|
||||
),
|
||||
],
|
||||
),
|
||||
Wave(
|
||||
@ -488,15 +542,21 @@ class OnslaughtGame(bs.CoopGameActivity[Player, Team]):
|
||||
Spawn(ChargerBot, spacing=30),
|
||||
Spawn(TriggerBot, spacing=30),
|
||||
Spawn(TriggerBot, spacing=30),
|
||||
Spawn(TriggerBot, spacing=30)
|
||||
if self._preset is Preset.PRO
|
||||
else None,
|
||||
Spawn(TriggerBot, spacing=30)
|
||||
if player_count > 1
|
||||
else None,
|
||||
Spawn(TriggerBot, spacing=30)
|
||||
if player_count > 3
|
||||
else None,
|
||||
(
|
||||
Spawn(TriggerBot, spacing=30)
|
||||
if self._preset is Preset.PRO
|
||||
else None
|
||||
),
|
||||
(
|
||||
Spawn(TriggerBot, spacing=30)
|
||||
if player_count > 1
|
||||
else None
|
||||
),
|
||||
(
|
||||
Spawn(TriggerBot, spacing=30)
|
||||
if player_count > 3
|
||||
else None
|
||||
),
|
||||
Spawn(ChargerBot, spacing=30),
|
||||
],
|
||||
),
|
||||
@ -504,16 +564,22 @@ class OnslaughtGame(bs.CoopGameActivity[Player, Team]):
|
||||
base_angle=90,
|
||||
entries=[
|
||||
Spawn(StickyBot, spacing=50),
|
||||
Spawn(StickyBot, spacing=50)
|
||||
if self._preset is Preset.PRO
|
||||
else None,
|
||||
(
|
||||
Spawn(StickyBot, spacing=50)
|
||||
if self._preset is Preset.PRO
|
||||
else None
|
||||
),
|
||||
Spawn(StickyBot, spacing=50),
|
||||
Spawn(StickyBot, spacing=50)
|
||||
if player_count > 1
|
||||
else None,
|
||||
Spawn(StickyBot, spacing=50)
|
||||
if player_count > 3
|
||||
else None,
|
||||
(
|
||||
Spawn(StickyBot, spacing=50)
|
||||
if player_count > 1
|
||||
else None
|
||||
),
|
||||
(
|
||||
Spawn(StickyBot, spacing=50)
|
||||
if player_count > 3
|
||||
else None
|
||||
),
|
||||
],
|
||||
),
|
||||
Wave(
|
||||
@ -521,14 +587,18 @@ class OnslaughtGame(bs.CoopGameActivity[Player, Team]):
|
||||
entries=[
|
||||
Spawn(TriggerBot, spacing=72),
|
||||
Spawn(TriggerBot, spacing=72),
|
||||
Spawn(TriggerBot, spacing=72)
|
||||
if self._preset is Preset.PRO
|
||||
else None,
|
||||
(
|
||||
Spawn(TriggerBot, spacing=72)
|
||||
if self._preset is Preset.PRO
|
||||
else None
|
||||
),
|
||||
Spawn(TriggerBot, spacing=72),
|
||||
Spawn(TriggerBot, spacing=72),
|
||||
Spawn(TriggerBot, spacing=36)
|
||||
if player_count > 2
|
||||
else None,
|
||||
(
|
||||
Spawn(TriggerBot, spacing=36)
|
||||
if player_count > 2
|
||||
else None
|
||||
),
|
||||
],
|
||||
),
|
||||
Wave(
|
||||
@ -536,15 +606,21 @@ class OnslaughtGame(bs.CoopGameActivity[Player, Team]):
|
||||
entries=[
|
||||
Spawn(ChargerBotProShielded, spacing=50),
|
||||
Spawn(ChargerBotProShielded, spacing=50),
|
||||
Spawn(ChargerBotProShielded, spacing=50)
|
||||
if self._preset is Preset.PRO
|
||||
else None,
|
||||
Spawn(ChargerBotProShielded, spacing=50)
|
||||
if player_count > 1
|
||||
else None,
|
||||
Spawn(ChargerBotProShielded, spacing=50)
|
||||
if player_count > 2
|
||||
else None,
|
||||
(
|
||||
Spawn(ChargerBotProShielded, spacing=50)
|
||||
if self._preset is Preset.PRO
|
||||
else None
|
||||
),
|
||||
(
|
||||
Spawn(ChargerBotProShielded, spacing=50)
|
||||
if player_count > 1
|
||||
else None
|
||||
),
|
||||
(
|
||||
Spawn(ChargerBotProShielded, spacing=50)
|
||||
if player_count > 2
|
||||
else None
|
||||
),
|
||||
],
|
||||
),
|
||||
]
|
||||
@ -562,15 +638,21 @@ class OnslaughtGame(bs.CoopGameActivity[Player, Team]):
|
||||
self._waves = [
|
||||
Wave(
|
||||
entries=[
|
||||
Spawn(BomberBotProStatic, Point.TURRET_TOP_MIDDLE_LEFT)
|
||||
if hard
|
||||
else None,
|
||||
(
|
||||
Spawn(
|
||||
BomberBotProStatic, Point.TURRET_TOP_MIDDLE_LEFT
|
||||
)
|
||||
if hard
|
||||
else None
|
||||
),
|
||||
Spawn(
|
||||
BomberBotProStatic, Point.TURRET_TOP_MIDDLE_RIGHT
|
||||
),
|
||||
Spawn(BomberBotProStatic, Point.TURRET_TOP_LEFT)
|
||||
if player_count > 2
|
||||
else None,
|
||||
(
|
||||
Spawn(BomberBotProStatic, Point.TURRET_TOP_LEFT)
|
||||
if player_count > 2
|
||||
else None
|
||||
),
|
||||
Spawn(ExplodeyBot, Point.TOP_RIGHT),
|
||||
Delay(4.0),
|
||||
Spawn(ExplodeyBot, Point.TOP_LEFT),
|
||||
@ -580,9 +662,11 @@ class OnslaughtGame(bs.CoopGameActivity[Player, Team]):
|
||||
entries=[
|
||||
Spawn(ChargerBot, Point.LEFT),
|
||||
Spawn(ChargerBot, Point.RIGHT),
|
||||
Spawn(ChargerBot, Point.RIGHT_UPPER_MORE)
|
||||
if player_count > 2
|
||||
else None,
|
||||
(
|
||||
Spawn(ChargerBot, Point.RIGHT_UPPER_MORE)
|
||||
if player_count > 2
|
||||
else None
|
||||
),
|
||||
Spawn(BomberBotProStatic, Point.TURRET_TOP_LEFT),
|
||||
Spawn(BomberBotProStatic, Point.TURRET_TOP_RIGHT),
|
||||
]
|
||||
@ -590,29 +674,39 @@ class OnslaughtGame(bs.CoopGameActivity[Player, Team]):
|
||||
Wave(
|
||||
entries=[
|
||||
Spawn(TriggerBotPro, Point.TOP_RIGHT),
|
||||
Spawn(TriggerBotPro, Point.RIGHT_UPPER_MORE)
|
||||
if player_count > 1
|
||||
else None,
|
||||
(
|
||||
Spawn(TriggerBotPro, Point.RIGHT_UPPER_MORE)
|
||||
if player_count > 1
|
||||
else None
|
||||
),
|
||||
Spawn(TriggerBotPro, Point.RIGHT_UPPER),
|
||||
Spawn(TriggerBotPro, Point.RIGHT_LOWER)
|
||||
if hard
|
||||
else None,
|
||||
Spawn(TriggerBotPro, Point.RIGHT_LOWER_MORE)
|
||||
if player_count > 2
|
||||
else None,
|
||||
(
|
||||
Spawn(TriggerBotPro, Point.RIGHT_LOWER)
|
||||
if hard
|
||||
else None
|
||||
),
|
||||
(
|
||||
Spawn(TriggerBotPro, Point.RIGHT_LOWER_MORE)
|
||||
if player_count > 2
|
||||
else None
|
||||
),
|
||||
Spawn(TriggerBotPro, Point.BOTTOM_RIGHT),
|
||||
]
|
||||
),
|
||||
Wave(
|
||||
entries=[
|
||||
Spawn(ChargerBotProShielded, Point.BOTTOM_RIGHT),
|
||||
Spawn(ChargerBotProShielded, Point.BOTTOM)
|
||||
if player_count > 2
|
||||
else None,
|
||||
(
|
||||
Spawn(ChargerBotProShielded, Point.BOTTOM)
|
||||
if player_count > 2
|
||||
else None
|
||||
),
|
||||
Spawn(ChargerBotProShielded, Point.BOTTOM_LEFT),
|
||||
Spawn(ChargerBotProShielded, Point.TOP)
|
||||
if hard
|
||||
else None,
|
||||
(
|
||||
Spawn(ChargerBotProShielded, Point.TOP)
|
||||
if hard
|
||||
else None
|
||||
),
|
||||
Spawn(BomberBotProStatic, Point.TURRET_TOP_MIDDLE),
|
||||
]
|
||||
),
|
||||
@ -639,12 +733,21 @@ class OnslaughtGame(bs.CoopGameActivity[Player, Team]):
|
||||
Spawn(BomberBotProStatic, Point.TURRET_TOP_RIGHT),
|
||||
Spawn(BomberBotProStatic, Point.TURRET_BOTTOM_LEFT),
|
||||
Spawn(BomberBotProStatic, Point.TURRET_BOTTOM_RIGHT),
|
||||
Spawn(BomberBotProStatic, Point.TURRET_TOP_MIDDLE_LEFT)
|
||||
if hard
|
||||
else None,
|
||||
Spawn(BomberBotProStatic, Point.TURRET_TOP_MIDDLE_RIGHT)
|
||||
if hard
|
||||
else None,
|
||||
(
|
||||
Spawn(
|
||||
BomberBotProStatic, Point.TURRET_TOP_MIDDLE_LEFT
|
||||
)
|
||||
if hard
|
||||
else None
|
||||
),
|
||||
(
|
||||
Spawn(
|
||||
BomberBotProStatic,
|
||||
Point.TURRET_TOP_MIDDLE_RIGHT,
|
||||
)
|
||||
if hard
|
||||
else None
|
||||
),
|
||||
]
|
||||
),
|
||||
]
|
||||
@ -663,12 +766,14 @@ class OnslaughtGame(bs.CoopGameActivity[Player, Team]):
|
||||
# Spit out a few powerups and start dropping more shortly.
|
||||
self._drop_powerups(
|
||||
standard_points=True,
|
||||
poweruptype='curse'
|
||||
if self._preset in [Preset.UBER, Preset.UBER_EASY]
|
||||
else (
|
||||
'land_mines'
|
||||
if self._preset in [Preset.ROOKIE, Preset.ROOKIE_EASY]
|
||||
else None
|
||||
poweruptype=(
|
||||
'curse'
|
||||
if self._preset in [Preset.UBER, Preset.UBER_EASY]
|
||||
else (
|
||||
'land_mines'
|
||||
if self._preset in [Preset.ROOKIE, Preset.ROOKIE_EASY]
|
||||
else None
|
||||
)
|
||||
),
|
||||
)
|
||||
bs.timer(4.0, self._start_powerup_drops)
|
||||
@ -825,6 +930,7 @@ class OnslaughtGame(bs.CoopGameActivity[Player, Team]):
|
||||
break
|
||||
entry_count += 1
|
||||
|
||||
@override
|
||||
def spawn_player(self, player: Player) -> bs.Actor:
|
||||
# We keep track of who got hurt each wave for score purposes.
|
||||
player.has_been_hurt = False
|
||||
@ -1414,6 +1520,7 @@ class OnslaughtGame(bs.CoopGameActivity[Player, Team]):
|
||||
assert self._scoreboard is not None
|
||||
self._scoreboard.set_team_value(self.teams[0], score, max_score=None)
|
||||
|
||||
@override
|
||||
def handlemessage(self, msg: Any) -> Any:
|
||||
if isinstance(msg, PlayerSpazHurtMessage):
|
||||
msg.spaz.getplayer(Player, True).has_been_hurt = True
|
||||
@ -1526,6 +1633,7 @@ class OnslaughtGame(bs.CoopGameActivity[Player, Team]):
|
||||
def _set_can_end_wave(self) -> None:
|
||||
self._can_end_wave = True
|
||||
|
||||
@override
|
||||
def end_game(self) -> None:
|
||||
# Tell our bots to celebrate just to rub it in.
|
||||
assert self._bots is not None
|
||||
@ -1534,6 +1642,7 @@ class OnslaughtGame(bs.CoopGameActivity[Player, Team]):
|
||||
self.do_end('defeat', delay=2.0)
|
||||
bs.setmusic(None)
|
||||
|
||||
@override
|
||||
def on_continue(self) -> None:
|
||||
for player in self.players:
|
||||
if not player.is_alive():
|
||||
|
||||
@ -12,11 +12,13 @@ import logging
|
||||
from typing import TYPE_CHECKING
|
||||
from dataclasses import dataclass
|
||||
|
||||
from typing_extensions import override
|
||||
import bascenev1 as bs
|
||||
|
||||
from bascenev1lib.actor.bomb import Bomb
|
||||
from bascenev1lib.actor.playerspaz import PlayerSpaz
|
||||
from bascenev1lib.actor.scoreboard import Scoreboard
|
||||
from bascenev1lib.gameutils import SharedObjects
|
||||
import bascenev1 as bs
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any, Sequence
|
||||
@ -84,6 +86,7 @@ class RaceGame(bs.TeamGameActivity[Player, Team]):
|
||||
label='Time', lower_is_better=True, scoretype=bs.ScoreType.MILLISECONDS
|
||||
)
|
||||
|
||||
@override
|
||||
@classmethod
|
||||
def get_available_settings(
|
||||
cls, sessiontype: type[bs.Session]
|
||||
@ -133,10 +136,12 @@ class RaceGame(bs.TeamGameActivity[Player, Team]):
|
||||
)
|
||||
return settings
|
||||
|
||||
@override
|
||||
@classmethod
|
||||
def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool:
|
||||
return issubclass(sessiontype, bs.MultiTeamSession)
|
||||
|
||||
@override
|
||||
@classmethod
|
||||
def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]:
|
||||
assert bs.app.classic is not None
|
||||
@ -179,6 +184,7 @@ class RaceGame(bs.TeamGameActivity[Player, Team]):
|
||||
bs.MusicType.EPIC_RACE if self._epic_mode else bs.MusicType.RACE
|
||||
)
|
||||
|
||||
@override
|
||||
def get_instance_description(self) -> str | Sequence:
|
||||
if (
|
||||
isinstance(self.session, bs.DualTeamSession)
|
||||
@ -192,11 +198,13 @@ class RaceGame(bs.TeamGameActivity[Player, Team]):
|
||||
return 'Run ${ARG1} laps.' + t_str, self._laps
|
||||
return 'Run 1 lap.' + t_str
|
||||
|
||||
@override
|
||||
def get_instance_description_short(self) -> str | Sequence:
|
||||
if self._laps > 1:
|
||||
return 'run ${ARG1} laps', self._laps
|
||||
return 'run 1 lap'
|
||||
|
||||
@override
|
||||
def on_transition_in(self) -> None:
|
||||
super().on_transition_in()
|
||||
shared = SharedObjects.get()
|
||||
@ -379,9 +387,11 @@ class RaceGame(bs.TeamGameActivity[Player, Team]):
|
||||
except Exception:
|
||||
logging.exception('Error printing lap.')
|
||||
|
||||
@override
|
||||
def on_team_join(self, team: Team) -> None:
|
||||
self._update_scoreboard()
|
||||
|
||||
@override
|
||||
def on_player_leave(self, player: Player) -> None:
|
||||
super().on_player_leave(player)
|
||||
|
||||
@ -442,6 +452,7 @@ class RaceGame(bs.TeamGameActivity[Player, Team]):
|
||||
show_value=False,
|
||||
)
|
||||
|
||||
@override
|
||||
def on_begin(self) -> None:
|
||||
from bascenev1lib.actor.onscreentimer import OnScreenTimer
|
||||
|
||||
@ -670,6 +681,7 @@ class RaceGame(bs.TeamGameActivity[Player, Team]):
|
||||
self._flash_mine(m_index)
|
||||
bs.timer(0.95, bs.Call(self._make_mine, m_index))
|
||||
|
||||
@override
|
||||
def spawn_player(self, player: Player) -> bs.Actor:
|
||||
if player.team.finished:
|
||||
# FIXME: This is not type-safe!
|
||||
@ -758,6 +770,7 @@ class RaceGame(bs.TeamGameActivity[Player, Team]):
|
||||
self.end_game()
|
||||
return
|
||||
|
||||
@override
|
||||
def end_game(self) -> None:
|
||||
# Stop updating our time text, and set it to show the exact last
|
||||
# finish time if we have one. (so users don't get upset if their
|
||||
@ -765,9 +778,11 @@ class RaceGame(bs.TeamGameActivity[Player, Team]):
|
||||
assert self._timer is not None
|
||||
if self._timer.has_started():
|
||||
self._timer.stop(
|
||||
endtime=None
|
||||
if self._last_team_time is None
|
||||
else (self._timer.getstarttime() + self._last_team_time)
|
||||
endtime=(
|
||||
None
|
||||
if self._last_team_time is None
|
||||
else (self._timer.getstarttime() + self._last_team_time)
|
||||
)
|
||||
)
|
||||
|
||||
results = bs.GameResults()
|
||||
@ -787,6 +802,7 @@ class RaceGame(bs.TeamGameActivity[Player, Team]):
|
||||
announce_winning_team=isinstance(self.session, bs.DualTeamSession),
|
||||
)
|
||||
|
||||
@override
|
||||
def handlemessage(self, msg: Any) -> Any:
|
||||
if isinstance(msg, bs.PlayerDiedMessage):
|
||||
# Augment default behavior.
|
||||
|
||||
@ -16,6 +16,9 @@ from enum import Enum
|
||||
from dataclasses import dataclass
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from typing_extensions import override
|
||||
import bascenev1 as bs
|
||||
|
||||
from bascenev1lib.actor.popuptext import PopupText
|
||||
from bascenev1lib.actor.bomb import TNTSpawner
|
||||
from bascenev1lib.actor.scoreboard import Scoreboard
|
||||
@ -40,7 +43,6 @@ from bascenev1lib.actor.spazbot import (
|
||||
BomberBotPro,
|
||||
BrawlerBotPro,
|
||||
)
|
||||
import bascenev1 as bs
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any, Sequence
|
||||
@ -195,6 +197,7 @@ class RunaroundGame(bs.CoopGameActivity[Player, Team]):
|
||||
self._flawless_bonus: int | None = None
|
||||
self._wave_update_timer: bs.Timer | None = None
|
||||
|
||||
@override
|
||||
def on_transition_in(self) -> None:
|
||||
super().on_transition_in()
|
||||
self._scoreboard = Scoreboard(
|
||||
@ -212,6 +215,7 @@ class RunaroundGame(bs.CoopGameActivity[Player, Team]):
|
||||
)
|
||||
)
|
||||
|
||||
@override
|
||||
def on_begin(self) -> None:
|
||||
super().on_begin()
|
||||
player_count = len(self.players)
|
||||
@ -276,9 +280,11 @@ class RunaroundGame(bs.CoopGameActivity[Player, Team]):
|
||||
Spacing(duration=1.0),
|
||||
Spawn(TriggerBot, path=3),
|
||||
Spacing(duration=1.0),
|
||||
Spawn(TriggerBot, path=1)
|
||||
if (player_count > 1 and hard)
|
||||
else None,
|
||||
(
|
||||
Spawn(TriggerBot, path=1)
|
||||
if (player_count > 1 and hard)
|
||||
else None
|
||||
),
|
||||
Spacing(duration=1.0),
|
||||
Spawn(TriggerBot, path=2) if player_count > 2 else None,
|
||||
Spacing(duration=1.0),
|
||||
@ -317,17 +323,23 @@ class RunaroundGame(bs.CoopGameActivity[Player, Team]):
|
||||
Spacing(duration=1.5),
|
||||
Spawn(BomberBotProShielded, path=1) if hard else None,
|
||||
Spacing(duration=1.5) if hard else None,
|
||||
Spawn(BomberBotProShielded, path=3)
|
||||
if player_count > 1
|
||||
else None,
|
||||
(
|
||||
Spawn(BomberBotProShielded, path=3)
|
||||
if player_count > 1
|
||||
else None
|
||||
),
|
||||
Spacing(duration=1.5),
|
||||
Spawn(BomberBotProShielded, path=2)
|
||||
if player_count > 2
|
||||
else None,
|
||||
(
|
||||
Spawn(BomberBotProShielded, path=2)
|
||||
if player_count > 2
|
||||
else None
|
||||
),
|
||||
Spacing(duration=1.5),
|
||||
Spawn(BomberBotProShielded, path=1)
|
||||
if player_count > 3
|
||||
else None,
|
||||
(
|
||||
Spawn(BomberBotProShielded, path=1)
|
||||
if player_count > 3
|
||||
else None
|
||||
),
|
||||
]
|
||||
),
|
||||
]
|
||||
@ -349,9 +361,11 @@ class RunaroundGame(bs.CoopGameActivity[Player, Team]):
|
||||
BrawlerBotPro if hard else BrawlerBot,
|
||||
point=Point.BOTTOM_LEFT,
|
||||
),
|
||||
Spawn(BrawlerBotPro, point=Point.BOTTOM_RIGHT)
|
||||
if player_count > 2
|
||||
else None,
|
||||
(
|
||||
Spawn(BrawlerBotPro, point=Point.BOTTOM_RIGHT)
|
||||
if player_count > 2
|
||||
else None
|
||||
),
|
||||
]
|
||||
),
|
||||
Wave(
|
||||
@ -372,9 +386,11 @@ class RunaroundGame(bs.CoopGameActivity[Player, Team]):
|
||||
Spawn(BomberBotProShielded, path=3),
|
||||
Spawn(BomberBotProShielded, path=3),
|
||||
Spawn(ChargerBot, point=Point.BOTTOM_RIGHT),
|
||||
Spawn(ChargerBot, point=Point.BOTTOM_LEFT)
|
||||
if player_count > 2
|
||||
else None,
|
||||
(
|
||||
Spawn(ChargerBot, point=Point.BOTTOM_LEFT)
|
||||
if player_count > 2
|
||||
else None
|
||||
),
|
||||
]
|
||||
),
|
||||
Wave(
|
||||
@ -385,12 +401,16 @@ class RunaroundGame(bs.CoopGameActivity[Player, Team]):
|
||||
Spawn(TriggerBotPro, path=1 if hard else 2),
|
||||
Spawn(TriggerBotPro, path=1 if hard else 2),
|
||||
Spawn(TriggerBotPro, path=1 if hard else 2),
|
||||
Spawn(TriggerBotPro, path=1 if hard else 2)
|
||||
if player_count > 1
|
||||
else None,
|
||||
Spawn(TriggerBotPro, path=1 if hard else 2)
|
||||
if player_count > 3
|
||||
else None,
|
||||
(
|
||||
Spawn(TriggerBotPro, path=1 if hard else 2)
|
||||
if player_count > 1
|
||||
else None
|
||||
),
|
||||
(
|
||||
Spawn(TriggerBotPro, path=1 if hard else 2)
|
||||
if player_count > 3
|
||||
else None
|
||||
),
|
||||
]
|
||||
),
|
||||
Wave(
|
||||
@ -399,12 +419,20 @@ class RunaroundGame(bs.CoopGameActivity[Player, Team]):
|
||||
TriggerBotProShielded if hard else TriggerBotPro,
|
||||
point=Point.BOTTOM_LEFT,
|
||||
),
|
||||
Spawn(TriggerBotProShielded, point=Point.BOTTOM_RIGHT)
|
||||
if hard
|
||||
else None,
|
||||
Spawn(TriggerBotProShielded, point=Point.BOTTOM_RIGHT)
|
||||
if player_count > 2
|
||||
else None,
|
||||
(
|
||||
Spawn(
|
||||
TriggerBotProShielded, point=Point.BOTTOM_RIGHT
|
||||
)
|
||||
if hard
|
||||
else None
|
||||
),
|
||||
(
|
||||
Spawn(
|
||||
TriggerBotProShielded, point=Point.BOTTOM_RIGHT
|
||||
)
|
||||
if player_count > 2
|
||||
else None
|
||||
),
|
||||
Spawn(BomberBot, path=3),
|
||||
Spawn(BomberBot, path=3),
|
||||
Spacing(duration=5.0),
|
||||
@ -422,15 +450,19 @@ class RunaroundGame(bs.CoopGameActivity[Player, Team]):
|
||||
Spawn(StickyBot, point=Point.BOTTOM_RIGHT),
|
||||
Spawn(BomberBotProShielded, path=2),
|
||||
Spawn(BomberBotProShielded, path=2),
|
||||
Spawn(StickyBot, point=Point.BOTTOM_RIGHT)
|
||||
if player_count > 2
|
||||
else None,
|
||||
(
|
||||
Spawn(StickyBot, point=Point.BOTTOM_RIGHT)
|
||||
if player_count > 2
|
||||
else None
|
||||
),
|
||||
Spawn(BomberBotProShielded, path=2),
|
||||
Spawn(ExplodeyBot, point=Point.BOTTOM_LEFT),
|
||||
Spawn(BomberBotProShielded, path=2),
|
||||
Spawn(BomberBotProShielded, path=2)
|
||||
if player_count > 1
|
||||
else None,
|
||||
(
|
||||
Spawn(BomberBotProShielded, path=2)
|
||||
if player_count > 1
|
||||
else None
|
||||
),
|
||||
Spacing(duration=5.0),
|
||||
Spawn(StickyBot, point=Point.BOTTOM_LEFT),
|
||||
Spacing(duration=2.0),
|
||||
@ -458,9 +490,7 @@ class RunaroundGame(bs.CoopGameActivity[Player, Team]):
|
||||
l_offs = (
|
||||
-80
|
||||
if uiscale is bs.UIScale.SMALL
|
||||
else -40
|
||||
if uiscale is bs.UIScale.MEDIUM
|
||||
else 0
|
||||
else -40 if uiscale is bs.UIScale.MEDIUM else 0
|
||||
)
|
||||
|
||||
self._lives_bg = bs.NodeActor(
|
||||
@ -586,6 +616,7 @@ class RunaroundGame(bs.CoopGameActivity[Player, Team]):
|
||||
),
|
||||
)
|
||||
|
||||
@override
|
||||
def on_continue(self) -> None:
|
||||
self._lives = 3
|
||||
assert self._lives_text is not None
|
||||
@ -593,6 +624,7 @@ class RunaroundGame(bs.CoopGameActivity[Player, Team]):
|
||||
self._lives_text.node.text = str(self._lives)
|
||||
self._bots.start_moving()
|
||||
|
||||
@override
|
||||
def spawn_player(self, player: Player) -> bs.Actor:
|
||||
pos = (
|
||||
self._spawn_center[0] + random.uniform(-1.5, 1.5),
|
||||
@ -669,6 +701,7 @@ class RunaroundGame(bs.CoopGameActivity[Player, Team]):
|
||||
),
|
||||
).autoretain()
|
||||
|
||||
@override
|
||||
def end_game(self) -> None:
|
||||
bs.pushcall(bs.Call(self.do_end, 'defeat'))
|
||||
bs.setmusic(None)
|
||||
@ -1301,6 +1334,7 @@ class RunaroundGame(bs.CoopGameActivity[Player, Team]):
|
||||
# Revert to normal bot behavior otherwise..
|
||||
return False
|
||||
|
||||
@override
|
||||
def handlemessage(self, msg: Any) -> Any:
|
||||
if isinstance(msg, bs.PlayerScoredMessage):
|
||||
self._score += msg.score
|
||||
|
||||
@ -10,11 +10,13 @@ from __future__ import annotations
|
||||
import random
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from typing_extensions import override
|
||||
import bascenev1 as bs
|
||||
|
||||
from bascenev1lib.actor.scoreboard import Scoreboard
|
||||
from bascenev1lib.actor.onscreencountdown import OnScreenCountdown
|
||||
from bascenev1lib.actor.bomb import Bomb
|
||||
from bascenev1lib.actor.popuptext import PopupText
|
||||
import bascenev1 as bs
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any, Sequence
|
||||
@ -49,10 +51,12 @@ class TargetPracticeGame(bs.TeamGameActivity[Player, Team]):
|
||||
]
|
||||
default_music = bs.MusicType.FORWARD_MARCH
|
||||
|
||||
@override
|
||||
@classmethod
|
||||
def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]:
|
||||
return ['Doom Shroom']
|
||||
|
||||
@override
|
||||
@classmethod
|
||||
def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool:
|
||||
# We support any teams or versus sessions.
|
||||
@ -70,10 +74,12 @@ class TargetPracticeGame(bs.TeamGameActivity[Player, Team]):
|
||||
self._enable_impact_bombs = bool(settings['Enable Impact Bombs'])
|
||||
self._enable_triple_bombs = bool(settings['Enable Triple Bombs'])
|
||||
|
||||
@override
|
||||
def on_team_join(self, team: Team) -> None:
|
||||
if self.has_begun():
|
||||
self.update_scoreboard()
|
||||
|
||||
@override
|
||||
def on_begin(self) -> None:
|
||||
super().on_begin()
|
||||
self.update_scoreboard()
|
||||
@ -86,6 +92,7 @@ class TargetPracticeGame(bs.TeamGameActivity[Player, Team]):
|
||||
self._countdown = OnScreenCountdown(60, endcall=self.end_game)
|
||||
bs.timer(4.0, self._countdown.start)
|
||||
|
||||
@override
|
||||
def spawn_player(self, player: Player) -> bs.Actor:
|
||||
spawn_center = (0, 3, -5)
|
||||
pos = (
|
||||
@ -169,6 +176,7 @@ class TargetPracticeGame(bs.TeamGameActivity[Player, Team]):
|
||||
# Clear out targets that have died.
|
||||
self._targets = [t for t in self._targets if t]
|
||||
|
||||
@override
|
||||
def handlemessage(self, msg: Any) -> Any:
|
||||
# When players die, respawn them.
|
||||
if isinstance(msg, bs.PlayerDiedMessage):
|
||||
@ -188,6 +196,7 @@ class TargetPracticeGame(bs.TeamGameActivity[Player, Team]):
|
||||
for team in self.teams:
|
||||
self._scoreboard.set_team_value(team, team.score)
|
||||
|
||||
@override
|
||||
def end_game(self) -> None:
|
||||
results = bs.GameResults()
|
||||
for team in self.teams:
|
||||
@ -252,9 +261,11 @@ class Target(bs.Actor):
|
||||
bs.animate_array(loc3, 'size', 1, {0.1: [0.0], 0.3: [self._r3 * 2.0]})
|
||||
bs.getsound('laserReverse').play()
|
||||
|
||||
@override
|
||||
def exists(self) -> bool:
|
||||
return bool(self._nodes)
|
||||
|
||||
@override
|
||||
def handlemessage(self, msg: Any) -> Any:
|
||||
if isinstance(msg, bs.DieMessage):
|
||||
for node in self._nodes:
|
||||
@ -310,11 +321,15 @@ class Target(bs.Actor):
|
||||
bs.getsound(
|
||||
'orchestraHit4'
|
||||
if streak > 3
|
||||
else 'orchestraHit3'
|
||||
if streak > 2
|
||||
else 'orchestraHit2'
|
||||
if streak > 1
|
||||
else 'orchestraHit'
|
||||
else (
|
||||
'orchestraHit3'
|
||||
if streak > 2
|
||||
else (
|
||||
'orchestraHit2'
|
||||
if streak > 1
|
||||
else 'orchestraHit'
|
||||
)
|
||||
)
|
||||
).play()
|
||||
elif dist <= self._r2 + self._rfudge:
|
||||
self._nodes[0].color = cdull
|
||||
|
||||
@ -9,6 +9,9 @@ import logging
|
||||
from dataclasses import dataclass
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from typing_extensions import override
|
||||
import bascenev1 as bs
|
||||
|
||||
from bascenev1lib.actor.playerspaz import PlayerSpaz
|
||||
from bascenev1lib.actor.bomb import TNTSpawner
|
||||
from bascenev1lib.actor.scoreboard import Scoreboard
|
||||
@ -29,7 +32,6 @@ from bascenev1lib.actor.spazbot import (
|
||||
StickyBot,
|
||||
ExplodeyBot,
|
||||
)
|
||||
import bascenev1 as bs
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any, Sequence
|
||||
@ -109,6 +111,7 @@ class TheLastStandGame(bs.CoopGameActivity[Player, Team]):
|
||||
ExplodeyBot: SpawnInfo(0.05, 0.02, 0.002),
|
||||
}
|
||||
|
||||
@override
|
||||
def on_transition_in(self) -> None:
|
||||
super().on_transition_in()
|
||||
bs.timer(1.3, self._new_wave_sound.play)
|
||||
@ -116,6 +119,7 @@ class TheLastStandGame(bs.CoopGameActivity[Player, Team]):
|
||||
label=bs.Lstr(resource='scoreText'), score_split=0.5
|
||||
)
|
||||
|
||||
@override
|
||||
def on_begin(self) -> None:
|
||||
super().on_begin()
|
||||
|
||||
@ -129,6 +133,7 @@ class TheLastStandGame(bs.CoopGameActivity[Player, Team]):
|
||||
position=self._tntspawnpos, respawn_time=10.0
|
||||
)
|
||||
|
||||
@override
|
||||
def spawn_player(self, player: Player) -> bs.Actor:
|
||||
pos = (
|
||||
self._spawn_center[0] + random.uniform(-1.5, 1.5),
|
||||
@ -290,6 +295,7 @@ class TheLastStandGame(bs.CoopGameActivity[Player, Team]):
|
||||
assert self._scoreboard is not None
|
||||
self._scoreboard.set_team_value(self.teams[0], score, max_score=None)
|
||||
|
||||
@override
|
||||
def handlemessage(self, msg: Any) -> Any:
|
||||
if isinstance(msg, bs.PlayerDiedMessage):
|
||||
player = msg.getplayer(Player)
|
||||
@ -327,6 +333,7 @@ class TheLastStandGame(bs.CoopGameActivity[Player, Team]):
|
||||
else:
|
||||
super().handlemessage(msg)
|
||||
|
||||
@override
|
||||
def end_game(self) -> None:
|
||||
# Tell our bots to celebrate just to rub it in.
|
||||
self._bots.final_celebrate()
|
||||
|
||||
@ -10,6 +10,7 @@ import random
|
||||
import weakref
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from typing_extensions import override
|
||||
import bascenev1 as bs
|
||||
import bauiv1 as bui
|
||||
|
||||
@ -44,6 +45,7 @@ class MainMenuActivity(bs.Activity[bs.Player, bs.Team]):
|
||||
self._news: NewsDisplay | None = None
|
||||
self._attract_mode_timer: bs.Timer | None = None
|
||||
|
||||
@override
|
||||
def on_transition_in(self) -> None:
|
||||
# pylint: disable=too-many-locals
|
||||
# pylint: disable=too-many-statements
|
||||
@ -1139,6 +1141,7 @@ class MainMenuSession(bs.Session):
|
||||
self._locked = False
|
||||
self.setactivity(bs.newactivity(MainMenuActivity))
|
||||
|
||||
@override
|
||||
def on_activity_end(self, activity: bs.Activity, results: Any) -> None:
|
||||
if self._locked:
|
||||
bui.unlock_all_input()
|
||||
@ -1146,6 +1149,7 @@ class MainMenuSession(bs.Session):
|
||||
# Any ending activity leads us into the main menu one.
|
||||
self.setactivity(bs.newactivity(MainMenuActivity))
|
||||
|
||||
@override
|
||||
def on_player_request(self, player: bs.SessionPlayer) -> bool:
|
||||
# Reject all player requests.
|
||||
return False
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user