From 416e3e6a19c03aad58dacd7d95f3740dd225b343 Mon Sep 17 00:00:00 2001 From: vishal332008 Date: Wed, 15 Jul 2026 20:46:55 +0530 Subject: [PATCH 01/14] few changes --- dist/ba_data/python/efro/dataclassio/_api.py | 2 ++ dist/ba_data/python/efro/dataclassio/_base.py | 7 +++++-- dist/ba_data/python/efro/dataclassio/_inputter.py | 2 ++ dist/ba_data/python/efro/dataclassio/_outputter.py | 2 ++ dist/ba_data/python/efro/dataclassio/_pathcapture.py | 2 ++ dist/ba_data/python/efro/dataclassio/_prep.py | 2 ++ dist/ba_data/python/efro/error.py | 2 ++ dist/ba_data/python/efro/terminal.py | 2 ++ dist/ba_data/python/efro/util.py | 2 ++ dist/ba_root/mods/plugins/__init__.py | 4 ++-- dist/ba_root/mods/plugins/auto_stunt.py | 4 ++-- dist/ba_root/mods/plugins/bcs_plugin.py | 2 +- dist/ba_root/mods/plugins/color_explosion.py | 2 +- dist/ba_root/mods/plugins/elPatronPowerups.py | 2 +- dist/ba_root/mods/plugins/importcustomcharacters.py | 2 +- dist/ba_root/mods/plugins/wavedash.py | 2 +- 16 files changed, 30 insertions(+), 11 deletions(-) diff --git a/dist/ba_data/python/efro/dataclassio/_api.py b/dist/ba_data/python/efro/dataclassio/_api.py index 8e3080f..2579b82 100644 --- a/dist/ba_data/python/efro/dataclassio/_api.py +++ b/dist/ba_data/python/efro/dataclassio/_api.py @@ -8,6 +8,8 @@ unrecognized attribute data, allowing older clients to interact with newer data formats in a nondestructive manner. """ +from __future__ import annotations + import json from enum import Enum from typing import TYPE_CHECKING diff --git a/dist/ba_data/python/efro/dataclassio/_base.py b/dist/ba_data/python/efro/dataclassio/_base.py index 5a726de..07a7f9b 100644 --- a/dist/ba_data/python/efro/dataclassio/_base.py +++ b/dist/ba_data/python/efro/dataclassio/_base.py @@ -2,6 +2,8 @@ # """Core components of dataclassio.""" +from __future__ import annotations + import dataclasses import typing import warnings @@ -11,6 +13,7 @@ from typing import TYPE_CHECKING, get_args, override, final from typing import _AnnotatedAlias # type: ignore + if TYPE_CHECKING: from typing import Any, Callable, Literal, ClassVar, Self @@ -20,8 +23,8 @@ SIMPLE_TYPES = {int, bool, str, float, type(None)} # Attr name for dict of extra attributes included on dataclass # instances. Note that this is only added if extra attributes are # present. -EXTRA_ATTRS_ATTR = '_DCIOEXATTRS' - +EXTRA_ATTRS_ATTR = '_DCIOEXATTRS' fgb + # Attr name for a bool attr for flagging data as lossy, which means it # may have been modified in some way during load and should generally # not be written back out. diff --git a/dist/ba_data/python/efro/dataclassio/_inputter.py b/dist/ba_data/python/efro/dataclassio/_inputter.py index f35c8d8..43fd6fe 100644 --- a/dist/ba_data/python/efro/dataclassio/_inputter.py +++ b/dist/ba_data/python/efro/dataclassio/_inputter.py @@ -6,6 +6,8 @@ # frowned upon (stuff like isinstance() is usually encouraged). # pylint: disable=unidiomatic-typecheck +from __future__ import annotations + from enum import Enum import dataclasses import typing diff --git a/dist/ba_data/python/efro/dataclassio/_outputter.py b/dist/ba_data/python/efro/dataclassio/_outputter.py index 3273218..11cf29f 100644 --- a/dist/ba_data/python/efro/dataclassio/_outputter.py +++ b/dist/ba_data/python/efro/dataclassio/_outputter.py @@ -6,6 +6,8 @@ # frowned upon (stuff like isinstance() is usually encouraged). # pylint: disable=unidiomatic-typecheck +from __future__ import annotations + from enum import Enum import dataclasses import typing diff --git a/dist/ba_data/python/efro/dataclassio/_pathcapture.py b/dist/ba_data/python/efro/dataclassio/_pathcapture.py index 9f40db0..db01f6f 100644 --- a/dist/ba_data/python/efro/dataclassio/_pathcapture.py +++ b/dist/ba_data/python/efro/dataclassio/_pathcapture.py @@ -2,6 +2,8 @@ # """Functionality related to capturing nested dataclass paths.""" +from __future__ import annotations + import dataclasses from typing import TYPE_CHECKING diff --git a/dist/ba_data/python/efro/dataclassio/_prep.py b/dist/ba_data/python/efro/dataclassio/_prep.py index a4d8ecb..6950256 100644 --- a/dist/ba_data/python/efro/dataclassio/_prep.py +++ b/dist/ba_data/python/efro/dataclassio/_prep.py @@ -7,6 +7,8 @@ # # pylint: disable=unidiomatic-typecheck +from __future__ import annotations + import logging from enum import Enum import dataclasses diff --git a/dist/ba_data/python/efro/error.py b/dist/ba_data/python/efro/error.py index b9a1be0..0edc724 100644 --- a/dist/ba_data/python/efro/error.py +++ b/dist/ba_data/python/efro/error.py @@ -5,6 +5,8 @@ # """Common errors and related functionality.""" +from __future__ import annotations + from typing import TYPE_CHECKING, override import errno diff --git a/dist/ba_data/python/efro/terminal.py b/dist/ba_data/python/efro/terminal.py index f7c8e40..4ddbcf1 100644 --- a/dist/ba_data/python/efro/terminal.py +++ b/dist/ba_data/python/efro/terminal.py @@ -2,6 +2,8 @@ # """Functionality related to terminal IO.""" +from __future__ import annotations + import sys import os from enum import Enum, unique diff --git a/dist/ba_data/python/efro/util.py b/dist/ba_data/python/efro/util.py index 864bee3..56031a4 100644 --- a/dist/ba_data/python/efro/util.py +++ b/dist/ba_data/python/efro/util.py @@ -6,6 +6,8 @@ # pylint: disable=too-many-lines """Small handy bits of functionality.""" +from __future__ import annotations + import os import time import random diff --git a/dist/ba_root/mods/plugins/__init__.py b/dist/ba_root/mods/plugins/__init__.py index 6f21715..1e77138 100644 --- a/dist/ba_root/mods/plugins/__init__.py +++ b/dist/ba_root/mods/plugins/__init__.py @@ -6,7 +6,7 @@ tests since they are widely used in live client and server code. license : MIT, see LICENSE for more details. """ -# ba_meta require api 8 +# ba_meta require api 9 # (see https://ballistica.net/wiki/meta-tag-system) from __future__ import annotations @@ -19,6 +19,6 @@ if TYPE_CHECKING: pass -# ba_meta export plugin +# ba_meta export babase.Plugin class Init(babase.Plugin): # pylint: disable=too-few-public-methods """Initializes all of the plugins in the directory.""" diff --git a/dist/ba_root/mods/plugins/auto_stunt.py b/dist/ba_root/mods/plugins/auto_stunt.py index 12f6762..5e3556f 100644 --- a/dist/ba_root/mods/plugins/auto_stunt.py +++ b/dist/ba_root/mods/plugins/auto_stunt.py @@ -1,4 +1,4 @@ -# ba_meta require api 8 +# ba_meta require api 9 # AutoStunt mod by - Mr.Smoothy x Rikko # https://discord.gg/ucyaesh # https://bombsquad.ga @@ -553,7 +553,7 @@ def on_begin(self, *args, **kwargs) -> None: return original_on_begin(self, *args, **kwargs) -# ba_meta export plugin +# ba_meta export babase.Plugin class byHeySmoothy(babase.Plugin): def on_app_running(self): try: diff --git a/dist/ba_root/mods/plugins/bcs_plugin.py b/dist/ba_root/mods/plugins/bcs_plugin.py index 0e419a7..d36cbef 100644 --- a/dist/ba_root/mods/plugins/bcs_plugin.py +++ b/dist/ba_root/mods/plugins/bcs_plugin.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # coding: utf-8 -# ba_meta require api 8 +# ba_meta require api 9 # from gunicorn.app.base import BaseApplication # from gunicorn.workers import ggevent as gevent_worker diff --git a/dist/ba_root/mods/plugins/color_explosion.py b/dist/ba_root/mods/plugins/color_explosion.py index abc8c60..2f782a9 100644 --- a/dist/ba_root/mods/plugins/color_explosion.py +++ b/dist/ba_root/mods/plugins/color_explosion.py @@ -1,6 +1,6 @@ """Define a simple example plugin.""" -# ba_meta require api 8 +# ba_meta require api 9 from __future__ import annotations diff --git a/dist/ba_root/mods/plugins/elPatronPowerups.py b/dist/ba_root/mods/plugins/elPatronPowerups.py index 6f23a11..fe234d8 100644 --- a/dist/ba_root/mods/plugins/elPatronPowerups.py +++ b/dist/ba_root/mods/plugins/elPatronPowerups.py @@ -1,4 +1,4 @@ -# ba_meta require api 8 +# ba_meta require api 9 from __future__ import annotations _sp_ = ('\n') diff --git a/dist/ba_root/mods/plugins/importcustomcharacters.py b/dist/ba_root/mods/plugins/importcustomcharacters.py index 4635562..cae4a72 100644 --- a/dist/ba_root/mods/plugins/importcustomcharacters.py +++ b/dist/ba_root/mods/plugins/importcustomcharacters.py @@ -1,6 +1,6 @@ """Module to update `setting.json`.""" -# ba_meta require api 8 +# ba_meta require api 9 # (see https://ballistica.net/wiki/meta-tag-system) from __future__ import annotations diff --git a/dist/ba_root/mods/plugins/wavedash.py b/dist/ba_root/mods/plugins/wavedash.py index 10bb717..effd8f9 100644 --- a/dist/ba_root/mods/plugins/wavedash.py +++ b/dist/ba_root/mods/plugins/wavedash.py @@ -4,7 +4,7 @@ """ -# ba_meta require api 8 +# ba_meta require api 9 from __future__ import annotations From e03fec686b3b6a68dec54dfe989121f10ad333b4 Mon Sep 17 00:00:00 2001 From: vishal332008 Date: Wed, 15 Jul 2026 20:48:14 +0530 Subject: [PATCH 02/14] removing test text --- dist/ba_data/python/efro/dataclassio/_base.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dist/ba_data/python/efro/dataclassio/_base.py b/dist/ba_data/python/efro/dataclassio/_base.py index 07a7f9b..6229b59 100644 --- a/dist/ba_data/python/efro/dataclassio/_base.py +++ b/dist/ba_data/python/efro/dataclassio/_base.py @@ -23,8 +23,8 @@ SIMPLE_TYPES = {int, bool, str, float, type(None)} # Attr name for dict of extra attributes included on dataclass # instances. Note that this is only added if extra attributes are # present. -EXTRA_ATTRS_ATTR = '_DCIOEXATTRS' fgb - +EXTRA_ATTRS_ATTR = '_DCIOEXATTRS' + # Attr name for a bool attr for flagging data as lossy, which means it # may have been modified in some way during load and should generally # not be written back out. From 523dbeb82c1ef8d6590ad7c7ebb9d2fa6d9fd350 Mon Sep 17 00:00:00 2001 From: vishal332008 Date: Wed, 15 Jul 2026 21:31:03 +0530 Subject: [PATCH 03/14] removing babase.Call error --- dist/ba_root/mods/features/afk_check.py | 2 +- dist/ba_root/mods/features/text_on_map.py | 2 +- dist/ba_root/mods/plugins/bombsquad_service.py | 10 +++++----- dist/ba_root/mods/tools/servercheck.py | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/dist/ba_root/mods/features/afk_check.py b/dist/ba_root/mods/features/afk_check.py index 9cd596a..755acf3 100644 --- a/dist/ba_root/mods/features/afk_check.py +++ b/dist/ba_root/mods/features/afk_check.py @@ -15,7 +15,7 @@ cLastIdle = 0 class checkIdle(object): def start(self): - self.t1 = babase.AppTimer(2, babase.Call(self.check), repeat=True) + self.t1 = babase.AppTimer(2, babase.CallStrict(self.check), repeat=True) self.lobbies = {} def check(self): diff --git a/dist/ba_root/mods/features/text_on_map.py b/dist/ba_root/mods/features/text_on_map.py index 9b7e1ff..6b5fb84 100644 --- a/dist/ba_root/mods/features/text_on_map.py +++ b/dist/ba_root/mods/features/text_on_map.py @@ -41,7 +41,7 @@ class textonmap: self.season_reset(_babase.season_ends_in_days) if setti["leaderboard"]["enable"]: self.leaderBoard() - self.timer = bs.timer(8, babase.Call(self.highlights_), repeat=True) + self.timer = bs.timer(8, babase.CallStrict(self.highlights_), repeat=True) def highlights_(self): if setti["textonmap"]['center highlights']["randomColor"]: diff --git a/dist/ba_root/mods/plugins/bombsquad_service.py b/dist/ba_root/mods/plugins/bombsquad_service.py index 5c0a11f..bdec815 100644 --- a/dist/ba_root/mods/plugins/bombsquad_service.py +++ b/dist/ba_root/mods/plugins/bombsquad_service.py @@ -33,9 +33,9 @@ class BsDataThread(object): )["ballistica_web"]["discord_link"] stats["vapidKey"] = notification_manager.get_vapid_keys()["public_key"] - self.refresh_stats_cache_timer = bs.AppTimer(8, babase.Call( + self.refresh_stats_cache_timer = bs.AppTimer(8, babase.CallStrict( self.refreshStats), repeat=True) - self.refresh_leaderboard_cache_timer = bs.AppTimer(10, babase.Call( + self.refresh_leaderboard_cache_timer = bs.AppTimer(10, babase.CallStrict( self.refreshLeaderboard), repeat=True) def startThread(self): @@ -118,7 +118,7 @@ class BsDataThread(object): return data -v = bs.AppTimer(8, babase.Call( +v = bs.AppTimer(8, babase.CallStrict( BsDataThread)) @@ -282,10 +282,10 @@ def update_server_config(config): def do_action(action, value): if action == "message": - _babase.pushcall(babase.Call(bs.chatmessage, value), + _babase.pushcall(babase.CallPartial(bs.chatmessage, value), from_other_thread=True) elif action == "quit": - _babase.pushcall(babase.Call(_babase.quit), from_other_thread=True) + _babase.pushcall(babase.CallStrict(_babase.quit), from_other_thread=True) def subscribe_player(sub, account_id, name): diff --git a/dist/ba_root/mods/tools/servercheck.py b/dist/ba_root/mods/tools/servercheck.py index a279936..98e2430 100644 --- a/dist/ba_root/mods/tools/servercheck.py +++ b/dist/ba_root/mods/tools/servercheck.py @@ -57,7 +57,7 @@ class ServerCheck: self.ip_client_map: Dict[str, List[int]] = {} self.device_client_map: Dict[str, List[int]] = {} self.ip_join: Dict[str, IPJoin] = {} - self.timer = bs.AppTimer(1, babase.Call(self.check), repeat=True) + self.timer = bs.AppTimer(1, babase.CallStrict(self.check), repeat=True) def check(self) -> None: """ From 792014425cc67bb5d769668ed305ff63cde0fd2d Mon Sep 17 00:00:00 2001 From: vishal332008 Date: Thu, 16 Jul 2026 13:07:27 +0530 Subject: [PATCH 04/14] few fixes --- .gitignore | 5 ++- dist/ba_root/config.json | 41 ++++++++++++++----- dist/ba_root/mods/custom_hooks.py | 8 ++-- dist/ba_root/mods/features/afk_check.py | 2 +- dist/ba_root/mods/features/dual_team_score.py | 3 +- dist/ba_root/mods/features/hearts.py | 5 ++- .../ba_root/mods/plugins/bombsquad_service.py | 2 +- dist/ba_root/mods/setting.json | 2 +- dist/ba_root/mods/spazmod/spaz_effects.py | 6 +-- dist/ba_root/mods/spazmod/tag.py | 9 ++-- dist/ba_root/mods/stats/mystats.py | 2 +- dist/ba_root/mods/stats/stats.json | 15 ++++++- dist/ba_root/mods/stats/stats.json.backup | 15 ++++++- dist/ba_root/mods/tools/servercheck.py | 12 +++--- 14 files changed, 89 insertions(+), 38 deletions(-) diff --git a/.gitignore b/.gitignore index 8fce3d2..0297cf5 100644 --- a/.gitignore +++ b/.gitignore @@ -9,4 +9,7 @@ dist/ba_root/mods/serverdata/*.log dist/ba_root/mods/serverdata/*.log* dist/ba_root/mods/serverdata/*.json dist/ba_root/mods/stats/*.json - +dist/ba_root/cache/* +dist/ba_root/*.json +dist/ba_root/config.json +dist/*.keys diff --git a/dist/ba_root/config.json b/dist/ba_root/config.json index 8b6edcd..7ee2e97 100644 --- a/dist/ba_root/config.json +++ b/dist/ba_root/config.json @@ -175,6 +175,14 @@ } }, "Campaigns": {}, + "CloudVals": { + "gct": [ + "asyncio.trsock.TransportSocket", + "asyncio.selector_events._SelectorSocketTransport", + "TimeoutError", + "asyncio.exceptions.CancelledError" + ] + }, "Custom Team Colors": [ [ 0.8, @@ -195,21 +203,35 @@ "Client Input Device #1": "__account__" }, "FFA Series Length": 24, - "Fleet Zone Ping Last Flush Time": 1744468224, + "Fleet Zone Ping Last Flush Time": 1784128904, "Fleet Zone Pings": { "prod": { - "bangkok.v4": 106.51884313655319, - "delhi.v4": 60.29963269479843, - "hyderabad.v4": 84.80298814475032, - "kolkata.v4": 50.75696343299192, - "mumbai.v4": 66.94819074099888 + "bangkok.v4": 169.84028096308512, + "delhi.v4": 217.6381037222891, + "helsinki.v4": 181.6233879981155, + "hong_kong.v4": 97.65329500078224, + "hyderabad.v4": 90.04969035134027, + "jakarta.v4": 126.03041445786221, + "kolkata.v4": 48.5306748606865, + "kuala_lampur.v4": 80.35435232571763, + "manila.v4": 82.0402399986051, + "mumbai.v4": 71.56822602374099, + "seoul.v4": 130.2257630013628, + "singapore.v4": 91.58391039609705, + "taipei.v4": 101.02094900139491, + "tel_aviv.v4": 206.06530000077328, + "tokyo.v4": 137.08936700277263, + "warsaw.v4": 190.2154919989698 } }, + "Fleet Zone Pings Updated Time": { + "prod": 1784187190 + }, "Free-for-All Playlist Randomize": true, "Free-for-All Playlist Selection": "__default__", "Free-for-All Playlists": {}, "Idle Exit Minutes": 20.0, - "Local Account Name": "Server21364126", + "Local Account Name": "Server25997855", "PPM Settings": { "Healing Damage PTG": 72, "Powers Gravity": true, @@ -255,9 +277,6 @@ } }, "Plugins": { - "create_server.EntryPoint": { - "enabled": true - }, "custom_hooks.modSetup": { "enabled": true }, @@ -276,7 +295,7 @@ "Team Tournament Playlist Selection": "\u041a\u043e\u043f\u0438\u044f \u0421\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 \u043f\u043b\u0435\u0439-\u043b\u0438\u0441\u0442 \u0440\u0435\u0436\u0438\u043c\u0430 \u041a\u043e\u043c\u0430\u043d\u0434\u044b", "Team Tournament Playlists": {}, "Teams Series Length": 7, - "launchCount": 107, + "launchCount": 130, "lc14173": 1, "lc14292": 1 } \ No newline at end of file diff --git a/dist/ba_root/mods/custom_hooks.py b/dist/ba_root/mods/custom_hooks.py index c459a50..168887b 100644 --- a/dist/ba_root/mods/custom_hooks.py +++ b/dist/ba_root/mods/custom_hooks.py @@ -277,7 +277,7 @@ def on_player_join(self, player) -> None: team_balancer.on_player_join() try: from shop.shop_system import preload_player - account_id = player.get_v1_account_id() + account_id = player.get_account_id() if account_id: preload_player(account_id) except Exception as e: @@ -366,12 +366,12 @@ def on_player_request(func) -> bool: def wrapper(*args, **kwargs): player = args[1] count = 0 - if not (player.get_v1_account_id( + if not (player.get_account_id( ) in serverdata.clients and - serverdata.clients[player.get_v1_account_id()]["verified"]): + serverdata.clients[player.get_account_id()]["verified"]): return False for current_player in args[0].sessionplayers: - if current_player.get_v1_account_id() == player.get_v1_account_id(): + if current_player.get_account_id() == player.get_account_id(): count += 1 if count >= settings["maxPlayersPerDevice"]: bs.broadcastmessage("Reached max players limit per device", diff --git a/dist/ba_root/mods/features/afk_check.py b/dist/ba_root/mods/features/afk_check.py index 755acf3..6e8e8f9 100644 --- a/dist/ba_root/mods/features/afk_check.py +++ b/dist/ba_root/mods/features/afk_check.py @@ -38,7 +38,7 @@ class checkIdle(object): cLastIdle = current if afk_time in range(INGAME_TIME, INGAME_TIME + 20): - self.warn_player(player.get_v1_account_id(), + self.warn_player(player.get_account_id(), "Press any button within " + str( INGAME_TIME + 20 - afk_time) + " secs") if afk_time > INGAME_TIME + 20: diff --git a/dist/ba_root/mods/features/dual_team_score.py b/dist/ba_root/mods/features/dual_team_score.py index 272b54e..e7e5154 100644 --- a/dist/ba_root/mods/features/dual_team_score.py +++ b/dist/ba_root/mods/features/dual_team_score.py @@ -39,7 +39,8 @@ class TeamVictoryScoreScreenActivity(MultiTeamScoreScreenActivity): # 'First to 4'. session = self.session assert isinstance(session, bs.MultiTeamSession) - if bs.app.lang.get_resource('bestOfUseFirstToInstead'): + best_of_use_first_to_instead = 0 + if best_of_use_first_to_instead: best_txt = babase.Lstr(resource='firstToSeriesText', subs=[('${COUNT}', str(session.get_series_length() / 2 + 1)) diff --git a/dist/ba_root/mods/features/hearts.py b/dist/ba_root/mods/features/hearts.py index 3dd3167..84a7454 100644 --- a/dist/ba_root/mods/features/hearts.py +++ b/dist/ba_root/mods/features/hearts.py @@ -112,8 +112,9 @@ class PopupText(bs.Actor): # kill ourself self._die_timer = bs.Timer( - lifespan, bs.WeakCall(self.handlemessage, bs.DieMessage()) - ) + lifespan, bs.WeakCallPartial( + self.handlemessage, bs.DieMessage() + )) def handlemessage(self, msg: Any) -> Any: assert not self.expired diff --git a/dist/ba_root/mods/plugins/bombsquad_service.py b/dist/ba_root/mods/plugins/bombsquad_service.py index bdec815..d9ca539 100644 --- a/dist/ba_root/mods/plugins/bombsquad_service.py +++ b/dist/ba_root/mods/plugins/bombsquad_service.py @@ -111,7 +111,7 @@ class BsDataThread(object): True), 'inGame': player.in_game, 'character': player.character, - 'account_id': player.get_v1_account_id() + 'account_id': player.get_account_id() } data[str(team.id)]['players'].append(teamplayer) diff --git a/dist/ba_root/mods/setting.json b/dist/ba_root/mods/setting.json index a26b54a..859d295 100644 --- a/dist/ba_root/mods/setting.json +++ b/dist/ba_root/mods/setting.json @@ -138,7 +138,7 @@ "enable": false }, "minAgeToChatInHours": 78, - "minAgeToJoinInHours": 24, + "minAgeToJoinInHours": 0.001, "newResultBoard": true, "playermod": { "default_bomb": "normal", diff --git a/dist/ba_root/mods/spazmod/spaz_effects.py b/dist/ba_root/mods/spazmod/spaz_effects.py index 9593843..c81a1a7 100644 --- a/dist/ba_root/mods/spazmod/spaz_effects.py +++ b/dist/ba_root/mods/spazmod/spaz_effects.py @@ -34,7 +34,7 @@ def effect(repeat_interval=0): else: raise - effect_activation = bs.Timer(repeat_interval, babase.Call(_caller), + effect_activation = bs.Timer(repeat_interval, babase.CallStrict(_caller), repeat=repeat_interval > 0) self._activations.append(effect_activation) @@ -54,7 +54,7 @@ def node(check_interval=0): node.delete() self._activations = [] - node_activation = bs.Timer(check_interval, babase.Call(_caller), + node_activation = bs.Timer(check_interval, babase.CallStrict(_caller), repeat=check_interval > 0) try: self._activations.append(node_activation) @@ -90,7 +90,7 @@ class NewPlayerSpaz(PlayerSpaz): async def set_effects(self): try: - account_id = self._player._sessionplayer.get_v1_account_id() + account_id = self._player._sessionplayer.get_account_id() except: return diff --git a/dist/ba_root/mods/spazmod/tag.py b/dist/ba_root/mods/spazmod/tag.py index 84679ce..c745da0 100644 --- a/dist/ba_root/mods/spazmod/tag.py +++ b/dist/ba_root/mods/spazmod/tag.py @@ -10,7 +10,7 @@ sett = setting.get_settings_data() def addtag(node, player): session_player = player.sessionplayer - account_id = session_player.get_v1_account_id() + account_id = session_player.get_account_id() customtag_ = pdata.get_custom() customtag = customtag_['customtag'] roles = pdata.get_roles() @@ -33,7 +33,7 @@ def addtag(node, player): def addrank(node, player): session_player = player.sessionplayer - account_id = session_player.get_v1_account_id() + account_id = session_player.get_account_id() rank = mystats.getRank(account_id) if rank: @@ -48,7 +48,7 @@ def addhp(node, spaz): position=(0, 1.75, 0), shad=1.4) else: spaz.hptimer = None - spaz.hptimer = bs.Timer(2, babase.Call( + spaz.hptimer = bs.Timer(2, babase.CallStrict( showHP), repeat=True) @@ -164,5 +164,4 @@ class HitPoint(object): self._Text.delete() m.delete() - self.timer = bs.Timer(2, babase.Call( - a)) + self.timer = bs.Timer(2, babase.CallStrict(a)) diff --git a/dist/ba_root/mods/stats/mystats.py b/dist/ba_root/mods/stats/mystats.py index 1914ebb..13b9ee3 100644 --- a/dist/ba_root/mods/stats/mystats.py +++ b/dist/ba_root/mods/stats/mystats.py @@ -191,7 +191,7 @@ def update(score_set): player = p_entry.player if player is None: continue - account_id = player.get_v1_account_id() + account_id = player.get_account_id() if account_id is None: continue name = player.getname(True) diff --git a/dist/ba_root/mods/stats/stats.json b/dist/ba_root/mods/stats/stats.json index 0756a22..550fc67 100644 --- a/dist/ba_root/mods/stats/stats.json +++ b/dist/ba_root/mods/stats/stats.json @@ -1,5 +1,5 @@ { - "startDate": "25-03-2026", + "startDate": "15-07-2026", "stats": { "pb-IF4VAk4a": { "rank": 1, @@ -13,6 +13,19 @@ "avg_score": 0.0, "aid": "pb-IF4VAk4a", "last_seen": "2022-04-26 17:01:13.715014" + }, + "pb-IF5cVXEyAA==": { + "rank": 2, + "name": "Vishyyy", + "scores": 639, + "total_damage": 0.0, + "kills": 0, + "deaths": 3, + "games": 8, + "kd": 0.0, + "avg_score": 79.875, + "last_seen": "2026-07-16 02:33:01.093212", + "aid": "pb-IF5cVXEyAA==" } } } \ No newline at end of file diff --git a/dist/ba_root/mods/stats/stats.json.backup b/dist/ba_root/mods/stats/stats.json.backup index 0756a22..550fc67 100644 --- a/dist/ba_root/mods/stats/stats.json.backup +++ b/dist/ba_root/mods/stats/stats.json.backup @@ -1,5 +1,5 @@ { - "startDate": "25-03-2026", + "startDate": "15-07-2026", "stats": { "pb-IF4VAk4a": { "rank": 1, @@ -13,6 +13,19 @@ "avg_score": 0.0, "aid": "pb-IF4VAk4a", "last_seen": "2022-04-26 17:01:13.715014" + }, + "pb-IF5cVXEyAA==": { + "rank": 2, + "name": "Vishyyy", + "scores": 639, + "total_damage": 0.0, + "kills": 0, + "deaths": 3, + "games": 8, + "kd": 0.0, + "avg_score": 79.875, + "last_seen": "2026-07-16 02:33:01.093212", + "aid": "pb-IF5cVXEyAA==" } } } \ No newline at end of file diff --git a/dist/ba_root/mods/tools/servercheck.py b/dist/ba_root/mods/tools/servercheck.py index 98e2430..33bba8f 100644 --- a/dist/ba_root/mods/tools/servercheck.py +++ b/dist/ba_root/mods/tools/servercheck.py @@ -14,7 +14,7 @@ import _babase import _bascenev1 import babase import bascenev1 as bs -from babase._general import Call +from babase._general import CallPartial from features import profanity from playersdata import pdata from repository import profiles @@ -28,6 +28,7 @@ blacklist = pdata.get_blacklist() # Get settings settings = setting.get_settings_data() +ipjoin = {} @dataclass class PlayerData: @@ -212,6 +213,7 @@ def on_player_join_server(pbid: str, player_data: Optional[Dict[str, Any]], ip: serverdata.clients[pbid]["lastJoin"] = now if player_data is not None: + print(player_data) handle_existing_player(pbid, player_data, ip, device_id, client_id, display_string) else: @@ -435,7 +437,7 @@ class LoadProfile(threading.Thread): def run(self) -> None: player_data = pdata.get_info(self.pbid) _babase.pushcall( - Call(on_player_join_server, self.pbid, + CallPartial(on_player_join_server, self.pbid, player_data, self.ip, self.device_id), from_other_thread=True, ) @@ -455,7 +457,7 @@ class FetchThread(threading.Thread): data = self.method(pb_id) if self.callback is not None: _babase.pushcall( - Call(self.callback, data, pb_id, display_string), + CallPartial(self.callback, data, pb_id, display_string), from_other_thread=True, ) @@ -559,12 +561,12 @@ def account_check(account_id: str, ip: str, client_id: int) -> None: profiles.upsert_ip(account_id, ip) except urllib.error.URLError: _babase.pushcall( - Call(bs.chatmessage, "Click stats button and login your V2 account, to verify your identity", [ + CallPartial(bs.chatmessage, "Click stats button and login your V2 account, to verify your identity", [ client_id]), from_other_thread=True, ) _babase.pushcall( - Call(bs.disconnect_client, client_id, 2), from_other_thread=True) + CallPartial(bs.disconnect_client, client_id, 2), from_other_thread=True) # Instantiate the server check From 7f5da6b396e0cde026272672294f5e1fbfdf9d9d Mon Sep 17 00:00:00 2001 From: Vishyyy Date: Thu, 16 Jul 2026 13:15:31 +0530 Subject: [PATCH 05/14] resolving conflicts --- dist/ba_root/mods/custom_hooks.py | 2 +- dist/ba_root/mods/stats/stats.json | 13 ------------- dist/ba_root/mods/stats/stats.json.backup | 13 ------------- dist/ba_root/mods/tools/servercheck.py | 4 +++- 4 files changed, 4 insertions(+), 28 deletions(-) diff --git a/dist/ba_root/mods/custom_hooks.py b/dist/ba_root/mods/custom_hooks.py index 168887b..ac7ffea 100644 --- a/dist/ba_root/mods/custom_hooks.py +++ b/dist/ba_root/mods/custom_hooks.py @@ -368,7 +368,7 @@ def on_player_request(func) -> bool: count = 0 if not (player.get_account_id( ) in serverdata.clients and - serverdata.clients[player.get_account_id()]["verified"]): + serverdata.clients[player.get_v1_account_id()]["verified"]): return False for current_player in args[0].sessionplayers: if current_player.get_account_id() == player.get_account_id(): diff --git a/dist/ba_root/mods/stats/stats.json b/dist/ba_root/mods/stats/stats.json index 550fc67..0544059 100644 --- a/dist/ba_root/mods/stats/stats.json +++ b/dist/ba_root/mods/stats/stats.json @@ -13,19 +13,6 @@ "avg_score": 0.0, "aid": "pb-IF4VAk4a", "last_seen": "2022-04-26 17:01:13.715014" - }, - "pb-IF5cVXEyAA==": { - "rank": 2, - "name": "Vishyyy", - "scores": 639, - "total_damage": 0.0, - "kills": 0, - "deaths": 3, - "games": 8, - "kd": 0.0, - "avg_score": 79.875, - "last_seen": "2026-07-16 02:33:01.093212", - "aid": "pb-IF5cVXEyAA==" } } } \ No newline at end of file diff --git a/dist/ba_root/mods/stats/stats.json.backup b/dist/ba_root/mods/stats/stats.json.backup index 550fc67..0544059 100644 --- a/dist/ba_root/mods/stats/stats.json.backup +++ b/dist/ba_root/mods/stats/stats.json.backup @@ -13,19 +13,6 @@ "avg_score": 0.0, "aid": "pb-IF4VAk4a", "last_seen": "2022-04-26 17:01:13.715014" - }, - "pb-IF5cVXEyAA==": { - "rank": 2, - "name": "Vishyyy", - "scores": 639, - "total_damage": 0.0, - "kills": 0, - "deaths": 3, - "games": 8, - "kd": 0.0, - "avg_score": 79.875, - "last_seen": "2026-07-16 02:33:01.093212", - "aid": "pb-IF5cVXEyAA==" } } } \ No newline at end of file diff --git a/dist/ba_root/mods/tools/servercheck.py b/dist/ba_root/mods/tools/servercheck.py index 33bba8f..bd0c6f6 100644 --- a/dist/ba_root/mods/tools/servercheck.py +++ b/dist/ba_root/mods/tools/servercheck.py @@ -28,7 +28,9 @@ blacklist = pdata.get_blacklist() # Get settings settings = setting.get_settings_data() -ipjoin = {} +# Track IP join statistics for rate limiting/spam protection +ipjoin: Dict[str, IPJoin] = {} + @dataclass class PlayerData: From 1e9ec7828bc84f23a1360ae579d2ef02af1b1b39 Mon Sep 17 00:00:00 2001 From: vishal332008 Date: Thu, 16 Jul 2026 16:28:43 +0530 Subject: [PATCH 06/14] few more fixes --- dist/ba_data/python/efro/dataclassio/_api.py | 2 -- dist/ba_data/python/efro/dataclassio/_base.py | 2 -- .../python/efro/dataclassio/_inputter.py | 2 -- .../python/efro/dataclassio/_outputter.py | 2 -- .../python/efro/dataclassio/_pathcapture.py | 2 -- dist/ba_data/python/efro/dataclassio/_prep.py | 2 -- dist/ba_data/python/efro/error.py | 2 -- dist/ba_data/python/efro/terminal.py | 2 -- dist/ba_data/python/efro/util.py | 2 -- dist/ba_root/config.json | 26 ++++++------------- dist/ba_root/mods/custom_hooks.py | 6 ++--- dist/ba_root/mods/features/dual_team_score.py | 6 ++--- dist/ba_root/mods/features/votingmachine.py | 5 +++- dist/ba_root/mods/stats/stats.json | 13 ++++++++++ dist/ba_root/mods/stats/stats.json.backup | 13 ++++++++++ dist/ba_root/mods/tools/servercheck.py | 1 - 16 files changed, 44 insertions(+), 44 deletions(-) diff --git a/dist/ba_data/python/efro/dataclassio/_api.py b/dist/ba_data/python/efro/dataclassio/_api.py index 2579b82..8e3080f 100644 --- a/dist/ba_data/python/efro/dataclassio/_api.py +++ b/dist/ba_data/python/efro/dataclassio/_api.py @@ -8,8 +8,6 @@ unrecognized attribute data, allowing older clients to interact with newer data formats in a nondestructive manner. """ -from __future__ import annotations - import json from enum import Enum from typing import TYPE_CHECKING diff --git a/dist/ba_data/python/efro/dataclassio/_base.py b/dist/ba_data/python/efro/dataclassio/_base.py index 6229b59..97bca72 100644 --- a/dist/ba_data/python/efro/dataclassio/_base.py +++ b/dist/ba_data/python/efro/dataclassio/_base.py @@ -2,8 +2,6 @@ # """Core components of dataclassio.""" -from __future__ import annotations - import dataclasses import typing import warnings diff --git a/dist/ba_data/python/efro/dataclassio/_inputter.py b/dist/ba_data/python/efro/dataclassio/_inputter.py index 43fd6fe..f35c8d8 100644 --- a/dist/ba_data/python/efro/dataclassio/_inputter.py +++ b/dist/ba_data/python/efro/dataclassio/_inputter.py @@ -6,8 +6,6 @@ # frowned upon (stuff like isinstance() is usually encouraged). # pylint: disable=unidiomatic-typecheck -from __future__ import annotations - from enum import Enum import dataclasses import typing diff --git a/dist/ba_data/python/efro/dataclassio/_outputter.py b/dist/ba_data/python/efro/dataclassio/_outputter.py index 11cf29f..3273218 100644 --- a/dist/ba_data/python/efro/dataclassio/_outputter.py +++ b/dist/ba_data/python/efro/dataclassio/_outputter.py @@ -6,8 +6,6 @@ # frowned upon (stuff like isinstance() is usually encouraged). # pylint: disable=unidiomatic-typecheck -from __future__ import annotations - from enum import Enum import dataclasses import typing diff --git a/dist/ba_data/python/efro/dataclassio/_pathcapture.py b/dist/ba_data/python/efro/dataclassio/_pathcapture.py index db01f6f..9f40db0 100644 --- a/dist/ba_data/python/efro/dataclassio/_pathcapture.py +++ b/dist/ba_data/python/efro/dataclassio/_pathcapture.py @@ -2,8 +2,6 @@ # """Functionality related to capturing nested dataclass paths.""" -from __future__ import annotations - import dataclasses from typing import TYPE_CHECKING diff --git a/dist/ba_data/python/efro/dataclassio/_prep.py b/dist/ba_data/python/efro/dataclassio/_prep.py index 6950256..a4d8ecb 100644 --- a/dist/ba_data/python/efro/dataclassio/_prep.py +++ b/dist/ba_data/python/efro/dataclassio/_prep.py @@ -7,8 +7,6 @@ # # pylint: disable=unidiomatic-typecheck -from __future__ import annotations - import logging from enum import Enum import dataclasses diff --git a/dist/ba_data/python/efro/error.py b/dist/ba_data/python/efro/error.py index 0edc724..b9a1be0 100644 --- a/dist/ba_data/python/efro/error.py +++ b/dist/ba_data/python/efro/error.py @@ -5,8 +5,6 @@ # """Common errors and related functionality.""" -from __future__ import annotations - from typing import TYPE_CHECKING, override import errno diff --git a/dist/ba_data/python/efro/terminal.py b/dist/ba_data/python/efro/terminal.py index 4ddbcf1..f7c8e40 100644 --- a/dist/ba_data/python/efro/terminal.py +++ b/dist/ba_data/python/efro/terminal.py @@ -2,8 +2,6 @@ # """Functionality related to terminal IO.""" -from __future__ import annotations - import sys import os from enum import Enum, unique diff --git a/dist/ba_data/python/efro/util.py b/dist/ba_data/python/efro/util.py index 56031a4..864bee3 100644 --- a/dist/ba_data/python/efro/util.py +++ b/dist/ba_data/python/efro/util.py @@ -6,8 +6,6 @@ # pylint: disable=too-many-lines """Small handy bits of functionality.""" -from __future__ import annotations - import os import time import random diff --git a/dist/ba_root/config.json b/dist/ba_root/config.json index 7ee2e97..72a17e7 100644 --- a/dist/ba_root/config.json +++ b/dist/ba_root/config.json @@ -206,26 +206,16 @@ "Fleet Zone Ping Last Flush Time": 1784128904, "Fleet Zone Pings": { "prod": { - "bangkok.v4": 169.84028096308512, - "delhi.v4": 217.6381037222891, - "helsinki.v4": 181.6233879981155, - "hong_kong.v4": 97.65329500078224, - "hyderabad.v4": 90.04969035134027, - "jakarta.v4": 126.03041445786221, - "kolkata.v4": 48.5306748606865, - "kuala_lampur.v4": 80.35435232571763, - "manila.v4": 82.0402399986051, - "mumbai.v4": 71.56822602374099, - "seoul.v4": 130.2257630013628, - "singapore.v4": 91.58391039609705, - "taipei.v4": 101.02094900139491, - "tel_aviv.v4": 206.06530000077328, - "tokyo.v4": 137.08936700277263, - "warsaw.v4": 190.2154919989698 + "bangkok.v4": 79.76979999511968, + "delhi.v4": 52.73921035118477, + "hyderabad.v4": 27.893118701544765, + "kolkata.v4": 52.23812143063419, + "mumbai.v4": 105.13554275932287, + "singapore.v4": 47.26909899909515 } }, "Fleet Zone Pings Updated Time": { - "prod": 1784187190 + "prod": 1784199269 }, "Free-for-All Playlist Randomize": true, "Free-for-All Playlist Selection": "__default__", @@ -295,7 +285,7 @@ "Team Tournament Playlist Selection": "\u041a\u043e\u043f\u0438\u044f \u0421\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 \u043f\u043b\u0435\u0439-\u043b\u0438\u0441\u0442 \u0440\u0435\u0436\u0438\u043c\u0430 \u041a\u043e\u043c\u0430\u043d\u0434\u044b", "Team Tournament Playlists": {}, "Teams Series Length": 7, - "launchCount": 130, + "launchCount": 153, "lc14173": 1, "lc14292": 1 } \ No newline at end of file diff --git a/dist/ba_root/mods/custom_hooks.py b/dist/ba_root/mods/custom_hooks.py index 8754030..53bcc6c 100644 --- a/dist/ba_root/mods/custom_hooks.py +++ b/dist/ba_root/mods/custom_hooks.py @@ -330,7 +330,7 @@ def on_player_join(self, player) -> None: try: from shop.shop_system import preload_player - account_id = player.get_account_id() + account_id = player.sessionplayer.get_account_id() if account_id: preload_player(account_id) except Exception as e: @@ -417,11 +417,11 @@ ServerController.shutdown = shutdown(ServerController.shutdown) def on_player_request(func) -> bool: def wrapper(*args, **kwargs): - player = args[1] + player: bs.SessionPlayer = args[1] count = 0 if not (player.get_account_id( ) in serverdata.clients and - serverdata.clients[player.get_v1_account_id()]["verified"]): + serverdata.clients[player.get_account_id()]["verified"]): return False for current_player in args[0].sessionplayers: diff --git a/dist/ba_root/mods/features/dual_team_score.py b/dist/ba_root/mods/features/dual_team_score.py index e7e5154..aec3cfa 100644 --- a/dist/ba_root/mods/features/dual_team_score.py +++ b/dist/ba_root/mods/features/dual_team_score.py @@ -63,7 +63,7 @@ class TeamVictoryScoreScreenActivity(MultiTeamScoreScreenActivity): for team in self.session.sessionteams: bs.timer( i * 0.15 + 0.15, - bs.WeakCall(self._show_team_name, vval - i * height, team, + bs.WeakCallPartial(self._show_team_name, vval - i * height, team, i * 0.2, shift_time - (i * 0.150 + 0.150))) bs.timer(i * 0.150 + 0.5, self._score_display_sound_small.play) scored = (team is self._winner) @@ -72,13 +72,13 @@ class TeamVictoryScoreScreenActivity(MultiTeamScoreScreenActivity): delay = 1.2 bs.timer( i * 0.150 + 0.2, - bs.WeakCall(self._show_team_old_score, vval - i * height, + bs.WeakCallPartial(self._show_team_old_score, vval - i * height, team, shift_time - (i * 0.15 + 0.2))) bs.timer(i * 0.15 + 1.5, self._score_display_sound.play) bs.timer( i * 0.150 + delay, - bs.WeakCall(self._show_team_score, vval - i * height, team, + bs.WeakCallParial(self._show_team_score, vval - i * height, team, scored, i * 0.2 + 0.1, shift_time - (i * 0.15 + delay))) i += 1 diff --git a/dist/ba_root/mods/features/votingmachine.py b/dist/ba_root/mods/features/votingmachine.py index bef2c6f..b76b8db 100644 --- a/dist/ba_root/mods/features/votingmachine.py +++ b/dist/ba_root/mods/features/votingmachine.py @@ -78,7 +78,10 @@ def vote(pb_id, client_id, vote_type): try: activity = bs.get_foreground_host_activity() with activity.context: - bs.get_foreground_host_activity().end() + results = bs.GameResults() + for team in activity.teams: + results.set_team_score(team, team.score) + bs.get_foreground_host_activity().end(results=results) except: pass elif vote_type == "nv": diff --git a/dist/ba_root/mods/stats/stats.json b/dist/ba_root/mods/stats/stats.json index 46f425e..ea6c6eb 100644 --- a/dist/ba_root/mods/stats/stats.json +++ b/dist/ba_root/mods/stats/stats.json @@ -26,6 +26,19 @@ "avg_score": 0.0, "last_seen": "2026-07-15 08:46:34.946691", "aid": "a-1828" + }, + "pb-IF5cVXEyAA==": { + "rank": 3, + "name": "Vishyyy", + "scores": 93, + "total_damage": 0.0, + "kills": 0, + "deaths": 1, + "games": 4, + "kd": 0.0, + "avg_score": 23.25, + "last_seen": "2026-07-16 16:21:28.671836", + "aid": "pb-IF5cVXEyAA==" } } } \ No newline at end of file diff --git a/dist/ba_root/mods/stats/stats.json.backup b/dist/ba_root/mods/stats/stats.json.backup index 46f425e..644af46 100644 --- a/dist/ba_root/mods/stats/stats.json.backup +++ b/dist/ba_root/mods/stats/stats.json.backup @@ -26,6 +26,19 @@ "avg_score": 0.0, "last_seen": "2026-07-15 08:46:34.946691", "aid": "a-1828" + }, + "pb-IF5cVXEyAA==": { + "rank": 3, + "name": "Vishyyy", + "scores": 93, + "total_damage": 0.0, + "kills": 0, + "deaths": 0, + "games": 3, + "kd": 0.0, + "avg_score": 31.0, + "last_seen": "2026-07-16 15:27:54.340453", + "aid": "pb-IF5cVXEyAA==" } } } \ No newline at end of file diff --git a/dist/ba_root/mods/tools/servercheck.py b/dist/ba_root/mods/tools/servercheck.py index 4eaa7e1..d247875 100644 --- a/dist/ba_root/mods/tools/servercheck.py +++ b/dist/ba_root/mods/tools/servercheck.py @@ -216,7 +216,6 @@ def on_player_join_server(pbid: str, player_data: Optional[Dict[str, Any]], ip: serverdata.clients[pbid]["lastJoin"] = now if player_data is not None: - print(player_data) handle_existing_player(pbid, player_data, ip, device_id, client_id, display_string) else: From c82bccd9260dff08736513891ba5c65d6d7a7665 Mon Sep 17 00:00:00 2001 From: vishal332008 Date: Thu, 16 Jul 2026 16:33:25 +0530 Subject: [PATCH 07/14] test commit (ignore this) --- .gitignore | 1 + dist/ba_data/python/efro/util.py | 2 ++ 2 files changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 0297cf5..f24b538 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ dist/ba_root/cache/* dist/ba_root/*.json dist/ba_root/config.json dist/*.keys +dist/ba_data/* diff --git a/dist/ba_data/python/efro/util.py b/dist/ba_data/python/efro/util.py index 864bee3..56031a4 100644 --- a/dist/ba_data/python/efro/util.py +++ b/dist/ba_data/python/efro/util.py @@ -6,6 +6,8 @@ # pylint: disable=too-many-lines """Small handy bits of functionality.""" +from __future__ import annotations + import os import time import random From fdd2f5e39f5ca39eed0c8fd254118f5c2f5f0e68 Mon Sep 17 00:00:00 2001 From: vishal332008 Date: Thu, 16 Jul 2026 16:34:38 +0530 Subject: [PATCH 08/14] few more fixes --- dist/ba_data/python/efro/util.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/dist/ba_data/python/efro/util.py b/dist/ba_data/python/efro/util.py index 56031a4..864bee3 100644 --- a/dist/ba_data/python/efro/util.py +++ b/dist/ba_data/python/efro/util.py @@ -6,8 +6,6 @@ # pylint: disable=too-many-lines """Small handy bits of functionality.""" -from __future__ import annotations - import os import time import random From 099ca775f15bc43c1e6eebf8fcaf6e827fb41e4e Mon Sep 17 00:00:00 2001 From: vishal332008 Date: Thu, 16 Jul 2026 16:45:53 +0530 Subject: [PATCH 09/14] will remove these in the end --- .gitignore | 1 - dist/ba_data/python/efro/dataclassio/_api.py | 2 ++ dist/ba_data/python/efro/dataclassio/_base.py | 2 ++ dist/ba_data/python/efro/dataclassio/_inputter.py | 2 ++ dist/ba_data/python/efro/dataclassio/_outputter.py | 2 ++ dist/ba_data/python/efro/dataclassio/_pathcapture.py | 2 ++ dist/ba_data/python/efro/dataclassio/_prep.py | 2 ++ dist/ba_data/python/efro/error.py | 2 ++ dist/ba_data/python/efro/terminal.py | 2 ++ dist/ba_data/python/efro/util.py | 2 ++ 10 files changed, 18 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index f24b538..0297cf5 100644 --- a/.gitignore +++ b/.gitignore @@ -13,4 +13,3 @@ dist/ba_root/cache/* dist/ba_root/*.json dist/ba_root/config.json dist/*.keys -dist/ba_data/* diff --git a/dist/ba_data/python/efro/dataclassio/_api.py b/dist/ba_data/python/efro/dataclassio/_api.py index 8e3080f..2579b82 100644 --- a/dist/ba_data/python/efro/dataclassio/_api.py +++ b/dist/ba_data/python/efro/dataclassio/_api.py @@ -8,6 +8,8 @@ unrecognized attribute data, allowing older clients to interact with newer data formats in a nondestructive manner. """ +from __future__ import annotations + import json from enum import Enum from typing import TYPE_CHECKING diff --git a/dist/ba_data/python/efro/dataclassio/_base.py b/dist/ba_data/python/efro/dataclassio/_base.py index 97bca72..6229b59 100644 --- a/dist/ba_data/python/efro/dataclassio/_base.py +++ b/dist/ba_data/python/efro/dataclassio/_base.py @@ -2,6 +2,8 @@ # """Core components of dataclassio.""" +from __future__ import annotations + import dataclasses import typing import warnings diff --git a/dist/ba_data/python/efro/dataclassio/_inputter.py b/dist/ba_data/python/efro/dataclassio/_inputter.py index f35c8d8..43fd6fe 100644 --- a/dist/ba_data/python/efro/dataclassio/_inputter.py +++ b/dist/ba_data/python/efro/dataclassio/_inputter.py @@ -6,6 +6,8 @@ # frowned upon (stuff like isinstance() is usually encouraged). # pylint: disable=unidiomatic-typecheck +from __future__ import annotations + from enum import Enum import dataclasses import typing diff --git a/dist/ba_data/python/efro/dataclassio/_outputter.py b/dist/ba_data/python/efro/dataclassio/_outputter.py index 3273218..11cf29f 100644 --- a/dist/ba_data/python/efro/dataclassio/_outputter.py +++ b/dist/ba_data/python/efro/dataclassio/_outputter.py @@ -6,6 +6,8 @@ # frowned upon (stuff like isinstance() is usually encouraged). # pylint: disable=unidiomatic-typecheck +from __future__ import annotations + from enum import Enum import dataclasses import typing diff --git a/dist/ba_data/python/efro/dataclassio/_pathcapture.py b/dist/ba_data/python/efro/dataclassio/_pathcapture.py index 9f40db0..db01f6f 100644 --- a/dist/ba_data/python/efro/dataclassio/_pathcapture.py +++ b/dist/ba_data/python/efro/dataclassio/_pathcapture.py @@ -2,6 +2,8 @@ # """Functionality related to capturing nested dataclass paths.""" +from __future__ import annotations + import dataclasses from typing import TYPE_CHECKING diff --git a/dist/ba_data/python/efro/dataclassio/_prep.py b/dist/ba_data/python/efro/dataclassio/_prep.py index a4d8ecb..6950256 100644 --- a/dist/ba_data/python/efro/dataclassio/_prep.py +++ b/dist/ba_data/python/efro/dataclassio/_prep.py @@ -7,6 +7,8 @@ # # pylint: disable=unidiomatic-typecheck +from __future__ import annotations + import logging from enum import Enum import dataclasses diff --git a/dist/ba_data/python/efro/error.py b/dist/ba_data/python/efro/error.py index b9a1be0..0edc724 100644 --- a/dist/ba_data/python/efro/error.py +++ b/dist/ba_data/python/efro/error.py @@ -5,6 +5,8 @@ # """Common errors and related functionality.""" +from __future__ import annotations + from typing import TYPE_CHECKING, override import errno diff --git a/dist/ba_data/python/efro/terminal.py b/dist/ba_data/python/efro/terminal.py index f7c8e40..4ddbcf1 100644 --- a/dist/ba_data/python/efro/terminal.py +++ b/dist/ba_data/python/efro/terminal.py @@ -2,6 +2,8 @@ # """Functionality related to terminal IO.""" +from __future__ import annotations + import sys import os from enum import Enum, unique diff --git a/dist/ba_data/python/efro/util.py b/dist/ba_data/python/efro/util.py index 864bee3..56031a4 100644 --- a/dist/ba_data/python/efro/util.py +++ b/dist/ba_data/python/efro/util.py @@ -6,6 +6,8 @@ # pylint: disable=too-many-lines """Small handy bits of functionality.""" +from __future__ import annotations + import os import time import random From 50450e14a8c1caaffd4a06d767f6163dd1ee7231 Mon Sep 17 00:00:00 2001 From: vishal332008 Date: Fri, 17 Jul 2026 08:54:52 +0530 Subject: [PATCH 10/14] updating few games to api 9 --- dist/ba_root/config.json | 26 +- dist/ba_root/mods/features/dual_team_score.py | 856 ++++++++++-------- dist/ba_root/mods/games/air_soccer.py | 12 +- .../mods/games/alliance_elimination.py | 8 +- dist/ba_root/mods/games/arms_race.py | 15 +- dist/ba_root/mods/games/avalanche.py | 9 +- dist/ba_root/mods/games/basket_bomb.py | 14 +- dist/ba_root/mods/games/better_deathmatch.py | 15 +- dist/ba_root/mods/games/better_elimination.py | 11 +- dist/ba_root/mods/games/big_ball.py | 14 +- dist/ba_root/mods/games/bomb_on_my_head.py | 11 +- dist/ba_root/mods/games/boxing.py | 8 +- dist/ba_root/mods/games/bridgit_mash.py | 236 ----- dist/ba_root/mods/games/canon_fight.py | 24 +- dist/ba_root/mods/games/collector.py | 8 +- dist/ba_root/mods/maps/bridgit_mash.py | 17 +- dist/ba_root/mods/stats/stats.json.backup | 8 +- 17 files changed, 558 insertions(+), 734 deletions(-) delete mode 100644 dist/ba_root/mods/games/bridgit_mash.py diff --git a/dist/ba_root/config.json b/dist/ba_root/config.json index 72a17e7..9c025d6 100644 --- a/dist/ba_root/config.json +++ b/dist/ba_root/config.json @@ -206,16 +206,26 @@ "Fleet Zone Ping Last Flush Time": 1784128904, "Fleet Zone Pings": { "prod": { - "bangkok.v4": 79.76979999511968, - "delhi.v4": 52.73921035118477, - "hyderabad.v4": 27.893118701544765, - "kolkata.v4": 52.23812143063419, - "mumbai.v4": 105.13554275932287, - "singapore.v4": 47.26909899909515 + "bangkok.v4": 81.62017577624344, + "delhi.v4": 63.964672644626035, + "helsinki.v4": 178.44603499997902, + "hong_kong.v4": 84.84311700021863, + "hyderabad.v4": 169.17364551628094, + "jakarta.v4": 120.16353614961386, + "kolkata.v4": 171.5810691091089, + "kuala_lampur.v4": 97.94705339403097, + "manila.v4": 85.0717169996642, + "mumbai.v4": 53.889843160696806, + "seoul.v4": 113.3862230003615, + "singapore.v4": 89.7048506555974, + "taipei.v4": 91.55671799999254, + "tel_aviv.v4": 227.04064399977142, + "tokyo.v4": 119.68682299993816, + "warsaw.v4": 190.9533369998826 } }, "Fleet Zone Pings Updated Time": { - "prod": 1784199269 + "prod": 1784222852 }, "Free-for-All Playlist Randomize": true, "Free-for-All Playlist Selection": "__default__", @@ -285,7 +295,7 @@ "Team Tournament Playlist Selection": "\u041a\u043e\u043f\u0438\u044f \u0421\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 \u043f\u043b\u0435\u0439-\u043b\u0438\u0441\u0442 \u0440\u0435\u0436\u0438\u043c\u0430 \u041a\u043e\u043c\u0430\u043d\u0434\u044b", "Team Tournament Playlists": {}, "Teams Series Length": 7, - "launchCount": 153, + "launchCount": 155, "lc14173": 1, "lc14292": 1 } \ No newline at end of file diff --git a/dist/ba_root/mods/features/dual_team_score.py b/dist/ba_root/mods/features/dual_team_score.py index aec3cfa..dca0ad7 100644 --- a/dist/ba_root/mods/features/dual_team_score.py +++ b/dist/ba_root/mods/features/dual_team_score.py @@ -1,419 +1,515 @@ # Released under the MIT License. See LICENSE for details. # -"""Functionality related to the end screen in dual-team mode.""" +"""Elimination mini-game.""" + +# ba_meta require api 9 +# (see https://ballistica.net/wiki/meta-tag-system) from __future__ import annotations from typing import TYPE_CHECKING +import logging import babase import bascenev1 as bs -from bascenev1lib.activity.multiteamscore import MultiTeamScoreScreenActivity -from bascenev1lib.actor.image import Image -from bascenev1lib.actor.text import Text -from bascenev1lib.actor.zoomtext import ZoomText +from bascenev1lib.actor.scoreboard import Scoreboard +from bascenev1lib.actor.spazfactory import SpazFactory if TYPE_CHECKING: - pass + from typing import (Any, Tuple, Type, List, Sequence, Optional, + Union) -class TeamVictoryScoreScreenActivity(MultiTeamScoreScreenActivity): - """Scorescreen between rounds of a dual-team session.""" +class Icon(bs.Actor): + """Creates in in-game icon on screen.""" + + def __init__(self, + player: Player, + position: Tuple[float, float], + scale: float, + show_lives: bool = True, + show_death: bool = True, + name_scale: float = 1.0, + name_maxwidth: float = 115.0, + flatness: float = 1.0, + shadow: float = 1.0): + super().__init__() + + self._player = player + self._show_lives = show_lives + self._show_death = show_death + self._name_scale = name_scale + self._outline_tex = bs.gettexture('characterIconMask') + + icon = player.get_icon() + self.node = bs.newnode('image', + delegate=self, + attrs={ + 'texture': icon['texture'], + 'tint_texture': icon['tint_texture'], + 'tint_color': icon['tint_color'], + 'vr_depth': 400, + 'tint2_color': icon['tint2_color'], + 'mask_texture': self._outline_tex, + 'opacity': 1.0, + 'absolute_scale': True, + 'attach': 'bottomCenter' + }) + self._name_text = bs.newnode( + 'text', + owner=self.node, + attrs={ + 'text': babase.Lstr(value=player.getname()), + 'color': babase.safecolor(player.team.color), + 'h_align': 'center', + 'v_align': 'center', + 'vr_depth': 410, + 'maxwidth': name_maxwidth, + 'shadow': shadow, + 'flatness': flatness, + 'h_attach': 'center', + 'v_attach': 'bottom' + }) + if self._show_lives: + self._lives_text = bs.newnode('text', + owner=self.node, + attrs={ + 'text': 'x0', + 'color': (1, 1, 0.5), + 'h_align': 'left', + 'vr_depth': 430, + 'shadow': 1.0, + 'flatness': 1.0, + 'h_attach': 'center', + 'v_attach': 'bottom' + }) + self.set_position_and_scale(position, scale) + + def set_position_and_scale(self, position: Tuple[float, float], + scale: float) -> None: + """(Re)position the icon.""" + assert self.node + self.node.position = position + self.node.scale = [70.0 * scale] + self._name_text.position = (position[0], position[1] + scale * 52.0) + self._name_text.scale = 1.0 * scale * self._name_scale + if self._show_lives: + self._lives_text.position = (position[0] + scale * 10.0, + position[1] - scale * 43.0) + self._lives_text.scale = 1.0 * scale + + def update_for_lives(self) -> None: + """Update for the target player's current lives.""" + if self._player: + lives = self._player.lives + else: + lives = 0 + if self._show_lives: + if lives > 0: + self._lives_text.text = 'x' + str(lives - 1) + else: + self._lives_text.text = '' + if lives == 0: + self._name_text.opacity = 0.2 + assert self.node + self.node.color = (0.7, 0.3, 0.3) + self.node.opacity = 0.2 + + def handle_player_spawned(self) -> None: + """Our player spawned; hooray!""" + if not self.node: + return + self.node.opacity = 1.0 + self.update_for_lives() + + def handle_player_died(self) -> None: + """Well poo; our player died.""" + if not self.node: + return + if self._show_death: + bs.animate( + self.node, 'opacity', { + 0.00: 1.0, + 0.05: 0.0, + 0.10: 1.0, + 0.15: 0.0, + 0.20: 1.0, + 0.25: 0.0, + 0.30: 1.0, + 0.35: 0.0, + 0.40: 1.0, + 0.45: 0.0, + 0.50: 1.0, + 0.55: 0.2 + }) + lives = self._player.lives + if lives == 0: + bs.timer(0.6, self.update_for_lives) + + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, bs.DieMessage): + self.node.delete() + return None + return super().handlemessage(msg) + + +class Player(bs.Player['Team']): + """Our player type for this game.""" + + def __init__(self) -> None: + self.lives = 0 + self.icons: List[Icon] = [] + + +class Team(bs.Team[Player]): + """Our team type for this game.""" + + def __init__(self) -> None: + self.survival_seconds: Optional[int] = None + self.spawn_order: List[Player] = [] + + +# ba_meta export bascenev1.GameActivity +class AllianceEliminationGame(bs.TeamGameActivity[Player, Team]): + """Game type where last player(s) left alive win.""" + + name = 'Alliance Elimination' + description = 'Fight in groups of duo, trio, or more.\nLast remaining alive wins.' + scoreconfig = bs.ScoreConfig(label='Survived', + scoretype=bs.ScoreType.SECONDS, + none_is_winner=True) + # Show messages when players die since it's meaningful here. + announce_player_deaths = True + + allow_mid_activity_joins = False + + @classmethod + def get_available_settings( + cls, sessiontype: Type[bs.Session]) -> List[bs.Setting]: + settings = [ + bs.IntSetting( + 'Lives Per Player', + default=1, + min_value=1, + max_value=10, + increment=1, + ), + bs.IntSetting( + 'Players Per Team In Arena', + default=2, + min_value=2, + max_value=10, + increment=1, + ), + bs.IntChoiceSetting( + 'Time Limit', + choices=[ + ('None', 0), + ('1 Minute', 60), + ('2 Minutes', 120), + ('5 Minutes', 300), + ('10 Minutes', 600), + ('20 Minutes', 1200), + ], + default=0, + ), + bs.FloatChoiceSetting( + 'Respawn Times', + choices=[ + ('Shorter', 0.25), + ('Short', 0.5), + ('Normal', 1.0), + ('Long', 2.0), + ('Longer', 4.0), + ], + default=1.0, + ), + bs.BoolSetting('Epic Mode', default=False), + ] + if issubclass(sessiontype, bs.DualTeamSession): + settings.append( + bs.BoolSetting('Balance Total Lives', default=False)) + return settings + + @classmethod + def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool: + return issubclass(sessiontype, bs.DualTeamSession) + + @classmethod + def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]: + return bs.app.classic.getmaps('melee') def __init__(self, settings: dict): - super().__init__(settings=settings) - self._winner: bs.SessionTeam = settings['winner'] - assert isinstance(self._winner, bs.SessionTeam) + super().__init__(settings) + self._scoreboard = Scoreboard() + self._start_time: Optional[float] = None + self._vs_text: Optional[bs.Actor] = None + self._round_end_timer: Optional[bs.Timer] = None + self._epic_mode = bool(settings['Epic Mode']) + self._lives_per_player = int(settings['Lives Per Player']) + self._time_limit = float(settings['Time Limit']) + self._balance_total_lives = bool( + settings.get('Balance Total Lives', False)) + self._players_per_team_in_arena = int( + settings['Players Per Team In Arena']) + + # Base class overrides: + self.slow_motion = self._epic_mode + self.default_music = (bs.MusicType.EPIC + if self._epic_mode else bs.MusicType.SURVIVAL) + + def get_instance_description(self) -> Union[str, Sequence]: + return 'Last team standing wins.' if isinstance( + self.session, bs.DualTeamSession) else 'Last one standing wins.' + + def get_instance_description_short(self) -> Union[str, Sequence]: + return 'last team standing wins' if isinstance( + self.session, bs.DualTeamSession) else 'last one standing wins' + + def on_player_join(self, player: Player) -> None: + + # No longer allowing mid-game joiners here; too easy to exploit. + if self.has_begun(): + + # Make sure their team has survival seconds set if they're all dead + # (otherwise blocked new ffa players are considered 'still alive' + # in score tallying). + if (self._get_total_team_lives(player.team) == 0 + and player.team.survival_seconds is None): + player.team.survival_seconds = 0 + bs.broadcastmessage( + babase.Lstr(resource='playerDelayedJoinText', + subs=[('${PLAYER}', player.getname(full=True))]), + color=(0, 1, 0), + ) + return + + player.lives = self._lives_per_player + + player.team.spawn_order.append(player) + self._update_alliance_mode() + + # Don't waste time doing this until begin. + if self.has_begun(): + self._update_icons() def on_begin(self) -> None: - babase.set_analytics_screen('Teams Score Screen') super().on_begin() + self._start_time = bs.time() + self.setup_standard_time_limit(self._time_limit) + self.setup_standard_powerup_drops() + self._vs_text = bs.NodeActor( + bs.newnode('text', + attrs={ + 'position': (0, 92), + 'h_attach': 'center', + 'h_align': 'center', + 'maxwidth': 200, + 'shadow': 0.5, + 'vr_depth': 390, + 'scale': 0.6, + 'v_attach': 'bottom', + 'color': (0.8, 0.8, 0.3, 1.0), + 'text': babase.Lstr(resource='vsText') + })) - height = 130 - active_team_count = len(self.teams) - vval = (height * active_team_count) / 2 - height / 2 - i = 0 - shift_time = 2.5 + # If balance-team-lives is on, add lives to the smaller team until + # total lives match. + if (isinstance(self.session, bs.DualTeamSession) + and self._balance_total_lives and self.teams[0].players + and self.teams[1].players): + if self._get_total_team_lives( + self.teams[0]) < self._get_total_team_lives(self.teams[1]): + lesser_team = self.teams[0] + greater_team = self.teams[1] + else: + lesser_team = self.teams[1] + greater_team = self.teams[0] + add_index = 0 + while (self._get_total_team_lives(lesser_team) < + self._get_total_team_lives(greater_team)): + lesser_team.players[add_index].lives += 1 + add_index = (add_index + 1) % len(lesser_team.players) - # Usually we say 'Best of 7', but if the language prefers we can say - # 'First to 4'. - session = self.session - assert isinstance(session, bs.MultiTeamSession) - best_of_use_first_to_instead = 0 - if best_of_use_first_to_instead: - best_txt = babase.Lstr(resource='firstToSeriesText', - subs=[('${COUNT}', - str(session.get_series_length() / 2 + 1)) - ]) - else: - best_txt = babase.Lstr(resource='bestOfSeriesText', - subs=[('${COUNT}', - str(session.get_series_length()))]) - if len(self.teams) != 2: - ZoomText(best_txt, - position=(0, 175), - shiftposition=(-250, 175), - shiftdelay=2.5, - flash=False, - trail=False, - h_align='center', - scale=0.25, - color=(0.5, 0.5, 0.5, 1.0), - jitter=3.0).autoretain() - for team in self.session.sessionteams: - bs.timer( - i * 0.15 + 0.15, - bs.WeakCallPartial(self._show_team_name, vval - i * height, team, - i * 0.2, shift_time - (i * 0.150 + 0.150))) - bs.timer(i * 0.150 + 0.5, self._score_display_sound_small.play) - scored = (team is self._winner) - delay = 0.2 - if scored: - delay = 1.2 - bs.timer( - i * 0.150 + 0.2, - bs.WeakCallPartial(self._show_team_old_score, vval - i * height, - team, shift_time - (i * 0.15 + 0.2))) - bs.timer(i * 0.15 + 1.5, self._score_display_sound.play) + self._update_icons() - bs.timer( - i * 0.150 + delay, - bs.WeakCallParial(self._show_team_score, vval - i * height, team, - scored, i * 0.2 + 0.1, - shift_time - (i * 0.15 + delay))) - i += 1 - self.show_player_scores() + # We could check game-over conditions at explicit trigger points, + # but lets just do the simple thing and poll it. + bs.timer(1.0, self._update, repeat=True) - def _show_team_name(self, pos_v: float, team: bs.SessionTeam, - kill_delay: float, shiftdelay: float) -> None: - del kill_delay # Unused arg. - if len(self.teams) != 2: - ZoomText( - babase.Lstr(value='${A}:', subs=[('${A}', team.name)]), - position=(100, pos_v), - shiftposition=(-150, pos_v), - shiftdelay=shiftdelay, - flash=False, - trail=False, - h_align='right', - maxwidth=300, - color=team.color, - jitter=1.0, - ).autoretain() - else: - ZoomText(babase.Lstr(value='${A}', subs=[('${A}', team.name)]), - position=(-250, 260) if pos_v == 65 else (250, 260), - shiftposition=(-250, 260) if pos_v == 65 else (250, 260), - shiftdelay=shiftdelay, - flash=False, - trail=False, - h_align='center', - maxwidth=300, - scale=0.45, - color=team.color, - jitter=1.0).autoretain() + def _update_alliance_mode(self) -> None: + # For both teams, find the first player on the spawn order list with + # lives remaining and spawn them if they're not alive. + for team in self.teams: + # Prune dead players from the spawn order. + players_spawned = 0 + team.spawn_order = [p for p in team.spawn_order if p] + for player in team.spawn_order: + assert isinstance(player, Player) + if player.lives > 0: + if not player.is_alive(): + self.spawn_player(player) + self._update_icons() + players_spawned += 1 + if players_spawned >= self._players_per_team_in_arena: + break - def _show_team_old_score(self, pos_v: float, sessionteam: bs.SessionTeam, - shiftdelay: float) -> None: + def _update_icons(self) -> None: + # pylint: disable=too-many-branches + # First off, clear out all icons. + for player in self.players: + player.icons = [] - if len(self.teams) != 2: - ZoomText( - str(sessionteam.customdata['score'] - 1), - position=(150, pos_v), - maxwidth=100, - color=(0.6, 0.6, 0.7), - shiftposition=(-100, pos_v), - shiftdelay=shiftdelay, - flash=False, - trail=False, - lifespan=1.0, - h_align='left', - jitter=1.0, - ).autoretain() - else: - ZoomText(str(sessionteam.customdata['score'] - 1), - position=(-250, 190) if pos_v == 65 else (250, 190), - maxwidth=100, - color=(0.6, 0.6, 0.7), - shiftposition=(-250, 190) if pos_v == 65 else (250, 190), - shiftdelay=shiftdelay, - flash=False, - trail=False, - lifespan=1.0, - scale=0.56, - h_align='center', - jitter=1.0).autoretain() + # Now for each team, cycle through our available players + # adding icons. + for team in self.teams: + if team.id == 0: + xval = -60 + x_offs = -78 + else: + xval = 60 + x_offs = 78 + nplayers = self._players_per_team_in_arena + test_lives = 1 + while True: + players_with_lives = [ + p for p in team.spawn_order + if p and p.lives >= test_lives + ] + if not players_with_lives: + break + for player in players_with_lives: + player.icons.append( + Icon(player, + position=(xval, (36 if nplayers > 0 else 25)), + scale=0.9 if nplayers > 0 else 0.5, + name_maxwidth=85 if nplayers > 0 else 75, + name_scale=0.8 if nplayers > 0 else 1.0, + flatness=0.0 if nplayers > 0 else 1.0, + shadow=0.5 if nplayers > 0 else 1.0, + show_death=True if nplayers > 0 else False, + show_lives=False)) + xval += x_offs * (0.85 if nplayers > 0 else 0.56) + nplayers -= 1 + test_lives += 1 - def _show_team_score(self, pos_v: float, sessionteam: bs.SessionTeam, - scored: bool, kill_delay: float, - shiftdelay: float) -> None: - del kill_delay # Unused arg. - if len(self.teams) != 2: - ZoomText( - str(sessionteam.customdata['score']), - position=(150, pos_v), - maxwidth=100, - color=(1.0, 0.9, 0.5) if scored else (0.6, 0.6, 0.7), - shiftposition=(-100, pos_v), - shiftdelay=shiftdelay, - flash=scored, - trail=scored, - h_align='left', - jitter=1.0, - trailcolor=(1, 0.8, 0.0, 0), - ).autoretain() - else: - ZoomText(str(sessionteam.customdata['score']), - position=(-250, 190) if pos_v == 65 else (250, 190), - maxwidth=100, - color=(1.0, 0.9, 0.5) if scored else (0.6, 0.6, 0.7), - shiftposition=(-250, 190) if pos_v == 65 else (250, 190), - shiftdelay=shiftdelay, - flash=scored, - trail=scored, - scale=0.56, - h_align='center', - jitter=1.0, - trailcolor=(1, 0.8, 0.0, 0)).autoretain() + def _get_spawn_point(self, player: Player) -> Optional[babase.Vec3]: + return None + def spawn_player(self, player: Player) -> bs.Actor: + actor = self.spawn_player_spaz(player, self._get_spawn_point(player)) -# =================================================================================================== + # If we have any icons, update their state. + for icon in player.icons: + icon.handle_player_spawned() + return actor -# score board -# ==================================================================================================== + def _print_lives(self, player: Player) -> None: + from bascenev1lib.actor import popuptext -def show_player_scores(self, - delay: float = 2.5, - results: bs.GameResults | None = None, - scale: float = 1.0, - x_offset: float = 0.0, - y_offset: float = 0.0) -> None: - """Show scores for individual players.""" - # pylint: disable=too-many-locals - # pylint: disable=too-many-statements + # We get called in a timer so it's possible our player has left/etc. + if not player or not player.is_alive() or not player.node: + return - ts_v_offset = 150.0 + y_offset - ts_h_offs = 80.0 + x_offset - tdelay = delay - spacing = 40 + popuptext.PopupText('x' + str(player.lives - 1), + color=(1, 1, 0, 1), + offset=(0, -0.8, 0), + random_offset=0.0, + scale=1.8, + position=player.node.position).autoretain() - is_free_for_all = isinstance(self.session, bs.FreeForAllSession) + def on_player_leave(self, player: Player) -> None: + super().on_player_leave(player) + player.icons = [] - is_two_team = True if len(self.session.sessionteams) == 2 else False + # Remove us from spawn-order. + if player in player.team.spawn_order: + player.team.spawn_order.remove(player) - def _get_prec_score(p_rec: bs.PlayerRecord) -> int | None: - if is_free_for_all and results is not None: - assert isinstance(results, bs.GameResults) - assert p_rec.team.activityteam is not None - val = results.get_sessionteam_score(p_rec.team) - return val - return p_rec.accumscore + # Update icons in a moment since our team will be gone from the + # list then. + bs.timer(0, self._update_icons) - def _get_prec_score_str(p_rec: bs.PlayerRecord) -> str | bs.Lstr: - if is_free_for_all and results is not None: - assert isinstance(results, bs.GameResults) - assert p_rec.team.activityteam is not None - val = results.get_sessionteam_score_str(p_rec.team) - assert val is not None - return val - return str(p_rec.accumscore) + # If the player to leave was the last in spawn order and had + # their final turn currently in-progress, mark the survival time + # for their team. + if self._get_total_team_lives(player.team) == 0: + assert self._start_time is not None + player.team.survival_seconds = int(bs.time() - self._start_time) - # stats.get_records() can return players that are no longer in - # the game.. if we're using results we have to filter those out - # (since they're not in results and that's where we pull their - # scores from) - if results is not None: - assert isinstance(results, bs.GameResults) - player_records = [] - assert self.stats - valid_players = list(self.stats.get_records().items()) + def _get_total_team_lives(self, team: Team) -> int: + return sum(player.lives for player in team.players) - def _get_player_score_set_entry( - player: bs.SessionPlayer) -> bs.PlayerRecord | None: - for p_rec in valid_players: - if p_rec[1].player is player: - return p_rec[1] - return None + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, bs.PlayerDiedMessage): - # Results is already sorted; just convert it into a list of - # score-set-entries. - for winnergroup in results.winnergroups: - for team in winnergroup.teams: - if len(team.players) == 1: - player_entry = _get_player_score_set_entry( - team.players[0]) - if player_entry is not None: - player_records.append(player_entry) - else: - player_records = [] - player_records_scores = [ - (_get_prec_score(p), name, p) - for name, p in list(self.stats.get_records().items()) + # Augment standard behavior. + super().handlemessage(msg) + player: Player = msg.getplayer(Player) + + player.lives -= 1 + if player.lives < 0: + logging.error( + "Got lives < 0 in Alliance Elimination; this shouldn't happen.") + player.lives = 0 + + # If we have any icons, update their state. + for icon in player.icons: + icon.handle_player_died() + + # Play big death sound on our last death + # or for every one. + if player.lives == 0: + SpazFactory.get().single_player_death_sound.play() + + # If we hit zero lives, we're dead (and our team might be too). + if player.lives == 0: + # If the whole team is now dead, mark their survival time. + if self._get_total_team_lives(player.team) == 0: + assert self._start_time is not None + player.team.survival_seconds = int(bs.time() - + self._start_time) + + # Put ourself at the back of the spawn order. + player.team.spawn_order.remove(player) + player.team.spawn_order.append(player) + player.node.delete() + + def _update(self) -> None: + # For both teams, find the first player on the spawn order + # list with lives remaining and spawn them if they're not alive. + for team in self.teams: + # Prune dead players from the spawn order. + team.spawn_order = [p for p in team.spawn_order if p] + players_spawned = 0 + for player in team.spawn_order: + assert isinstance(player, Player) + if player.lives > 0: + if not player.is_alive(): + self.spawn_player(player) + self._update_icons() + players_spawned += 1 + if players_spawned >= self._players_per_team_in_arena: + break + + # If we're down to 1 or fewer living teams, start a timer to end + # the game (allows the dust to settle and draws to occur if deaths + # are close enough). + if len(self._get_living_teams()) < 2: + self._round_end_timer = bs.Timer(0.5, self.end_game) + + def _get_living_teams(self) -> List[Team]: + return [ + team for team in self.teams + if len(team.players) > 0 and any(player.lives > 0 + for player in team.players) ] - player_records_scores.sort(reverse=True) - # Just want living player entries. - player_records = [p[2] for p in player_records_scores if p[2]] - - voffs = -140.0 + spacing * 5 * 0.5 - - voffs_team0 = voffs - tdelay_team0 = tdelay - - def _txt(xoffs: float, - yoffs: float, - text: babase.Lstr, - h_align: Text.HAlign = Text.HAlign.RIGHT, - extrascale: float = 1.0, - maxwidth: float | None = 120.0) -> None: - Text(text, - color=(0.5, 0.5, 0.6, 0.5), - position=(ts_h_offs + xoffs * scale, - ts_v_offset + (voffs + yoffs + 4.0) * scale), - h_align=h_align, - v_align=Text.VAlign.CENTER, - scale=0.8 * scale * extrascale, - maxwidth=maxwidth, - transition=Text.Transition.IN_LEFT, - transition_delay=tdelay).autoretain() - - session = self.session - assert isinstance(session, bs.MultiTeamSession) - if is_two_team: - tval = "Game " + str(session.get_game_number()) + " Results" - _txt(-75, - 160, - tval, - h_align=Text.HAlign.CENTER, - extrascale=1.4, - maxwidth=None) - else: - tval = babase.Lstr( - resource='gameLeadersText', - subs=[('${COUNT}', str(session.get_game_number()))], - ) - _txt( - 180, - 43, - tval, - h_align=Text.HAlign.CENTER, - extrascale=1.4, - maxwidth=None, - ) - _txt(-15, 4, babase.Lstr(resource='playerText'), h_align=Text.HAlign.LEFT) - _txt(180, 4, babase.Lstr(resource='killsText')) - _txt(280, 4, babase.Lstr(resource='deathsText'), maxwidth=100) - - score_label = 'Score' if results is None else results.score_label - translated = babase.Lstr(translate=('scoreNames', score_label)) - - _txt(390, 0, translated) - - if is_two_team: - _txt(-595, 4, babase.Lstr(resource='playerText'), - h_align=Text.HAlign.LEFT) - _txt(-400, 4, babase.Lstr(resource='killsText')) - _txt(-300, 4, babase.Lstr(resource='deathsText'), maxwidth=100) - _txt(-190, 0, translated) - - topkillcount = 0 - topkilledcount = 99999 - top_score = 0 if not player_records else _get_prec_score( - player_records[0]) - - for prec in player_records: - topkillcount = max(topkillcount, prec.accum_kill_count) - topkilledcount = min(topkilledcount, prec.accum_killed_count) - - def _scoretxt(text: str | bs.Lstr, - x_offs: float, - highlight: bool, - delay2: float, - maxwidth: float = 70.0, team_id=1) -> None: - - Text(text, - position=(ts_h_offs + x_offs * scale, - ts_v_offset + ( - voffs + 15) * scale) if team_id == 1 else ( - ts_h_offs + x_offs * scale, - ts_v_offset + (voffs_team0 + 15) * scale), - scale=scale, - 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, - transition=Text.Transition.IN_LEFT, - transition_delay=(tdelay + delay2) if team_id == 1 else ( - tdelay_team0 + delay2)).autoretain() - - for playerrec in player_records: - if is_two_team and playerrec.team.id == 0: - tdelay_team0 += 0.05 - voffs_team0 -= spacing - x_image = 617 - x_text = -595 - y = ts_v_offset + (voffs_team0 + 15.0) * scale - - else: - tdelay += 0.05 - voffs -= spacing - x_image = 12 - x_text = 10.0 - y = ts_v_offset + (voffs + 15.0) * scale - - Image(playerrec.get_icon(), - position=(ts_h_offs - x_image * scale, - y), - scale=(30.0 * scale, 30.0 * scale), - transition=Image.Transition.IN_LEFT, - transition_delay=tdelay if playerrec.team.id == 1 else tdelay_team0).autoretain() - Text(babase.Lstr(value=playerrec.getname(full=True)), - maxwidth=160, - scale=0.75 * scale, - position=(ts_h_offs + x_text * scale, - y), - h_align=Text.HAlign.LEFT, - v_align=Text.VAlign.CENTER, - color=babase.safecolor(playerrec.team.color + (1,)), - transition=Text.Transition.IN_LEFT, - transition_delay=tdelay if playerrec.team.id == 1 else tdelay_team0).autoretain() - - if is_two_team and playerrec.team.id == 0: - _scoretxt(str(playerrec.accum_kill_count), -400, - playerrec.accum_kill_count == topkillcount, 0.1, - team_id=0) - _scoretxt(str(playerrec.accum_killed_count), -300, - playerrec.accum_killed_count == topkilledcount, 0.1, - team_id=0) - _scoretxt(_get_prec_score_str(playerrec), -190, - _get_prec_score(playerrec) == top_score, 0.2, team_id=0) - else: - _scoretxt(str(playerrec.accum_kill_count), 180, - playerrec.accum_kill_count == topkillcount, 0.1) - _scoretxt(str(playerrec.accum_killed_count), 280, - playerrec.accum_killed_count == topkilledcount, 0.1) - _scoretxt(_get_prec_score_str(playerrec), 390, - _get_prec_score(playerrec) == top_score, 0.2) - - -# ======================== draw screen ============= -class DrawScoreScreenActivity(MultiTeamScoreScreenActivity): - """Score screen shown after a draw.""" - - default_music = None # Awkward silence... - - def on_begin(self) -> None: - babase.set_analytics_screen('Draw Score Screen') - super().on_begin() - ZoomText(babase.Lstr(resource='drawText'), - position=(0, 200), - maxwidth=400, - shiftposition=(0, 200), - shiftdelay=2.0, - flash=False, - scale=0.7, - trail=False, - jitter=1.0).autoretain() - bs.timer(0.35, self._score_display_sound.play) - self.show_player_scores(results=self.settings_raw.get('results', None)) + def end_game(self) -> None: + if self.has_ended(): + return + results = bs.GameResults() + self._vs_text = None # Kill our 'vs' if its there. + for team in self.teams: + results.set_team_score(team, team.survival_seconds) + self.end(results=results) diff --git a/dist/ba_root/mods/games/air_soccer.py b/dist/ba_root/mods/games/air_soccer.py index 75e9ba4..59fc99c 100644 --- a/dist/ba_root/mods/games/air_soccer.py +++ b/dist/ba_root/mods/games/air_soccer.py @@ -1,9 +1,8 @@ -# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport) # Released under the MIT License. See LICENSE for details. # BY Stary_Agent -"""Hockey game and support classes.""" +"""Air soccer game.""" -# ba_meta require api 8 +# ba_meta require api 9 # (see https://ballistica.net/wiki/meta-tag-system) from __future__ import annotations @@ -40,7 +39,7 @@ def create_slope(self): class Puck(bs.Actor): - """A lovely giant hockey puck.""" + """A lovely ball.""" def __init__(self, position: Sequence[float] = (0.0, 13.0, 0.0)): super().__init__() @@ -52,7 +51,6 @@ class Puck(bs.Actor): self.last_players_to_touch: Dict[int, Player] = {} self.scored = False assert activity is not None - assert isinstance(activity, HockeyGame) pmats = [shared.object_material, activity.puck_material] self.node = bs.newnode('prop', delegate=self, @@ -117,7 +115,7 @@ class Team(bs.Team[Player]): # ba_meta export bascenev1.GameActivity class AirSoccerGame(bs.TeamGameActivity[Player, Team]): - """Ice hockey game.""" + """Air soccer game.""" name = 'Epic Air Soccer' description = 'Score some goals.' @@ -656,6 +654,6 @@ class CreativeThoughts(bs.Map): try: - bs._map.register_map(CreativeThoughts) + bs.register_map(CreativeThoughts) except: pass diff --git a/dist/ba_root/mods/games/alliance_elimination.py b/dist/ba_root/mods/games/alliance_elimination.py index ab93299..dca0ad7 100644 --- a/dist/ba_root/mods/games/alliance_elimination.py +++ b/dist/ba_root/mods/games/alliance_elimination.py @@ -2,12 +2,13 @@ # """Elimination mini-game.""" -# ba_meta require api 8 +# ba_meta require api 9 # (see https://ballistica.net/wiki/meta-tag-system) from __future__ import annotations from typing import TYPE_CHECKING +import logging import babase import bascenev1 as bs @@ -184,7 +185,7 @@ class AllianceEliminationGame(bs.TeamGameActivity[Player, Team]): @classmethod def get_available_settings( - cls, sessiontype: Type[bs.Session]) -> List[babase.Setting]: + cls, sessiontype: Type[bs.Session]) -> List[bs.Setting]: settings = [ bs.IntSetting( 'Lives Per Player', @@ -448,7 +449,7 @@ class AllianceEliminationGame(bs.TeamGameActivity[Player, Team]): player.lives -= 1 if player.lives < 0: - babase.print_error( + logging.error( "Got lives < 0 in Alliance Elimination; this shouldn't happen.") player.lives = 0 @@ -472,6 +473,7 @@ class AllianceEliminationGame(bs.TeamGameActivity[Player, Team]): # Put ourself at the back of the spawn order. player.team.spawn_order.remove(player) player.team.spawn_order.append(player) + player.node.delete() def _update(self) -> None: # For both teams, find the first player on the spawn order diff --git a/dist/ba_root/mods/games/arms_race.py b/dist/ba_root/mods/games/arms_race.py index d9bae4f..d6aa463 100644 --- a/dist/ba_root/mods/games/arms_race.py +++ b/dist/ba_root/mods/games/arms_race.py @@ -1,10 +1,4 @@ -# Ported by your friend: Freaku - -# Join BCS: -# https://discord.gg/ucyaesh - - -# ba_meta require api 8 +# ba_meta require api 9 from __future__ import annotations @@ -37,7 +31,7 @@ class State: enable_bomb=self.bomb, enable_pickup=self.grab) if self.curse: - spaz.curse_time = -1 + spaz.curse_time = None spaz.curse() if self.bomb: spaz.bomb_type = self.bomb @@ -82,7 +76,7 @@ class ArmsRaceGame(bs.TeamGameActivity[Player, Team]): @classmethod def get_available_settings( - cls, sessiontype: Type[bs.Session]) -> List[babase.Setting]: + cls, sessiontype: Type[bs.Session]) -> List[bs.Setting]: settings = [ bs.IntChoiceSetting( 'Time Limit', @@ -149,11 +143,10 @@ class ArmsRaceGame(bs.TeamGameActivity[Player, Team]): def on_begin(self) -> None: super().on_begin() self.setup_standard_time_limit(self._time_limit) - # self.setup_standard_powerup_drops() def on_player_join(self, player): if player.state is None: - player.state = self.states[0] + player.state = self.states[5] self.spawn_player(player) # overriding the default character spawning.. diff --git a/dist/ba_root/mods/games/avalanche.py b/dist/ba_root/mods/games/avalanche.py index 43eed2f..6c986aa 100644 --- a/dist/ba_root/mods/games/avalanche.py +++ b/dist/ba_root/mods/games/avalanche.py @@ -1,7 +1,6 @@ -# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport) """Avalancha mini-game.""" -# ba_meta require api 8 +# ba_meta require api 9 # (see https://ballistica.net/wiki/meta-tag-system) from __future__ import annotations @@ -26,12 +25,12 @@ randomPic = ["lakeFrigidPreview", "hockeyStadiumPreview"] def ba_get_api_version(): - return 8 + return 9 def ba_get_levels(): return [ - bs._level.Level( + bs.Level( "Icy Emits", gametype=IcyEmitsGame, settings={}, @@ -127,7 +126,7 @@ class AvalanchaGame(MeteorShowerGame): pos = (pos[0], pos[1] + 0.4, pos[2]) dropdir = -1.0 if pos[0] > 0 else 1.0 vel = (random.randrange(-4, 4), 7.0, random.randrange(0, 4)) - bs.timer(delay, babase.Call(self._drop_bomb, pos, vel)) + bs.timer(delay, babase.CallPartial(self._drop_bomb, pos, vel)) delay += 0.1 self._set_meteor_timer() diff --git a/dist/ba_root/mods/games/basket_bomb.py b/dist/ba_root/mods/games/basket_bomb.py index 8c33edb..b4042ae 100644 --- a/dist/ba_root/mods/games/basket_bomb.py +++ b/dist/ba_root/mods/games/basket_bomb.py @@ -1,19 +1,14 @@ -# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport) # Released under the MIT License. See LICENSE for details. -# ba_meta require api 8 +# ba_meta require api 9 # (see https://ballistica.net/wiki/meta-tag-system) from __future__ import annotations from typing import TYPE_CHECKING -import babase -import bauiv1 as bui import bascenev1 as bs -import _babase from bascenev1lib.actor.playerspaz import PlayerSpaz from bascenev1lib.actor.scoreboard import Scoreboard -from bascenev1lib.actor.powerupbox import PowerupBoxFactory from bascenev1lib.gameutils import SharedObjects from bascenev1lib.actor import playerspaz as ps from bascenev1lib import maps @@ -558,9 +553,6 @@ class Cuadro(bs.Actor): 'materials': [self.collision, shared.footing_material]}) - # self.shield = bs.newnode('shield', attrs={'radius': 1.0, 'color': (0,10,0)}) - # self.region.connectattr('position', self.shield, 'position') - position = (position[0], position[1], position[2]+0.09) pos = list(position) oldpos = list(position) @@ -770,5 +762,5 @@ class BasketMapV2(maps.HockeyStadium): ] -bs._map.register_map(BasketMap) -bs._map.register_map(BasketMapV2) +bs.register_map(BasketMap) +bs.register_map(BasketMapV2) diff --git a/dist/ba_root/mods/games/better_deathmatch.py b/dist/ba_root/mods/games/better_deathmatch.py index 6882c8a..8ef29a6 100644 --- a/dist/ba_root/mods/games/better_deathmatch.py +++ b/dist/ba_root/mods/games/better_deathmatch.py @@ -1,10 +1,9 @@ -# Ported to api 8 by brostos using baport.(https://github.com/bombsquad-community/baport) # BetterDeathMatch # Made by your friend: @[Just] Freak#4999 """Defines a very-customisable DeathMatch mini-game""" -# ba_meta require api 8 +# ba_meta require api 9 from __future__ import annotations @@ -17,7 +16,7 @@ from bascenev1lib.actor.playerspaz import PlayerSpaz from bascenev1lib.actor.scoreboard import Scoreboard if TYPE_CHECKING: - from typing import Any, Type, List, Dict, Tuple, Union, Sequence, Optional + from typing import Any, Type, List, Union, Sequence, Optional class Player(bs.Player['Team']): @@ -43,7 +42,7 @@ class BetterDeathMatchGame(bs.TeamGameActivity[Player, Team]): @classmethod def get_available_settings( - cls, sessiontype: Type[bs.Session]) -> List[babase.Setting]: + cls, sessiontype: Type[bs.Session]) -> List[bs.Setting]: settings = [ bs.IntSetting( 'Kills to Win Per Player', @@ -138,19 +137,16 @@ class BetterDeathMatchGame(bs.TeamGameActivity[Player, Team]): bs.MusicType.TO_THE_DEATH) def get_instance_description(self) -> Union[str, Sequence]: - return 'Crush ${ARG1} of your enemies. byFREAK', self._score_to_win + return 'Crush ${ARG1} of your enemies.', self._score_to_win def get_instance_description_short(self) -> Union[str, Sequence]: - return 'kill ${ARG1} enemies. byFREAK', self._score_to_win + return 'kill ${ARG1} enemies.', self._score_to_win def on_team_join(self, team: Team) -> None: if self.has_begun(): self._update_scoreboard() - ## Run settings related: IcyFloor ## - - def on_transition_in(self) -> None: super().on_transition_in() activity = bs.getactivity() @@ -164,7 +160,6 @@ class BetterDeathMatchGame(bs.TeamGameActivity[Player, Team]): super().on_begin() self.setup_standard_time_limit(self._time_limit) - ## Run settings related: NightMode,Powerups ## if self._night_mode: bs.getactivity().globalsnode.tint = (0.5, 0.7, 1) diff --git a/dist/ba_root/mods/games/better_elimination.py b/dist/ba_root/mods/games/better_elimination.py index 8edd4c1..90d8598 100644 --- a/dist/ba_root/mods/games/better_elimination.py +++ b/dist/ba_root/mods/games/better_elimination.py @@ -1,4 +1,3 @@ -# Ported to api 8 by brostos using baport.(https://github.com/bombsquad-community/baport) # BetterElimination # Made by your friend: @[Just] Freak#4999 @@ -7,11 +6,12 @@ """Defines a very-customisable Elimination mini-game""" -# ba_meta require api 8 +# ba_meta require api 9 from __future__ import annotations from typing import TYPE_CHECKING +import logging import babase import bauiv1 as bui @@ -20,8 +20,7 @@ from bascenev1lib.actor.spazfactory import SpazFactory from bascenev1lib.actor.scoreboard import Scoreboard if TYPE_CHECKING: - from typing import (Any, Tuple, Dict, Type, List, Sequence, Optional, - Union) + from typing import Any, Tuple, Type, List, Sequence, Optional, Union class Icon(bs.Actor): @@ -187,7 +186,7 @@ class BetterEliminationGame(bs.TeamGameActivity[Player, Team]): @classmethod def get_available_settings( - cls, sessiontype: Type[bs.Session]) -> List[babase.Setting]: + cls, sessiontype: Type[bs.Session]) -> List[bs.Setting]: settings = [ bs.IntSetting( 'Life\'s Per Player', @@ -590,7 +589,7 @@ class BetterEliminationGame(bs.TeamGameActivity[Player, Team]): player.lives -= 1 if player.lives < 0: - babase.print_error( + logging.error( "Got lives < 0 in Elim; this shouldn't happen. solo:" + str(self._solo_mode)) player.lives = 0 diff --git a/dist/ba_root/mods/games/big_ball.py b/dist/ba_root/mods/games/big_ball.py index 597b797..d0c502d 100644 --- a/dist/ba_root/mods/games/big_ball.py +++ b/dist/ba_root/mods/games/big_ball.py @@ -1,8 +1,6 @@ # Made by MythB -# Ported by: MysteriousBoi - -# ba_meta require api 8 +# ba_meta require api 9 from __future__ import annotations from typing import TYPE_CHECKING @@ -25,8 +23,6 @@ class PuckDiedMessage: # goalpost - - class FlagKale(bs.Actor): def __init__(self, position=(0, 2.5, 0), color=(1, 1, 1)): super().__init__() @@ -305,8 +301,8 @@ class BBGame(bs.TeamGameActivity[Player, Team]): def get_instance_description_short(self) -> Union[str, Sequence]: if self._score_to_win == 1: - return 'score a goal' - return 'score ${ARG1} goals', self._score_to_win + return 'Score a goal' + return 'Score ${ARG1} goals', self._score_to_win def on_begin(self) -> None: super().on_begin() @@ -437,7 +433,7 @@ class BBGame(bs.TeamGameActivity[Player, Team]): if self._grant_power: for player in team.players: try: - player.actor.node.handlemessage( + player.node.handlemessage( bs.PowerupMessage('punch')) except: pass @@ -463,7 +459,7 @@ class BBGame(bs.TeamGameActivity[Player, Team]): if self._grant_power: for player in team.players: try: - player.actor.node.handlemessage( + player.node.handlemessage( bs.PowerupMessage('shield')) except: pass diff --git a/dist/ba_root/mods/games/bomb_on_my_head.py b/dist/ba_root/mods/games/bomb_on_my_head.py index 91a6a62..a794c11 100644 --- a/dist/ba_root/mods/games/bomb_on_my_head.py +++ b/dist/ba_root/mods/games/bomb_on_my_head.py @@ -1,4 +1,4 @@ -# ba_meta require api 8 +# ba_meta require api 9 # (see https://ballistica.net/wiki/meta-tag-system) from __future__ import annotations @@ -64,7 +64,7 @@ class NewPlayerSpaz(PlayerSpaz): self.check_avalible_bombs() self._bomb_check_timer = bs.timer( 0.5, - bs.WeakCall(self.check_avalible_bombs), + bs.WeakCallStrict(self.check_avalible_bombs), repeat=True) def drop_bomb(self) -> stdbomb.Bomb | None: @@ -95,7 +95,7 @@ class NewPlayerSpaz(PlayerSpaz): self.bomb_count -= 1 bomb.node.add_death_action( - bs.WeakCall(self.handlemessage, BombDiedMessage()) + bs.WeakCallPartial(self.handlemessage, BombDiedMessage()) ) self._pick_up(bomb.node) @@ -133,7 +133,7 @@ class BombOnMyHeadGame(bs.TeamGameActivity[Player, Team]): @classmethod def get_available_settings( cls, sessiontype: type[bs.Session] - ) -> list[babase.Setting]: + ) -> list[bs.Setting]: settings = [ bs.IntChoiceSetting( maxbomblimit, @@ -194,6 +194,7 @@ class BombOnMyHeadGame(bs.TeamGameActivity[Player, Team]): self.setup_standard_time_limit(self._time_limit) self._timer = OnScreenTimer() self._timer.start() + bs.timer(5.0, self._check_end_game) def spawn_player(self, player: Player) -> bs.Actor: from babase import _math @@ -236,7 +237,7 @@ class BombOnMyHeadGame(bs.TeamGameActivity[Player, Team]): animate(light, 'intensity', {0: 0, 0.25: 1, 0.5: 0}) bs.timer(0.5, light.delete) - bs.timer(1.0, bs.WeakCall(spaz.start_bomb_checking)) + bs.timer(1.0, bs.WeakCallStrict(spaz.start_bomb_checking)) spaz.set_bomb_count(self._max_bomb_limit) def handlemessage(self, msg: Any) -> Any: diff --git a/dist/ba_root/mods/games/boxing.py b/dist/ba_root/mods/games/boxing.py index 90612d2..6f6d264 100644 --- a/dist/ba_root/mods/games/boxing.py +++ b/dist/ba_root/mods/games/boxing.py @@ -1,4 +1,4 @@ -# ba_meta require api 8 +# ba_meta require api 9 # (see https://ballistica.net/wiki/meta-tag-system) from __future__ import annotations @@ -52,8 +52,8 @@ class NewPlayerSpaz(PlayerSpaz): self.super_jump_material.add_actions( conditions=('they_have_material', shared.footing_material), actions=( - ('call', 'at_connect', babase.Call(self.jump_state, True)), - ('call', 'at_disconnect', babase.Call(self.jump_state, False)) + ('call', 'at_connect', babase.CallPartial(self.jump_state, True)), + ('call', 'at_disconnect', babase.CallPartial(self.jump_state, False)) ), ) self.node.roller_materials += (self.super_jump_material,) @@ -98,7 +98,7 @@ class BoxingGame(DeathMatchGame): @classmethod def get_available_settings( cls, sessiontype: type[bs.Session] - ) -> list[babase.Setting]: + ) -> list[bs.Setting]: settings = [ bs.IntSetting( 'Kills to Win Per Player', diff --git a/dist/ba_root/mods/games/bridgit_mash.py b/dist/ba_root/mods/games/bridgit_mash.py deleted file mode 100644 index f65b508..0000000 --- a/dist/ba_root/mods/games/bridgit_mash.py +++ /dev/null @@ -1,236 +0,0 @@ -from __future__ import annotations - -from typing import TYPE_CHECKING - -import babase -import bauiv1 as bui -import bascenev1 as bs -from bascenev1lib.gameutils import SharedObjects -from bascenev1lib.actor.playerspaz import PlayerSpaz -import random -if TYPE_CHECKING: - from typing import Any, List, Dict - - -class mapdefs: - points = {} - # noinspection PyDictCreation - boxes = {} - boxes['area_of_interest_bounds'] = (0.0, 1.185751251, 0.4326226188) + ( - 0.0, 0.0, 0.0) + (29.8180273, 11.57249038, 18.89134176) - boxes['edge_box'] = (-0.103873591, 0.4133341891, 0.4294651013) + ( - 0.0, 0.0, 0.0) + (22.48295719, 1.290242794, 8.990252454) - points['ffa_spawn1'] = (-0.08015551329, 0.02275111462, - -4.373674593) + (8.895057015, 1.0, 0.444350722) - points['ffa_spawn2'] = (-0.08015551329, 0.02275111462, - 4.076288941) + (8.895057015, 1.0, 0.444350722) - points['flag1'] = (-10.99027878, 0.05744967453, 0.1095578275) - points['flag2'] = (11.01486398, 0.03986567039, 0.1095578275) - points['flag_default'] = (-0.1001374046, 0.04180340146, 0.1095578275) - boxes['goal1'] = (12.22454533, 1.0, - 0.1087926362) + (0.0, 0.0, 0.0) + (2.0, 2.0, 12.97466313) - boxes['goal2'] = (-12.15961605, 1.0, - 0.1097860203) + (0.0, 0.0, 0.0) + (2.0, 2.0, 13.11856424) - boxes['map_bounds'] = (0.0, 1.185751251, 0.4326226188) + (0.0, 0.0, 0.0) + ( - 42.09506485, 22.81173179, 29.76723155) - points['powerup_spawn1'] = (5.414681236, 0.9515026107, -5.037912441) - points['powerup_spawn2'] = (-5.555402285, 0.9515026107, -5.037912441) - points['powerup_spawn3'] = (5.414681236, 0.9515026107, 5.148223181) - points['powerup_spawn4'] = (-5.737266365, 0.9515026107, 5.148223181) - points['spawn1'] = (-10.03866341, 0.02275111462, 0.0) + (0.5, 1.0, 4.0) - points['spawn2'] = (9.823107149, 0.01092306765, 0.0) + (0.5, 1.0, 4.0) - points['tnt1'] = (-0.08421587483, 0.9515026107, -0.7762602271) - - -class BridgitMash(bs.Map): - """Stadium map for football games.""" - defs = mapdefs - defs.points['spawn1'] = (-12.03866341, 0.02275111462, - 0.0) + (0.5, 1.0, 4.0) - defs.points['spawn2'] = ( - 12.823107149, 0.01092306765, 0.0) + (0.5, 1.0, 4.0) - - defs.points["flag1"] = (-9.6, 0.747, -2.949) - defs.points["flag2"] = (9.6, 0.747, 3.15) - defs.points["flag3"] = (-9.6, 0.747, 3.15) - defs.points["flag4"] = (-0.1, 0.747, -2.949) - defs.points["flag5"] = (-0.1, 0.747, 0.152) - defs.points["flag6"] = (-0.1, 0.747, 3.15) - defs.points["flag7"] = (9.6, 0.747, -2.949) - defs.points["flag8"] = (9.6, 0.747, 0.152) - defs.points["flag9"] = (-9.6, 0.747, 0.152) - - defs.points["spawn_by_flag1"] = (-9.6, 0.747, -2.949) - defs.points["spawn_by_flag2"] = (9.6, 0.747, 3.15) - defs.points["spawn_by_flag3"] = (-9.6, 0.747, 3.15) - defs.points["spawn_by_flag4"] = (-0.1, 0.747, -2.949) - defs.points["spawn_by_flag5"] = (-0.1, 0.747, 0.152) - defs.points["spawn_by_flag6"] = (-0.1, 0.747, 3.15) - defs.points["spawn_by_flag7"] = (9.6, 0.747, -2.949) - defs.points["spawn_by_flag8"] = (9.6, 0.747, 0.152) - defs.points["spawn_by_flag9"] = (-9.6, 0.747, 0.152) - - name = 'Bridgit Mash' - - @classmethod - def get_play_types(cls) -> list[str]: - """Return valid play types for this map.""" - return ['melee', 'football', 'team_flag', 'keep_away', 'conquest'] - - @classmethod - def get_preview_texture_name(cls) -> str: - return 'footballStadiumPreview' - - @classmethod - def on_preload(cls) -> Any: - data: dict[str, Any] = { - 'mesh': bs.getmesh('footballStadium'), - 'vr_fill_mesh': bs.getmesh('footballStadiumVRFill'), - 'collision_mesh': bs.getcollisionmesh('footballStadiumCollide'), - 'tex': bs.gettexture('footballStadium') - } - return data - - def __init__(self) -> None: - super().__init__() - shared = SharedObjects.get() - # TODO vr fill data - gnode = bs.getactivity().globalsnode - gnode.tint = (1.3, 1.2, 1.0) - gnode.ambient_color = (1.3, 1.2, 1.0) - gnode.vignette_outer = (0.57, 0.57, 0.57) - gnode.vignette_inner = (0.9, 0.9, 0.9) - gnode.vr_camera_offset = (0, -0.8, -1.1) - gnode.vr_near_clip = 0.5 - cols = [(0.10, 0.3, 0.5), (0.6, 0.3, 0.6), (0.6, 0.3, 0.1), - (0.2, 0.4, 0.1), (0.4, 0.3, 0.7), (0.10, 0.3, 0.5)] - self.background = bs.newnode( - 'terrain', - attrs={ - 'mesh': bs.getmesh('natureBackground'), - 'lighting': False, - 'background': True, - 'color': cols[random.randrange(0, 6)] - }) - self.map_extend() - - def is_point_near_edge(self, - point: babase.Vec3, - running: bool = False) -> bool: - box_position = self.defs.boxes['edge_box'][0:3] - box_scale = self.defs.boxes['edge_box'][6:9] - xpos = (point.x - box_position[0]) / box_scale[0] - zpos = (point.z - box_position[2]) / box_scale[2] - return xpos < -0.5 or xpos > 0.5 or zpos < -0.5 or zpos > 0.5 - - def map_extend(self): - self.create_ramp(0, 0) - self.create_ramp(10.9, 0) - self.create_ramp(0, -3) - self.create_ramp(10.9, -2.8) - self.create_ramp(0, 3.0) - self.create_ramp(10.9, 3.2) - self.ground() - # _babase.prop_axis(1, 0, 0) - - def ground(self): - shared = SharedObjects.get() - self._real_wall_material = bs.Material() - - self._real_wall_material.add_actions( - - actions=( - ('modify_part_collision', 'collide', True), - ('modify_part_collision', 'physical', True) - )) - self.mat = bs.Material() - self.mat.add_actions( - - actions=(('modify_part_collision', 'physical', False), - ('modify_part_collision', 'collide', False)) - ) - - def create_ramp(self, loc, z_marg): - # try: - # _babase.prop_axis(0, 0, 0) - # except: - # pass - shared = SharedObjects.get() - self._real_wall_material = bs.Material() - - self._real_wall_material.add_actions( - - actions=( - ('modify_part_collision', 'collide', True), - ('modify_part_collision', 'physical', True) - - )) - self.mat = bs.Material() - self.mat.add_actions( - - actions=(('modify_part_collision', 'physical', False), - ('modify_part_collision', 'collide', False)) - ) - spaz_collide_mat = bs.Material() - # spaz_collide_mat.add_actions( - # conditions=('they_have_material',shared.player_material), - # actions=( - # ('modify_part_collision', 'collide', True), - # ( 'call','at_connect',babase.Call(self._handle_player_pad_collide,real )), - # ), - # ) - pos = (-5.3 + loc, 0.7, 1.1+z_marg) - self.ud_1_r = bs.newnode('region', attrs={'position': pos, 'scale': ( - 2, 1, 2), 'type': 'box', 'materials': [shared.footing_material, spaz_collide_mat]}) - - self.node = bs.newnode('prop', - owner=self.ud_1_r, - attrs={ - 'mesh': bs.getmesh('bridgitLevelTop'), - 'light_mesh': bs.getmesh('powerupSimple'), - 'position': (2, 7, 2), - 'body': 'puck', - 'shadow_size': 0.0, - 'velocity': (0, 0, 0), - 'color_texture': bs.gettexture('bridgitLevelColor'), - 'mesh_scale': 0.72, - 'reflection_scale': [1.5], - 'materials': [self.mat, shared.object_material, shared.footing_material], - - 'density': 9000000000 - }) - self.node.changerotation(0, 0, 0) - mnode = bs.newnode('math', - owner=self.ud_1_r, - attrs={ - 'input1': (0, -2.9, 0), - 'operation': 'add' - }) - - self.ud_1_r.connectattr('position', mnode, 'input2') - mnode.connectattr('output', self.node, 'position') - - # /// region to stand long bar =============== - - pos = (-9.67+loc, 0.1, 0+z_marg) - self.left_region = bs.newnode('region', attrs={'position': pos, 'scale': (2.4, 0.7, 3.2), 'type': 'box', 'materials': [ - shared.footing_material, self._real_wall_material, spaz_collide_mat]}) - - pos = (-5.67+loc, 0.1, 0+z_marg) - self.center_region = bs.newnode('region', attrs={'position': pos, 'scale': ( - 8, 0.7, 1), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material, spaz_collide_mat]}) - pos = (-1.3+loc, 0.1, 0+z_marg) - self.right_region = bs.newnode('region', attrs={'position': pos, 'scale': (2.4, 0.7, 3.2), 'type': 'box', 'materials': [ - shared.footing_material, self._real_wall_material, spaz_collide_mat]}) - - def _handle_player_collide(self): - try: - player = bs.getcollision().opposingnode.getdelegate( - PlayerSpaz, True) - except bs.NotFoundError: - return - if player.is_alive(): - player.shatter(True) - - -bs._map.register_map(BridgitMash) diff --git a/dist/ba_root/mods/games/canon_fight.py b/dist/ba_root/mods/games/canon_fight.py index 9061d8d..d8d688a 100644 --- a/dist/ba_root/mods/games/canon_fight.py +++ b/dist/ba_root/mods/games/canon_fight.py @@ -1,9 +1,8 @@ -# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport) # Released under the MIT License. See LICENSE for details. # -"""DeathMatch game and support classes.""" +"""Cannon Fight game and support classes.""" -# ba_meta require api 8 +# ba_meta require api 9 # (see https://ballistica.net/wiki/meta-tag-system) from __future__ import annotations @@ -24,9 +23,6 @@ if TYPE_CHECKING: from typing import Any, Union, Sequence, Optional - - - # ba_meta export bascenev1.GameActivity class CanonFightGame(DeathMatchGame): """A game type based on acquiring kills.""" @@ -39,7 +35,7 @@ class CanonFightGame(DeathMatchGame): @classmethod def get_available_settings( - cls, sessiontype: type[bs.Session]) -> list[babase.Setting]: + cls, sessiontype: type[bs.Session]) -> list[bs.Setting]: settings = [ bs.IntSetting( 'Kills to Win Per Player', @@ -111,7 +107,7 @@ class CanonFightGame(DeathMatchGame): bs.MusicType.TO_THE_DEATH) self.wtindex=0 - self.wttimer = bs.timer(5, babase.Call(self.wt_), repeat=True) + self.wttimer = bs.timer(5, babase.CallStrict(self.wt_), repeat=True) self.wthighlights=["Created by Mr.Smoothy","hey smoothy youtube","smoothy#multiverse"] def wt_(self): @@ -155,10 +151,6 @@ class CanonFightGame(DeathMatchGame): def handlemessage(self, msg: Any) -> Any: if isinstance(msg, bs.PlayerDiedMessage): - - # Augment standard behavior. - super().handlemessage(msg) - player = msg.getplayer(Player) self.respawn_player(player) @@ -264,7 +256,7 @@ class CanonFightGame(DeathMatchGame): self.fake_explosion( (-5.708631629943848, 7.437141418457031, -4.525400638580322)) Bomb(position=(-6,7.5,-4),bomb_type=type,owner=owner,source_player=source_player,velocity=(19,y,z)).autoretain() - bs.timer(0.6,babase.Call(self.launch_bomb_byA,owner,type,source_player,count-1)) + bs.timer(0.6,babase.CallPartial(self.launch_bomb_byA,owner,type,source_player,count-1)) else: return def launch_bomb_byB(self,owner,type,source_player,count): @@ -274,7 +266,7 @@ class CanonFightGame(DeathMatchGame): self.fake_explosion( (5.708631629943848, 7.437141418457031, -4.525400638580322)) Bomb(position=(6,7.5,-4),bomb_type=type,owner=owner,source_player=source_player,velocity=(-19,y,z)).autoretain() - bs.timer(0.6,babase.Call(self.launch_bomb_byB,owner,type,source_player,count-1)) + bs.timer(0.6,babase.CallPartial(self.launch_bomb_byB,owner,type,source_player,count-1)) else: return @@ -306,7 +298,7 @@ class CanonFightGame(DeathMatchGame): actions=( ('modify_part_collision', 'collide', True), ('modify_part_collision', 'physical', True), - ('call','at_connect',babase.Call(self._handle_canon_load_A)) + ('call','at_connect',babase.CallStrict(self._handle_canon_load_A)) ), ) self.ud_1_r=bs.newnode('region',attrs={'position': (-8.908631629943848, 7.337141418457031, -4.525400638580322),'scale': (2,1,1),'type': 'box','materials': [canon_load_mat ]}) @@ -368,7 +360,7 @@ class CanonFightGame(DeathMatchGame): actions=( ('modify_part_collision', 'collide', True), ('modify_part_collision', 'physical', True), - ('call','at_connect',babase.Call(self._handle_canon_load_B)) + ('call','at_connect',babase.CallStrict(self._handle_canon_load_B)) ), ) self.ud_1_r2=bs.newnode('region',attrs={'position': (8.908631629943848+0.81, 7.327141418457031, -4.525400638580322),'scale': (2,1,1),'type': 'box','materials': [canon_load_mat ]}) diff --git a/dist/ba_root/mods/games/collector.py b/dist/ba_root/mods/games/collector.py index ba547bc..aea0350 100644 --- a/dist/ba_root/mods/games/collector.py +++ b/dist/ba_root/mods/games/collector.py @@ -1,4 +1,4 @@ -# ba_meta require api 8 +# ba_meta require api 9 # (see https://ballistica.net/wiki/meta-tag-system) ''' @@ -128,7 +128,7 @@ class CollectorGame(bs.TeamGameActivity[Player, Team]): @classmethod def get_available_settings( cls, sessiontype: type[bs.Session] - ) -> list[babase.Setting]: + ) -> list[bs.Setting]: settings = [ bs.IntSetting( capsules_to_win, @@ -223,12 +223,12 @@ class CollectorGame(bs.TeamGameActivity[Player, Team]): ( 'call', 'at_connect', - babase.Call(self._handle_player_flag_region_collide, True), + babase.CallPartial(self._handle_player_flag_region_collide, True), ), ( 'call', 'at_disconnect', - babase.Call(self._handle_player_flag_region_collide, False), + babase.CallPartial(self._handle_player_flag_region_collide, False), ), ), ) diff --git a/dist/ba_root/mods/maps/bridgit_mash.py b/dist/ba_root/mods/maps/bridgit_mash.py index f65b508..7ea65ed 100644 --- a/dist/ba_root/mods/maps/bridgit_mash.py +++ b/dist/ba_root/mods/maps/bridgit_mash.py @@ -3,13 +3,12 @@ from __future__ import annotations from typing import TYPE_CHECKING import babase -import bauiv1 as bui import bascenev1 as bs from bascenev1lib.gameutils import SharedObjects from bascenev1lib.actor.playerspaz import PlayerSpaz import random if TYPE_CHECKING: - from typing import Any, List, Dict + from typing import Any class mapdefs: @@ -131,7 +130,6 @@ class BridgitMash(bs.Map): self.create_ramp(0, 3.0) self.create_ramp(10.9, 3.2) self.ground() - # _babase.prop_axis(1, 0, 0) def ground(self): shared = SharedObjects.get() @@ -151,10 +149,6 @@ class BridgitMash(bs.Map): ) def create_ramp(self, loc, z_marg): - # try: - # _babase.prop_axis(0, 0, 0) - # except: - # pass shared = SharedObjects.get() self._real_wall_material = bs.Material() @@ -172,13 +166,6 @@ class BridgitMash(bs.Map): ('modify_part_collision', 'collide', False)) ) spaz_collide_mat = bs.Material() - # spaz_collide_mat.add_actions( - # conditions=('they_have_material',shared.player_material), - # actions=( - # ('modify_part_collision', 'collide', True), - # ( 'call','at_connect',babase.Call(self._handle_player_pad_collide,real )), - # ), - # ) pos = (-5.3 + loc, 0.7, 1.1+z_marg) self.ud_1_r = bs.newnode('region', attrs={'position': pos, 'scale': ( 2, 1, 2), 'type': 'box', 'materials': [shared.footing_material, spaz_collide_mat]}) @@ -233,4 +220,4 @@ class BridgitMash(bs.Map): player.shatter(True) -bs._map.register_map(BridgitMash) +bs.register_map(BridgitMash) diff --git a/dist/ba_root/mods/stats/stats.json.backup b/dist/ba_root/mods/stats/stats.json.backup index 644af46..ea6c6eb 100644 --- a/dist/ba_root/mods/stats/stats.json.backup +++ b/dist/ba_root/mods/stats/stats.json.backup @@ -33,11 +33,11 @@ "scores": 93, "total_damage": 0.0, "kills": 0, - "deaths": 0, - "games": 3, + "deaths": 1, + "games": 4, "kd": 0.0, - "avg_score": 31.0, - "last_seen": "2026-07-16 15:27:54.340453", + "avg_score": 23.25, + "last_seen": "2026-07-16 16:21:28.671836", "aid": "pb-IF5cVXEyAA==" } } From a14dda408be7e029bf0f787ea319f2ea32b45ea9 Mon Sep 17 00:00:00 2001 From: vishal332008 Date: Fri, 17 Jul 2026 08:58:11 +0530 Subject: [PATCH 11/14] reverting a mistake --- dist/ba_root/mods/features/dual_team_score.py | 856 ++++++++---------- 1 file changed, 380 insertions(+), 476 deletions(-) diff --git a/dist/ba_root/mods/features/dual_team_score.py b/dist/ba_root/mods/features/dual_team_score.py index dca0ad7..58e3bce 100644 --- a/dist/ba_root/mods/features/dual_team_score.py +++ b/dist/ba_root/mods/features/dual_team_score.py @@ -1,515 +1,419 @@ # Released under the MIT License. See LICENSE for details. # -"""Elimination mini-game.""" - -# ba_meta require api 9 -# (see https://ballistica.net/wiki/meta-tag-system) +"""Functionality related to the end screen in dual-team mode.""" from __future__ import annotations from typing import TYPE_CHECKING -import logging import babase import bascenev1 as bs -from bascenev1lib.actor.scoreboard import Scoreboard -from bascenev1lib.actor.spazfactory import SpazFactory +from bascenev1lib.activity.multiteamscore import MultiTeamScoreScreenActivity +from bascenev1lib.actor.image import Image +from bascenev1lib.actor.text import Text +from bascenev1lib.actor.zoomtext import ZoomText if TYPE_CHECKING: - from typing import (Any, Tuple, Type, List, Sequence, Optional, - Union) + pass -class Icon(bs.Actor): - """Creates in in-game icon on screen.""" - - def __init__(self, - player: Player, - position: Tuple[float, float], - scale: float, - show_lives: bool = True, - show_death: bool = True, - name_scale: float = 1.0, - name_maxwidth: float = 115.0, - flatness: float = 1.0, - shadow: float = 1.0): - super().__init__() - - self._player = player - self._show_lives = show_lives - self._show_death = show_death - self._name_scale = name_scale - self._outline_tex = bs.gettexture('characterIconMask') - - icon = player.get_icon() - self.node = bs.newnode('image', - delegate=self, - attrs={ - 'texture': icon['texture'], - 'tint_texture': icon['tint_texture'], - 'tint_color': icon['tint_color'], - 'vr_depth': 400, - 'tint2_color': icon['tint2_color'], - 'mask_texture': self._outline_tex, - 'opacity': 1.0, - 'absolute_scale': True, - 'attach': 'bottomCenter' - }) - self._name_text = bs.newnode( - 'text', - owner=self.node, - attrs={ - 'text': babase.Lstr(value=player.getname()), - 'color': babase.safecolor(player.team.color), - 'h_align': 'center', - 'v_align': 'center', - 'vr_depth': 410, - 'maxwidth': name_maxwidth, - 'shadow': shadow, - 'flatness': flatness, - 'h_attach': 'center', - 'v_attach': 'bottom' - }) - if self._show_lives: - self._lives_text = bs.newnode('text', - owner=self.node, - attrs={ - 'text': 'x0', - 'color': (1, 1, 0.5), - 'h_align': 'left', - 'vr_depth': 430, - 'shadow': 1.0, - 'flatness': 1.0, - 'h_attach': 'center', - 'v_attach': 'bottom' - }) - self.set_position_and_scale(position, scale) - - def set_position_and_scale(self, position: Tuple[float, float], - scale: float) -> None: - """(Re)position the icon.""" - assert self.node - self.node.position = position - self.node.scale = [70.0 * scale] - self._name_text.position = (position[0], position[1] + scale * 52.0) - self._name_text.scale = 1.0 * scale * self._name_scale - if self._show_lives: - self._lives_text.position = (position[0] + scale * 10.0, - position[1] - scale * 43.0) - self._lives_text.scale = 1.0 * scale - - def update_for_lives(self) -> None: - """Update for the target player's current lives.""" - if self._player: - lives = self._player.lives - else: - lives = 0 - if self._show_lives: - if lives > 0: - self._lives_text.text = 'x' + str(lives - 1) - else: - self._lives_text.text = '' - if lives == 0: - self._name_text.opacity = 0.2 - assert self.node - self.node.color = (0.7, 0.3, 0.3) - self.node.opacity = 0.2 - - def handle_player_spawned(self) -> None: - """Our player spawned; hooray!""" - if not self.node: - return - self.node.opacity = 1.0 - self.update_for_lives() - - def handle_player_died(self) -> None: - """Well poo; our player died.""" - if not self.node: - return - if self._show_death: - bs.animate( - self.node, 'opacity', { - 0.00: 1.0, - 0.05: 0.0, - 0.10: 1.0, - 0.15: 0.0, - 0.20: 1.0, - 0.25: 0.0, - 0.30: 1.0, - 0.35: 0.0, - 0.40: 1.0, - 0.45: 0.0, - 0.50: 1.0, - 0.55: 0.2 - }) - lives = self._player.lives - if lives == 0: - bs.timer(0.6, self.update_for_lives) - - def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, bs.DieMessage): - self.node.delete() - return None - return super().handlemessage(msg) - - -class Player(bs.Player['Team']): - """Our player type for this game.""" - - def __init__(self) -> None: - self.lives = 0 - self.icons: List[Icon] = [] - - -class Team(bs.Team[Player]): - """Our team type for this game.""" - - def __init__(self) -> None: - self.survival_seconds: Optional[int] = None - self.spawn_order: List[Player] = [] - - -# ba_meta export bascenev1.GameActivity -class AllianceEliminationGame(bs.TeamGameActivity[Player, Team]): - """Game type where last player(s) left alive win.""" - - name = 'Alliance Elimination' - description = 'Fight in groups of duo, trio, or more.\nLast remaining alive wins.' - scoreconfig = bs.ScoreConfig(label='Survived', - scoretype=bs.ScoreType.SECONDS, - none_is_winner=True) - # Show messages when players die since it's meaningful here. - announce_player_deaths = True - - allow_mid_activity_joins = False - - @classmethod - def get_available_settings( - cls, sessiontype: Type[bs.Session]) -> List[bs.Setting]: - settings = [ - bs.IntSetting( - 'Lives Per Player', - default=1, - min_value=1, - max_value=10, - increment=1, - ), - bs.IntSetting( - 'Players Per Team In Arena', - default=2, - min_value=2, - max_value=10, - increment=1, - ), - bs.IntChoiceSetting( - 'Time Limit', - choices=[ - ('None', 0), - ('1 Minute', 60), - ('2 Minutes', 120), - ('5 Minutes', 300), - ('10 Minutes', 600), - ('20 Minutes', 1200), - ], - default=0, - ), - bs.FloatChoiceSetting( - 'Respawn Times', - choices=[ - ('Shorter', 0.25), - ('Short', 0.5), - ('Normal', 1.0), - ('Long', 2.0), - ('Longer', 4.0), - ], - default=1.0, - ), - bs.BoolSetting('Epic Mode', default=False), - ] - if issubclass(sessiontype, bs.DualTeamSession): - settings.append( - bs.BoolSetting('Balance Total Lives', default=False)) - return settings - - @classmethod - def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool: - return issubclass(sessiontype, bs.DualTeamSession) - - @classmethod - def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]: - return bs.app.classic.getmaps('melee') +class TeamVictoryScoreScreenActivity(MultiTeamScoreScreenActivity): + """Scorescreen between rounds of a dual-team session.""" def __init__(self, settings: dict): - super().__init__(settings) - self._scoreboard = Scoreboard() - self._start_time: Optional[float] = None - self._vs_text: Optional[bs.Actor] = None - self._round_end_timer: Optional[bs.Timer] = None - self._epic_mode = bool(settings['Epic Mode']) - self._lives_per_player = int(settings['Lives Per Player']) - self._time_limit = float(settings['Time Limit']) - self._balance_total_lives = bool( - settings.get('Balance Total Lives', False)) - self._players_per_team_in_arena = int( - settings['Players Per Team In Arena']) - - # Base class overrides: - self.slow_motion = self._epic_mode - self.default_music = (bs.MusicType.EPIC - if self._epic_mode else bs.MusicType.SURVIVAL) - - def get_instance_description(self) -> Union[str, Sequence]: - return 'Last team standing wins.' if isinstance( - self.session, bs.DualTeamSession) else 'Last one standing wins.' - - def get_instance_description_short(self) -> Union[str, Sequence]: - return 'last team standing wins' if isinstance( - self.session, bs.DualTeamSession) else 'last one standing wins' - - def on_player_join(self, player: Player) -> None: - - # No longer allowing mid-game joiners here; too easy to exploit. - if self.has_begun(): - - # Make sure their team has survival seconds set if they're all dead - # (otherwise blocked new ffa players are considered 'still alive' - # in score tallying). - if (self._get_total_team_lives(player.team) == 0 - and player.team.survival_seconds is None): - player.team.survival_seconds = 0 - bs.broadcastmessage( - babase.Lstr(resource='playerDelayedJoinText', - subs=[('${PLAYER}', player.getname(full=True))]), - color=(0, 1, 0), - ) - return - - player.lives = self._lives_per_player - - player.team.spawn_order.append(player) - self._update_alliance_mode() - - # Don't waste time doing this until begin. - if self.has_begun(): - self._update_icons() + super().__init__(settings=settings) + self._winner: bs.SessionTeam = settings['winner'] + assert isinstance(self._winner, bs.SessionTeam) def on_begin(self) -> None: + babase.set_analytics_screen('Teams Score Screen') super().on_begin() - self._start_time = bs.time() - self.setup_standard_time_limit(self._time_limit) - self.setup_standard_powerup_drops() - self._vs_text = bs.NodeActor( - bs.newnode('text', - attrs={ - 'position': (0, 92), - 'h_attach': 'center', - 'h_align': 'center', - 'maxwidth': 200, - 'shadow': 0.5, - 'vr_depth': 390, - 'scale': 0.6, - 'v_attach': 'bottom', - 'color': (0.8, 0.8, 0.3, 1.0), - 'text': babase.Lstr(resource='vsText') - })) - # If balance-team-lives is on, add lives to the smaller team until - # total lives match. - if (isinstance(self.session, bs.DualTeamSession) - and self._balance_total_lives and self.teams[0].players - and self.teams[1].players): - if self._get_total_team_lives( - self.teams[0]) < self._get_total_team_lives(self.teams[1]): - lesser_team = self.teams[0] - greater_team = self.teams[1] - else: - lesser_team = self.teams[1] - greater_team = self.teams[0] - add_index = 0 - while (self._get_total_team_lives(lesser_team) < - self._get_total_team_lives(greater_team)): - lesser_team.players[add_index].lives += 1 - add_index = (add_index + 1) % len(lesser_team.players) + height = 130 + active_team_count = len(self.teams) + vval = (height * active_team_count) / 2 - height / 2 + i = 0 + shift_time = 2.5 - self._update_icons() + # Usually we say 'Best of 7', but if the language prefers we can say + # 'First to 4'. + session = self.session + assert isinstance(session, bs.MultiTeamSession) + best_of_use_first_to_instead = 0 + if best_of_use_first_to_instead: + best_txt = babase.Lstr(resource='firstToSeriesText', + subs=[('${COUNT}', + str(session.get_series_length() / 2 + 1)) + ]) + else: + best_txt = babase.Lstr(resource='bestOfSeriesText', + subs=[('${COUNT}', + str(session.get_series_length()))]) + if len(self.teams) != 2: + ZoomText(best_txt, + position=(0, 175), + shiftposition=(-250, 175), + shiftdelay=2.5, + flash=False, + trail=False, + h_align='center', + scale=0.25, + color=(0.5, 0.5, 0.5, 1.0), + jitter=3.0).autoretain() + for team in self.session.sessionteams: + bs.timer( + i * 0.15 + 0.15, + bs.WeakCallPartial(self._show_team_name, vval - i * height, team, + i * 0.2, shift_time - (i * 0.150 + 0.150))) + bs.timer(i * 0.150 + 0.5, self._score_display_sound_small.play) + scored = (team is self._winner) + delay = 0.2 + if scored: + delay = 1.2 + bs.timer( + i * 0.150 + 0.2, + bs.WeakCallPartial(self._show_team_old_score, vval - i * height, + team, shift_time - (i * 0.15 + 0.2))) + bs.timer(i * 0.15 + 1.5, self._score_display_sound.play) - # We could check game-over conditions at explicit trigger points, - # but lets just do the simple thing and poll it. - bs.timer(1.0, self._update, repeat=True) + bs.timer( + i * 0.150 + delay, + bs.WeakCallPartial(self._show_team_score, vval - i * height, team, + scored, i * 0.2 + 0.1, + shift_time - (i * 0.15 + delay))) + i += 1 + self.show_player_scores() - def _update_alliance_mode(self) -> None: - # For both teams, find the first player on the spawn order list with - # lives remaining and spawn them if they're not alive. - for team in self.teams: - # Prune dead players from the spawn order. - players_spawned = 0 - team.spawn_order = [p for p in team.spawn_order if p] - for player in team.spawn_order: - assert isinstance(player, Player) - if player.lives > 0: - if not player.is_alive(): - self.spawn_player(player) - self._update_icons() - players_spawned += 1 - if players_spawned >= self._players_per_team_in_arena: - break + def _show_team_name(self, pos_v: float, team: bs.SessionTeam, + kill_delay: float, shiftdelay: float) -> None: + del kill_delay # Unused arg. + if len(self.teams) != 2: + ZoomText( + babase.Lstr(value='${A}:', subs=[('${A}', team.name)]), + position=(100, pos_v), + shiftposition=(-150, pos_v), + shiftdelay=shiftdelay, + flash=False, + trail=False, + h_align='right', + maxwidth=300, + color=team.color, + jitter=1.0, + ).autoretain() + else: + ZoomText(babase.Lstr(value='${A}', subs=[('${A}', team.name)]), + position=(-250, 260) if pos_v == 65 else (250, 260), + shiftposition=(-250, 260) if pos_v == 65 else (250, 260), + shiftdelay=shiftdelay, + flash=False, + trail=False, + h_align='center', + maxwidth=300, + scale=0.45, + color=team.color, + jitter=1.0).autoretain() - def _update_icons(self) -> None: - # pylint: disable=too-many-branches - # First off, clear out all icons. - for player in self.players: - player.icons = [] + def _show_team_old_score(self, pos_v: float, sessionteam: bs.SessionTeam, + shiftdelay: float) -> None: - # Now for each team, cycle through our available players - # adding icons. - for team in self.teams: - if team.id == 0: - xval = -60 - x_offs = -78 - else: - xval = 60 - x_offs = 78 - nplayers = self._players_per_team_in_arena - test_lives = 1 - while True: - players_with_lives = [ - p for p in team.spawn_order - if p and p.lives >= test_lives - ] - if not players_with_lives: - break - for player in players_with_lives: - player.icons.append( - Icon(player, - position=(xval, (36 if nplayers > 0 else 25)), - scale=0.9 if nplayers > 0 else 0.5, - name_maxwidth=85 if nplayers > 0 else 75, - name_scale=0.8 if nplayers > 0 else 1.0, - flatness=0.0 if nplayers > 0 else 1.0, - shadow=0.5 if nplayers > 0 else 1.0, - show_death=True if nplayers > 0 else False, - show_lives=False)) - xval += x_offs * (0.85 if nplayers > 0 else 0.56) - nplayers -= 1 - test_lives += 1 + if len(self.teams) != 2: + ZoomText( + str(sessionteam.customdata['score'] - 1), + position=(150, pos_v), + maxwidth=100, + color=(0.6, 0.6, 0.7), + shiftposition=(-100, pos_v), + shiftdelay=shiftdelay, + flash=False, + trail=False, + lifespan=1.0, + h_align='left', + jitter=1.0, + ).autoretain() + else: + ZoomText(str(sessionteam.customdata['score'] - 1), + position=(-250, 190) if pos_v == 65 else (250, 190), + maxwidth=100, + color=(0.6, 0.6, 0.7), + shiftposition=(-250, 190) if pos_v == 65 else (250, 190), + shiftdelay=shiftdelay, + flash=False, + trail=False, + lifespan=1.0, + scale=0.56, + h_align='center', + jitter=1.0).autoretain() - def _get_spawn_point(self, player: Player) -> Optional[babase.Vec3]: - return None + def _show_team_score(self, pos_v: float, sessionteam: bs.SessionTeam, + scored: bool, kill_delay: float, + shiftdelay: float) -> None: + del kill_delay # Unused arg. + if len(self.teams) != 2: + ZoomText( + str(sessionteam.customdata['score']), + position=(150, pos_v), + maxwidth=100, + color=(1.0, 0.9, 0.5) if scored else (0.6, 0.6, 0.7), + shiftposition=(-100, pos_v), + shiftdelay=shiftdelay, + flash=scored, + trail=scored, + h_align='left', + jitter=1.0, + trailcolor=(1, 0.8, 0.0, 0), + ).autoretain() + else: + ZoomText(str(sessionteam.customdata['score']), + position=(-250, 190) if pos_v == 65 else (250, 190), + maxwidth=100, + color=(1.0, 0.9, 0.5) if scored else (0.6, 0.6, 0.7), + shiftposition=(-250, 190) if pos_v == 65 else (250, 190), + shiftdelay=shiftdelay, + flash=scored, + trail=scored, + scale=0.56, + h_align='center', + jitter=1.0, + trailcolor=(1, 0.8, 0.0, 0)).autoretain() - def spawn_player(self, player: Player) -> bs.Actor: - actor = self.spawn_player_spaz(player, self._get_spawn_point(player)) - # If we have any icons, update their state. - for icon in player.icons: - icon.handle_player_spawned() - return actor +# =================================================================================================== - def _print_lives(self, player: Player) -> None: - from bascenev1lib.actor import popuptext +# score board +# ==================================================================================================== - # We get called in a timer so it's possible our player has left/etc. - if not player or not player.is_alive() or not player.node: - return +def show_player_scores(self, + delay: float = 2.5, + results: bs.GameResults | None = None, + scale: float = 1.0, + x_offset: float = 0.0, + y_offset: float = 0.0) -> None: + """Show scores for individual players.""" + # pylint: disable=too-many-locals + # pylint: disable=too-many-statements - popuptext.PopupText('x' + str(player.lives - 1), - color=(1, 1, 0, 1), - offset=(0, -0.8, 0), - random_offset=0.0, - scale=1.8, - position=player.node.position).autoretain() + ts_v_offset = 150.0 + y_offset + ts_h_offs = 80.0 + x_offset + tdelay = delay + spacing = 40 - def on_player_leave(self, player: Player) -> None: - super().on_player_leave(player) - player.icons = [] + is_free_for_all = isinstance(self.session, bs.FreeForAllSession) - # Remove us from spawn-order. - if player in player.team.spawn_order: - player.team.spawn_order.remove(player) + is_two_team = True if len(self.session.sessionteams) == 2 else False - # Update icons in a moment since our team will be gone from the - # list then. - bs.timer(0, self._update_icons) + def _get_prec_score(p_rec: bs.PlayerRecord) -> int | None: + if is_free_for_all and results is not None: + assert isinstance(results, bs.GameResults) + assert p_rec.team.activityteam is not None + val = results.get_sessionteam_score(p_rec.team) + return val + return p_rec.accumscore - # If the player to leave was the last in spawn order and had - # their final turn currently in-progress, mark the survival time - # for their team. - if self._get_total_team_lives(player.team) == 0: - assert self._start_time is not None - player.team.survival_seconds = int(bs.time() - self._start_time) + def _get_prec_score_str(p_rec: bs.PlayerRecord) -> str | bs.Lstr: + if is_free_for_all and results is not None: + assert isinstance(results, bs.GameResults) + assert p_rec.team.activityteam is not None + val = results.get_sessionteam_score_str(p_rec.team) + assert val is not None + return val + return str(p_rec.accumscore) - def _get_total_team_lives(self, team: Team) -> int: - return sum(player.lives for player in team.players) + # stats.get_records() can return players that are no longer in + # the game.. if we're using results we have to filter those out + # (since they're not in results and that's where we pull their + # scores from) + if results is not None: + assert isinstance(results, bs.GameResults) + player_records = [] + assert self.stats + valid_players = list(self.stats.get_records().items()) - def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, bs.PlayerDiedMessage): + def _get_player_score_set_entry( + player: bs.SessionPlayer) -> bs.PlayerRecord | None: + for p_rec in valid_players: + if p_rec[1].player is player: + return p_rec[1] + return None - # Augment standard behavior. - super().handlemessage(msg) - player: Player = msg.getplayer(Player) - - player.lives -= 1 - if player.lives < 0: - logging.error( - "Got lives < 0 in Alliance Elimination; this shouldn't happen.") - player.lives = 0 - - # If we have any icons, update their state. - for icon in player.icons: - icon.handle_player_died() - - # Play big death sound on our last death - # or for every one. - if player.lives == 0: - SpazFactory.get().single_player_death_sound.play() - - # If we hit zero lives, we're dead (and our team might be too). - if player.lives == 0: - # If the whole team is now dead, mark their survival time. - if self._get_total_team_lives(player.team) == 0: - assert self._start_time is not None - player.team.survival_seconds = int(bs.time() - - self._start_time) - - # Put ourself at the back of the spawn order. - player.team.spawn_order.remove(player) - player.team.spawn_order.append(player) - player.node.delete() - - def _update(self) -> None: - # For both teams, find the first player on the spawn order - # list with lives remaining and spawn them if they're not alive. - for team in self.teams: - # Prune dead players from the spawn order. - team.spawn_order = [p for p in team.spawn_order if p] - players_spawned = 0 - for player in team.spawn_order: - assert isinstance(player, Player) - if player.lives > 0: - if not player.is_alive(): - self.spawn_player(player) - self._update_icons() - players_spawned += 1 - if players_spawned >= self._players_per_team_in_arena: - break - - # If we're down to 1 or fewer living teams, start a timer to end - # the game (allows the dust to settle and draws to occur if deaths - # are close enough). - if len(self._get_living_teams()) < 2: - self._round_end_timer = bs.Timer(0.5, self.end_game) - - def _get_living_teams(self) -> List[Team]: - return [ - team for team in self.teams - if len(team.players) > 0 and any(player.lives > 0 - for player in team.players) + # Results is already sorted; just convert it into a list of + # score-set-entries. + for winnergroup in results.winnergroups: + for team in winnergroup.teams: + if len(team.players) == 1: + player_entry = _get_player_score_set_entry( + team.players[0]) + if player_entry is not None: + player_records.append(player_entry) + else: + player_records = [] + player_records_scores = [ + (_get_prec_score(p), name, p) + for name, p in list(self.stats.get_records().items()) ] + player_records_scores.sort(reverse=True) - def end_game(self) -> None: - if self.has_ended(): - return - results = bs.GameResults() - self._vs_text = None # Kill our 'vs' if its there. - for team in self.teams: - results.set_team_score(team, team.survival_seconds) - self.end(results=results) + # Just want living player entries. + player_records = [p[2] for p in player_records_scores if p[2]] + + voffs = -140.0 + spacing * 5 * 0.5 + + voffs_team0 = voffs + tdelay_team0 = tdelay + + def _txt(xoffs: float, + yoffs: float, + text: babase.Lstr, + h_align: Text.HAlign = Text.HAlign.RIGHT, + extrascale: float = 1.0, + maxwidth: float | None = 120.0) -> None: + Text(text, + color=(0.5, 0.5, 0.6, 0.5), + position=(ts_h_offs + xoffs * scale, + ts_v_offset + (voffs + yoffs + 4.0) * scale), + h_align=h_align, + v_align=Text.VAlign.CENTER, + scale=0.8 * scale * extrascale, + maxwidth=maxwidth, + transition=Text.Transition.IN_LEFT, + transition_delay=tdelay).autoretain() + + session = self.session + assert isinstance(session, bs.MultiTeamSession) + if is_two_team: + tval = "Game " + str(session.get_game_number()) + " Results" + _txt(-75, + 160, + tval, + h_align=Text.HAlign.CENTER, + extrascale=1.4, + maxwidth=None) + else: + tval = babase.Lstr( + resource='gameLeadersText', + subs=[('${COUNT}', str(session.get_game_number()))], + ) + _txt( + 180, + 43, + tval, + h_align=Text.HAlign.CENTER, + extrascale=1.4, + maxwidth=None, + ) + _txt(-15, 4, babase.Lstr(resource='playerText'), h_align=Text.HAlign.LEFT) + _txt(180, 4, babase.Lstr(resource='killsText')) + _txt(280, 4, babase.Lstr(resource='deathsText'), maxwidth=100) + + score_label = 'Score' if results is None else results.score_label + translated = babase.Lstr(translate=('scoreNames', score_label)) + + _txt(390, 0, translated) + + if is_two_team: + _txt(-595, 4, babase.Lstr(resource='playerText'), + h_align=Text.HAlign.LEFT) + _txt(-400, 4, babase.Lstr(resource='killsText')) + _txt(-300, 4, babase.Lstr(resource='deathsText'), maxwidth=100) + _txt(-190, 0, translated) + + topkillcount = 0 + topkilledcount = 99999 + top_score = 0 if not player_records else _get_prec_score( + player_records[0]) + + for prec in player_records: + topkillcount = max(topkillcount, prec.accum_kill_count) + topkilledcount = min(topkilledcount, prec.accum_killed_count) + + def _scoretxt(text: str | bs.Lstr, + x_offs: float, + highlight: bool, + delay2: float, + maxwidth: float = 70.0, team_id=1) -> None: + + Text(text, + position=(ts_h_offs + x_offs * scale, + ts_v_offset + ( + voffs + 15) * scale) if team_id == 1 else ( + ts_h_offs + x_offs * scale, + ts_v_offset + (voffs_team0 + 15) * scale), + scale=scale, + 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, + transition=Text.Transition.IN_LEFT, + transition_delay=(tdelay + delay2) if team_id == 1 else ( + tdelay_team0 + delay2)).autoretain() + + for playerrec in player_records: + if is_two_team and playerrec.team.id == 0: + tdelay_team0 += 0.05 + voffs_team0 -= spacing + x_image = 617 + x_text = -595 + y = ts_v_offset + (voffs_team0 + 15.0) * scale + + else: + tdelay += 0.05 + voffs -= spacing + x_image = 12 + x_text = 10.0 + y = ts_v_offset + (voffs + 15.0) * scale + + Image(playerrec.get_icon(), + position=(ts_h_offs - x_image * scale, + y), + scale=(30.0 * scale, 30.0 * scale), + transition=Image.Transition.IN_LEFT, + transition_delay=tdelay if playerrec.team.id == 1 else tdelay_team0).autoretain() + Text(babase.Lstr(value=playerrec.getname(full=True)), + maxwidth=160, + scale=0.75 * scale, + position=(ts_h_offs + x_text * scale, + y), + h_align=Text.HAlign.LEFT, + v_align=Text.VAlign.CENTER, + color=babase.safecolor(playerrec.team.color + (1,)), + transition=Text.Transition.IN_LEFT, + transition_delay=tdelay if playerrec.team.id == 1 else tdelay_team0).autoretain() + + if is_two_team and playerrec.team.id == 0: + _scoretxt(str(playerrec.accum_kill_count), -400, + playerrec.accum_kill_count == topkillcount, 0.1, + team_id=0) + _scoretxt(str(playerrec.accum_killed_count), -300, + playerrec.accum_killed_count == topkilledcount, 0.1, + team_id=0) + _scoretxt(_get_prec_score_str(playerrec), -190, + _get_prec_score(playerrec) == top_score, 0.2, team_id=0) + else: + _scoretxt(str(playerrec.accum_kill_count), 180, + playerrec.accum_kill_count == topkillcount, 0.1) + _scoretxt(str(playerrec.accum_killed_count), 280, + playerrec.accum_killed_count == topkilledcount, 0.1) + _scoretxt(_get_prec_score_str(playerrec), 390, + _get_prec_score(playerrec) == top_score, 0.2) + + +# ======================== draw screen ============= +class DrawScoreScreenActivity(MultiTeamScoreScreenActivity): + """Score screen shown after a draw.""" + + default_music = None # Awkward silence... + + def on_begin(self) -> None: + babase.set_analytics_screen('Draw Score Screen') + super().on_begin() + ZoomText(babase.Lstr(resource='drawText'), + position=(0, 200), + maxwidth=400, + shiftposition=(0, 200), + shiftdelay=2.0, + flash=False, + scale=0.7, + trail=False, + jitter=1.0).autoretain() + bs.timer(0.35, self._score_display_sound.play) + self.show_player_scores(results=self.settings_raw.get('results', None)) \ No newline at end of file From 4d6361e0db0b979f77c7108a7a4ce10116696a3b Mon Sep 17 00:00:00 2001 From: vishal332008 Date: Sun, 19 Jul 2026 18:02:28 +0530 Subject: [PATCH 12/14] few fixes --- dist/ba_root/mods/games/arms_race.py | 2 +- dist/ba_root/mods/games/demolition_war.py | 14 ++-- dist/ba_root/mods/games/dodge_the_ball.py | 23 +++--- .../ba_root/mods/games/down_into_the_abyss.py | 74 +----------------- dist/ba_root/mods/maps/abyss.py | 75 +++++++++++++++++++ 5 files changed, 96 insertions(+), 92 deletions(-) create mode 100644 dist/ba_root/mods/maps/abyss.py diff --git a/dist/ba_root/mods/games/arms_race.py b/dist/ba_root/mods/games/arms_race.py index d6aa463..5e7efad 100644 --- a/dist/ba_root/mods/games/arms_race.py +++ b/dist/ba_root/mods/games/arms_race.py @@ -146,7 +146,7 @@ class ArmsRaceGame(bs.TeamGameActivity[Player, Team]): def on_player_join(self, player): if player.state is None: - player.state = self.states[5] + player.state = self.states[0] self.spawn_player(player) # overriding the default character spawning.. diff --git a/dist/ba_root/mods/games/demolition_war.py b/dist/ba_root/mods/games/demolition_war.py index 84817a7..dd915ee 100644 --- a/dist/ba_root/mods/games/demolition_war.py +++ b/dist/ba_root/mods/games/demolition_war.py @@ -1,4 +1,4 @@ -# ba_meta require api 8 +# ba_meta require api 9 """ DemolitionWar - BombFight on wooden floor flying in air. Author: Mr.Smoothy @@ -25,10 +25,8 @@ if TYPE_CHECKING: # ba_meta export bascenev1.GameActivity - - class DemolitionWar(EliminationGame): - name = 'DemolitionWar' + name = 'Demolition War' description = 'Last remaining alive wins.' scoreconfig = bs.ScoreConfig( label='Survived', scoretype=bs.ScoreType.SECONDS, none_is_winner=True @@ -41,7 +39,7 @@ class DemolitionWar(EliminationGame): @classmethod def get_available_settings( cls, sessiontype: type[bs.Session] - ) -> list[babase.Setting]: + ) -> list[bs.Setting]: settings = [ bs.IntSetting( 'Lives Per Player', @@ -124,7 +122,7 @@ class DemolitionWar(EliminationGame): node = bs.getcollision().sourcenode bs.emitfx((node.position[0], 0.9, node.position[2]), (0, 2, 0), 30, 1, spread=1, chunk_type='splinter') - bs.timer(0.1, babase.Call(node.delete)) + bs.timer(0.1, babase.CallStrict(node.delete)) def map_extend(self): # TODO need to improve here , so we can increase size of map easily with settings @@ -137,7 +135,7 @@ class DemolitionWar(EliminationGame): actions=( ('modify_part_collision', 'collide', True), ('modify_part_collision', 'physical', True), - ('call', 'at_connect', babase.Call(self.on_blast)) + ('call', 'at_connect', babase.CallStrict(self.on_blast)) )) self.ramps = [] for i in p: @@ -309,6 +307,6 @@ class WoodenFloor( try: - bs._map.register_map(WoodenFloor) + bs.register_map(WoodenFloor) except: pass diff --git a/dist/ba_root/mods/games/dodge_the_ball.py b/dist/ba_root/mods/games/dodge_the_ball.py index f1d75a6..6470558 100644 --- a/dist/ba_root/mods/games/dodge_the_ball.py +++ b/dist/ba_root/mods/games/dodge_the_ball.py @@ -6,7 +6,7 @@ # Feel free to edit. -# ba_meta require api 8 +# ba_meta require api 9 from __future__ import annotations from enum import Enum @@ -57,7 +57,7 @@ class Ball(bs.Actor): def __init__(self, position: Sequence[float], velocity: Sequence[float], - texture: babase.Texture, + texture: bs.Texture, body_scale: float = 1.0, gravity_scale: float = 1.0, ) -> NoReturn: @@ -99,7 +99,7 @@ class Ball(bs.Actor): ) # die the ball manually incase the ball doesn't fall the outside of the map - bs.timer(2.5, bs.WeakCall(self.handlemessage, bs.DieMessage())) + bs.timer(2.5, bs.WeakCallPartial(self.handlemessage, bs.DieMessage())) # i am not handling anything in this ball Class(except for diemessage). # all game things and logics going to be in the box class @@ -213,7 +213,7 @@ class Box(bs.Actor): self.force_shoot_speed: float = 0.0 self.ball_mag = 3000 self.ball_gravity: float = 1.0 - self.ball_tex: babase.Texture | None = None + self.ball_tex: bs.Texture | None = None # only for Hard ball_type self.player_facing_direction: list[float, float] = [0.0, 0.0] # ball shoot soound. @@ -384,7 +384,7 @@ class Box(bs.Actor): # And a circle outline with ugly animation. circle_outline = bs.newnode( "locator", - owner=player.actor.node, + owner=player.node, attrs={ 'shape': 'circleOutline', 'color': (1.0, 0.0, 0.0), @@ -409,8 +409,8 @@ class Box(bs.Actor): ) # coonect it and... - player.actor.node.connectattr("position", light, "position") - player.actor.node.connectattr("position", circle_outline, "position") + player.node.connectattr("position", light, "position") + player.node.connectattr("position", circle_outline, "position") # immediately delete the node after another player has been targeted. self.shoot_speed = 0.5 if self.shoot_speed == 0.0 else self.shoot_speed @@ -424,8 +424,11 @@ class Box(bs.Actor): # and i got it how analog stick values are works. # just need to store analog stick facing direction and need some calculation according how far player pushed analog stick. # Notice that how vertical direction is inverted, so we need to put a minus infront of veriable.(so ball isn't shoot at wrong direction). - self.player_facing_direction[0] = player.actor.node.move_left_right - self.player_facing_direction[1] = -player.actor.node.move_up_down + try: + self.player_facing_direction[0] = player.node.move_left_right + self.player_facing_direction[1] = -player.node.move_up_down + except: + pass # if player is too close and the player pushing his analog stick fully the ball shoot's too far away to player. # so, we need to reduce the value of "self.player_facing_direction" to fix this problem. @@ -485,8 +488,6 @@ class Team(bs.Team[Player]): # and main thing don't allow player to camp inside of box are going in this class. # ba_meta export bascenev1.GameActivity - - class DodgeTheBall(bs.TeamGameActivity[Player, Team]): # defining name, description and settings.. name = 'Dodge the ball' diff --git a/dist/ba_root/mods/games/down_into_the_abyss.py b/dist/ba_root/mods/games/down_into_the_abyss.py index ab26ef5..cefdce4 100644 --- a/dist/ba_root/mods/games/down_into_the_abyss.py +++ b/dist/ba_root/mods/games/down_into_the_abyss.py @@ -1,5 +1,4 @@ -# Ported to api 8 by brostos using baport.(https://github.com/bombsquad-community/baport) -# ba_meta require api 8 +# ba_meta require api 9 # (see https://ballistica.net/wiki/meta-tag-system) from __future__ import annotations @@ -11,7 +10,6 @@ import bauiv1 as bui import bascenev1 as bs import _babase import random -from bascenev1._map import register_map from bascenev1lib.actor.spaz import PickupMessage from bascenev1lib.actor.playerspaz import PlayerSpaz from bascenev1lib.actor.spazfactory import SpazFactory @@ -59,74 +57,6 @@ else: hint_use_punch = 'You can punch your enemies now!' -class AbyssMap(bs.Map): - from bascenev1lib.mapdata import happy_thoughts as defs - # Add the y-dimension space for players - defs.boxes['map_bounds'] = (-0.8748348681, 9.212941713, -9.729538885) \ - + (0.0, 0.0, 0.0) \ - + (36.09666006, 26.19950145, 20.89541168) - name = 'Abyss Unhappy' - - @classmethod - def get_play_types(cls) -> list[str]: - """Return valid play types for this map.""" - return ['abyss'] - - @classmethod - def get_preview_texture_name(cls) -> str: - return 'alwaysLandPreview' - - @classmethod - def on_preload(cls) -> Any: - data: dict[str, Any] = { - 'mesh': bs.getmesh('alwaysLandLevel'), - 'bottom_mesh': bs.getmesh('alwaysLandLevelBottom'), - 'bgmesh': bs.getmesh('alwaysLandBG'), - 'collision_mesh': bs.getcollisionmesh('alwaysLandLevelCollide'), - 'tex': bs.gettexture('alwaysLandLevelColor'), - 'bgtex': bs.gettexture('alwaysLandBGColor'), - 'vr_fill_mound_mesh': bs.getmesh('alwaysLandVRFillMound'), - 'vr_fill_mound_tex': bs.gettexture('vrFillMound') - } - return data - - @classmethod - def get_music_type(cls) -> bs.MusicType: - return bs.MusicType.FLYING - - def __init__(self) -> None: - super().__init__(vr_overlay_offset=(0, -3.7, 2.5)) - self.background = bs.newnode( - 'terrain', - attrs={ - 'mesh': self.preloaddata['bgmesh'], - 'lighting': False, - 'background': True, - 'color_texture': self.preloaddata['bgtex'] - }) - bs.newnode('terrain', - attrs={ - 'mesh': self.preloaddata['vr_fill_mound_mesh'], - 'lighting': False, - 'vr_only': True, - 'color': (0.2, 0.25, 0.2), - 'background': True, - 'color_texture': self.preloaddata['vr_fill_mound_tex'] - }) - gnode = bs.getactivity().globalsnode - gnode.happy_thoughts_mode = True - gnode.shadow_offset = (0.0, 8.0, 5.0) - gnode.tint = (1.3, 1.23, 1.0) - gnode.ambient_color = (1.3, 1.23, 1.0) - gnode.vignette_outer = (0.64, 0.59, 0.69) - gnode.vignette_inner = (0.95, 0.95, 0.93) - gnode.vr_near_clip = 1.0 - self.is_flying = True - - -register_map(AbyssMap) - - class SpazTouchFoothold: pass @@ -491,7 +421,7 @@ class AbyssGame(bs.TeamGameActivity[Player, Team]): @classmethod def get_available_settings( - cls, sessiontype: type[bs.Session]) -> list[babase.Setting]: + cls, sessiontype: type[bs.Session]) -> list[bs.Setting]: settings = [ bs.FloatChoiceSetting( peaceTime, diff --git a/dist/ba_root/mods/maps/abyss.py b/dist/ba_root/mods/maps/abyss.py new file mode 100644 index 0000000..cbd4baa --- /dev/null +++ b/dist/ba_root/mods/maps/abyss.py @@ -0,0 +1,75 @@ + +from typing import TYPE_CHECKING + +import bascenev1 as bs +from bascenev1._map import register_map + +if TYPE_CHECKING: + from typing import Any + + +class AbyssMap(bs.Map): + from bascenev1lib.mapdata import happy_thoughts as defs + # Add the y-dimension space for players + defs.boxes['map_bounds'] = (-0.8748348681, 9.212941713, -9.729538885) \ + + (0.0, 0.0, 0.0) \ + + (36.09666006, 26.19950145, 20.89541168) + name = 'Abyss Unhappy' + + @classmethod + def get_play_types(cls) -> list[str]: + """Return valid play types for this map.""" + return ['abyss'] + + @classmethod + def get_preview_texture_name(cls) -> str: + return 'alwaysLandPreview' + + @classmethod + def on_preload(cls) -> Any: + data: dict[str, Any] = { + 'mesh': bs.getmesh('alwaysLandLevel'), + 'bottom_mesh': bs.getmesh('alwaysLandLevelBottom'), + 'bgmesh': bs.getmesh('alwaysLandBG'), + 'collision_mesh': bs.getcollisionmesh('alwaysLandLevelCollide'), + 'tex': bs.gettexture('alwaysLandLevelColor'), + 'bgtex': bs.gettexture('alwaysLandBGColor'), + 'vr_fill_mound_mesh': bs.getmesh('alwaysLandVRFillMound'), + 'vr_fill_mound_tex': bs.gettexture('vrFillMound') + } + return data + + @classmethod + def get_music_type(cls) -> bs.MusicType: + return bs.MusicType.FLYING + + def __init__(self) -> None: + super().__init__(vr_overlay_offset=(0, -3.7, 2.5)) + self.background = bs.newnode( + 'terrain', + attrs={ + 'mesh': self.preloaddata['bgmesh'], + 'lighting': False, + 'background': True, + 'color_texture': self.preloaddata['bgtex'] + }) + bs.newnode('terrain', + attrs={ + 'mesh': self.preloaddata['vr_fill_mound_mesh'], + 'lighting': False, + 'vr_only': True, + 'color': (0.2, 0.25, 0.2), + 'background': True, + 'color_texture': self.preloaddata['vr_fill_mound_tex'] + }) + gnode = bs.getactivity().globalsnode + gnode.happy_thoughts_mode = True + gnode.shadow_offset = (0.0, 8.0, 5.0) + gnode.tint = (1.3, 1.23, 1.0) + gnode.ambient_color = (1.3, 1.23, 1.0) + gnode.vignette_outer = (0.64, 0.59, 0.69) + gnode.vignette_inner = (0.95, 0.95, 0.93) + gnode.vr_near_clip = 1.0 + self.is_flying = True + +register_map(AbyssMap) \ No newline at end of file From bccf0fc62f8db82621507df3c3e284fe4fbadc01 Mon Sep 17 00:00:00 2001 From: vishal332008 Date: Sun, 19 Jul 2026 18:11:07 +0530 Subject: [PATCH 13/14] conflict fixing --- dist/ba_root/mods/tools/servercheck.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/dist/ba_root/mods/tools/servercheck.py b/dist/ba_root/mods/tools/servercheck.py index d247875..878d496 100644 --- a/dist/ba_root/mods/tools/servercheck.py +++ b/dist/ba_root/mods/tools/servercheck.py @@ -14,7 +14,7 @@ import _babase import _bascenev1 import babase import bascenev1 as bs -from babase._general import CallPartial +from babase._general import Call from features import profanity from playersdata import pdata from repository import profiles @@ -443,8 +443,7 @@ class LoadProfile(threading.Thread): def run(self) -> None: player_data = pdata.get_info(self.pbid) _babase.pushcall( - CallPartial(on_player_join_server, self.pbid, - player_data, self.ip, self.device_id), + Call(_on_profile_loaded, self.pbid, player_data, self.ip, self.device_id, self.client_id, self.display_string), from_other_thread=True, ) From 83394cd4dc31246cc538d25f656e9682b2a141c4 Mon Sep 17 00:00:00 2001 From: vishal332008 Date: Sun, 19 Jul 2026 18:40:37 +0530 Subject: [PATCH 14/14] small cleanup --- dist/ba_data/python/efro/dataclassio/_api.py | 2 -- dist/ba_data/python/efro/dataclassio/_base.py | 3 --- dist/ba_data/python/efro/dataclassio/_inputter.py | 2 -- dist/ba_data/python/efro/dataclassio/_outputter.py | 2 -- dist/ba_data/python/efro/dataclassio/_pathcapture.py | 2 -- dist/ba_data/python/efro/dataclassio/_prep.py | 2 -- dist/ba_data/python/efro/error.py | 2 -- dist/ba_data/python/efro/terminal.py | 2 -- dist/ba_data/python/efro/util.py | 2 -- dist/ba_root/mods/games/alliance_elimination.py | 1 - dist/ba_root/mods/setting.json | 2 +- dist/ba_root/mods/tools/servercheck.py | 9 ++++----- 12 files changed, 5 insertions(+), 26 deletions(-) diff --git a/dist/ba_data/python/efro/dataclassio/_api.py b/dist/ba_data/python/efro/dataclassio/_api.py index 2579b82..8e3080f 100644 --- a/dist/ba_data/python/efro/dataclassio/_api.py +++ b/dist/ba_data/python/efro/dataclassio/_api.py @@ -8,8 +8,6 @@ unrecognized attribute data, allowing older clients to interact with newer data formats in a nondestructive manner. """ -from __future__ import annotations - import json from enum import Enum from typing import TYPE_CHECKING diff --git a/dist/ba_data/python/efro/dataclassio/_base.py b/dist/ba_data/python/efro/dataclassio/_base.py index 6229b59..5a726de 100644 --- a/dist/ba_data/python/efro/dataclassio/_base.py +++ b/dist/ba_data/python/efro/dataclassio/_base.py @@ -2,8 +2,6 @@ # """Core components of dataclassio.""" -from __future__ import annotations - import dataclasses import typing import warnings @@ -13,7 +11,6 @@ from typing import TYPE_CHECKING, get_args, override, final from typing import _AnnotatedAlias # type: ignore - if TYPE_CHECKING: from typing import Any, Callable, Literal, ClassVar, Self diff --git a/dist/ba_data/python/efro/dataclassio/_inputter.py b/dist/ba_data/python/efro/dataclassio/_inputter.py index 43fd6fe..f35c8d8 100644 --- a/dist/ba_data/python/efro/dataclassio/_inputter.py +++ b/dist/ba_data/python/efro/dataclassio/_inputter.py @@ -6,8 +6,6 @@ # frowned upon (stuff like isinstance() is usually encouraged). # pylint: disable=unidiomatic-typecheck -from __future__ import annotations - from enum import Enum import dataclasses import typing diff --git a/dist/ba_data/python/efro/dataclassio/_outputter.py b/dist/ba_data/python/efro/dataclassio/_outputter.py index 11cf29f..3273218 100644 --- a/dist/ba_data/python/efro/dataclassio/_outputter.py +++ b/dist/ba_data/python/efro/dataclassio/_outputter.py @@ -6,8 +6,6 @@ # frowned upon (stuff like isinstance() is usually encouraged). # pylint: disable=unidiomatic-typecheck -from __future__ import annotations - from enum import Enum import dataclasses import typing diff --git a/dist/ba_data/python/efro/dataclassio/_pathcapture.py b/dist/ba_data/python/efro/dataclassio/_pathcapture.py index db01f6f..9f40db0 100644 --- a/dist/ba_data/python/efro/dataclassio/_pathcapture.py +++ b/dist/ba_data/python/efro/dataclassio/_pathcapture.py @@ -2,8 +2,6 @@ # """Functionality related to capturing nested dataclass paths.""" -from __future__ import annotations - import dataclasses from typing import TYPE_CHECKING diff --git a/dist/ba_data/python/efro/dataclassio/_prep.py b/dist/ba_data/python/efro/dataclassio/_prep.py index 6950256..a4d8ecb 100644 --- a/dist/ba_data/python/efro/dataclassio/_prep.py +++ b/dist/ba_data/python/efro/dataclassio/_prep.py @@ -7,8 +7,6 @@ # # pylint: disable=unidiomatic-typecheck -from __future__ import annotations - import logging from enum import Enum import dataclasses diff --git a/dist/ba_data/python/efro/error.py b/dist/ba_data/python/efro/error.py index 0edc724..b9a1be0 100644 --- a/dist/ba_data/python/efro/error.py +++ b/dist/ba_data/python/efro/error.py @@ -5,8 +5,6 @@ # """Common errors and related functionality.""" -from __future__ import annotations - from typing import TYPE_CHECKING, override import errno diff --git a/dist/ba_data/python/efro/terminal.py b/dist/ba_data/python/efro/terminal.py index 4ddbcf1..f7c8e40 100644 --- a/dist/ba_data/python/efro/terminal.py +++ b/dist/ba_data/python/efro/terminal.py @@ -2,8 +2,6 @@ # """Functionality related to terminal IO.""" -from __future__ import annotations - import sys import os from enum import Enum, unique diff --git a/dist/ba_data/python/efro/util.py b/dist/ba_data/python/efro/util.py index 56031a4..864bee3 100644 --- a/dist/ba_data/python/efro/util.py +++ b/dist/ba_data/python/efro/util.py @@ -6,8 +6,6 @@ # pylint: disable=too-many-lines """Small handy bits of functionality.""" -from __future__ import annotations - import os import time import random diff --git a/dist/ba_root/mods/games/alliance_elimination.py b/dist/ba_root/mods/games/alliance_elimination.py index dca0ad7..5460bb6 100644 --- a/dist/ba_root/mods/games/alliance_elimination.py +++ b/dist/ba_root/mods/games/alliance_elimination.py @@ -473,7 +473,6 @@ class AllianceEliminationGame(bs.TeamGameActivity[Player, Team]): # Put ourself at the back of the spawn order. player.team.spawn_order.remove(player) player.team.spawn_order.append(player) - player.node.delete() def _update(self) -> None: # For both teams, find the first player on the spawn order diff --git a/dist/ba_root/mods/setting.json b/dist/ba_root/mods/setting.json index 859d295..a26b54a 100644 --- a/dist/ba_root/mods/setting.json +++ b/dist/ba_root/mods/setting.json @@ -138,7 +138,7 @@ "enable": false }, "minAgeToChatInHours": 78, - "minAgeToJoinInHours": 0.001, + "minAgeToJoinInHours": 24, "newResultBoard": true, "playermod": { "default_bomb": "normal", diff --git a/dist/ba_root/mods/tools/servercheck.py b/dist/ba_root/mods/tools/servercheck.py index f86afa1..8f01fa4 100644 --- a/dist/ba_root/mods/tools/servercheck.py +++ b/dist/ba_root/mods/tools/servercheck.py @@ -17,7 +17,6 @@ import _babase import _bascenev1 import babase import bascenev1 as bs -from babase._general import Call from features import profanity from playersdata import pdata @@ -566,7 +565,7 @@ class LoadProfile(threading.Thread): def run(self) -> None: player_data = pdata.get_info(self.pbid) _babase.pushcall( - Call(_on_profile_loaded, self.pbid, player_data, self.ip, self.device_id, self.client_id, self.display_string), + babase.CallPartial(_on_profile_loaded, self.pbid, player_data, self.ip, self.device_id, self.client_id, self.display_string), from_other_thread=True, ) @@ -585,7 +584,7 @@ class FetchThread(threading.Thread): data = self.method(pb_id) if self.callback is not None: _babase.pushcall( - CallPartial(self.callback, data, pb_id, display_string), + babase.CallPartial(self.callback, data, pb_id, display_string), from_other_thread=True, ) @@ -698,12 +697,12 @@ def account_check(account_id: str, ip: str, client_id: int) -> None: profiles.upsert_ip(account_id, ip) except urllib.error.URLError: _babase.pushcall( - CallPartial(bs.chatmessage, "Click stats button and login your V2 account, to verify your identity", [ + babase.CallPartial(bs.chatmessage, "Click stats button and login your V2 account, to verify your identity", [ client_id]), from_other_thread=True, ) _babase.pushcall( - CallPartial(bs.disconnect_client, client_id, 2), from_other_thread=True) + babase.CallPartial(bs.disconnect_client, client_id, 2), from_other_thread=True) # Instantiate the server check