diff --git a/README.md b/README.md index f062de6..33f9f93 100644 --- a/README.md +++ b/README.md @@ -149,17 +149,17 @@ diff --git a/plugins/utilities/sample_plugin.py b/plugins/utilities/sample_plugi index ebb7dcc..da2b312 100644 --- a/plugins/utilities/sample_plugin.py +++ b/plugins/utilities/sample_plugin.py -@@ -5,6 +5,7 @@ import ba - class Main(ba.Plugin): +@@ -5,6 +5,7 @@ import babase + class Main(babase.Plugin): def on_app_running(self): - ba.screenmessage("Hi! I am a sample plugin!") + babase.screenmessage("Hi! I am a sample plugin!") def has_settings_ui(self): return True def show_settings_ui(self, source_widget): -- ba.screenmessage("You tapped my settings!") -+ ba.screenmessage("Hey! This is my new screenmessage!") +- babase.screenmessage("You tapped my settings!") ++ babase.screenmessage("Hey! This is my new screenmessage!") ``` To name this new version as `1.1.0`, add `"1.1.0": null,` just above the previous plugin version in `utilities.json`: diff --git a/plugins/minigames.json b/plugins/minigames.json index ae4f540..8d698fe 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -14,6 +14,12 @@ } ], "versions": { + "2.0.0": { + "api_version": 8, + "commit_sha": "a941899", + "released_on": "20-07-2023", + "md5sum": "19f033445a8fe30fc7f4f62d94a54444" + }, "1.0.0": { "api_version": 7, "commit_sha": "e59073b", @@ -22,6 +28,44 @@ } } }, + "icy_emits": { + "description": "Survice from icy bombs emitting through cold platform. Playable in teams/ffa/co-op", + "external_url": "", + "authors": [ + { + "name": "Freaku", + "email": "", + "discord": "" + } + ], + "versions": { + "1.0.0": { + "api_version": 8, + "commit_sha": "48f9302", + "released_on": "28-07-2023", + "md5sum": "cedc448a3d625065d586445e115fcd1f" + } + } + }, + "frozen_one": { + "description": "Survive until the timer runs out", + "external_url": "", + "authors": [ + { + "name": "Freaku", + "email": "", + "discord": "" + } + ], + "versions": { + "1.0.0": { + "api_version": 8, + "commit_sha": "48f9302", + "released_on": "28-07-2023", + "md5sum": "529c8b9c9a450317d5aa75e8eab47497" + } + } + }, "simon_says": { "description": "You better do what Simon says", "external_url": "", @@ -109,6 +153,12 @@ } ], "versions": { + "2.0.0": { + "api_version": 8, + "commit_sha": "6263872", + "released_on": "23-07-2023", + "md5sum": "9789ad3583f1d92d4e4b7bc03d09591d" + }, "1.0.0": { "api_version": 7, "commit_sha": "2fda676", @@ -187,10 +237,16 @@ { "name": "Freaku", "email": "", - "discord": "[Just] Freak#4999" + "discord": "" } ], "versions": { + "2.0.0": { + "api_version": 8, + "commit_sha": "48f9302", + "released_on": "28-07-2023", + "md5sum": "2c457b80b5a35adf0cad1436af4ab3fe" + }, "1.1.0": { "api_version": 7, "commit_sha": "0bc9522", @@ -206,10 +262,16 @@ { "name": "Freaku", "email": "", - "discord": "[Just] Freak#4999" + "discord": "" } ], "versions": { + "2.0.0": { + "api_version": 8, + "commit_sha": "48f9302", + "released_on": "28-07-2023", + "md5sum": "49ae645a5afc390ead44d7219b388c78" + }, "1.0.0": { "api_version": 7, "commit_sha": "858030b", @@ -225,10 +287,16 @@ { "name": "Freaku", "email": "", - "discord": "[Just] Freak#4999" + "discord": "" } ], "versions": { + "2.0.0": { + "api_version": 8, + "commit_sha": "48f9302", + "released_on": "28-07-2023", + "md5sum": "4cb6510f9f3ce151720a53a957986864" + }, "1.0.0": { "api_version": 7, "commit_sha": "858030b", @@ -316,6 +384,12 @@ } ], "versions": { + "2.0.0": { + "api_version": 8, + "commit_sha": "f54c993", + "released_on": "27-07-2023", + "md5sum": "7699483f4c379db809676ac917943d3c" + }, "1.0.0": { "api_version": 7, "commit_sha": "2aa1e50", @@ -412,15 +486,16 @@ { "name": "Freaku", "email": "", - "discord": "[Just] Freak#4999" - }, - { - "name": "LoupGarou", - "email": "LoupGarou5418@outlook.com", - "discord": "ʟօʊքɢǟʀօʊ#3063" + "discord": "" } ], "versions": { + "2.0.0": { + "api_version": 8, + "commit_sha": "48f9302", + "released_on": "28-07-2023", + "md5sum": "22b51a147524d84fbc249e61f21ae424" + }, "1.1.0": { "api_version": 7, "commit_sha": "2e2540a", @@ -451,6 +526,12 @@ } ], "versions": { + "2.0.0": { + "api_version": 8, + "commit_sha": "e8bbb61", + "released_on": "23-07-2023", + "md5sum": "1acbeecffada937bdd745f4e4d43f1be" + }, "1.0.0": { "api_version": 7, "commit_sha": "7219487", @@ -470,6 +551,12 @@ } ], "versions": { + "2.0.0": { + "api_version": 8, + "commit_sha": "1a8037e", + "released_on": "23-07-2023", + "md5sum": "916e37f6e1a8a5be3dd0389ed2c4b261" + }, "1.0.0": { "api_version": 7, "commit_sha": "7219487", @@ -573,6 +660,25 @@ } } }, + "quake_original": { + "description": "Good ol' Quake minigame", + "external_url": "", + "authors": [ + { + "name": "Unknown", + "email": "", + "discord": "" + } + ], + "versions": { + "1.0.0": { + "api_version": 8, + "commit_sha": "185480d", + "released_on": "24-07-2023", + "md5sum": "f68395cc90dc8cddb166a23b2da81b7b" + } + } + }, "ufo_fight": { "description": "Fight the UFO boss!", "external_url": "", @@ -599,7 +705,7 @@ { "name": "Freaku", "email": "", - "discord": "[Just] Freak#4999" + "discord": "" } ], "versions": { @@ -610,6 +716,87 @@ "md5sum": "197a377652ab0c3bfbe1ca07833924b4" } } + }, + "big_ball": { + "description": "Score some goals with Big Ball on Football map", + "external_url": "", + "authors": [ + { + "name": "MythB", + "email": "", + "discord": "" + } + ], + "versions": { + "1.0.0": { + "api_version": 8, + "commit_sha": "ca3221b", + "released_on": "27-07-2023", + "md5sum": "39c5b18efd5d5314f30c12fc0bec4931" + } + } + }, + "handball": { + "description": "Score some goals with handball", + "external_url": "", + "authors": [ + { + "name": "Unknown", + "email": "", + "discord": "" + } + ], + "versions": { + "1.0.0": { + "api_version": 8, + "commit_sha": "2309aab", + "released_on": "24-07-2023", + "md5sum": "01b85dc9ef1d464ab604387af09f05dc" + } + } + }, + "super_duel": { + "description": "Crush your enemy in a 1v1", + "external_url": "https://www.youtube.com/watch?v=hvRtiXR-oC0", + "authors": [ + { + "name": "JoseAng3l", + "email": "", + "discord": "joseang3l" + } + ], + "versions": { + "1.0.0": { + "api_version": 8, + "commit_sha": "ab26786", + "released_on": "27-07-2023", + "md5sum": "d0c9c0472d7b145eadf535957a462fdf" + } + } + }, + "supersmash": { + "description": "Blow up your enemies off the map!", + "external_url": "", + "authors": [ + { + "name": "Mrmaxmeier", + "email": "", + "discord": "" + }, + { + "name": "JoseAngel", + "email": "", + "discord": "joseang3l" + } + ], + "versions": { + "1.0.0": { + "api_version": 8, + "commit_sha": "68e77f2", + "released_on": "24-07-2023", + "md5sum": "1cbe5b3e85b5dfcee1eb322f33568fd4" + } + } } } } \ No newline at end of file diff --git a/plugins/minigames/arms_race.py b/plugins/minigames/arms_race.py index b7ea3f5..475811a 100644 --- a/plugins/minigames/arms_race.py +++ b/plugins/minigames/arms_race.py @@ -1,17 +1,18 @@ -# Ported by: Freaku / @[Just] Freak#4999 +# Ported by your friend: Freaku # Join BCS: # https://discord.gg/ucyaesh -# ba_meta require api 7 +# ba_meta require api 8 from __future__ import annotations from typing import TYPE_CHECKING -import ba -from bastd.actor.playerspaz import PlayerSpaz +import babase +import bascenev1 as bs +from bascenev1lib.actor.playerspaz import PlayerSpaz if TYPE_CHECKING: from typing import Any, Type, List, Dict, Tuple, Union, Sequence, Optional @@ -30,8 +31,7 @@ class State: self.next = None self.index = None - def apply(self, player, spaz): - + def apply(self, spaz): spaz.disconnect_controls_from_player() spaz.connect_controls_to_player(enable_punch=self.punch, enable_bomb=self.bomb, @@ -43,18 +43,6 @@ class State: spaz.bomb_type = self.bomb spaz.set_score_text(self.name) - def set_controls(): - player.actor.node.bomb_pressed = True - player.actor.on_bomb_release() - - release_input = (ba.InputType.PUNCH_RELEASE, ba.InputType.PICK_UP_RELEASE) - if not self.bomb is None: - for release in release_input: - player.assigninput( - release, - set_controls - ) - def get_setting(self): return (self.name) @@ -68,22 +56,22 @@ states = [State(bomb='normal', name='Basic Bombs'), State(curse=True, name='Cursed', final=True)] -class Player(ba.Player['Team']): +class Player(bs.Player['Team']): """Our player type for this game.""" def __init__(self): self.state = None -class Team(ba.Team[Player]): +class Team(bs.Team[Player]): """Our team type for this game.""" def __init__(self) -> None: self.score = 0 -# ba_meta export game -class ArmsRaceGame(ba.TeamGameActivity[Player, Team]): +# ba_meta export bascenev1.GameActivity +class ArmsRaceGame(bs.TeamGameActivity[Player, Team]): """A game type based on acquiring kills.""" name = 'Arms Race' @@ -94,9 +82,9 @@ class ArmsRaceGame(ba.TeamGameActivity[Player, Team]): @classmethod def get_available_settings( - cls, sessiontype: Type[ba.Session]) -> List[ba.Setting]: + cls, sessiontype: Type[bs.Session]) -> List[babase.Setting]: settings = [ - ba.IntChoiceSetting( + bs.IntChoiceSetting( 'Time Limit', choices=[ ('None', 0), @@ -108,7 +96,7 @@ class ArmsRaceGame(ba.TeamGameActivity[Player, Team]): ], default=0, ), - ba.FloatChoiceSetting( + bs.FloatChoiceSetting( 'Respawn Times', choices=[ ('Shorter', 0.25), @@ -119,21 +107,21 @@ class ArmsRaceGame(ba.TeamGameActivity[Player, Team]): ], default=1.0, ), - ba.BoolSetting('Epic Mode', default=False)] + bs.BoolSetting('Epic Mode', default=False)] for state in states: if not state.required: - settings.append(ba.BoolSetting(state.get_setting(), default=True)) + settings.append(bs.BoolSetting(state.get_setting(), default=True)) return settings @classmethod - def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool: - return (issubclass(sessiontype, ba.DualTeamSession) - or issubclass(sessiontype, ba.FreeForAllSession)) + def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool: + return (issubclass(sessiontype, bs.DualTeamSession) + or issubclass(sessiontype, bs.FreeForAllSession)) @classmethod - def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: - return ba.getmaps('melee') + 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) @@ -142,14 +130,14 @@ class ArmsRaceGame(ba.TeamGameActivity[Player, Team]): if i < len(self.states) and not state.final: state.next = self.states[i + 1] state.index = i - self._dingsound = ba.getsound('dingSmall') + self._dingsound = bs.getsound('dingSmall') self._epic_mode = bool(settings['Epic Mode']) self._time_limit = float(settings['Time Limit']) # Base class overrides. self.slow_motion = self._epic_mode - self.default_music = (ba.MusicType.EPIC if self._epic_mode else - ba.MusicType.TO_THE_DEATH) + self.default_music = (bs.MusicType.EPIC if self._epic_mode else + bs.MusicType.TO_THE_DEATH) def get_instance_description(self) -> Union[str, Sequence]: return 'Upgrade your weapon by eliminating enemies.' @@ -168,12 +156,11 @@ class ArmsRaceGame(ba.TeamGameActivity[Player, Team]): self.spawn_player(player) # overriding the default character spawning.. - def spawn_player(self, player): if player.state is None: player.state = self.states[0] super().spawn_player(player) - player.state.apply(player, player.actor) + player.state.apply(player.actor) def isValidKill(self, m): if m.getkillerplayer(Player) is None: @@ -186,13 +173,12 @@ class ArmsRaceGame(ba.TeamGameActivity[Player, Team]): def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, ba.PlayerDiedMessage): + if isinstance(msg, bs.PlayerDiedMessage): if self.isValidKill(msg): self.stats.player_scored(msg.getkillerplayer(Player), 10, kill=True) if not msg.getkillerplayer(Player).state.final: msg.getkillerplayer(Player).state = msg.getkillerplayer(Player).state.next - msg.getkillerplayer(Player).state.apply( - msg.getkillerplayer(Player), msg.getkillerplayer(Player).actor) + msg.getkillerplayer(Player).state.apply(msg.getkillerplayer(Player).actor) else: msg.getkillerplayer(Player).team.score += 1 self.end_game() @@ -203,7 +189,7 @@ class ArmsRaceGame(ba.TeamGameActivity[Player, Team]): return None def end_game(self) -> None: - results = ba.GameResults() + results = bs.GameResults() for team in self.teams: results.set_team_score(team, team.score) self.end(results=results) diff --git a/plugins/minigames/big_ball.py b/plugins/minigames/big_ball.py new file mode 100644 index 0000000..9976722 --- /dev/null +++ b/plugins/minigames/big_ball.py @@ -0,0 +1,524 @@ +# Made by MythB +# Ported by: MysteriousBoi + + +# ba_meta require api 8 +from __future__ import annotations +from typing import TYPE_CHECKING +import babase +import bauiv1 as bui +import bascenev1 as bs +import random +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.flag import Flag +if TYPE_CHECKING: + from typing import Any, Sequence, Dict, Type, List, Optional, Union + + +class PuckDiedMessage: + """Inform something that a puck has died.""" + + def __init__(self, puck: Puck): + self.puck = puck + +# goalpost + + +class FlagKale(bs.Actor): + def __init__(self, position=(0, 2.5, 0), color=(1, 1, 1)): + super().__init__() + activity = self.getactivity() + shared = SharedObjects.get() + self.node = bs.newnode('flag', + attrs={'position': (position[0], position[1]+0.75, position[2]), + 'color_texture': activity._flagKaleTex, + 'color': color, + 'materials': [shared.object_material, activity._kaleMaterial], + }, + delegate=self) + + def handleMessage(self, m): + if isinstance(m, bs.DieMessage): + if self.node.exists(): + self.node.delete() + elif isinstance(m, bs.OutOfBoundsMessage): + self.handlemessage(bs.DieMessage()) + else: + super().handlemessage(msg) + + +class Puck(bs.Actor): + def __init__(self, position: Sequence[float] = (0.0, 1.0, 0.0)): + super().__init__() + shared = SharedObjects.get() + activity = self.getactivity() + + # Spawn just above the provided point. + self._spawn_pos = (position[0], position[1] + 1.0, position[2]) + self.last_players_to_touch: Dict[int, Player] = {} + self.scored = False + assert activity is not None + assert isinstance(activity, BBGame) + pmats = [shared.object_material, activity.puck_material] + self.node = bs.newnode('prop', + delegate=self, + attrs={ + 'mesh': activity._ballModel, + 'color_texture': activity._ballTex, + 'body': 'sphere', + 'reflection': 'soft', + 'reflection_scale': [0.2], + 'shadow_size': 0.8, + 'is_area_of_interest': True, + 'position': self._spawn_pos, + 'materials': pmats, + 'body_scale': 4, + 'mesh_scale': 1, + 'density': 0.02}) + bs.animate(self.node, 'mesh_scale', {0: 0, 0.2: 1.3, 0.26: 1}) + + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, bs.DieMessage): + assert self.node + self.node.delete() + activity = self._activity() + if activity and not msg.immediate: + activity.handlemessage(PuckDiedMessage(self)) + + # If we go out of bounds, move back to where we started. + elif isinstance(msg, bs.OutOfBoundsMessage): + assert self.node + self.node.position = self._spawn_pos + + elif isinstance(msg, bs.HitMessage): + assert self.node + assert msg.force_direction is not None + self.node.handlemessage( + 'impulse', msg.pos[0], msg.pos[1], msg.pos[2], msg.velocity[0], + msg.velocity[1], msg.velocity[2], 1.0 * msg.magnitude, + 1.0 * msg.velocity_magnitude, msg.radius, 0, + msg.force_direction[0], msg.force_direction[1], + msg.force_direction[2]) + + # If this hit came from a player, log them as the last to touch us. + s_player = msg.get_source_player(Player) + if s_player is not None: + activity = self._activity() + if activity: + if s_player in activity.players: + self.last_players_to_touch[s_player.team.id] = s_player + else: + super().handlemessage(msg) + +# for night mode: using a actor with large shadow and little mesh scale. Better then tint i think, players and objects more visible + + +class NightMod(bs.Actor): + def __init__(self, position=(0, 0, 0)): + super().__init__() + shared = SharedObjects.get() + activity = self.getactivity() + # spawn just above the provided point + self._spawnPos = (position[0], position[1], position[2]) + self.node = bs.newnode("prop", + attrs={'mesh': activity._nightModel, + 'color_texture': activity._nightTex, + 'body': 'sphere', + 'reflection': 'soft', + 'body_scale': 0.1, + 'mesh_scale': 0.001, + 'density': 0.010, + 'reflection_scale': [0.23], + 'shadow_size': 999999.0, + 'is_area_of_interest': True, + 'position': self._spawnPos, + 'materials': [activity._nightMaterial] + }, + delegate=self) + + def handlemssage(self, m): + super().handlemessage(m) + + +class Player(bs.Player['Team']): + """Our player type for this game.""" + + +class Team(bs.Team[Player]): + """Our team type for this game.""" + + def __init__(self) -> None: + self.score = 0 + + +# ba_meta export bascenev1.GameActivity +class BBGame(bs.TeamGameActivity[Player, Team]): + name = 'Big Ball' + description = 'Score some goals.\nFlags are goalposts.\nScored team players get boxing gloves,\nNon-scored team players getting shield (if Grant Powers on Score).\nYou can also set Night Mode!' + available_settings = [ + bs.IntSetting( + 'Score to Win', + min_value=1, + default=1, + 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', True), + bs.BoolSetting('Night Mode', False), + bs.BoolSetting('Grant Powers on Score', False) + ] + default_music = bs.MusicType.HOCKEY + + @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 ['Football Stadium'] + + def __init__(self, settings: dict): + super().__init__(settings) + shared = SharedObjects.get() + self._scoreboard = Scoreboard() + self._cheer_sound = bs.getsound('cheer') + self._chant_sound = bs.getsound('crowdChant') + self._foghorn_sound = bs.getsound('foghorn') + self._swipsound = bs.getsound('swip') + self._whistle_sound = bs.getsound('refWhistle') + self._ballModel = bs.getmesh("shield") + self._ballTex = bs.gettexture("eggTex1") + self._ballSound = bs.getsound("impactMedium2") + self._flagKaleTex = bs.gettexture("star") + self._kaleSound = bs.getsound("metalHit") + self._nightModel = bs.getmesh("shield") + self._nightTex = bs.gettexture("black") + self._kaleMaterial = bs.Material() + # add friction to flags for standing our position (as far as) + self._kaleMaterial.add_actions(conditions=("they_have_material", shared.footing_material), + actions=(("modify_part_collision", "friction", 9999.5))) + self._kaleMaterial.add_actions(conditions=(("we_are_younger_than", 1), 'and', + ("they_have_material", shared.object_material)), + actions=(("modify_part_collision", "collide", False))) + self._kaleMaterial.add_actions(conditions=("they_have_material", shared.pickup_material), + actions=(("modify_part_collision", "collide", False))) + self._kaleMaterial.add_actions( + conditions=('they_have_material', shared.object_material), + actions=(('impact_sound', self._kaleSound, 2, 5))) + # we dont wanna hit the night so + self._nightMaterial = bs.Material() + self._nightMaterial.add_actions(conditions=(('they_have_material', shared.pickup_material), 'or', + ('they_have_material', shared.attack_material)), + actions=(('modify_part_collision', 'collide', False))) + # we also dont want anything moving it + self._nightMaterial.add_actions( + conditions=(('they_have_material', shared.object_material), 'or', + ('they_dont_have_material', shared.footing_material)), + actions=(('modify_part_collision', 'collide', False), + ('modify_part_collision', 'physical', False))) + self.puck_material = bs.Material() + self.puck_material.add_actions(actions=(('modify_part_collision', + 'friction', 0.5))) + self.puck_material.add_actions(conditions=('they_have_material', + shared.pickup_material), + actions=('modify_part_collision', + 'collide', False)) + self.puck_material.add_actions( + conditions=( + ('we_are_younger_than', 100), + 'and', + ('they_have_material', shared.object_material), + ), + actions=('modify_node_collision', 'collide', False), + ) + self.puck_material.add_actions(conditions=('they_have_material', + shared.footing_material), + actions=('impact_sound', + self._ballSound, 0.2, 5)) + + # Keep track of which player last touched the puck + self.puck_material.add_actions( + conditions=('they_have_material', shared.player_material), + actions=(('call', 'at_connect', + self._handle_puck_player_collide), )) + + # We want the puck to kill powerups; not get stopped by them + self.puck_material.add_actions( + conditions=('they_have_material', + PowerupBoxFactory.get().powerup_material), + actions=(('modify_part_collision', 'physical', False), + ('message', 'their_node', 'at_connect', bs.DieMessage()))) + self._score_region_material = bs.Material() + self._score_region_material.add_actions( + conditions=('they_have_material', self.puck_material), + actions=(('modify_part_collision', 'collide', + True), ('modify_part_collision', 'physical', False), + ('call', 'at_connect', self._handle_score))) + self._puck_spawn_pos: Optional[Sequence[float]] = None + self._score_regions: Optional[List[bs.NodeActor]] = None + self._puck: Optional[Puck] = None + self._score_to_win = int(settings['Score to Win']) + self._time_limit = float(settings['Time Limit']) + self._nm = bool(settings['Night Mode']) + self._grant_power = bool(settings['Grant Powers on Score']) + self._epic_mode = bool(settings['Epic Mode']) + # Base class overrides. + self.slow_motion = self._epic_mode + + def get_instance_description(self) -> Union[str, Sequence]: + if self._score_to_win == 1: + return 'Score a goal.' + return 'Score ${ARG1} goals.', self._score_to_win + + 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 + + def on_begin(self) -> None: + super().on_begin() + + self.setup_standard_time_limit(self._time_limit) + self.setup_standard_powerup_drops() + self._puck_spawn_pos = self.map.get_flag_position(None) + self._spawn_puck() + # for night mode we need night actor. And same goodies for nigh mode + if self._nm: + self._nightSpawny(), self._flagKaleFlash() + + # Set up the two score regions. + defs = self.map.defs + self._score_regions = [] + self._score_regions.append( + bs.NodeActor( + bs.newnode('region', + attrs={ + 'position': (13.75, 0.85744967453, 0.1095578275), + 'scale': (1.05, 1.1, 3.8), + 'type': 'box', + 'materials': [self._score_region_material] + }))) + self._score_regions.append( + bs.NodeActor( + bs.newnode('region', + attrs={ + 'position': (-13.55, 0.85744967453, 0.1095578275), + 'scale': (1.05, 1.1, 3.8), + 'type': 'box', + 'materials': [self._score_region_material] + }))) + self._update_scoreboard() + self._chant_sound.play() + + def _nightSpawny(self): + self.MythBrk = NightMod(position=(0, 0.05744967453, 0)) + + # spawn some goodies on nightmode for pretty visuals + def _flagKaleFlash(self): + # flags positions + kale1 = (-12.45, 0.05744967453, -2.075) + kale2 = (-12.45, 0.05744967453, 2.075) + kale3 = (12.66, 0.03986567039, 2.075) + kale4 = (12.66, 0.03986567039, -2.075) + + flash = bs.newnode("light", + attrs={'position': kale1, + 'radius': 0.15, + 'color': (1.0, 1.0, 0.7)}) + + flash = bs.newnode("light", + attrs={'position': kale2, + 'radius': 0.15, + 'color': (1.0, 1.0, 0.7)}) + + flash = bs.newnode("light", + attrs={'position': kale3, + 'radius': 0.15, + 'color': (0.7, 1.0, 1.0)}) + + flash = bs.newnode("light", + attrs={'position': kale4, + 'radius': 0.15, + 'color': (0.7, 1.0, 1.0)}) + # flags positions + + def _flagKalesSpawn(self): + for team in self.teams: + if team.id == 0: + _colorTeam0 = team.color + if team.id == 1: + _colorTeam1 = team.color + + self._MythB = FlagKale(position=(-12.45, 0.05744967453, -2.075), color=_colorTeam0) + self._MythB2 = FlagKale(position=(-12.45, 0.05744967453, 2.075), color=_colorTeam0) + self._MythB3 = FlagKale(position=(12.66, 0.03986567039, 2.075), color=_colorTeam1) + self._MythB4 = FlagKale(position=(12.66, 0.03986567039, -2.075), color=_colorTeam1) + + def on_team_join(self, team: Team) -> None: + self._update_scoreboard() + + def _handle_puck_player_collide(self) -> None: + collision = bs.getcollision() + try: + puck = collision.sourcenode.getdelegate(Puck, True) + player = collision.opposingnode.getdelegate(PlayerSpaz, + True).getplayer( + Player, True) + except bs.NotFoundError: + return + + puck.last_players_to_touch[player.team.id] = player + + def _kill_puck(self) -> None: + self._puck = None + + def _handle_score(self) -> None: + """A point has been scored.""" + + assert self._puck is not None + assert self._score_regions is not None + + # Our puck might stick around for a second or two + # we don't want it to be able to score again. + if self._puck.scored: + return + + region = bs.getcollision().sourcenode + index = 0 + for index in range(len(self._score_regions)): + if region == self._score_regions[index].node: + break + + for team in self.teams: + if team.id == index: + scoring_team = team + team.score += 1 + + # tell scored team players to celebrate and give them to boxing gloves + if self._grant_power: + for player in team.players: + try: + player.actor.node.handlemessage(bs.PowerupMessage('punch')) + except: + pass + + # Tell all players to celebrate. + for player in team.players: + if player.actor: + player.actor.handlemessage(bs.CelebrateMessage(2.0)) + + # If we've got the player from the scoring team that last + # touched us, give them points. + if (scoring_team.id in self._puck.last_players_to_touch + and self._puck.last_players_to_touch[scoring_team.id]): + self.stats.player_scored( + self._puck.last_players_to_touch[scoring_team.id], + 100, + big_message=True) + + # End game if we won. + if team.score >= self._score_to_win: + self.end_game() + else: + if self._grant_power: + for player in team.players: + try: + player.actor.node.handlemessage(bs.PowerupMessage('shield')) + except: + pass + + self._foghorn_sound.play() + self._cheer_sound.play() + + self._puck.scored = True + + # Kill the puck (it'll respawn itself shortly). + bs.timer(1.0, self._kill_puck) + + light = bs.newnode('light', + attrs={ + 'position': bs.getcollision().position, + 'height_attenuated': False, + 'color': (1, 0, 0) + }) + bs.animate(light, 'intensity', {0: 0, 0.5: 1, 1.0: 0}, loop=True) + bs.timer(1.0, light.delete) + + bs.cameraflash(duration=10.0) + self._update_scoreboard() + + def end_game(self) -> None: + results = bs.GameResults() + for team in self.teams: + results.set_team_score(team, team.score) + self.end(results=results) + + def _update_scoreboard(self) -> None: + winscore = self._score_to_win + for team in self.teams: + self._scoreboard.set_team_value(team, team.score, winscore) + + def handlemessage(self, msg: Any) -> Any: + + # Respawn dead players if they're still in the game. + if isinstance(msg, bs.PlayerDiedMessage): + # Augment standard behavior... + super().handlemessage(msg) + self.respawn_player(msg.getplayer(Player)) + + # Respawn dead pucks. + elif isinstance(msg, PuckDiedMessage): + if not self.has_ended(): + bs.timer(3.0, self._spawn_puck) + else: + super().handlemessage(msg) + + def _flash_puck_spawn(self) -> None: + light = bs.newnode('light', + attrs={ + 'position': self._puck_spawn_pos, + 'height_attenuated': False, + 'color': (1, 0, 0) + }) + bs.animate(light, 'intensity', {0.0: 0, 0.25: 1, 0.5: 0}, loop=True) + bs.timer(1.0, light.delete) + + def _spawn_puck(self) -> None: + self._swipsound.play() + self._whistle_sound.play() + self._flagKalesSpawn() + self._flash_puck_spawn() + assert self._puck_spawn_pos is not None + self._puck = Puck(position=self._puck_spawn_pos) + self._puck.light = bs.newnode('light', + owner=self._puck.node, + attrs={'intensity': 0.3, + 'height_attenuated': False, + 'radius': 0.2, + 'color': (0.9, 0.2, 0.9)}) + self._puck.node.connectattr('position', self._puck.light, 'position') diff --git a/plugins/minigames/boxing.py b/plugins/minigames/boxing.py index 35a7c75..9208784 100644 --- a/plugins/minigames/boxing.py +++ b/plugins/minigames/boxing.py @@ -1,20 +1,22 @@ -# ba_meta require api 7 +# ba_meta require api 8 # (see https://ballistica.net/wiki/meta-tag-system) from __future__ import annotations from typing import TYPE_CHECKING -import ba -from bastd.actor.playerspaz import PlayerSpaz -from bastd.actor.scoreboard import Scoreboard -from bastd.game.deathmatch import DeathMatchGame +import babase +import bauiv1 as bui +import bascenev1 as bs +from bascenev1lib.actor.playerspaz import PlayerSpaz +from bascenev1lib.actor.scoreboard import Scoreboard +from bascenev1lib.game.deathmatch import DeathMatchGame if TYPE_CHECKING: from typing import Any, Sequence -lang = ba.app.lang.language +lang = bs.app.lang.language if lang == 'Spanish': name = 'Super Boxeo' @@ -33,7 +35,7 @@ else: class NewPlayerSpaz(PlayerSpaz): def __init__(self, - player: ba.Player, + player: bs.Player, color: Sequence[float] = (1.0, 1.0, 1.0), highlight: Sequence[float] = (0.5, 0.5, 0.5), character: str = 'Spaz', @@ -44,16 +46,16 @@ class NewPlayerSpaz(PlayerSpaz): highlight=highlight, character=character, powerups_expire=powerups_expire) - from bastd.gameutils import SharedObjects + from bascenev1lib.gameutils import SharedObjects shared = SharedObjects.get() self._super_jump = super_jump self.jump_mode = False - self.super_jump_material = ba.Material() + self.super_jump_material = bs.Material() self.super_jump_material.add_actions( conditions=('they_have_material', shared.footing_material), actions=( - ('call', 'at_connect', ba.Call(self.jump_state, True)), - ('call', 'at_disconnect', ba.Call(self.jump_state, False)) + ('call', 'at_connect', babase.Call(self.jump_state, True)), + ('call', 'at_disconnect', babase.Call(self.jump_state, False)) ), ) self.node.roller_materials += (self.super_jump_material, ) @@ -68,7 +70,7 @@ class NewPlayerSpaz(PlayerSpaz): """ if not self.node: return - t_ms = ba.time(timeformat=ba.TimeFormat.MILLISECONDS) + t_ms = int(bs.time() * 1000.0) assert isinstance(t_ms, int) if t_ms - self.last_jump_time_ms >= self._jump_cooldown: self.node.jump_pressed = True @@ -81,15 +83,15 @@ class NewPlayerSpaz(PlayerSpaz): self.node.position[0], self.node.position[1], self.node.position[2], - 0, 0, 0, 150, 150, 0, 0, 0, 1, 0 + 0, 0, 0, 95, 95, 0, 0, 0, 1, 0 ) - ba.timer(0.0, do_jump) - ba.timer(0.1, do_jump) - ba.timer(0.2, do_jump) + bs.timer(0.0, do_jump) + bs.timer(0.1, do_jump) + bs.timer(0.2, do_jump) self._turbo_filter_add_press('jump') -# ba_meta export game +# ba_meta export bascenev1.GameActivity class BoxingGame(DeathMatchGame): name = name @@ -97,16 +99,16 @@ class BoxingGame(DeathMatchGame): @classmethod def get_available_settings( - cls, sessiontype: type[ba.Session] - ) -> list[ba.Setting]: + cls, sessiontype: type[bs.Session] + ) -> list[babase.Setting]: settings = [ - ba.IntSetting( + bs.IntSetting( 'Kills to Win Per Player', min_value=1, default=5, increment=1, ), - ba.IntChoiceSetting( + bs.IntChoiceSetting( 'Time Limit', choices=[ ('None', 0), @@ -118,7 +120,7 @@ class BoxingGame(DeathMatchGame): ], default=0, ), - ba.FloatChoiceSetting( + bs.FloatChoiceSetting( 'Respawn Times', choices=[ ('Shorter', 0.25), @@ -129,9 +131,9 @@ class BoxingGame(DeathMatchGame): ], default=1.0, ), - ba.BoolSetting(super_jump_text, default=False), - ba.BoolSetting(enable_powerups, default=False), - ba.BoolSetting('Epic Mode', default=False), + bs.BoolSetting(super_jump_text, default=False), + bs.BoolSetting(enable_powerups, default=False), + bs.BoolSetting('Epic Mode', default=False), ] # In teams mode, a suicide gives a point to the other team, but in @@ -139,9 +141,9 @@ class BoxingGame(DeathMatchGame): # this at zero to benefit new players, but pro players might like to # be able to go negative. (to avoid a strategy of just # suiciding until you get a good drop) - if issubclass(sessiontype, ba.FreeForAllSession): + if issubclass(sessiontype, bs.FreeForAllSession): settings.append( - ba.BoolSetting('Allow Negative Scores', default=False) + bs.BoolSetting('Allow Negative Scores', default=False) ) return settings @@ -150,7 +152,7 @@ class BoxingGame(DeathMatchGame): super().__init__(settings) self._scoreboard = Scoreboard() self._score_to_win: int | None = None - self._dingsound = ba.getsound('dingSmall') + self._dingsound = bs.getsound('dingSmall') self._epic_mode = bool(settings['Epic Mode']) self._kills_to_win_per_player = int(settings['Kills to Win Per Player']) self._time_limit = float(settings['Time Limit']) @@ -163,11 +165,11 @@ class BoxingGame(DeathMatchGame): # Base class overrides. self.slow_motion = self._epic_mode self.default_music = ( - ba.MusicType.EPIC if self._epic_mode else ba.MusicType.TO_THE_DEATH + bs.MusicType.EPIC if self._epic_mode else bs.MusicType.TO_THE_DEATH ) def on_begin(self) -> None: - ba.TeamGameActivity.on_begin(self) + bs.TeamGameActivity.on_begin(self) self.setup_standard_time_limit(self._time_limit) if self._enable_powerups: self.setup_standard_powerup_drops() @@ -180,7 +182,7 @@ class BoxingGame(DeathMatchGame): def _standard_drop_powerup(self, index: int, expire: bool = True) -> None: # pylint: disable=cyclic-import - from bastd.actor.powerupbox import PowerupBox, PowerupBoxFactory + from bascenev1lib.actor.powerupbox import PowerupBox, PowerupBoxFactory PowerupBox( position=self.map.powerup_spawn_points[index], @@ -191,13 +193,13 @@ class BoxingGame(DeathMatchGame): expire=expire, ).autoretain() - def spawn_player(self, player: Player) -> ba.Actor: + def spawn_player(self, player: Player) -> bs.Actor: import random - from ba import _math - from ba._gameutils import animate - from ba._coopsession import CoopSession + from babase import _math + from bascenev1._gameutils import animate + from bascenev1._coopsession import CoopSession - if isinstance(self.session, ba.DualTeamSession): + if isinstance(self.session, bs.DualTeamSession): position = self.map.get_start_position(player.team.id) else: # otherwise do free-for-all spawn locations @@ -208,7 +210,7 @@ class BoxingGame(DeathMatchGame): highlight = player.highlight light_color = _math.normalized_color(color) - display_color = ba.safecolor(color, target_intensity=0.75) + display_color = babase.safecolor(color, target_intensity=0.75) spaz = NewPlayerSpaz(color=color, highlight=highlight, @@ -224,14 +226,14 @@ class BoxingGame(DeathMatchGame): # Move to the stand position and add a flash of light. spaz.handlemessage( - ba.StandMessage( + bs.StandMessage( position, angle if angle is not None else random.uniform(0, 360))) - ba.playsound(self._spawn_sound, 1, position=spaz.node.position) - light = ba.newnode('light', attrs={'color': light_color}) + self._spawn_sound.play(1, position=spaz.node.position) + light = bs.newnode('light', attrs={'color': light_color}) spaz.node.connectattr('position', light, 'position') animate(light, 'intensity', {0: 0, 0.25: 1, 0.5: 0}) - ba.timer(0.5, light.delete) + bs.timer(0.5, light.delete) # custom spaz.connect_controls_to_player(enable_bomb=False) diff --git a/plugins/minigames/collector.py b/plugins/minigames/collector.py index 0f9bbc3..da4b416 100644 --- a/plugins/minigames/collector.py +++ b/plugins/minigames/collector.py @@ -1,4 +1,4 @@ -# ba_meta require api 7 +# ba_meta require api 8 # (see https://ballistica.net/wiki/meta-tag-system) ''' @@ -31,19 +31,21 @@ import weakref from enum import Enum from typing import TYPE_CHECKING -import ba +import babase +import bauiv1 as bui +import bascenev1 as bs import random -from bastd.actor.flag import Flag -from bastd.actor.popuptext import PopupText -from bastd.actor.playerspaz import PlayerSpaz -from bastd.actor.scoreboard import Scoreboard -from bastd.gameutils import SharedObjects +from bascenev1lib.actor.flag import Flag +from bascenev1lib.actor.popuptext import PopupText +from bascenev1lib.actor.playerspaz import PlayerSpaz +from bascenev1lib.actor.scoreboard import Scoreboard +from bascenev1lib.gameutils import SharedObjects if TYPE_CHECKING: from typing import Any, Sequence -lang = ba.app.lang.language +lang = bs.app.lang.language if lang == 'Spanish': name = 'Coleccionista' description = ('Elimina a tus oponentes para robar sus cápsulas.\n' @@ -99,7 +101,7 @@ class FlagState(Enum): HELD = 3 -class Player(ba.Player['Team']): +class Player(bs.Player['Team']): """Our player type for this game.""" def __init__(self) -> None: @@ -108,15 +110,15 @@ class Player(ba.Player['Team']): self.light = None -class Team(ba.Team[Player]): +class Team(bs.Team[Player]): """Our team type for this game.""" def __init__(self) -> None: self.score = 0 -# ba_meta export game -class CollectorGame(ba.TeamGameActivity[Player, Team]): +# ba_meta export bascenev1.GameActivity +class CollectorGame(bs.TeamGameActivity[Player, Team]): name = name description = description @@ -127,23 +129,23 @@ class CollectorGame(ba.TeamGameActivity[Player, Team]): @classmethod def get_available_settings( - cls, sessiontype: type[ba.Session] - ) -> list[ba.Setting]: + cls, sessiontype: type[bs.Session] + ) -> list[babase.Setting]: settings = [ - ba.IntSetting( + bs.IntSetting( capsules_to_win, min_value=1, default=10, increment=1, ), - ba.IntSetting( + bs.IntSetting( capsules_death, min_value=1, max_value=10, default=2, increment=1, ), - ba.IntChoiceSetting( + bs.IntChoiceSetting( 'Time Limit', choices=[ ('None', 0), @@ -155,7 +157,7 @@ class CollectorGame(ba.TeamGameActivity[Player, Team]): ], default=0, ), - ba.FloatChoiceSetting( + bs.FloatChoiceSetting( 'Respawn Times', choices=[ ('Shorter', 0.25), @@ -166,33 +168,33 @@ class CollectorGame(ba.TeamGameActivity[Player, Team]): ], default=1.0, ), - ba.BoolSetting(lucky_capsules, default=True), - ba.BoolSetting('Epic Mode', default=False), + bs.BoolSetting(lucky_capsules, default=True), + bs.BoolSetting('Epic Mode', default=False), ] return settings @classmethod - def supports_session_type(cls, sessiontype: type[ba.Session]) -> bool: - return issubclass(sessiontype, ba.DualTeamSession) or issubclass( - sessiontype, ba.FreeForAllSession + def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool: + return issubclass(sessiontype, bs.DualTeamSession) or issubclass( + sessiontype, bs.FreeForAllSession ) @classmethod - def get_supported_maps(cls, sessiontype: type[ba.Session]) -> list[str]: - return ba.getmaps('keep_away') + def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]: + return bs.app.classic.getmaps('keep_away') def __init__(self, settings: dict): super().__init__(settings) shared = SharedObjects.get() self._scoreboard = Scoreboard() self._score_to_win: int | None = None - self._swipsound = ba.getsound('swip') - self._lucky_sound = ba.getsound('ding') + self._swipsound = bs.getsound('swip') + self._lucky_sound = bs.getsound('ding') self._flag_pos: Sequence[float] | None = None self._flag_state: FlagState | None = None self._flag: Flag | None = None - self._flag_light: ba.Node | None = None + self._flag_light: bs.Node | None = None self._scoring_team: weakref.ref[Team] | None = None self._time_limit = float(settings['Time Limit']) self._epic_mode = bool(settings['Epic Mode']) @@ -202,19 +204,19 @@ class CollectorGame(ba.TeamGameActivity[Player, Team]): self._lucky_capsules = bool(settings[lucky_capsules]) self._capsules: list[Any] = [] - self._capsule_model = ba.getmodel('bomb') - self._capsule_tex = ba.gettexture('bombColor') - self._capsule_lucky_tex = ba.gettexture('bombStickyColor') - self._collect_sound = ba.getsound('powerup01') - self._lucky_collect_sound = ba.getsound('cashRegister2') + self._capsule_mesh = bs.getmesh('bomb') + self._capsule_tex = bs.gettexture('bombColor') + self._capsule_lucky_tex = bs.gettexture('bombStickyColor') + self._collect_sound = bs.getsound('powerup01') + self._lucky_collect_sound = bs.getsound('cashRegister2') - self._capsule_material = ba.Material() + self._capsule_material = bs.Material() self._capsule_material.add_actions( conditions=('they_have_material', shared.player_material), actions=('call', 'at_connect', self._on_capsule_player_collide), ) - self._flag_region_material = ba.Material() + self._flag_region_material = bs.Material() self._flag_region_material.add_actions( conditions=('they_have_material', shared.player_material), actions=( @@ -223,12 +225,12 @@ class CollectorGame(ba.TeamGameActivity[Player, Team]): ( 'call', 'at_connect', - ba.Call(self._handle_player_flag_region_collide, True), + babase.Call(self._handle_player_flag_region_collide, True), ), ( 'call', 'at_disconnect', - ba.Call(self._handle_player_flag_region_collide, False), + babase.Call(self._handle_player_flag_region_collide, False), ), ), ) @@ -236,7 +238,7 @@ class CollectorGame(ba.TeamGameActivity[Player, Team]): # Base class overrides. self.slow_motion = self._epic_mode self.default_music = ( - ba.MusicType.EPIC if self._epic_mode else ba.MusicType.SCARY + bs.MusicType.EPIC if self._epic_mode else bs.MusicType.SCARY ) def get_instance_description(self) -> str | Sequence: @@ -245,7 +247,7 @@ class CollectorGame(ba.TeamGameActivity[Player, Team]): def get_instance_description_short(self) -> str | Sequence: return description_short, self._score_to_win - def create_team(self, sessionteam: ba.SessionTeam) -> Team: + def create_team(self, sessionteam: bs.SessionTeam) -> Team: return Team() def on_team_join(self, team: Team) -> None: @@ -263,18 +265,18 @@ class CollectorGame(ba.TeamGameActivity[Player, Team]): ) self._update_scoreboard() - if isinstance(self.session, ba.FreeForAllSession): + if isinstance(self.session, bs.FreeForAllSession): self._flag_pos = self.map.get_flag_position(random.randint(0, 1)) else: self._flag_pos = self.map.get_flag_position(None) - ba.timer(1.0, self._tick, repeat=True) + bs.timer(1.0, self._tick, repeat=True) self._flag_state = FlagState.NEW Flag.project_stand(self._flag_pos) self._flag = Flag( position=self._flag_pos, touchable=False, color=(1, 1, 1) ) - self._flag_light = ba.newnode( + self._flag_light = bs.newnode( 'light', attrs={ 'position': self._flag_pos, @@ -286,7 +288,7 @@ class CollectorGame(ba.TeamGameActivity[Player, Team]): ) # Flag region. flagmats = [self._flag_region_material, shared.region_material] - ba.newnode( + bs.newnode( 'region', attrs={ 'position': self._flag_pos, @@ -308,7 +310,7 @@ class CollectorGame(ba.TeamGameActivity[Player, Team]): if not scoring_team: return - if isinstance(self.session, ba.FreeForAllSession): + if isinstance(self.session, bs.FreeForAllSession): players = self.players else: players = scoring_team.players @@ -331,10 +333,7 @@ class CollectorGame(ba.TeamGameActivity[Player, Team]): self._flag_pos[1]+1, self._flag_pos[2] ), player) - ba.playsound( - self._collect_sound, - 0.8, - position=self._flag_pos) + self._collect_sound.play(0.8, position=self._flag_pos) self._update_scoreboard() if player.capsules > 0: @@ -347,7 +346,7 @@ class CollectorGame(ba.TeamGameActivity[Player, Team]): self.end_game() def end_game(self) -> None: - results = ba.GameResults() + results = bs.GameResults() for team in self.teams: results.set_team_score(team, team.score) self.end(results=results, announce_delay=0) @@ -369,7 +368,7 @@ class CollectorGame(ba.TeamGameActivity[Player, Team]): holding_team = list(holding_teams)[0] self._flag_state = FlagState.HELD self._scoring_team = weakref.ref(holding_team) - self._flag_light.color = ba.normalized_color(holding_team.color) + self._flag_light.color = babase.normalized_color(holding_team.color) self._flag.node.color = holding_team.color else: self._flag_state = FlagState.UNCONTESTED @@ -377,12 +376,12 @@ class CollectorGame(ba.TeamGameActivity[Player, Team]): self._flag_light.color = (0.2, 0.2, 0.2) self._flag.node.color = (1, 1, 1) if self._flag_state != prev_state: - ba.playsound(self._swipsound) + self._swipsound.play() def _handle_player_flag_region_collide(self, colliding: bool) -> None: try: - spaz = ba.getcollision().opposingnode.getdelegate(PlayerSpaz, True) - except ba.NotFoundError: + spaz = bs.getcollision().opposingnode.getdelegate(PlayerSpaz, True) + except bs.NotFoundError: return if not spaz.is_alive(): @@ -442,7 +441,7 @@ class CollectorGame(ba.TeamGameActivity[Player, Team]): def _on_capsule_player_collide(self) -> None: if self.has_ended(): return - collision = ba.getcollision() + collision = bs.getcollision() # Be defensive here; we could be hitting the corpse of a player # who just left/etc. @@ -451,7 +450,7 @@ class CollectorGame(ba.TeamGameActivity[Player, Team]): player = collision.opposingnode.getdelegate( PlayerSpaz, True ).getplayer(Player, True) - except ba.NotFoundError: + except bs.NotFoundError: return if not player.is_alive(): @@ -465,30 +464,24 @@ class CollectorGame(ba.TeamGameActivity[Player, Team]): scale=1.5, position=capsule.node.position ).autoretain() - ba.playsound( - self._lucky_collect_sound, - 1.0, - position=capsule.node.position) - ba.emitfx( + self._lucky_collect_sound.play(1.0, position=capsule.node.position) + bs.emitfx( position=capsule.node.position, velocity=(0, 0, 0), count=int(6.4+random.random()*24), scale=1.2, spread=2.0, chunk_type='spark') - ba.emitfx( + bs.emitfx( position=capsule.node.position, velocity=(0, 0, 0), count=int(4.0+random.random()*6), emit_type='tendrils') else: player.capsules += 1 - ba.playsound( - self._collect_sound, - 0.6, - position=capsule.node.position) + self._collect_sound.play(0.6, position=capsule.node.position) # create a flash - light = ba.newnode( + light = bs.newnode( 'light', attrs={ 'position': capsule.node.position, @@ -499,27 +492,27 @@ class CollectorGame(ba.TeamGameActivity[Player, Team]): # Create a short text informing about your inventory self._handle_capsule_storage(player.position, player) - ba.animate(light, 'intensity', { + bs.animate(light, 'intensity', { 0: 0, 0.1: 0.5, 0.2: 0 }, loop=False) - ba.timer(0.2, light.delete) - capsule.handlemessage(ba.DieMessage()) + bs.timer(0.2, light.delete) + capsule.handlemessage(bs.DieMessage()) def _update_player_light(self, player: Player, capsules: int) -> None: if player.light: intensity = 0.04 * capsules - ba.animate(player.light, 'intensity', { + bs.animate(player.light, 'intensity', { 0.0: player.light.intensity, 0.1: intensity }) def newintensity(): player.light.intensity = intensity - ba.timer(0.1, newintensity) + bs.timer(0.1, newintensity) else: - player.light = ba.newnode( + player.light = bs.newnode( 'light', attrs={ 'height_attenuated': False, @@ -558,7 +551,7 @@ class CollectorGame(ba.TeamGameActivity[Player, Team]): self._update_player_light(player, capsules) def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, ba.PlayerDiedMessage): + if isinstance(msg, bs.PlayerDiedMessage): super().handlemessage(msg) # Augment default. # No longer can count as time_at_flag once dead. player = msg.getplayer(Player) @@ -572,7 +565,7 @@ class CollectorGame(ba.TeamGameActivity[Player, Team]): return super().handlemessage(msg) -class Capsule(ba.Actor): +class Capsule(bs.Actor): def __init__(self, position: Sequence[float] = (0.0, 1.0, 0.0), @@ -586,12 +579,12 @@ class Capsule(ba.Actor): self._spawn_pos = (position[0], position[1], position[2]) if lucky: - ba.playsound(activity._lucky_sound, 1.0, self._spawn_pos) + activity._lucky_sound.play(1.0, self._spawn_pos) - self.node = ba.newnode( + self.node = bs.newnode( 'prop', attrs={ - 'model': activity._capsule_model, + 'mesh': activity._capsule_mesh, 'color_texture': activity._capsule_lucky_tex if lucky else ( activity._capsule_tex), 'body': 'crate' if lucky else 'capsule', @@ -606,12 +599,12 @@ class Capsule(ba.Actor): shared.object_material, activity._capsule_material] }, delegate=self) - ba.animate(self.node, 'model_scale', { + bs.animate(self.node, 'mesh_scale', { 0.0: 0.0, 0.1: 0.9 if lucky else 0.6, 0.16: 0.8 if lucky else 0.5 }) - self._light_capsule = ba.newnode( + self._light_capsule = bs.newnode( 'light', attrs={ 'position': self._spawn_pos, @@ -622,16 +615,16 @@ class Capsule(ba.Actor): self.node.connectattr('position', self._light_capsule, 'position') def handlemessage(self, msg: Any): - if isinstance(msg, ba.DieMessage): + if isinstance(msg, bs.DieMessage): self.node.delete() - ba.animate(self._light_capsule, 'intensity', { + bs.animate(self._light_capsule, 'intensity', { 0: 1.0, 0.05: 0.0 }, loop=False) - ba.timer(0.05, self._light_capsule.delete) - elif isinstance(msg, ba.OutOfBoundsMessage): - self.handlemessage(ba.DieMessage()) - elif isinstance(msg, ba.HitMessage): + bs.timer(0.05, self._light_capsule.delete) + elif isinstance(msg, bs.OutOfBoundsMessage): + self.handlemessage(bs.DieMessage()) + elif isinstance(msg, bs.HitMessage): self.node.handlemessage( 'impulse', msg.pos[0], msg.pos[1], msg.pos[2], diff --git a/plugins/minigames/demolition_war.py b/plugins/minigames/demolition_war.py index 1c26433..abafe06 100644 --- a/plugins/minigames/demolition_war.py +++ b/plugins/minigames/demolition_war.py @@ -1,5 +1,5 @@ -# ba_meta require api 7 +# ba_meta require api 8 """ DemolitionWar - BombFight on wooden floor flying in air. Author: Mr.Smoothy @@ -12,23 +12,26 @@ from __future__ import annotations from typing import TYPE_CHECKING -import ba -from bastd.game.elimination import EliminationGame, Player -from bastd.gameutils import SharedObjects -from bastd.actor.bomb import BombFactory +import babase +import bauiv1 as bui +import bascenev1 as bs +from bascenev1 import _map +from bascenev1lib.game.elimination import EliminationGame, Player +from bascenev1lib.gameutils import SharedObjects +from bascenev1lib.actor.bomb import BombFactory import random -from bastd.actor.playerspaz import PlayerSpaz +from bascenev1lib.actor.playerspaz import PlayerSpaz if TYPE_CHECKING: from typing import Any, Sequence -# ba_meta export game +# ba_meta export bascenev1.GameActivity class DemolitionWar(EliminationGame): name = 'DemolitionWar' description = 'Last remaining alive wins.' - scoreconfig = ba.ScoreConfig( - label='Survived', scoretype=ba.ScoreType.SECONDS, none_is_winner=True + 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 @@ -37,17 +40,17 @@ class DemolitionWar(EliminationGame): @classmethod def get_available_settings( - cls, sessiontype: type[ba.Session] - ) -> list[ba.Setting]: + cls, sessiontype: type[bs.Session] + ) -> list[babase.Setting]: settings = [ - ba.IntSetting( + bs.IntSetting( 'Lives Per Player', default=1, min_value=1, max_value=10, increment=1, ), - ba.IntChoiceSetting( + bs.IntChoiceSetting( 'Time Limit', choices=[ ('None', 0), @@ -59,7 +62,7 @@ class DemolitionWar(EliminationGame): ], default=0, ), - ba.FloatChoiceSetting( + bs.FloatChoiceSetting( 'Respawn Times', choices=[ ('Shorter', 0.25), @@ -70,23 +73,23 @@ class DemolitionWar(EliminationGame): ], default=1.0, ), - ba.BoolSetting('Epic Mode', default=False), + bs.BoolSetting('Epic Mode', default=False), ] - if issubclass(sessiontype, ba.DualTeamSession): - settings.append(ba.BoolSetting('Solo Mode', default=False)) + if issubclass(sessiontype, bs.DualTeamSession): + settings.append(bs.BoolSetting('Solo Mode', default=False)) settings.append( - ba.BoolSetting('Balance Total Lives', default=False) + bs.BoolSetting('Balance Total Lives', default=False) ) return settings @classmethod - def supports_session_type(cls, sessiontype: type[ba.Session]) -> bool: - return issubclass(sessiontype, ba.DualTeamSession) or issubclass( - sessiontype, ba.FreeForAllSession + def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool: + return issubclass(sessiontype, bs.DualTeamSession) or issubclass( + sessiontype, bs.FreeForAllSession ) @classmethod - def get_supported_maps(cls, sessiontype: type[ba.Session]) -> list[str]: + def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]: return ['Wooden Floor'] def __init__(self, settings: dict): @@ -95,7 +98,7 @@ class DemolitionWar(EliminationGame): self._solo_mode = False self._balance_total_lives = False - def spawn_player(self, player: Player) -> ba.Actor: + def spawn_player(self, player: Player) -> bs.Actor: p = [-6, -4.3, -2.6, -0.9, 0.8, 2.5, 4.2, 5.9] q = [-4, -2.3, -0.6, 1.1, 2.8, 4.5] @@ -118,23 +121,23 @@ class DemolitionWar(EliminationGame): self.map_extend() def on_blast(self): - node = ba.getcollision().sourcenode - ba.emitfx((node.position[0], 0.9, node.position[2]), + node = bs.getcollision().sourcenode + bs.emitfx((node.position[0], 0.9, node.position[2]), (0, 2, 0), 30, 1, spread=1, chunk_type='splinter') - ba.timer(0.1, ba.Call(node.delete)) + bs.timer(0.1, babase.Call(node.delete)) def map_extend(self): # TODO need to improve here , so we can increase size of map easily with settings p = [-6, -4.3, -2.6, -0.9, 0.8, 2.5, 4.2, 5.9] q = [-4, -2.3, -0.6, 1.1, 2.8, 4.5] factory = BombFactory.get() - self.ramp_bomb = ba.Material() + self.ramp_bomb = bs.Material() self.ramp_bomb.add_actions( conditions=('they_have_material', factory.bomb_material), actions=( ('modify_part_collision', 'collide', True), ('modify_part_collision', 'physical', True), - ('call', 'at_connect', ba.Call(self.on_blast)) + ('call', 'at_connect', babase.Call(self.on_blast)) )) self.ramps = [] for i in p: @@ -144,7 +147,7 @@ class DemolitionWar(EliminationGame): def create_ramp(self, x, z): shared = SharedObjects.get() - self._real_collied_material = ba.Material() + self._real_collied_material = bs.Material() self._real_collied_material.add_actions( actions=( @@ -152,32 +155,32 @@ class DemolitionWar(EliminationGame): ('modify_part_collision', 'physical', True) )) - self.mat = ba.Material() + self.mat = bs.Material() self.mat.add_actions( actions=(('modify_part_collision', 'physical', False), ('modify_part_collision', 'collide', False)) ) pos = (x, 0, z) - ud_1_r = ba.newnode('region', attrs={'position': pos, 'scale': (1.5, 1, 1.5), 'type': 'box', 'materials': [ + ud_1_r = bs.newnode('region', attrs={'position': pos, 'scale': (1.5, 1, 1.5), 'type': 'box', 'materials': [ shared.footing_material, self._real_collied_material, self.ramp_bomb]}) - node = ba.newnode('prop', + node = bs.newnode('prop', owner=ud_1_r, attrs={ - 'model': ba.getmodel('image1x1'), - 'light_model': ba.getmodel('powerupSimple'), + 'mesh': bs.getmesh('image1x1'), + 'light_mesh': bs.getmesh('powerupSimple'), 'position': (2, 7, 2), 'body': 'puck', 'shadow_size': 0.0, 'velocity': (0, 0, 0), - 'color_texture': ba.gettexture('tnt'), - 'model_scale': 1.5, + 'color_texture': bs.gettexture('tnt'), + 'mesh_scale': 1.5, 'reflection_scale': [1.5], 'materials': [self.mat, shared.object_material, shared.footing_material], 'density': 9000000000 }) - node.changerotation(1, 0, 0) - mnode = ba.newnode('math', + # node.changerotation(1, 0, 0) + mnode = bs.newnode('math', owner=ud_1_r, attrs={ 'input1': (0, 0.6, 0), @@ -218,7 +221,7 @@ class mapdefs: points['tnt1'] = (-0.08421587483, 0.9515026107, -0.7762602271) -class WoodenFloor(ba.Map): +class WoodenFloor(bs._map.Map): # ahdunno if this is correct way, change if u find better way """Stadium map for football games.""" defs = mapdefs defs.points['spawn1'] = (-12.03866341, 0.02275111462, 0.0) + (0.5, 1.0, 4.0) @@ -238,15 +241,15 @@ class WoodenFloor(ba.Map): def on_preload(cls) -> Any: data: dict[str, Any] = { - 'model_bg': ba.getmodel('doomShroomBG'), - 'bg_vr_fill_model': ba.getmodel('natureBackgroundVRFill'), - 'collide_model': ba.getcollidemodel('bridgitLevelCollide'), - 'tex': ba.gettexture('bridgitLevelColor'), - 'model_bg_tex': ba.gettexture('doomShroomBGColor'), - 'collide_bg': ba.getcollidemodel('natureBackgroundCollide'), - 'railing_collide_model': - (ba.getcollidemodel('bridgitLevelRailingCollide')), - 'bg_material': ba.Material() + 'mesh_bg': bs.getmesh('doomShroomBG'), + 'bg_vr_fill_mesh': bs.getmesh('natureBackgroundVRFill'), + 'collide_mesh': bs.getcollisionmesh('bridgitLevelCollide'), + 'tex': bs.gettexture('bridgitLevelColor'), + 'mesh_bg_tex': bs.gettexture('doomShroomBGColor'), + 'collide_bg': bs.getcollisionmesh('natureBackgroundCollide'), + 'railing_collide_mesh': + (bs.getcollisionmesh('bridgitLevelRailingCollide')), + 'bg_material': bs.Material() } data['bg_material'].add_actions(actions=('modify_part_collision', 'friction', 10.0)) @@ -255,23 +258,23 @@ class WoodenFloor(ba.Map): def __init__(self) -> None: super().__init__() shared = SharedObjects.get() - self.background = ba.newnode( + self.background = bs.newnode( 'terrain', attrs={ - 'model': self.preloaddata['model_bg'], + 'mesh': self.preloaddata['mesh_bg'], 'lighting': False, 'background': True, - 'color_texture': self.preloaddata['model_bg_tex'] + 'color_texture': self.preloaddata['mesh_bg_tex'] }) - self.vr = ba.newnode('terrain', + self.vr = bs.newnode('terrain', attrs={ - 'model': self.preloaddata['bg_vr_fill_model'], + 'mesh': self.preloaddata['bg_vr_fill_mesh'], 'lighting': False, 'vr_only': True, 'background': True, - 'color_texture': self.preloaddata['model_bg_tex'] + 'color_texture': self.preloaddata['mesh_bg_tex'] }) - gnode = ba.getactivity().globalsnode + 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) @@ -280,7 +283,7 @@ class WoodenFloor(ba.Map): gnode.vr_near_clip = 0.5 def is_point_near_edge(self, - point: ba.Vec3, + 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] @@ -290,15 +293,15 @@ class WoodenFloor(ba.Map): def _handle_player_collide(self): try: - player = ba.getcollision().opposingnode.getdelegate( + player = bs.getcollision().opposingnode.getdelegate( PlayerSpaz, True) - except ba.NotFoundError: + except bs.NotFoundError: return if player.is_alive(): player.shatter(True) try: - ba._map.register_map(WoodenFloor) + bs._map.register_map(WoodenFloor) except: pass diff --git a/plugins/minigames/dodge_the_ball.py b/plugins/minigames/dodge_the_ball.py index a950131..2bb1d92 100644 --- a/plugins/minigames/dodge_the_ball.py +++ b/plugins/minigames/dodge_the_ball.py @@ -6,18 +6,20 @@ # Feel free to edit. -# ba_meta require api 7 +# ba_meta require api 8 from __future__ import annotations from typing import TYPE_CHECKING -import ba +import babase +import bauiv1 as bui +import bascenev1 as bs from random import choice from enum import Enum -from bastd.actor.bomb import Blast -from bastd.actor.popuptext import PopupText -from bastd.actor.powerupbox import PowerupBox -from bastd.actor.onscreencountdown import OnScreenCountdown -from bastd.gameutils import SharedObjects +from bascenev1lib.actor.bomb import Blast +from bascenev1lib.actor.popuptext import PopupText +from bascenev1lib.actor.powerupbox import PowerupBox +from bascenev1lib.actor.onscreencountdown import OnScreenCountdown +from bascenev1lib.gameutils import SharedObjects if TYPE_CHECKING: from typing import NoReturn, Sequence, Any @@ -48,13 +50,13 @@ ball_type_dict: dict[BallType, int] = { } -class Ball(ba.Actor): +class Ball(bs.Actor): """ Shooting Ball """ def __init__(self, position: Sequence[float], velocity: Sequence[float], - texture: ba.Texture, + texture: babase.Texture, body_scale: float = 1.0, gravity_scale: float = 1.0, ) -> NoReturn: @@ -63,7 +65,7 @@ class Ball(ba.Actor): shared = SharedObjects.get() - ball_material = ba.Material() + ball_material = bs.Material() ball_material.add_actions( conditions=( ( @@ -77,7 +79,7 @@ class Ball(ba.Actor): actions=('modify_node_collision', 'collide', False), ) - self.node = ba.newnode( + self.node = bs.newnode( 'prop', delegate=self, attrs={ @@ -85,8 +87,8 @@ class Ball(ba.Actor): 'position': position, 'velocity': velocity, 'body_scale': body_scale, - 'model': ba.getmodel('frostyPelvis'), - 'model_scale': body_scale, + 'mesh': bs.getmesh('frostyPelvis'), + 'mesh_scale': body_scale, 'color_texture': texture, 'gravity_scale': gravity_scale, 'density': 4.0, # increase density of ball so ball collide with player with heavy force. # ammm very bad grammer @@ -95,19 +97,19 @@ class Ball(ba.Actor): ) # die the ball manually incase the ball doesn't fall the outside of the map - ba.timer(2.5, ba.WeakCall(self.handlemessage, ba.DieMessage())) + bs.timer(2.5, bs.WeakCall(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 def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, ba.DieMessage): + if isinstance(msg, bs.DieMessage): self.node.delete() else: super().handlemessage(msg) -class Box(ba.Actor): +class Box(bs.Actor): """ A box that spawn midle of map as a decoration perpose """ def __init__(self, @@ -119,7 +121,7 @@ class Box(ba.Actor): shared = SharedObjects.get() # self.ball_jump = 0.0; - no_hit_material = ba.Material() + no_hit_material = bs.Material() # we don't need that the box was move and collide with objects. no_hit_material.add_actions( conditions=( @@ -142,25 +144,25 @@ class Box(ba.Actor): ), ) - self.node = ba.newnode( + self.node = bs.newnode( 'prop', delegate=self, attrs={ 'body': 'box', 'position': position, - 'model': ba.getmodel('powerup'), - 'light_model': ba.getmodel('powerupSimple'), + 'mesh': bs.getmesh('powerup'), + 'light_mesh': bs.getmesh('powerupSimple'), 'shadow_size': 0.5, 'body_scale': 1.4, - 'model_scale': 1.4, - 'color_texture': ba.gettexture('landMineLit'), + 'mesh_scale': 1.4, + 'color_texture': bs.gettexture('landMineLit'), 'reflection': 'powerup', 'reflection_scale': [1.0], 'materials': (no_hit_material,), }, ) # light - self.light = ba.newnode( + self.light = bs.newnode( "light", owner=self.node, attrs={ @@ -173,7 +175,7 @@ class Box(ba.Actor): # Drawing circle and circleOutline in radius of 3, # so player can see that how close he is to the box. # If player is inside this circle the ball speed will increase. - circle = ba.newnode( + circle = bs.newnode( "locator", owner=self.node, attrs={ @@ -187,7 +189,7 @@ class Box(ba.Actor): ) self.node.connectattr("position", circle, "position") # also adding a outline cause its look nice. - circle_outline = ba.newnode( + circle_outline = bs.newnode( "locator", owner=self.node, attrs={ @@ -203,17 +205,17 @@ class Box(ba.Actor): # all ball attribute that we need. self.ball_type: BallType = BallType.EASY - self.shoot_timer: ba.Timer | None = None + self.shoot_timer: bs.Timer | None = None self.shoot_speed: float = 0.0 # this force the shoot if player is inside the red circle. self.force_shoot_speed: float = 0.0 self.ball_mag = 3000 self.ball_gravity: float = 1.0 - self.ball_tex: ba.Texture | None = None + self.ball_tex: babase.Texture | None = None # only for Hard ball_type self.player_facing_direction: list[float, float] = [0.0, 0.0] # ball shoot soound. - self.shoot_sound = ba.getsound('laserReverse') + self.shoot_sound = bs.getsound('laserReverse') # same as "powerupdist" self.ball_type_dist: list[BallType] = [] @@ -240,7 +242,7 @@ class Box(ba.Actor): # to finding difference between player and box. # we just need to subtract player pos and ball pos. # Same logic as eric applied in Target Practice Gamemode. - difference = ba.Vec3(target_player.position) - ba.Vec3(self.node.position) + difference = babase.Vec3(target_player.position) - babase.Vec3(self.node.position) # discard Y position so ball shoot more straight. difference[1] = 0.0 @@ -301,7 +303,7 @@ class Box(ba.Actor): difference[2] + self.player_facing_direction[1], # force direction Z ) # creating our timer and shoot the ball again.(and we create a loop) - self.shoot_timer = ba.Timer(self.shoot_speed, self.start_shoot) + self.shoot_timer = bs.Timer(self.shoot_speed, self.start_shoot) def upgrade_ball_type(self, ball_type: BallType) -> NoReturn: @@ -316,7 +318,7 @@ class Box(ba.Actor): self.ball_mag = 3000 # box light color and ball tex self.light.color = (1.0, 1.0, 0.0) - self.ball_tex = ba.gettexture('egg4') + self.ball_tex = bs.gettexture('egg4') elif ball_type == BallType.MEDIUM: self.ball_mag = 3000 # decrease the gravity scale so, ball shoot without falling and straight. @@ -325,7 +327,7 @@ class Box(ba.Actor): self.shoot_speed = 0.4 # box light color and ball tex. self.light.color = (1.0, 0.0, 1.0) - self.ball_tex = ba.gettexture('egg3') + self.ball_tex = bs.gettexture('egg3') elif ball_type == BallType.HARD: self.ball_mag = 2500 self.ball_gravity = 0.0 @@ -333,25 +335,26 @@ class Box(ba.Actor): self.shoot_speed = 0.6 # box light color and ball tex. self.light.color = (1.0, 0.2, 1.0) - self.ball_tex = ba.gettexture('egg1') + self.ball_tex = bs.gettexture('egg1') def shoot_animation(self) -> NoReturn: - ba.animate( + bs.animate( self.node, - "model_scale", { + "mesh_scale", { 0.00: 1.4, 0.05: 1.7, 0.10: 1.4, } ) # playing shoot sound. - ba.playsound(self.shoot_sound, position=self.node.position) + # self.shoot_sound, position = self.node.position.play(); + self.shoot_sound.play() - def highlight_target_player(self, player: ba.Player) -> NoReturn: + def highlight_target_player(self, player: bs.Player) -> NoReturn: # adding light - light = ba.newnode( + light = bs.newnode( "light", owner=self.node, attrs={ @@ -360,7 +363,7 @@ class Box(ba.Actor): 'color': (1.0, 0.0, 0.0), } ) - ba.animate( + bs.animate( light, "radius", { 0.05: 0.02, @@ -374,7 +377,7 @@ class Box(ba.Actor): } ) # And a circle outline with ugly animation. - circle_outline = ba.newnode( + circle_outline = bs.newnode( "locator", owner=player.actor.node, attrs={ @@ -385,7 +388,7 @@ class Box(ba.Actor): 'additive': True, }, ) - ba.animate_array( + bs.animate_array( circle_outline, 'size', 1, { @@ -406,10 +409,10 @@ class Box(ba.Actor): # 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 - ba.timer(self.shoot_speed, light.delete) - ba.timer(self.shoot_speed, circle_outline.delete) + bs.timer(self.shoot_speed, light.delete) + bs.timer(self.shoot_speed, circle_outline.delete) - def calculate_player_analog_stick(self, player: ba.Player, distance: float) -> NoReturn: + def calculate_player_analog_stick(self, player: bs.Player, distance: float) -> NoReturn: # at first i was very confused how i can read the player analog stick \ # then i saw TheMikirog#1984 autorun plugin code. # and i got it how analog stick values are works. @@ -461,48 +464,48 @@ class Box(ba.Actor): self.shoot_timer = None -class Player(ba.Player['Team']): +class Player(bs.Player['Team']): """Our player type for this game.""" -class Team(ba.Team[Player]): +class Team(bs.Team[Player]): """Our team type for this game.""" # almost 80 % for game we done in box class. # now remain things, like name, seetings, scoring, cooldonw, # and main thing don't allow player to camp inside of box are going in this class. -# ba_meta export game +# ba_meta export bascenev1.GameActivity -class DodgeTheBall(ba.TeamGameActivity[Player, Team]): +class DodgeTheBall(bs.TeamGameActivity[Player, Team]): # defining name, description and settings.. name = 'Dodge the ball' description = 'Survive from shooting balls' available_settings = [ - ba.IntSetting( + bs.IntSetting( 'Cooldown', min_value=20, default=45, increment=5, ), - ba.BoolSetting('Epic Mode', default=False) + bs.BoolSetting('Epic Mode', default=False) ] # Don't allow joining after we start. allow_mid_activity_joins = False @classmethod - def supports_session_type(cls, sessiontype: type[ba.Session]) -> bool: + def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool: # We support team and ffa sessions. - return issubclass(sessiontype, ba.FreeForAllSession) or issubclass( - sessiontype, ba.DualTeamSession, + return issubclass(sessiontype, bs.FreeForAllSession) or issubclass( + sessiontype, bs.DualTeamSession, ) @classmethod - def get_supported_maps(cls, sessiontype: type[ba.Session]) -> list[str]: + def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]: # This Game mode need a flat and perfect shape map where can player fall outside map. # bombsquad have "Doom Shroom" map. # Not perfect map for this game mode but its fine for this gamemode. @@ -514,21 +517,21 @@ class DodgeTheBall(ba.TeamGameActivity[Player, Team]): self._epic_mode = bool(settings['Epic Mode']) self.countdown_time = int(settings['Cooldown']) - self.check_player_pos_timer: ba.Timer | None = None - self.shield_drop_timer: ba.Timer | None = None + self.check_player_pos_timer: bs.Timer | None = None + self.shield_drop_timer: bs.Timer | None = None # cooldown and Box self._countdown: OnScreenCountdown | None = None self.box: Box | None = None # this lists for scoring. - self.joined_player_list: list[ba.Player] = [] - self.dead_player_list: list[ba.Player] = [] + self.joined_player_list: list[bs.Player] = [] + self.dead_player_list: list[bs.Player] = [] # normally play RUN AWAY music cause is match with our gamemode at.. my point, # but in epic switch to EPIC. self.slow_motion = self._epic_mode self.default_music = ( - ba.MusicType.EPIC if self._epic_mode else ba.MusicType.RUN_AWAY + bs.MusicType.EPIC if self._epic_mode else bs.MusicType.RUN_AWAY ) def get_instance_description(self) -> str | Sequence: @@ -554,19 +557,19 @@ class DodgeTheBall(ba.TeamGameActivity[Player, Team]): ) # and starts the cooldown and shootes. - ba.timer(5.0, self._countdown.start) - ba.timer(5.0, self.box.start_shoot) + bs.timer(5.0, self._countdown.start) + bs.timer(5.0, self.box.start_shoot) # start checking all player pos. - ba.timer(5.0, self.check_player_pos) + bs.timer(5.0, self.check_player_pos) # drop shield every ten Seconds # need five seconds delay Because shootes start after 5 seconds. - ba.timer(15.0, self.drop_shield) + bs.timer(15.0, self.drop_shield) # This function returns all alive players in game. # i thinck you see this function in Box class. - def get_alive_players(self) -> Sequence[ba.Player]: + def get_alive_players(self) -> Sequence[bs.Player]: alive_players = [] @@ -583,7 +586,7 @@ class DodgeTheBall(ba.TeamGameActivity[Player, Team]): for player in self.get_alive_players(): # same logic as applied for the ball - difference = ba.Vec3(player.position) - ba.Vec3(self.box.node.position) + difference = babase.Vec3(player.position) - babase.Vec3(self.box.node.position) distance = difference.length() @@ -609,7 +612,7 @@ class DodgeTheBall(ba.TeamGameActivity[Player, Team]): ).autoretain() # create our timer and start looping it - self.check_player_pos_timer = ba.Timer(0.1, self.check_player_pos) + self.check_player_pos_timer = bs.Timer(0.1, self.check_player_pos) # drop useless shield's too give player temptation. def drop_shield(self) -> NoReturn: @@ -626,7 +629,7 @@ class DodgeTheBall(ba.TeamGameActivity[Player, Team]): poweruptype='shield', ).autoretain() - self.shield_drop_timer = ba.Timer(10.0, self.drop_shield) + self.shield_drop_timer = bs.Timer(10.0, self.drop_shield) # when cooldown time up i don't want that the game end immediately. def play_victory_sound_and_end(self) -> NoReturn: @@ -636,7 +639,7 @@ class DodgeTheBall(ba.TeamGameActivity[Player, Team]): self.check_player_pos_timer = None self.shield_drop_timer = None - ba.timer(2.0, self.end_game) + bs.timer(2.0, self.end_game) # this function runs when A player spawn in map def spawn_player(self, player: Player) -> NoReturn: @@ -682,7 +685,7 @@ class DodgeTheBall(ba.TeamGameActivity[Player, Team]): # this gamemode needs to handle only one msg "PlayerDiedMessage". def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, ba.PlayerDiedMessage): + if isinstance(msg, bs.PlayerDiedMessage): # Augment standard behavior. super().handlemessage(msg) @@ -691,7 +694,7 @@ class DodgeTheBall(ba.TeamGameActivity[Player, Team]): self.dead_player_list.append(msg.getplayer(Player)) # check the end game. - ba.timer(1.0, self._check_end_game) + bs.timer(1.0, self._check_end_game) def end_game(self): # kill timers @@ -736,7 +739,7 @@ class DodgeTheBall(ba.TeamGameActivity[Player, Team]): # Ok now calc game results: set a score for each team and then tell \ # the game to end. - results = ba.GameResults() + results = bs.GameResults() # Remember that 'free-for-all' mode is simply a special form \ # of 'teams' mode where each player gets their own team, so we can \ diff --git a/plugins/minigames/frozen_one.py b/plugins/minigames/frozen_one.py new file mode 100644 index 0000000..9b0c9ba --- /dev/null +++ b/plugins/minigames/frozen_one.py @@ -0,0 +1,18 @@ +# Ported by your friend: Freaku + + +import babase +import bascenev1 as bs +from bascenev1lib.game.chosenone import Player, ChosenOneGame + + +# ba_meta require api 8 +# ba_meta export bascenev1.GameActivity +class FrozenOneGame(ChosenOneGame): + name = 'Frozen One' + + def _set_chosen_one_player(self, player: Player) -> None: + super()._set_chosen_one_player(player) + if hasattr(player, 'actor'): + player.actor.frozen = True + player.actor.node.frozen = 1 diff --git a/plugins/minigames/handball.py b/plugins/minigames/handball.py new file mode 100644 index 0000000..dfb439d --- /dev/null +++ b/plugins/minigames/handball.py @@ -0,0 +1,383 @@ +# Released under the MIT License. See LICENSE for details. +# +"""Hockey game and support classes.""" + +# ba_meta require api 8 +# (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 +from bascenev1lib.actor.playerspaz import PlayerSpaz +from bascenev1lib.actor.scoreboard import Scoreboard +from bascenev1lib.actor.powerupbox import PowerupBoxFactory +from bascenev1lib.gameutils import SharedObjects + +if TYPE_CHECKING: + from typing import Any, Sequence, Optional, Union + + +class PuckDiedMessage: + """Inform something that a puck has died.""" + + def __init__(self, puck: Puck): + self.puck = puck + + +class Puck(bs.Actor): + """A lovely giant hockey puck.""" + + def __init__(self, position: Sequence[float] = (0.0, 1.0, 0.0)): + super().__init__() + shared = SharedObjects.get() + activity = self.getactivity() + + # Spawn just above the provided point. + self._spawn_pos = (position[0], position[1] + 1.0, position[2]) + 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, + attrs={ + 'mesh': activity.puck_mesh, + 'color_texture': activity.puck_tex, + 'body': 'sphere', + 'reflection': 'soft', + 'reflection_scale': [0.2], + 'shadow_size': 0.8, + 'is_area_of_interest': True, + 'position': self._spawn_pos, + 'materials': pmats + }) + bs.animate(self.node, 'mesh_scale', {0: 0, 0.2: 1.3, 0.26: 1}) + + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, bs.DieMessage): + assert self.node + self.node.delete() + activity = self._activity() + if activity and not msg.immediate: + activity.handlemessage(PuckDiedMessage(self)) + + # If we go out of bounds, move back to where we started. + elif isinstance(msg, bs.OutOfBoundsMessage): + assert self.node + self.node.position = self._spawn_pos + + elif isinstance(msg, bs.HitMessage): + assert self.node + assert msg.force_direction is not None + self.node.handlemessage( + 'impulse', msg.pos[0], msg.pos[1], msg.pos[2], msg.velocity[0], + msg.velocity[1], msg.velocity[2], 1.0 * msg.magnitude, + 1.0 * msg.velocity_magnitude, msg.radius, 0, + msg.force_direction[0], msg.force_direction[1], + msg.force_direction[2]) + + # If this hit came from a player, log them as the last to touch us. + s_player = msg.get_source_player(Player) + if s_player is not None: + activity = self._activity() + if activity: + if s_player in activity.players: + self.last_players_to_touch[s_player.team.id] = s_player + else: + super().handlemessage(msg) + + +class Player(bs.Player['Team']): + """Our player type for this game.""" + + +class Team(bs.Team[Player]): + """Our team type for this game.""" + + def __init__(self) -> None: + self.score = 0 + + +# ba_meta export bascenev1.GameActivity +class HockeyGame(bs.TeamGameActivity[Player, Team]): + """Ice hockey game.""" + + name = 'Handball' + description = 'Score some goals.' + available_settings = [ + bs.IntSetting( + 'Score to Win', + min_value=1, + default=1, + 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), + + ] + default_music = bs.MusicType.HOCKEY + + @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('hockey') + + def __init__(self, settings: dict): + super().__init__(settings) + shared = SharedObjects.get() + self._scoreboard = Scoreboard() + self._cheer_sound = bs.getsound('cheer') + self._chant_sound = bs.getsound('crowdChant') + self._foghorn_sound = bs.getsound('foghorn') + self._swipsound = bs.getsound('swip') + self._whistle_sound = bs.getsound('refWhistle') + self.puck_mesh = bs.getmesh('bomb') + self.puck_tex = bs.gettexture('bonesColor') + self._puck_sound = bs.getsound('metalHit') + self._epic_mode = bool(settings['Epic Mode']) + self.slow_motion = self._epic_mode + self.default_music = (bs.MusicType.EPIC + if self._epic_mode else bs.MusicType.FOOTBALL) + self.puck_material = bs.Material() + self.puck_material.add_actions(actions=(('modify_part_collision', + 'friction', 0.5))) + self.puck_material.add_actions(conditions=('they_have_material', + shared.pickup_material), + actions=('modify_part_collision', + 'collide', False)) + self.puck_material = bs.Material() + self.puck_material.add_actions(actions=(('modify_part_collision', + 'friction', 0.5))) + self.puck_material.add_actions(conditions=('they_have_material', + shared.pickup_material), + actions=('modify_part_collision', + 'collide', True)) + self.puck_material.add_actions( + conditions=( + ('we_are_younger_than', 100), + 'and', + ('they_have_material', shared.object_material), + ), + actions=('modify_node_collision', 'collide', False), + ) + self.puck_material.add_actions(conditions=('they_have_material', + shared.footing_material), + actions=('impact_sound', + self._puck_sound, 0.2, 5)) + + # Keep track of which player last touched the puck + self.puck_material.add_actions( + conditions=('they_have_material', shared.player_material), + actions=(('call', 'at_connect', + self._handle_puck_player_collide), )) + + # We want the puck to kill powerups; not get stopped by them + self.puck_material.add_actions( + conditions=('they_have_material', + PowerupBoxFactory.get().powerup_material), + actions=(('modify_part_collision', 'physical', False), + ('message', 'their_node', 'at_connect', bs.DieMessage()))) + self._score_region_material = bs.Material() + self._score_region_material.add_actions( + conditions=('they_have_material', self.puck_material), + actions=(('modify_part_collision', 'collide', + True), ('modify_part_collision', 'physical', False), + ('call', 'at_connect', self._handle_score))) + self._puck_spawn_pos: Optional[Sequence[float]] = None + self._score_regions: Optional[list[bs.NodeActor]] = None + self._puck: Optional[Puck] = None + self._score_to_win = int(settings['Score to Win']) + self._time_limit = float(settings['Time Limit']) + + def get_instance_description(self) -> Union[str, Sequence]: + if self._score_to_win == 1: + return 'Score a goal.' + return 'Score ${ARG1} goals.', self._score_to_win + + 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 + + def on_begin(self) -> None: + super().on_begin() + + self.setup_standard_time_limit(self._time_limit) + self.setup_standard_powerup_drops() + self._puck_spawn_pos = self.map.get_flag_position(None) + self._spawn_puck() + + # Set up the two score regions. + defs = self.map.defs + self._score_regions = [] + self._score_regions.append( + bs.NodeActor( + bs.newnode('region', + attrs={ + 'position': defs.boxes['goal1'][0:3], + 'scale': defs.boxes['goal1'][6:9], + 'type': 'box', + 'materials': [self._score_region_material] + }))) + self._score_regions.append( + bs.NodeActor( + bs.newnode('region', + attrs={ + 'position': defs.boxes['goal2'][0:3], + 'scale': defs.boxes['goal2'][6:9], + 'type': 'box', + 'materials': [self._score_region_material] + }))) + self._update_scoreboard() + self._chant_sound.play() + + def on_team_join(self, team: Team) -> None: + self._update_scoreboard() + + def _handle_puck_player_collide(self) -> None: + collision = bs.getcollision() + try: + puck = collision.sourcenode.getdelegate(Puck, True) + player = collision.opposingnode.getdelegate(PlayerSpaz, + True).getplayer( + Player, True) + except bs.NotFoundError: + return + + puck.last_players_to_touch[player.team.id] = player + + def _kill_puck(self) -> None: + self._puck = None + + def _handle_score(self) -> None: + """A point has been scored.""" + + assert self._puck is not None + assert self._score_regions is not None + + # Our puck might stick around for a second or two + # we don't want it to be able to score again. + if self._puck.scored: + return + + region = bs.getcollision().sourcenode + index = 0 + for index, score_region in enumerate(self._score_regions): + if region == score_region.node: + break + + for team in self.teams: + if team.id == index: + scoring_team = team + team.score += 1 + + # Tell all players to celebrate. + for player in team.players: + if player.actor: + player.actor.handlemessage(bs.CelebrateMessage(2.0)) + + # If we've got the player from the scoring team that last + # touched us, give them points. + if (scoring_team.id in self._puck.last_players_to_touch + and self._puck.last_players_to_touch[scoring_team.id]): + self.stats.player_scored( + self._puck.last_players_to_touch[scoring_team.id], + 100, + big_message=True) + + # End game if we won. + if team.score >= self._score_to_win: + self.end_game() + + self._foghorn_sound.play() + self._cheer_sound.play() + + self._puck.scored = True + + # Kill the puck (it'll respawn itself shortly). + bs.timer(1.0, self._kill_puck) + + light = bs.newnode('light', + attrs={ + 'position': bs.getcollision().position, + 'height_attenuated': False, + 'color': (1, 0, 0) + }) + bs.animate(light, 'intensity', {0: 0, 0.5: 1, 1.0: 0}, loop=True) + bs.timer(1.0, light.delete) + + bs.cameraflash(duration=10.0) + self._update_scoreboard() + + def end_game(self) -> None: + results = bs.GameResults() + for team in self.teams: + results.set_team_score(team, team.score) + self.end(results=results) + + def _update_scoreboard(self) -> None: + winscore = self._score_to_win + for team in self.teams: + self._scoreboard.set_team_value(team, team.score, winscore) + + def handlemessage(self, msg: Any) -> Any: + + # Respawn dead players if they're still in the game. + if isinstance(msg, bs.PlayerDiedMessage): + # Augment standard behavior... + super().handlemessage(msg) + self.respawn_player(msg.getplayer(Player)) + + # Respawn dead pucks. + elif isinstance(msg, PuckDiedMessage): + if not self.has_ended(): + bs.timer(3.0, self._spawn_puck) + else: + super().handlemessage(msg) + + def _flash_puck_spawn(self) -> None: + light = bs.newnode('light', + attrs={ + 'position': self._puck_spawn_pos, + 'height_attenuated': False, + 'color': (1, 0, 0) + }) + bs.animate(light, 'intensity', {0.0: 0, 0.25: 1, 0.5: 0}, loop=True) + bs.timer(1.0, light.delete) + + def _spawn_puck(self) -> None: + self._swipsound.play() + self._whistle_sound.play() + self._flash_puck_spawn() + assert self._puck_spawn_pos is not None + self._puck = Puck(position=self._puck_spawn_pos) diff --git a/plugins/minigames/icy_emits.py b/plugins/minigames/icy_emits.py new file mode 100644 index 0000000..f5467e3 --- /dev/null +++ b/plugins/minigames/icy_emits.py @@ -0,0 +1,48 @@ +# Made by your friend: Freaku + + +import babase +import bascenev1 as bs +import random +from bascenev1lib.actor.bomb import Bomb +from bascenev1lib.game.meteorshower import Player, MeteorShowerGame + + +# ba_meta require api 8 +# ba_meta export bascenev1.GameActivity +class IcyEmitsGame(MeteorShowerGame): + name = 'Icy Emits' + + @classmethod + def get_supported_maps(cls, sessiontype): + return ['Lake Frigid', 'Hockey Stadium'] + + def _drop_bomb_cluster(self) -> None: + delay = 0.0 + for _i in range(random.randrange(1, 3)): + # Drop them somewhere within our bounds with velocity pointing + # toward the opposite side. + pos = (-7.3 + 15.3 * random.random(), 5.3, + -5.5 + 2.1 * random.random()) + dropdir = (-1.0 if pos[0] > 0 else 1.0) + vel = (0, 10, 0) + bs.timer(delay, babase.Call(self._drop_bomb, pos, vel)) + delay += 0.1 + self._set_meteor_timer() + + def _drop_bomb(self, position, velocity): + random_xpositions = [-10, -9, -8, -7, -6, -5, - + 4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + random_zpositions = [-5, -4.5, -4, -3.5, -3, -2.5, -2, - + 1.5, -1, -0.5, 0, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5] + bomb_position = (random.choice(random_xpositions), 0.2, random.choice(random_zpositions)) + Bomb(position=bomb_position, velocity=velocity, bomb_type='ice').autoretain() + + +# ba_meta export plugin +class byFreaku(babase.Plugin): + def __init__(self): + ## Campaign support ## + randomPic = ['lakeFrigidPreview', 'hockeyStadiumPreview'] + babase.app.classic.add_coop_practice_level(bs.Level( + name='Icy Emits', displayname='${GAME}', gametype=IcyEmitsGame, settings={}, preview_texture_name=random.choice(randomPic))) diff --git a/plugins/minigames/memory_game.py b/plugins/minigames/memory_game.py index c5c0204..5ab2502 100644 --- a/plugins/minigames/memory_game.py +++ b/plugins/minigames/memory_game.py @@ -2,7 +2,7 @@ from __future__ import annotations ## Original creator: byANG3L ## -## Made by: Freaku / @[Just] Freak#4999 ## +## Made by: Freaku ## ## From: BSWorld Modpack (https://youtu.be/1TN56NLlShE) ## @@ -16,73 +16,63 @@ from __future__ import annotations # def spawnAllMap(self) -# ba_meta require api 7 +# ba_meta require api 8 from typing import TYPE_CHECKING, overload -import _ba -import ba +import _babase +import babase import random -from bastd.gameutils import SharedObjects +import bascenev1 as bs +from bascenev1lib.gameutils import SharedObjects if TYPE_CHECKING: from typing import Any, Sequence, Optional, List, Dict, Type, Union, Any, Literal -class OnTimer(ba.Actor): +class OnTimer(bs.Actor): """Timer which counts but doesn't show on-screen""" def __init__(self) -> None: super().__init__() - self._starttime_ms: Optional[int] = None - self.node = ba.newnode('text', attrs={'v_attach': 'top', 'h_attach': 'center', 'h_align': 'center', 'color': ( + self._starttime_ms: int | None = None + self.node = bs.newnode('text', attrs={'v_attach': 'top', 'h_attach': 'center', 'h_align': 'center', 'color': ( 1, 1, 0.5, 1), 'flatness': 0.5, 'shadow': 0.5, 'position': (0, -70), 'scale': 0, 'text': ''}) - self.inputnode = ba.newnode('timedisplay', attrs={ - 'timemin': 0, 'showsubseconds': True}) + self.inputnode = bs.newnode( + 'timedisplay', attrs={'timemin': 0, 'showsubseconds': True} + ) self.inputnode.connectattr('output', self.node, 'text') def start(self) -> None: - tval = ba.time(timeformat=ba.TimeFormat.MILLISECONDS) + """Start the timer.""" + tval = int(bs.time() * 1000.0) assert isinstance(tval, int) self._starttime_ms = tval self.inputnode.time1 = self._starttime_ms - ba.getactivity().globalsnode.connectattr('time', self.inputnode, 'time2') + bs.getactivity().globalsnode.connectattr( + 'time', self.inputnode, 'time2' + ) def has_started(self) -> bool: + """Return whether this timer has started yet.""" return self._starttime_ms is not None - def stop(self, - endtime: Union[int, float] = None, - timeformat: ba.TimeFormat = ba.TimeFormat.SECONDS) -> None: + def stop(self, endtime: int | float | None = None) -> None: + """End the timer. + + If 'endtime' is not None, it is used when calculating + the final display time; otherwise the current time is used. + """ if endtime is None: - endtime = ba.time(timeformat=ba.TimeFormat.MILLISECONDS) - timeformat = ba.TimeFormat.MILLISECONDS + endtime = bs.time() + if self._starttime_ms is None: - print('Warning: OnTimer.stop() called without start() first') + logging.warning( + 'OnScreenTimer.stop() called without first calling start()' + ) else: - endtime_ms: int - if timeformat is ba.TimeFormat.SECONDS: - endtime_ms = int(endtime * 1000) - elif timeformat is ba.TimeFormat.MILLISECONDS: - assert isinstance(endtime, int) - endtime_ms = endtime - else: - raise ValueError(f'invalid timeformat: {timeformat}') - + endtime_ms = int(endtime * 1000) self.inputnode.timemax = endtime_ms - self._starttime_ms - # Overloads so type checker knows our exact return type based in args. - @overload - def getstarttime(self, timeformat: Literal[ba.TimeFormat.SECONDS] = ba.TimeFormat.SECONDS) -> float: - ... - - @overload - def getstarttime(self, - timeformat: Literal[ba.TimeFormat.MILLISECONDS]) -> int: - ... - - def getstarttime( - self, - timeformat: ba.TimeFormat = ba.TimeFormat.SECONDS - ) -> Union[int, float]: - """Return the sim-time when start() was called. + def getstarttime(self) -> float: + """Return the scene-time when start() was called. Time will be returned in seconds if timeformat is SECONDS or milliseconds if it is MILLISECONDS. @@ -90,15 +80,11 @@ class OnTimer(ba.Actor): val_ms: Any if self._starttime_ms is None: print('WARNING: getstarttime() called on un-started timer') - val_ms = ba.time(timeformat=ba.TimeFormat.MILLISECONDS) + val_ms = int(bs.time() * 1000.0) else: val_ms = self._starttime_ms assert isinstance(val_ms, int) - if timeformat is ba.TimeFormat.SECONDS: - return 0.001 * val_ms - if timeformat is ba.TimeFormat.MILLISECONDS: - return val_ms - raise ValueError(f'invalid timeformat: {timeformat}') + return 0.001 * val_ms @property def starttime(self) -> float: @@ -107,12 +93,12 @@ class OnTimer(ba.Actor): def handlemessage(self, msg: Any) -> Any: # if we're asked to die, just kill our node/timer - if isinstance(msg, ba.DieMessage): + if isinstance(msg, bs.DieMessage): if self.node: self.node.delete() -class Player(ba.Player['Team']): +class Player(bs.Player['Team']): """Our player type for this game.""" def __init__(self) -> None: @@ -120,33 +106,33 @@ class Player(ba.Player['Team']): self.death_time: Optional[float] = None -class Team(ba.Team[Player]): +class Team(bs.Team[Player]): """Our team type for this game.""" -# ba_meta export game -class MGgame(ba.TeamGameActivity[Player, Team]): +# ba_meta export bascenev1.GameActivity +class MGgame(bs.TeamGameActivity[Player, Team]): name = 'Memory Game' description = 'Memories tiles and survive till the end!' - available_settings = [ba.BoolSetting( - 'Epic Mode', default=False), ba.BoolSetting('Enable Bottom Credits', True)] - scoreconfig = ba.ScoreConfig(label='Survived', scoretype=ba.ScoreType.MILLISECONDS, version='B') + available_settings = [bs.BoolSetting( + 'Epic Mode', default=False), bs.BoolSetting('Enable Bottom Credits', True)] + scoreconfig = bs.ScoreConfig(label='Survived', scoretype=bs.ScoreType.MILLISECONDS, version='B') # Print messages when players die (since its meaningful in this game). announce_player_deaths = True # we're currently hard-coded for one map.. @classmethod - def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: + def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]: return ['Sky Tiles'] # We support teams, free-for-all, and co-op sessions. @classmethod - def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool: - return (issubclass(sessiontype, ba.DualTeamSession) - or issubclass(sessiontype, ba.FreeForAllSession) - or issubclass(sessiontype, ba.CoopSession)) + def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool: + return (issubclass(sessiontype, bs.DualTeamSession) + or issubclass(sessiontype, bs.FreeForAllSession) + or issubclass(sessiontype, babase.CoopSession)) def __init__(self, settings: dict): super().__init__(settings) @@ -157,14 +143,14 @@ class MGgame(ba.TeamGameActivity[Player, Team]): self.credit_text = bool(settings['Enable Bottom Credits']) # Some base class overrides: - self.default_music = (ba.MusicType.EPIC - if self._epic_mode else ba.MusicType.SURVIVAL) + self.default_music = (bs.MusicType.EPIC + if self._epic_mode else bs.MusicType.SURVIVAL) if self._epic_mode: self.slow_motion = True shared = SharedObjects.get() - self._collide_with_player = ba.Material() + self._collide_with_player = bs.Material() self._collide_with_player.add_actions(actions=(('modify_part_collision', 'collide', True))) - self.dont_collide = ba.Material() + self.dont_collide = bs.Material() self.dont_collide.add_actions(actions=(('modify_part_collision', 'collide', False))) self._levelStage = 0 @@ -172,46 +158,46 @@ class MGgame(ba.TeamGameActivity[Player, Team]): self._lastPlayerDeathTime = None self._spawnCenter = (-3.17358, 2.75764, -2.99124) - self._mapFGPModel = ba.getmodel('buttonSquareOpaque') - self._mapFGPDefaultTex = ba.gettexture('achievementOffYouGo') + self._mapFGPModel = bs.getmesh('buttonSquareOpaque') + self._mapFGPDefaultTex = bs.gettexture('achievementOffYouGo') - self._mapFGCurseTex = ba.gettexture('powerupCurse') - self._mapFGHealthTex = ba.gettexture('powerupHealth') - self._mapFGIceTex = ba.gettexture('powerupIceBombs') - self._mapFGImpactTex = ba.gettexture('powerupImpactBombs') - self._mapFGMinesTex = ba.gettexture('powerupLandMines') - self._mapFGPunchTex = ba.gettexture('powerupPunch') - self._mapFGShieldTex = ba.gettexture('powerupShield') - self._mapFGStickyTex = ba.gettexture('powerupStickyBombs') + self._mapFGCurseTex = bs.gettexture('powerupCurse') + self._mapFGHealthTex = bs.gettexture('powerupHealth') + self._mapFGIceTex = bs.gettexture('powerupIceBombs') + self._mapFGImpactTex = bs.gettexture('powerupImpactBombs') + self._mapFGMinesTex = bs.gettexture('powerupLandMines') + self._mapFGPunchTex = bs.gettexture('powerupPunch') + self._mapFGShieldTex = bs.gettexture('powerupShield') + self._mapFGStickyTex = bs.gettexture('powerupStickyBombs') - self._mapFGSpaz = ba.gettexture('neoSpazIcon') - self._mapFGZoe = ba.gettexture('zoeIcon') - self._mapFGSnake = ba.gettexture('ninjaIcon') - self._mapFGKronk = ba.gettexture('kronkIcon') - self._mapFGMel = ba.gettexture('melIcon') - self._mapFGJack = ba.gettexture('jackIcon') - self._mapFGSanta = ba.gettexture('santaIcon') - self._mapFGFrosty = ba.gettexture('frostyIcon') - self._mapFGBones = ba.gettexture('bonesIcon') - self._mapFGBernard = ba.gettexture('bearIcon') - self._mapFGPascal = ba.gettexture('penguinIcon') - self._mapFGAli = ba.gettexture('aliIcon') - self._mapFGRobot = ba.gettexture('cyborgIcon') - self._mapFGAgent = ba.gettexture('agentIcon') - self._mapFGGrumbledorf = ba.gettexture('wizardIcon') - self._mapFGPixel = ba.gettexture('pixieIcon') + self._mapFGSpaz = bs.gettexture('neoSpazIcon') + self._mapFGZoe = bs.gettexture('zoeIcon') + self._mapFGSnake = bs.gettexture('ninjaIcon') + self._mapFGKronk = bs.gettexture('kronkIcon') + self._mapFGMel = bs.gettexture('melIcon') + self._mapFGJack = bs.gettexture('jackIcon') + self._mapFGSanta = bs.gettexture('santaIcon') + self._mapFGFrosty = bs.gettexture('frostyIcon') + self._mapFGBones = bs.gettexture('bonesIcon') + self._mapFGBernard = bs.gettexture('bearIcon') + self._mapFGPascal = bs.gettexture('penguinIcon') + self._mapFGAli = bs.gettexture('aliIcon') + self._mapFGRobot = bs.gettexture('cyborgIcon') + self._mapFGAgent = bs.gettexture('agentIcon') + self._mapFGGrumbledorf = bs.gettexture('wizardIcon') + self._mapFGPixel = bs.gettexture('pixieIcon') - self._imageTextDefault = ba.gettexture('bg') - self._circleTex = ba.gettexture('circleShadow') + self._imageTextDefault = bs.gettexture('bg') + self._circleTex = bs.gettexture('circleShadow') - self._image = ba.newnode('image', + self._image = bs.newnode('image', attrs={'texture': self._imageTextDefault, 'position': (0, -100), 'scale': (100, 100), 'opacity': 0.0, 'attach': 'topCenter'}) - self._textCounter = ba.newnode('text', + self._textCounter = bs.newnode('text', attrs={'text': '10', 'position': (0, -100), 'scale': 2.3, @@ -223,7 +209,7 @@ class MGgame(ba.TeamGameActivity[Player, Team]): 'h_align': 'center', 'v_align': 'center'}) - self._textLevel = ba.newnode('text', + self._textLevel = bs.newnode('text', attrs={'text': 'Level ' + str(self._levelStage), 'position': (0, -28), 'scale': 1.3, @@ -236,21 +222,21 @@ class MGgame(ba.TeamGameActivity[Player, Team]): 'h_align': 'center', 'v_align': 'center'}) - self._imageCircle = ba.newnode('image', + self._imageCircle = bs.newnode('image', attrs={'texture': self._circleTex, 'position': (75, -75), 'scale': (20, 20), 'color': (0.2, 0.2, 0.2), 'opacity': 0.0, 'attach': 'topCenter'}) - self._imageCircle2 = ba.newnode('image', + self._imageCircle2 = bs.newnode('image', attrs={'texture': self._circleTex, 'position': (75, -100), 'scale': (20, 20), 'color': (0.2, 0.2, 0.2), 'opacity': 0.0, 'attach': 'topCenter'}) - self._imageCircle3 = ba.newnode('image', + self._imageCircle3 = bs.newnode('image', attrs={'texture': self._circleTex, 'position': (75, -125), 'scale': (20, 20), @@ -260,12 +246,12 @@ class MGgame(ba.TeamGameActivity[Player, Team]): def on_transition_in(self) -> None: super().on_transition_in() - self._bellLow = ba.getsound('bellLow') - self._bellMed = ba.getsound('bellMed') - self._bellHigh = ba.getsound('bellHigh') - self._tickSound = ba.getsound('tick') - self._tickFinal = ba.getsound('powerup01') - self._scoreSound = ba.getsound('score') + self._bellLow = bs.getsound('bellLow') + self._bellMed = bs.getsound('bellMed') + self._bellHigh = bs.getsound('bellHigh') + self._tickSound = bs.getsound('tick') + self._tickFinal = bs.getsound('powerup01') + self._scoreSound = bs.getsound('score') self._image.opacity = 1 self._textCounter.opacity = 1 @@ -282,8 +268,8 @@ class MGgame(ba.TeamGameActivity[Player, Team]): if self._levelStage == 1: timeStart = 6 - ba.timer(timeStart, self._randomPlatform) - ba.timer(timeStart, self.startCounter) + bs.timer(timeStart, self._randomPlatform) + bs.timer(timeStart, self.startCounter) def on_begin(self) -> None: super().on_begin() @@ -308,7 +294,7 @@ class MGgame(ba.TeamGameActivity[Player, Team]): self.coldel15 = True self.coldel16 = True if self.credit_text: - t = ba.newnode('text', + t = bs.newnode('text', attrs={'text': "Made by Freaku\nOriginally for 1.4: byANG3L", # Disable 'Enable Bottom Credits' when making playlist, No need to edit this lovely... 'scale': 0.7, 'position': (0, 0), @@ -317,13 +303,13 @@ class MGgame(ba.TeamGameActivity[Player, Team]): 'color': (1, 1, 1), 'h_align': 'center', 'v_attach': 'bottom'}) - self.spawnAllMap() - self.flashHide() + self.spawnAllMap() + self.flashHide() # Check for immediate end (if we've only got 1 player, etc). - ba.timer(5, self._check_end_game) - self._dingSound = ba.getsound('dingSmall') - self._dingSoundHigh = ba.getsound('dingSmallHigh') + bs.timer(5, self._check_end_game) + self._dingSound = bs.getsound('dingSmall') + self._dingSoundHigh = bs.getsound('dingSmallHigh') def startCounter(self): self._textCounter.text = '10' @@ -339,44 +325,44 @@ class MGgame(ba.TeamGameActivity[Player, Team]): def count1(): def countFinal(): self._textCounter.text = '' - ba.playsound(self._tickFinal) + self._tickFinal.play() self._stop() self._textCounter.text = '1' - ba.playsound(self._tickSound) - ba.timer(1, countFinal) + self._tickSound.play() + bs.timer(1, countFinal) self._textCounter.text = '2' - ba.playsound(self._tickSound) - ba.timer(1, count1) + self._tickSound.play() + bs.timer(1, count1) self._textCounter.text = '3' - ba.playsound(self._tickSound) - ba.timer(1, count2) + self._tickSound.play() + bs.timer(1, count2) self._textCounter.text = '4' - ba.playsound(self._tickSound) - ba.timer(1, count3) + self._tickSound.play() + bs.timer(1, count3) self._textCounter.text = '5' - ba.playsound(self._tickSound) - ba.timer(1, count4) + self._tickSound.play() + bs.timer(1, count4) self._textCounter.text = '6' - ba.playsound(self._tickSound) - ba.timer(1, count5) + self._tickSound.play() + bs.timer(1, count5) self._textCounter.text = '7' - ba.playsound(self._tickSound) - ba.timer(1, count6) + self._tickSound.play() + bs.timer(1, count6) self._textCounter.text = '8' - ba.playsound(self._tickSound) - ba.timer(1, count7) + self._tickSound.play() + bs.timer(1, count7) self._textCounter.text = '9' - ba.playsound(self._tickSound) - ba.timer(1, count8) - ba.timer(1, count9) + self._tickSound.play() + bs.timer(1, count8) + bs.timer(1, count9) def on_player_join(self, player: Player) -> None: # Don't allow joining after we start # (would enable leave/rejoin tomfoolery). if self.has_begun(): - ba.screenmessage( - ba.Lstr(resource='playerDelayedJoinText', - subs=[('${PLAYER}', player.getname(full=True))]), + bs.broadcastmessage( + babase.Lstr(resource='playerDelayedJoinText', + subs=[('${PLAYER}', player.getname(full=True))]), color=(0, 1, 0), transient=True, clients=[player.sessionplayer.inputdevice.client_id]) # For score purposes, mark them as having died right as the # game started. @@ -393,12 +379,12 @@ class MGgame(ba.TeamGameActivity[Player, Team]): self._check_end_game() # overriding the default character spawning.. - def spawn_player(self, player: Player) -> ba.Actor: + def spawn_player(self, player: Player) -> bs.Actor: spaz = self.spawn_player_spaz(player) pos = (self._spawnCenter[0] + random.uniform(-1.5, 2.5), self._spawnCenter[1], self._spawnCenter[2] + random.uniform(-2.5, 1.5)) spaz.connect_controls_to_player(enable_punch=False, enable_bomb=False, enable_pickup=False) - spaz.handlemessage(ba.StandMessage(pos)) + spaz.handlemessage(bs.StandMessage(pos)) return spaz def _randomSelect(self): @@ -453,17 +439,17 @@ class MGgame(ba.TeamGameActivity[Player, Team]): def circle3(): self._imageCircle3.color = (0.0, 1.0, 0.0) self._imageCircle3.opacity = 1.0 - ba.playsound(self._bellHigh) - ba.timer(0.2, self._doDelete) + self._bellHigh.play() + bs.timer(0.2, self._doDelete) self._imageCircle2.color = (1.0, 1.0, 0.0) self._imageCircle2.opacity = 1.0 - ba.playsound(self._bellMed) - ba.timer(1, circle3) + self._bellMed.play() + bs.timer(1, circle3) self._imageCircle.color = (1.0, 0.0, 0.0) self._imageCircle.opacity = 1.0 - ba.playsound(self._bellLow) - ba.timer(1, circle2) - ba.timer(1, circle) + self._bellLow.play() + bs.timer(1, circle2) + bs.timer(1, circle) def _randomPlatform(self): if self._levelStage == 1: @@ -564,13 +550,13 @@ class MGgame(ba.TeamGameActivity[Player, Team]): self._mixPlatform() def _mixPlatform(self): - ba.timer(1, self.flashShow) - ba.timer(3, self.flashHide) - ba.timer(4, self.flashShow) - ba.timer(6, self.flashHide) - ba.timer(7, self.flashShow) - ba.timer(9, self.flashHide) - ba.timer(13.2, self.flashShow) + bs.timer(1, self.flashShow) + bs.timer(3, self.flashHide) + bs.timer(4, self.flashShow) + bs.timer(6, self.flashHide) + bs.timer(7, self.flashShow) + bs.timer(9, self.flashHide) + bs.timer(13.2, self.flashShow) def flashHide(self): self.mapFGP.color_texture = self._mapFGPDefaultTex @@ -674,14 +660,14 @@ class MGgame(ba.TeamGameActivity[Player, Team]): self.mapFGP16col.delete() self.coldel16 = True - ba.timer(3.3, self._platformTexDefault) + bs.timer(3.3, self._platformTexDefault) def spawnAllMap(self): """ # Here's how it works: # First, create prop with a gravity scale of 0 - # Then use a in-game model which will suit it (For this one I didn't chose box, since it will look kinda weird) Right? - # Instead I used a 2d model (which is nothing but a button in menu) + # Then use a in-game mesh which will suit it (For this one I didn't chose box, since it will look kinda weird) Right? + # Instead I used a 2d mesh (which is nothing but a button in menu) # This prop SHOULD NOT collide with anything, since it has gravity_scale of 0 if it'll get weight it will fall down :(( # These are where we change those color-textures and is seen in-game @@ -696,130 +682,130 @@ class MGgame(ba.TeamGameActivity[Player, Team]): """ shared = SharedObjects.get() if self.coldel: - self.mapFGP = ba.newnode('prop', - attrs={'body': 'puck', 'position': (3, 2, -9), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGP = bs.newnode('prop', + attrs={'body': 'puck', 'position': (4.5, 2, -9), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) self.mapFGPTex = None - self.mapFGPcol = ba.newnode('region', attrs={'position': (3, 2, -9), 'scale': ( + self.mapFGPcol = bs.newnode('region', attrs={'position': (4.5, 2, -9), 'scale': ( 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) self.coldel = False if self.coldel2: - self.mapFGP2 = ba.newnode('prop', - attrs={'body': 'puck', 'position': (3, 2, -6), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGP2 = bs.newnode('prop', + attrs={'body': 'puck', 'position': (4.5, 2, -6), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) self.mapFGP2Tex = None - self.mapFGP2col = ba.newnode('region', attrs={'position': (3, 2, -6), 'scale': ( + self.mapFGP2col = bs.newnode('region', attrs={'position': (4.5, 2, -6), 'scale': ( 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) self.coldel2 = False if self.coldel3: - self.mapFGP3 = ba.newnode('prop', - attrs={'body': 'puck', 'position': (3, 2, -3), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGP3 = bs.newnode('prop', + attrs={'body': 'puck', 'position': (4.5, 2, -3), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) self.mapFGP3Tex = None - self.mapFGP3col = ba.newnode('region', attrs={'position': (3, 2, -3), 'scale': ( + self.mapFGP3col = bs.newnode('region', attrs={'position': (4.5, 2, -3), 'scale': ( 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) self.coldel3 = False if self.coldel4: - self.mapFGP4 = ba.newnode('prop', - attrs={'body': 'puck', 'position': (3, 2, 0), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGP4 = bs.newnode('prop', + attrs={'body': 'puck', 'position': (4.5, 2, 0), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) self.mapFGP4Tex = None - self.mapFGP4col = ba.newnode('region', attrs={'position': (3, 2, 0), 'scale': ( + self.mapFGP4col = bs.newnode('region', attrs={'position': (4.5, 2, 0), 'scale': ( 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) self.coldel4 = False if self.coldel5: - self.mapFGP5 = ba.newnode('prop', - attrs={'body': 'puck', 'position': (0, 2, -9), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGP5 = bs.newnode('prop', + attrs={'body': 'puck', 'position': (1.5, 2, -9), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) self.mapFGP5Tex = None - self.mapFGP5col = ba.newnode('region', attrs={'position': (0, 2, -9), 'scale': ( + self.mapFGP5col = bs.newnode('region', attrs={'position': (1.5, 2, -9), 'scale': ( 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) self.coldel5 = False if self.coldel6: - self.mapFGP6 = ba.newnode('prop', - attrs={'body': 'puck', 'position': (0, 2, -6), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGP6 = bs.newnode('prop', + attrs={'body': 'puck', 'position': (1.5, 2, -6), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) self.mapFGP6Tex = None - self.mapFGP6col = ba.newnode('region', attrs={'position': (0, 2, -6), 'scale': ( + self.mapFGP6col = bs.newnode('region', attrs={'position': (1.5, 2, -6), 'scale': ( 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) self.coldel6 = False if self.coldel7: - self.mapFGP7 = ba.newnode('prop', - attrs={'body': 'puck', 'position': (0, 2, -3), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGP7 = bs.newnode('prop', + attrs={'body': 'puck', 'position': (1.5, 2, -3), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) self.mapFGP7Tex = None - self.mapFGP7col = ba.newnode('region', attrs={'position': (0, 2, -3), 'scale': ( + self.mapFGP7col = bs.newnode('region', attrs={'position': (1.5, 2, -3), 'scale': ( 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) self.coldel7 = False if self.coldel8: - self.mapFGP8 = ba.newnode('prop', - attrs={'body': 'puck', 'position': (0, 2, 0), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGP8 = bs.newnode('prop', + attrs={'body': 'puck', 'position': (1.5, 2, 0), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) self.mapFGP8Tex = None - self.mapFGP8col = ba.newnode('region', attrs={'position': (0, 2, 0), 'scale': ( + self.mapFGP8col = bs.newnode('region', attrs={'position': (1.5, 2, 0), 'scale': ( 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) self.coldel8 = False if self.coldel9: - self.mapFGP9 = ba.newnode('prop', - attrs={'body': 'puck', 'position': (-3, 2, -9), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGP9 = bs.newnode('prop', + attrs={'body': 'puck', 'position': (-1.5, 2, -9), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) self.mapFGP9Tex = None - self.mapFGP9col = ba.newnode('region', attrs={'position': (-3, 2, -9), 'scale': ( + self.mapFGP9col = bs.newnode('region', attrs={'position': (-1.5, 2, -9), 'scale': ( 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) self.coldel9 = False if self.coldel10: - self.mapFGP10 = ba.newnode('prop', - attrs={'body': 'puck', 'position': (-3, 2, -6), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGP10 = bs.newnode('prop', + attrs={'body': 'puck', 'position': (-1.5, 2, -6), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) self.mapFGP10Tex = None - self.mapFGP10col = ba.newnode('region', attrs={'position': (-3, 2, -6), 'scale': ( + self.mapFGP10col = bs.newnode('region', attrs={'position': (-1.5, 2, -6), 'scale': ( 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) self.coldel10 = False if self.coldel11: - self.mapFGP11 = ba.newnode('prop', - attrs={'body': 'puck', 'position': (-3, 2, -3), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGP11 = bs.newnode('prop', + attrs={'body': 'puck', 'position': (-1.5, 2, -3), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) self.mapFGP11Tex = None - self.mapFGP11col = ba.newnode('region', attrs={'position': (-3, 2, -3), 'scale': ( + self.mapFGP11col = bs.newnode('region', attrs={'position': (-1.5, 2, -3), 'scale': ( 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) self.coldel11 = False if self.coldel12: - self.mapFGP12 = ba.newnode('prop', - attrs={'body': 'puck', 'position': (-3, 2, 0), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGP12 = bs.newnode('prop', + attrs={'body': 'puck', 'position': (-1.5, 2, 0), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) self.mapFGP12Tex = None - self.mapFGP12col = ba.newnode('region', attrs={'position': (-3, 2, 0), 'scale': ( + self.mapFGP12col = bs.newnode('region', attrs={'position': (-1.5, 2, 0), 'scale': ( 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) self.coldel12 = False if self.coldel13: - self.mapFGP13 = ba.newnode('prop', - attrs={'body': 'puck', 'position': (-6, 2, -9), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGP13 = bs.newnode('prop', + attrs={'body': 'puck', 'position': (-4.5, 2, -9), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) self.mapFGP13Tex = None - self.mapFGP13col = ba.newnode('region', attrs={'position': (-6, 2, -9), 'scale': ( + self.mapFGP13col = bs.newnode('region', attrs={'position': (-4.5, 2, -9), 'scale': ( 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) self.coldel13 = False if self.coldel14: - self.mapFGP14 = ba.newnode('prop', - attrs={'body': 'puck', 'position': (-6, 2, -6), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGP14 = bs.newnode('prop', + attrs={'body': 'puck', 'position': (-4.5, 2, -6), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) self.mapFGP14Tex = None - self.mapFGP14col = ba.newnode('region', attrs={'position': (-6, 2, -6), 'scale': ( + self.mapFGP14col = bs.newnode('region', attrs={'position': (-4.5, 2, -6), 'scale': ( 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) self.coldel14 = False if self.coldel15: - self.mapFGP15 = ba.newnode('prop', - attrs={'body': 'puck', 'position': (-6, 2, -3), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGP15 = bs.newnode('prop', + attrs={'body': 'puck', 'position': (-4.5, 2, -3), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) self.mapFGP15Tex = None - self.mapFGP15col = ba.newnode('region', attrs={'position': (-6, 2, -3), 'scale': ( + self.mapFGP15col = bs.newnode('region', attrs={'position': (-4.5, 2, -3), 'scale': ( 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) self.coldel15 = False if self.coldel16: - self.mapFGP16 = ba.newnode('prop', - attrs={'body': 'puck', 'position': (-6, 2, 0), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGP16 = bs.newnode('prop', + attrs={'body': 'puck', 'position': (-4.5, 2, 0), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) self.mapFGP16Tex = None - self.mapFGP16col = ba.newnode('region', attrs={'position': (-6, 2, 0), 'scale': ( + self.mapFGP16col = bs.newnode('region', attrs={'position': (-4.5, 2, 0), 'scale': ( 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) self.coldel16 = False @@ -843,27 +829,27 @@ class MGgame(ba.TeamGameActivity[Player, Team]): timeStart = 6 else: timeStart = 2 - ba.playsound(self._scoreSound) - activity = _ba.get_foreground_host_activity() + self._scoreSound.play() + activity = bs.get_foreground_host_activity() for i in activity.players: try: - i.actor.node.handlemessage(ba.CelebrateMessage(2.0)) + i.actor.node.handlemessage(bs.CelebrateMessage(2.0)) except: pass - ba.timer(timeStart, self._randomPlatform) - ba.timer(timeStart, self.startCounter) + bs.timer(timeStart, self._randomPlatform) + bs.timer(timeStart, self.startCounter) self.spawnAllMap() self.flashHide() # Various high-level game events come through this method. def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, ba.PlayerDiedMessage): + if isinstance(msg, bs.PlayerDiedMessage): # Augment standard behavior. super().handlemessage(msg) - curtime = ba.time() + curtime = bs.time() # Record the player's moment of death. # assert isinstance(msg.spaz.player @@ -873,15 +859,15 @@ class MGgame(ba.TeamGameActivity[Player, Team]): # (more accurate looking). # In teams/ffa, allow a one-second fudge-factor so we can # get more draws if players die basically at the same time. - if isinstance(self.session, ba.CoopSession): + if isinstance(self.session, bs.CoopSession): # Teams will still show up if we check now.. check in # the next cycle. - ba.pushcall(self._check_end_game) + babase.pushcall(self._check_end_game) # Also record this for a final setting of the clock. self._last_player_death_time = curtime else: - ba.timer(1.0, self._check_end_game) + bs.timer(1.0, self._check_end_game) else: # Default handler: return super().handlemessage(msg) @@ -897,7 +883,7 @@ class MGgame(ba.TeamGameActivity[Player, Team]): # In co-op, we go till everyone is dead.. otherwise we go # until one team remains. - if isinstance(self.session, ba.CoopSession): + if isinstance(self.session, bs.CoopSession): if living_team_count <= 0: self.end_game() else: @@ -905,7 +891,7 @@ class MGgame(ba.TeamGameActivity[Player, Team]): self.end_game() def end_game(self) -> None: - cur_time = ba.time() + cur_time = bs.time() assert self._timer is not None start_time = self._timer.getstarttime() @@ -936,7 +922,7 @@ class MGgame(ba.TeamGameActivity[Player, Team]): # Ok now calc game results: set a score for each team and then tell # the game to end. - results = ba.GameResults() + results = bs.GameResults() # Remember that 'free-for-all' mode is simply a special form # of 'teams' mode where each player gets their own team, so we can @@ -965,7 +951,7 @@ class MGdefs(): (0.0, 0.0, 0.0) + (29.23565494, 14.19991443, 29.92689344) -class MGmap(ba.Map): +class MGmap(bs.Map): defs = MGdefs() name = 'Sky Tiles' @@ -981,23 +967,23 @@ class MGmap(ba.Map): @classmethod def on_preload(cls) -> Any: data: Dict[str, Any] = { - 'bgtex': ba.gettexture('menuBG'), - 'bgmodel': ba.getmodel('thePadBG') + 'bgtex': bs.gettexture('menuBG'), + 'bgmesh': bs.getmesh('thePadBG') } return data def __init__(self) -> None: super().__init__() shared = SharedObjects.get() - self.node = ba.newnode( + self.node = bs.newnode( 'terrain', attrs={ - 'model': self.preloaddata['bgmodel'], + 'mesh': self.preloaddata['bgmesh'], 'lighting': False, 'background': True, 'color_texture': self.preloaddata['bgtex'] }) - gnode = ba.getactivity().globalsnode + 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) @@ -1006,12 +992,12 @@ class MGmap(ba.Map): gnode.vr_near_clip = 0.5 -ba._map.register_map(MGmap) +bs._map.register_map(MGmap) # ba_meta export plugin -class byFreaku(ba.Plugin): +class byFreaku(babase.Plugin): def __init__(self): ## Campaign support ## - ba.app.add_coop_practice_level(ba.Level(name='Memory Game', displayname='${GAME}', gametype=MGgame, settings={ - }, preview_texture_name='achievementOffYouGo')) + babase.app.classic.add_coop_practice_level(bs.Level( + name='Memory Game', displayname='${GAME}', gametype=MGgame, settings={}, preview_texture_name='achievementOffYouGo')) diff --git a/plugins/minigames/musical_flags.py b/plugins/minigames/musical_flags.py index fbe9d2e..7934c10 100644 --- a/plugins/minigames/musical_flags.py +++ b/plugins/minigames/musical_flags.py @@ -1,5 +1,5 @@ # Made by MattZ45986 on GitHub -# Ported by: Freaku / @[Just] Freak#4999 +# Ported by your friend: Freaku # Bug Fixes & Improvements as well... @@ -10,76 +10,69 @@ from __future__ import annotations from typing import TYPE_CHECKING -import _ba -import ba +import _babase import random import math -from bastd.actor.flag import Flag, FlagPickedUpMessage -from bastd.actor.playerspaz import PlayerSpaz +import bascenev1 as bs +from bascenev1lib.actor.flag import Flag, FlagPickedUpMessage +from bascenev1lib.actor.playerspaz import PlayerSpaz if TYPE_CHECKING: from typing import Any, Type, List, Dict, Tuple, Union, Sequence, Optional -class Player(ba.Player['Team']): +class Player(bs.Player['Team']): def __init__(self) -> None: self.done: bool = False self.survived: bool = True -class Team(ba.Team[Player]): +class Team(bs.Team[Player]): def __init__(self) -> None: self.score = 0 -# ba_meta require api 7 -# ba_meta export game -class MFGame(ba.TeamGameActivity[Player, Team]): +# ba_meta require api 8 +# ba_meta export bascenev1.GameActivity +class MFGame(bs.TeamGameActivity[Player, Team]): name = 'Musical Flags' description = "Don't be the one stuck without a flag!" @classmethod def get_available_settings( - cls, sessiontype: Type[ba.Session]) -> List[ba.Setting]: + cls, sessiontype: Type[bs.Session]) -> List[babase.Setting]: settings = [ - ba.IntChoiceSetting( - 'Time Limit', - choices=[ - ('None', 0), - ('1 Minute', 60), - ('2 Minutes', 120), - ('5 Minutes', 300), - ('10 Minutes', 600), - ('20 Minutes', 1200), - ], - default=0, + bs.IntSetting( + 'Max Round Time', + min_value=15, + default=25, + increment=5, ), - ba.BoolSetting('Epic Mode', default=False), - ba.BoolSetting('Enable Running', default=True), - ba.BoolSetting('Enable Punching', default=False), - ba.BoolSetting('Enable Bottom Credit', True) + bs.BoolSetting('Epic Mode', default=False), + bs.BoolSetting('Enable Running', default=True), + bs.BoolSetting('Enable Punching', default=False), + bs.BoolSetting('Enable Bottom Credit', True) ] return settings @classmethod - def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool: - return (issubclass(sessiontype, ba.DualTeamSession) - or issubclass(sessiontype, ba.FreeForAllSession)) + def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool: + return (issubclass(sessiontype, bs.DualTeamSession) + or issubclass(sessiontype, bs.FreeForAllSession)) @classmethod - def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: + def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]: return ['Doom Shroom'] def __init__(self, settings: dict): super().__init__(settings) self.nodes = [] - self._dingsound = ba.getsound('dingSmall') + self._dingsound = bs.getsound('dingSmall') self._epic_mode = bool(settings['Epic Mode']) self.credit_text = bool(settings['Enable Bottom Credit']) - self._time_limit = float(settings['Time Limit']) self.is_punch = bool(settings['Enable Punching']) self.is_run = bool(settings['Enable Running']) - self._textRound = ba.newnode('text', + self._textRound = bs.newnode('text', attrs={'text': '', 'position': (0, -38), 'scale': 1, @@ -91,10 +84,16 @@ class MFGame(ba.TeamGameActivity[Player, Team]): 'h_attach': 'center', 'h_align': 'center', 'v_align': 'center'}) + self.round_time = int(settings['Max Round Time']) + self.reset_round_time = int(settings['Max Round Time']) + self.should_die_occur = True + self.round_time_textnode = bs.newnode('text', + attrs={ + 'text': "", 'flatness': 1.0, 'h_align': 'center', 'h_attach': 'center', 'v_attach': 'top', 'v_align': 'center', 'position': (0, -15), 'scale': 0.9, 'color': (1, 0.7, 0.9)}) self.slow_motion = self._epic_mode # A cool music, matching our gamemode theme - self.default_music = ba.MusicType.FLAG_CATCHER + self.default_music = bs.MusicType.FLAG_CATCHER def get_instance_description(self) -> Union[str, Sequence]: return 'Catch Flag for yourself' @@ -104,8 +103,8 @@ class MFGame(ba.TeamGameActivity[Player, Team]): def on_player_join(self, player: Player) -> None: if self.has_begun(): - ba.screenmessage( - ba.Lstr(resource='playerDelayedJoinText', + bs.broadcastmessage( + bs.Lstr(resource='playerDelayedJoinText', subs=[('${PLAYER}', player.getname(full=True))]), color=(0, 1, 0), transient=True) player.survived = False @@ -115,7 +114,7 @@ class MFGame(ba.TeamGameActivity[Player, Team]): def on_player_leave(self, player: Player) -> None: super().on_player_leave(player) # A departing player may trigger game-over. - self.checkEnd() + bs.timer(0, self.checkEnd) def on_begin(self) -> None: super().on_begin() @@ -124,9 +123,8 @@ class MFGame(ba.TeamGameActivity[Player, Team]): self.nodes = [] self.flags = [] self.spawned = [] - self.setup_standard_time_limit(self._time_limit) if self.credit_text: - t = ba.newnode('text', + t = bs.newnode('text', attrs={'text': "Ported by Freaku\nMade by MattZ45986", # Disable 'Enable Bottom Credits' when making playlist, No need to edit this lovely... 'scale': 0.7, 'position': (0, 0), @@ -137,7 +135,32 @@ class MFGame(ba.TeamGameActivity[Player, Team]): 'v_attach': 'bottom'}) self.makeRound() self._textRound.text = 'Round ' + str(self.roundNum) - ba.timer(5, self.checkEnd) + bs.timer(3, self.checkEnd) + self.keepcalling = bs.timer(1, self._timeround, True) + + def _timeround(self): + if self.round_time == 0 and self.should_die_occur: + self.should_die_occur = False + self.round_time_textnode.opacity = 0 + bs.broadcastmessage('Proceeding Round...') + for player in self.spawned: + if not player.done: + try: + player.survived = False + player.actor.handlemessage(bs.StandMessage((0, 3, -2))) + bs.timer(0.5, bs.Call(player.actor.handlemessage, bs.FreezeMessage())) + bs.timer(1.5, bs.Call(player.actor.handlemessage, bs.FreezeMessage())) + bs.timer(2.5, bs.Call(player.actor.handlemessage, bs.FreezeMessage())) + bs.timer(3, bs.Call(player.actor.handlemessage, bs.ShouldShatterMessage())) + except: + pass + bs.timer(3.5, self.killRound) + bs.timer(3.55, self.makeRound) + self.round_time_textnode.opacity = 0 + self.round_time = self.reset_round_time + else: + self.round_time_textnode.text = "Time: " + str(self.round_time) + self.round_time -= 1 def makeRound(self): for player in self.players: @@ -147,6 +170,9 @@ class MFGame(ba.TeamGameActivity[Player, Team]): self._textRound.text = 'Round ' + str(self.roundNum) self.flags = [] self.spawned = [] + self.should_die_occur = True + self.round_time = self.reset_round_time + self.round_time_textnode.opacity = 1 angle = random.randint(0, 359) c = 0 for player in self.players: @@ -165,6 +191,13 @@ class MFGame(ba.TeamGameActivity[Player, Team]): self.checkEnd() colors = [(1, 0, 0), (0, 1, 0), (0, 0, 1), (1, 1, 0), (1, 0, 1), (0, 1, 1), (0, 0, 0), (0.5, 0.8, 0), (0, 0.8, 0.5), (0.8, 0.25, 0.7), (0, 0.27, 0.55), (2, 2, 0.6), (0.4, 3, 0.85)] + + # Add support for more than 13 players + if c > 12: + for i in range(c-12): + colors.append((random.uniform(0.1, 1), random.uniform( + 0.1, 1), random.uniform(0.1, 1))) + # Smart Mathematics: # All Flags spawn same distance from the players for i in range(c-1): @@ -179,19 +212,19 @@ class MFGame(ba.TeamGameActivity[Player, Team]): self.numPickedUp = 0 for player in self.players: if player.is_alive(): - player.actor.handlemessage(ba.DieMessage()) + player.actor.handlemessage(bs.DieMessage()) for flag in self.flags: flag.node.delete() for light in self.nodes: light.delete() - def spawn_player(self, player: Player, pos: tuple = (0, 0, 0)) -> ba.Actor: + def spawn_player(self, player: Player, pos: tuple = (0, 0, 0)) -> bs.Actor: spaz = self.spawn_player_spaz(player) if pos == (0, 0, 0): pos = (-.5+random.random()*2, 3+random.random()*2, -5+random.random()*2) spaz.connect_controls_to_player(enable_punch=self.is_punch, enable_bomb=False, enable_run=self.is_run) - spaz.handlemessage(ba.StandMessage(pos)) + spaz.handlemessage(bs.StandMessage(pos)) return spaz def check_respawn(self, player): @@ -200,36 +233,38 @@ class MFGame(ba.TeamGameActivity[Player, Team]): def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, ba.PlayerDiedMessage): + if isinstance(msg, bs.PlayerDiedMessage): super().handlemessage(msg) player = msg.getplayer(Player) - ba.timer(0.1, ba.Call(self.check_respawn, player)) - ba.timer(0.5, self.checkEnd) + bs.timer(0.1, bs.Call(self.check_respawn, player)) + bs.timer(0.5, self.checkEnd) elif isinstance(msg, FlagPickedUpMessage): self.numPickedUp += 1 msg.node.getdelegate(PlayerSpaz, True).getplayer(Player, True).done = True - l = ba.newnode('light', + l = bs.newnode('light', owner=None, attrs={'color': msg.node.color, 'position': (msg.node.position_center), 'intensity': 1}) self.nodes.append(l) - msg.flag.handlemessage(ba.DieMessage()) - msg.node.handlemessage(ba.DieMessage()) + msg.flag.handlemessage(bs.DieMessage()) + msg.node.handlemessage(bs.DieMessage()) msg.node.delete() if self.numPickedUp == len(self.flags): + self.round_time_textnode.opacity = 0 + self.round_time = self.reset_round_time for player in self.spawned: if not player.done: try: player.survived = False - ba.screenmessage("No Flag? "+player.getname()) - player.actor.handlemessage(ba.StandMessage((0, 3, -2))) - ba.timer(0.5, ba.Call(player.actor.handlemessage, ba.FreezeMessage())) - ba.timer(3, ba.Call(player.actor.handlemessage, ba.ShouldShatterMessage())) + bs.broadcastmessage("No Flag? "+player.getname()) + player.actor.handlemessage(bs.StandMessage((0, 3, -2))) + bs.timer(0.5, bs.Call(player.actor.handlemessage, bs.FreezeMessage())) + bs.timer(3, bs.Call(player.actor.handlemessage, bs.ShouldShatterMessage())) except: pass - ba.timer(3.5, self.killRound) - ba.timer(3.55, self.makeRound) + bs.timer(3.5, self.killRound) + bs.timer(3.55, self.makeRound) else: return super().handlemessage(msg) return None @@ -243,10 +278,10 @@ class MFGame(ba.TeamGameActivity[Player, Team]): for player in self.players: if player.survived: player.team.score += 10 - ba.timer(2.5, self.end_game) + bs.timer(2.5, self.end_game) def end_game(self) -> None: - results = ba.GameResults() + results = bs.GameResults() for team in self.teams: results.set_team_score(team, team.score) self.end(results=results) diff --git a/plugins/minigames/quake_original.py b/plugins/minigames/quake_original.py new file mode 100644 index 0000000..84ff0f6 --- /dev/null +++ b/plugins/minigames/quake_original.py @@ -0,0 +1,624 @@ +# Created By Idk +# Ported to 1.7 by Yan + +# ba_meta require api 8 +from __future__ import annotations + +from typing import TYPE_CHECKING + +from bascenev1lib.actor.powerupbox import PowerupBox as Powerup +from bascenev1lib.actor.playerspaz import PlayerSpaz +from bascenev1lib.actor.scoreboard import Scoreboard +from bascenev1lib.gameutils import SharedObjects + +import bascenev1lib.actor.bomb +import bascenev1lib.actor.spaz +import weakref +import random +import math +import babase +import bauiv1 as bui +import bascenev1 as bs + +if TYPE_CHECKING: + pass + + +class TouchedToSpaz(object): + pass + + +class TouchedToAnything(object): + pass + + +class TouchedToFootingMaterial(object): + pass + + +class QuakeBallFactory(object): + """Components used by QuakeBall stuff + + category: Game Classes + + """ + _STORENAME = babase.storagename() + + @classmethod + def get(cls) -> QuakeBallFactory: + """Get/create a shared bascenev1lib.actor.bomb.BombFactory object.""" + activity = bs.getactivity() + factory = activity.customdata.get(cls._STORENAME) + if factory is None: + factory = QuakeBallFactory() + activity.customdata[cls._STORENAME] = factory + assert isinstance(factory, QuakeBallFactory) + return factory + + def __init__(self): + shared = SharedObjects.get() + + self.ball_material = bs.Material() + + self.ball_material.add_actions( + conditions=((('we_are_younger_than', 5), 'or', ('they_are_younger_than', 50)), + 'and', ('they_have_material', shared.object_material)), + actions=(('modify_node_collision', 'collide', False))) + + self.ball_material.add_actions( + conditions=('they_have_material', shared.pickup_material), + actions=(('modify_part_collision', 'use_node_collide', False))) + + self.ball_material.add_actions( + actions=('modify_part_collision', 'friction', 0)) + + self.ball_material.add_actions( + conditions=('they_have_material', shared.player_material), + actions=(('modify_part_collision', 'physical', False), + ('message', 'our_node', 'at_connect', TouchedToSpaz()))) + + self.ball_material.add_actions( + conditions=(('they_dont_have_material', shared.player_material), 'and', + ('they_have_material', shared.object_material)), + actions=('message', 'our_node', 'at_connect', TouchedToAnything())) + + self.ball_material.add_actions( + conditions=(('they_dont_have_material', shared.player_material), 'and', + ('they_have_material', shared.footing_material)), + actions=('message', 'our_node', 'at_connect', TouchedToFootingMaterial())) + + def give(self, spaz): + spaz.punch_callback = self.shot + self.last_shot = int(bs.time() * 1000) + + def shot(self, spaz): + time = int(bs.time() * 1000) + if time - self.last_shot > 0.6: + self.last_shot = time + p1 = spaz.node.position_center + p2 = spaz.node.position_forward + direction = [p1[0]-p2[0], p2[1]-p1[1], p1[2]-p2[2]] + direction[1] = 0.0 + + mag = 10.0/babase.Vec3(*direction).length() + vel = [v * mag for v in direction] + QuakeBall( + position=spaz.node.position, + velocity=(vel[0]*2, vel[1]*2, vel[2]*2), + owner=spaz._player, + source_player=spaz._player, + color=spaz.node.color).autoretain() + + +class QuakeBall(bs.Actor): + + def __init__(self, + position=(0, 5, 0), + velocity=(0, 2, 0), + source_player=None, + owner=None, + color=(random.random(), random.random(), random.random()), + light_radius=0 + ): + super().__init__() + + shared = SharedObjects.get() + b_shared = QuakeBallFactory.get() + + self.source_player = source_player + self.owner = owner + + self.node = bs.newnode('prop', delegate=self, attrs={ + 'position': position, + 'velocity': velocity, + 'mesh': bs.getmesh('impactBomb'), + 'body': 'sphere', + 'color_texture': bs.gettexture('bunnyColor'), + 'mesh_scale': 0.2, + 'is_area_of_interest': True, + 'body_scale': 0.8, + 'materials': [shared.object_material, + b_shared.ball_material]}) + + self.light_node = bs.newnode('light', attrs={ + 'position': position, + 'color': color, + 'radius': 0.1+light_radius, + 'volume_intensity_scale': 15.0}) + + self.node.connectattr('position', self.light_node, 'position') + self.emit_time = bs.Timer(0.015, bs.WeakCall(self.emit), repeat=True) + self.life_time = bs.Timer(5.0, bs.WeakCall(self.handlemessage, bs.DieMessage())) + + def emit(self): + bs.emitfx( + position=self.node.position, + velocity=self.node.velocity, + count=10, + scale=0.4, + spread=0.01, + chunk_type='spark') + + def handlemessage(self, m): + if isinstance(m, TouchedToAnything): + node = bs.getcollision().opposingnode + if node is not None and node.exists(): + v = self.node.velocity + t = self.node.position + hitdir = self.node.velocity + m = self.node + node.handlemessage( + bs.HitMessage( + pos=t, + velocity=v, + magnitude=babase.Vec3(*v).length()*40, + velocity_magnitude=babase.Vec3(*v).length()*40, + radius=0, + srcnode=self.node, + source_player=self.source_player, + force_direction=hitdir)) + + self.node.handlemessage(bs.DieMessage()) + + elif isinstance(m, bs.DieMessage): + if self.node.exists(): + velocity = self.node.velocity + explosion = bs.newnode('explosion', attrs={ + 'position': self.node.position, + 'velocity': (velocity[0], max(-1.0, velocity[1]), velocity[2]), + 'radius': 1, + 'big': False}) + + bs.getsound(random.choice(['impactHard', 'impactHard2', 'impactHard3'])).play(), + position = self.node.position + + self.emit_time = None + self.light_node.delete() + self.node.delete() + + elif isinstance(m, bs.OutOfBoundsMessage): + self.handlemessage(bs.DieMessage()) + + elif isinstance(m, bs.HitMessage): + self.node.handlemessage('impulse', m.pos[0], m.pos[1], m.pos[2], + m.velocity[0], m.velocity[1], m.velocity[2], + 1.0*m.magnitude, 1.0*m.velocity_magnitude, m.radius, 0, + m.force_direction[0], m.force_direction[1], m.force_direction[2]) + + elif isinstance(m, TouchedToSpaz): + node = bs.getcollision() .opposingnode + if node is not None and node.exists() and node != self.owner \ + and node.getdelegate(object)._player.team != self.owner.team: + node.handlemessage(bs.FreezeMessage()) + v = self.node.velocity + t = self.node.position + hitdir = self.node.velocity + + node.handlemessage( + bs.HitMessage( + pos=t, + velocity=(10, 10, 10), + magnitude=50, + velocity_magnitude=50, + radius=0, + srcnode=self.node, + source_player=self.source_player, + force_direction=hitdir)) + + self.node.handlemessage(bs.DieMessage()) + + elif isinstance(m, TouchedToFootingMaterial): + bs.getsound('blip').play(), + position = self.node.position + else: + super().handlemessage(m) + + +class Player(bs.Player['Team']): + ... + + +class Team(bs.Team[Player]): + """Our team type for this game.""" + + def __init__(self) -> None: + self.score = 0 + +# ba_meta export bascenev1.GameActivity + + +class QuakeGame(bs.TeamGameActivity[Player, Team]): + """A game type based on acquiring kills.""" + + name = 'Quake' + description = 'Kill a set number of enemies to win.' + + # Print messages when players die since it matters here. + announce_player_deaths = True + + @classmethod + def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool: + return issubclass(sessiontype, bs.DualTeamSession) or issubclass( + sessiontype, bs.FreeForAllSession + ) + + @classmethod + def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]: + return ['Doom Shroom', 'Monkey Face', 'Football Stadium'] + + @classmethod + def get_available_settings( + cls, sessiontype: type[bs.Session] + ) -> list[babase.Setting]: + settings = [ + bs.IntSetting( + 'Kills to Win Per Player', + min_value=1, + default=5, + 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.IntChoiceSetting( + 'Graphics', + choices=[ + ('Normal', 1), + ('High', 2) + ], + default=1), + bs.BoolSetting('Fast Movespeed', default=True), + bs.BoolSetting('Enable Jump', default=False), + bs.BoolSetting('Enable Pickup', default=False), + bs.BoolSetting('Enable Bomb', default=False), + bs.BoolSetting('Obstacles', default=False), + bs.IntChoiceSetting( + 'Obstacles Shape', + choices=[ + ('Cube', 1), + ('Sphere', 2), + ('Puck', 3), + ('Egg', 4), + ('Random', 5), + ], + default=1), + bs.BoolSetting('Obstacles Bounces Shots', default=False), + bs.IntSetting( + 'Obstacle Count', + min_value=1, + default=16, + increment=1, + ), + bs.BoolSetting('Random Obstacle Color', default=True), + bs.BoolSetting('Epic Mode', default=False), + ] + return settings + + def __init__(self, settings: dict): + super().__init__(settings) + self._scoreboard = Scoreboard() + self._score_to_win: int | None = None + self._dingsound = bs.getsound('dingSmall') + self._epic_mode = bool(settings['Epic Mode']) + self._kills_to_win_per_player = int(settings['Kills to Win Per Player']) + self._time_limit = float(settings['Time Limit']) + self._allow_negative_scores = bool( + settings.get('Allow Negative Scores', False) + ) + + # Base class overrides. + self.slow_motion = self._epic_mode + self.default_music = ( + bs.MusicType.EPIC if self._epic_mode else bs.MusicType.TO_THE_DEATH + ) + self.settings = settings + + def get_instance_description(self) -> str | Sequence: + return 'Crush ${ARG1} of your enemies.', self._score_to_win + + def get_instance_description_short(self) -> str | Sequence: + return 'kill ${ARG1} enemies', self._score_to_win + + def on_team_join(self, team: Team) -> None: + if self.has_begun(): + self._update_scoreboard() + + def on_begin(self) -> None: + super().on_begin() + self.dingsound = bs.getsound('dingSmall') + self.setup_standard_time_limit(self._time_limit) + + self.drop_shield() + self.drop_shield_timer = bs.Timer(8.001, bs.WeakCall(self.drop_shield), repeat=True) + + shared = SharedObjects.get() + if self.settings['Obstacles']: + count = self.settings['Obstacle Count'] + map = bs.getactivity()._map.getname() + for i in range(count): + if map == 'Football Stadium': + radius = (random.uniform(-10, 1), + 6, + random.uniform(-4.5, 4.5)) \ + if i > count/2 else (random.uniform(10, 1), 6, random.uniform(-4.5, 4.5)) + else: + radius = (random.uniform(-10, 1), + 6, + random.uniform(-8, 8)) \ + if i > count/2 else (random.uniform(10, 1), 6, random.uniform(-8, 8)) + + Obstacle( + position=radius, + graphics=self.settings['Graphics'], + random_color=self.settings['Random Obstacle Color'], + rebound=self.settings['Obstacles Bounces Shots'], + shape=int(self.settings['Obstacles Shape'])).autoretain() + + if self.settings['Graphics'] == 2: + bs.getactivity().globalsnode.tint = (bs.getactivity( + ).globalsnode.tint[0]-0.6, bs.getactivity().globalsnode.tint[1]-0.6, bs.getactivity().globalsnode.tint[2]-0.6) + light = bs.newnode('light', attrs={ + 'position': (9, 10, 0) if map == 'Football Stadium' else (6, 7, -2) + if not map == 'Rampage' else (6, 11, -2) if not map == 'The Pad' else (6, 8.5, -2), + 'color': (0.4, 0.4, 0.45), + 'radius': 1, + 'intensity': 6, + 'volume_intensity_scale': 10.0}) + + light2 = bs.newnode('light', attrs={ + 'position': (-9, 10, 0) if map == 'Football Stadium' else (-6, 7, -2) + if not map == 'Rampage' else (-6, 11, -2) if not map == 'The Pad' else (-6, 8.5, -2), + 'color': (0.4, 0.4, 0.45), + 'radius': 1, + 'intensity': 6, + 'volume_intensity_scale': 10.0}) + + if len(self.teams) > 0: + self._score_to_win = self.settings['Kills to Win Per Player'] * \ + max(1, max(len(t.players) for t in self.teams)) + else: + self._score_to_win = self.settings['Kills to Win Per Player'] + self._update_scoreboard() + + def drop_shield(self): + p = Powerup( + poweruptype='shield', + position=(random.uniform(-10, 10), 6, random.uniform(-5, 5))).autoretain() + + bs.getsound('dingSmall').play() + + p_light = bs.newnode('light', attrs={ + 'position': (0, 0, 0), + 'color': (0.3, 0.0, 0.4), + 'radius': 0.3, + 'intensity': 2, + 'volume_intensity_scale': 10.0}) + + p.node.connectattr('position', p_light, 'position') + + bs.animate(p_light, 'intensity', {0: 2, 8000: 0}) + + def check_exists(): + if p is None or p.node.exists() == False: + delete_light() + del_checker() + + self._checker = bs.Timer(0.1, babase.Call(check_exists), repeat=True) + + def del_checker(): + if self._checker is not None: + self._checker = None + + def delete_light(): + if p_light.exists(): + p_light.delete() + + bs.timer(6.9, babase.Call(del_checker)) + bs.timer(7.0, babase.Call(delete_light)) + + def spawn_player(self, player: bs.Player): + spaz = self.spawn_player_spaz(player) + QuakeBallFactory().give(spaz) + spaz.connect_controls_to_player( + enable_jump=self.settings['Enable Jump'], + enable_punch=True, + enable_pickup=self.settings['Enable Pickup'], + enable_bomb=self.settings['Enable Bomb'], + enable_run=True, + enable_fly=False) + + if self.settings['Fast Movespeed']: + spaz.node.hockey = True + spaz.spaz_light = bs.newnode('light', attrs={ + 'position': (0, 0, 0), + 'color': spaz.node.color, + 'radius': 0.12, + 'intensity': 1, + 'volume_intensity_scale': 10.0}) + + spaz.node.connectattr('position', spaz.spaz_light, 'position') + + 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) + + killer = msg.getkillerplayer(Player) + if hasattr(player.actor, 'spaz_light'): + player.actor.spaz_light.delete() + if killer is None: + return None + + # Handle team-kills. + if killer.team is player.team: + + # In free-for-all, killing yourself loses you a point. + if isinstance(self.session, bs.FreeForAllSession): + new_score = player.team.score - 1 + if not self._allow_negative_scores: + new_score = max(0, new_score) + player.team.score = new_score + + # In teams-mode it gives a point to the other team. + else: + self._dingsound.play() + for team in self.teams: + if team is not killer.team: + team.score += 1 + + # Killing someone on another team nets a kill. + else: + killer.team.score += 1 + self._dingsound.play() + + # In FFA show scores since its hard to find on the scoreboard. + if isinstance(killer.actor, PlayerSpaz) and killer.actor: + killer.actor.set_score_text( + str(killer.team.score) + '/' + str(self._score_to_win), + color=killer.team.color, + flash=True, + ) + + self._update_scoreboard() + + # If someone has won, set a timer to end shortly. + # (allows the dust to clear and draws to occur if deaths are + # close enough) + assert self._score_to_win is not None + if any(team.score >= self._score_to_win for team in self.teams): + bs.timer(0.5, self.end_game) + + else: + return super().handlemessage(msg) + return None + + def _update_scoreboard(self) -> None: + for team in self.teams: + self._scoreboard.set_team_value( + team, team.score, self._score_to_win + ) + + def end_game(self) -> None: + results = bs.GameResults() + for team in self.teams: + results.set_team_score(team, team.score) + self.end(results=results) + + +class Obstacle(bs.Actor): + + def __init__(self, + position: tuple(float, float, float), + graphics: bool, + random_color: bool, + rebound: bool, + shape: int) -> None: + super().__init__() + + shared = SharedObjects.get() + if shape == 1: + mesh = 'tnt' + body = 'crate' + elif shape == 2: + mesh = 'bomb' + body = 'sphere' + elif shape == 3: + mesh = 'puck' + body = 'puck' + elif shape == 4: + mesh = 'egg' + body = 'capsule' + elif shape == 5: + pair = random.choice([ + {'mesh': 'tnt', 'body': 'crate'}, + {'mesh': 'bomb', 'body': 'sphere'}, + {'mesh': 'puckModel', 'body': 'puck'}, + {'mesh': 'egg', 'body': 'capsule'} + ]) + mesh = pair['mesh'] + body = pair['body'] + + self.node = bs.newnode('prop', delegate=self, attrs={ + 'position': position, + 'mesh': bs.getmesh(mesh), + 'body': body, + 'body_scale': 1.3, + 'mesh_scale': 1.3, + 'reflection': 'powerup', + 'reflection_scale': [0.7], + 'color_texture': bs.gettexture('bunnyColor'), + 'materials': [shared.footing_material if rebound else shared.object_material, + shared.footing_material]}) + + if graphics == 2: + self.light_node = bs.newnode('light', attrs={ + 'position': (0, 0, 0), + 'color': ((0.8, 0.2, 0.2) if i < count/2 else (0.2, 0.2, 0.8)) + if not random_color else ((random.uniform(0, 1.1), random.uniform(0, 1.1), random.uniform(0, 1.1))), + 'radius': 0.2, + 'intensity': 1, + 'volume_intensity_scale': 10.0}) + + self.node.connectattr('position', self.light_node, 'position') + + def handlemessage(self, m): + if isinstance(m, bs.DieMessage): + if self.node.exists(): + if hasattr(self, 'light_node'): + self.light_node.delete() + self.node.delete() + + elif isinstance(m, bs.OutOfBoundsMessage): + if self.node.exists(): + self.handlemessage(bs.DieMessage()) + + elif isinstance(m, bs.HitMessage): + self.node.handlemessage('impulse', m.pos[0], m.pos[1], m.pos[2], + m.velocity[0], m.velocity[1], m.velocity[2], + m.magnitude, m.velocity_magnitude, m.radius, 0, + m.velocity[0], m.velocity[1], m.velocity[2]) diff --git a/plugins/minigames/soccer.py b/plugins/minigames/soccer.py index d86c7d5..cd9b4f5 100644 --- a/plugins/minigames/soccer.py +++ b/plugins/minigames/soccer.py @@ -2,18 +2,20 @@ # BY Stary_Agent """Hockey game and support classes.""" -# ba_meta require api 7 +# ba_meta require api 8 # (see https://ballistica.net/wiki/meta-tag-system) from __future__ import annotations from typing import TYPE_CHECKING -import ba -from bastd.actor.playerspaz import PlayerSpaz -from bastd.actor.scoreboard import Scoreboard -from bastd.actor.powerupbox import PowerupBoxFactory -from bastd.gameutils import SharedObjects +import babase +import bauiv1 as bui +import bascenev1 as bs +from bascenev1lib.actor.playerspaz import PlayerSpaz +from bascenev1lib.actor.scoreboard import Scoreboard +from bascenev1lib.actor.powerupbox import PowerupBoxFactory +from bascenev1lib.gameutils import SharedObjects if TYPE_CHECKING: from typing import Any, Sequence, Dict, Type, List, Optional, Union @@ -26,7 +28,7 @@ class PuckDiedMessage: self.puck = puck -class Puck(ba.Actor): +class Puck(bs.Actor): """A lovely giant hockey puck.""" def __init__(self, position: Sequence[float] = (0.0, 1.0, 0.0)): @@ -41,10 +43,10 @@ class Puck(ba.Actor): assert activity is not None assert isinstance(activity, HockeyGame) pmats = [shared.object_material, activity.puck_material] - self.node = ba.newnode('prop', + self.node = bs.newnode('prop', delegate=self, attrs={ - 'model': activity.puck_model, + 'mesh': activity.puck_model, 'color_texture': activity.puck_tex, 'body': 'sphere', 'reflection': 'soft', @@ -54,10 +56,10 @@ class Puck(ba.Actor): 'position': self._spawn_pos, 'materials': pmats }) - ba.animate(self.node, 'model_scale', {0: 0, 0.2: 1.3, 0.26: 1}) + bs.animate(self.node, 'mesh_scale', {0: 0, 0.2: 1.3, 0.26: 1}) def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, ba.DieMessage): + if isinstance(msg, bs.DieMessage): assert self.node self.node.delete() activity = self._activity() @@ -65,11 +67,11 @@ class Puck(ba.Actor): activity.handlemessage(PuckDiedMessage(self)) # If we go out of bounds, move back to where we started. - elif isinstance(msg, ba.OutOfBoundsMessage): + elif isinstance(msg, bs.OutOfBoundsMessage): assert self.node self.node.position = self._spawn_pos - elif isinstance(msg, ba.HitMessage): + elif isinstance(msg, bs.HitMessage): assert self.node assert msg.force_direction is not None self.node.handlemessage( @@ -90,31 +92,31 @@ class Puck(ba.Actor): super().handlemessage(msg) -class Player(ba.Player['Team']): +class Player(bs.Player['Team']): """Our player type for this game.""" -class Team(ba.Team[Player]): +class Team(bs.Team[Player]): """Our team type for this game.""" def __init__(self) -> None: self.score = 0 -# ba_meta export game -class HockeyGame(ba.TeamGameActivity[Player, Team]): +# ba_meta export bascenev1.GameActivity +class HockeyGame(bs.TeamGameActivity[Player, Team]): """Ice hockey game.""" name = 'Epic Soccer' description = 'Score some goals.' available_settings = [ - ba.IntSetting( + bs.IntSetting( 'Score to Win', min_value=1, default=1, increment=1, ), - ba.IntChoiceSetting( + bs.IntChoiceSetting( 'Time Limit', choices=[ ('None', 0), @@ -126,7 +128,7 @@ class HockeyGame(ba.TeamGameActivity[Player, Team]): ], default=0, ), - ba.FloatChoiceSetting( + bs.FloatChoiceSetting( 'Respawn Times', choices=[ ('Shorter', 0.1), @@ -138,31 +140,32 @@ class HockeyGame(ba.TeamGameActivity[Player, Team]): default=1.0, ), ] - default_music = ba.MusicType.HOCKEY + default_music = bs.MusicType.HOCKEY @classmethod - def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool: - return issubclass(sessiontype, ba.DualTeamSession) + def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool: + return issubclass(sessiontype, bs.DualTeamSession) @classmethod - def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: - return ba.getmaps('football') + def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]: + assert babase.app.classic is not None + return babase.app.classic.getmaps('football') def __init__(self, settings: dict): super().__init__(settings) shared = SharedObjects.get() self.slow_motion = True self._scoreboard = Scoreboard() - self._cheer_sound = ba.getsound('cheer') - self._chant_sound = ba.getsound('crowdChant') - self._foghorn_sound = ba.getsound('foghorn') - self._swipsound = ba.getsound('swip') - self._whistle_sound = ba.getsound('refWhistle') - self.puck_model = ba.getmodel('bomb') - self.puck_tex = ba.gettexture('landMine') - self.puck_scored_tex = ba.gettexture('landMineLit') - self._puck_sound = ba.getsound('metalHit') - self.puck_material = ba.Material() + self._cheer_sound = bui.getsound('cheer') + self._chant_sound = bui.getsound('crowdChant') + self._foghorn_sound = bui.getsound('foghorn') + self._swipsound = bui.getsound('swip') + self._whistle_sound = bui.getsound('refWhistle') + self.puck_model = bs.getmesh('bomb') + self.puck_tex = bs.gettexture('landMine') + self.puck_scored_tex = bs.gettexture('landMineLit') + self._puck_sound = bs.getsound('metalHit') + self.puck_material = bs.Material() self.puck_material.add_actions(actions=(('modify_part_collision', 'friction', 0.5))) self.puck_material.add_actions(conditions=('they_have_material', @@ -193,15 +196,15 @@ class HockeyGame(ba.TeamGameActivity[Player, Team]): conditions=('they_have_material', PowerupBoxFactory.get().powerup_material), actions=(('modify_part_collision', 'physical', False), - ('message', 'their_node', 'at_connect', ba.DieMessage()))) - self._score_region_material = ba.Material() + ('message', 'their_node', 'at_connect', bs.DieMessage()))) + self._score_region_material = bs.Material() self._score_region_material.add_actions( conditions=('they_have_material', self.puck_material), actions=(('modify_part_collision', 'collide', True), ('modify_part_collision', 'physical', False), ('call', 'at_connect', self._handle_score))) self._puck_spawn_pos: Optional[Sequence[float]] = None - self._score_regions: Optional[List[ba.NodeActor]] = None + self._score_regions: Optional[List[bs.NodeActor]] = None self._puck: Optional[Puck] = None self._score_to_win = int(settings['Score to Win']) self._time_limit = float(settings['Time Limit']) @@ -228,8 +231,8 @@ class HockeyGame(ba.TeamGameActivity[Player, Team]): defs = self.map.defs self._score_regions = [] self._score_regions.append( - ba.NodeActor( - ba.newnode('region', + bs.NodeActor( + bs.newnode('region', attrs={ 'position': defs.boxes['goal1'][0:3], 'scale': defs.boxes['goal1'][6:9], @@ -237,8 +240,8 @@ class HockeyGame(ba.TeamGameActivity[Player, Team]): 'materials': [self._score_region_material] }))) self._score_regions.append( - ba.NodeActor( - ba.newnode('region', + bs.NodeActor( + bs.newnode('region', attrs={ 'position': defs.boxes['goal2'][0:3], 'scale': defs.boxes['goal2'][6:9], @@ -246,19 +249,19 @@ class HockeyGame(ba.TeamGameActivity[Player, Team]): 'materials': [self._score_region_material] }))) self._update_scoreboard() - ba.playsound(self._chant_sound) + self._chant_sound.play() def on_team_join(self, team: Team) -> None: self._update_scoreboard() def _handle_puck_player_collide(self) -> None: - collision = ba.getcollision() + collision = bs.getcollision() try: puck = collision.sourcenode.getdelegate(Puck, True) player = collision.opposingnode.getdelegate(PlayerSpaz, True).getplayer( Player, True) - except ba.NotFoundError: + except bs.NotFoundError: return puck.last_players_to_touch[player.team.id] = player @@ -277,7 +280,7 @@ class HockeyGame(ba.TeamGameActivity[Player, Team]): if self._puck.scored: return - region = ba.getcollision().sourcenode + region = bs.getcollision().sourcenode index = 0 for index in range(len(self._score_regions)): if region == self._score_regions[index].node: @@ -291,7 +294,7 @@ class HockeyGame(ba.TeamGameActivity[Player, Team]): # Tell all players to celebrate. for player in team.players: if player.actor: - player.actor.handlemessage(ba.CelebrateMessage(2.0)) + player.actor.handlemessage(bs.CelebrateMessage(2.0)) # If we've got the player from the scoring team that last # touched us, give them points. @@ -306,30 +309,30 @@ class HockeyGame(ba.TeamGameActivity[Player, Team]): if team.score >= self._score_to_win: self.end_game() - ba.playsound(self._foghorn_sound) - ba.playsound(self._cheer_sound) + self._foghorn_sound.play() + self._cheer_sound.play() self._puck.scored = True # Change puck texture to something cool self._puck.node.color_texture = self.puck_scored_tex # Kill the puck (it'll respawn itself shortly). - ba.timer(1.0, self._kill_puck) + bs.timer(1.0, self._kill_puck) - light = ba.newnode('light', + light = bs.newnode('light', attrs={ - 'position': ba.getcollision().position, + 'position': bs.getcollision().position, 'height_attenuated': False, 'color': (1, 0, 0) }) - ba.animate(light, 'intensity', {0: 0, 0.5: 1, 1.0: 0}, loop=True) - ba.timer(1.0, light.delete) + bs.animate(light, 'intensity', {0: 0, 0.5: 1, 1.0: 0}, loop=True) + bs.timer(1.0, light.delete) - ba.cameraflash(duration=10.0) + bs.cameraflash(duration=10.0) self._update_scoreboard() def end_game(self) -> None: - results = ba.GameResults() + results = bs.GameResults() for team in self.teams: results.set_team_score(team, team.score) self.end(results=results) @@ -342,7 +345,7 @@ class HockeyGame(ba.TeamGameActivity[Player, Team]): def handlemessage(self, msg: Any) -> Any: # Respawn dead players if they're still in the game. - if isinstance(msg, ba.PlayerDiedMessage): + if isinstance(msg, bs.PlayerDiedMessage): # Augment standard behavior... super().handlemessage(msg) self.respawn_player(msg.getplayer(Player)) @@ -350,23 +353,23 @@ class HockeyGame(ba.TeamGameActivity[Player, Team]): # Respawn dead pucks. elif isinstance(msg, PuckDiedMessage): if not self.has_ended(): - ba.timer(3.0, self._spawn_puck) + bs.timer(3.0, self._spawn_puck) else: super().handlemessage(msg) def _flash_puck_spawn(self) -> None: - light = ba.newnode('light', + light = bs.newnode('light', attrs={ 'position': self._puck_spawn_pos, 'height_attenuated': False, 'color': (1, 0, 0) }) - ba.animate(light, 'intensity', {0.0: 0, 0.25: 1, 0.5: 0}, loop=True) - ba.timer(1.0, light.delete) + bs.animate(light, 'intensity', {0.0: 0, 0.25: 1, 0.5: 0}, loop=True) + bs.timer(1.0, light.delete) def _spawn_puck(self) -> None: - ba.playsound(self._swipsound) - ba.playsound(self._whistle_sound) + self._swipsound.play() + self._whistle_sound.play() self._flash_puck_spawn() assert self._puck_spawn_pos is not None self._puck = Puck(position=self._puck_spawn_pos) diff --git a/plugins/minigames/super_duel.py b/plugins/minigames/super_duel.py new file mode 100644 index 0000000..b6fc239 --- /dev/null +++ b/plugins/minigames/super_duel.py @@ -0,0 +1,602 @@ +"""New Duel / Created by: byANG3L""" + +# ba_meta require api 8 +# (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 random +from bascenev1lib.actor.playerspaz import PlayerSpaz +from bascenev1lib.actor.scoreboard import Scoreboard +from bascenev1lib.game.elimination import Icon + +if TYPE_CHECKING: + from typing import Any, Type, List, Dict, Tuple, Union, Sequence, Optional + + +class SuperSpaz(PlayerSpaz): + + def __init__(self, + player: bs.Player, + color: Sequence[float] = (1.0, 1.0, 1.0), + highlight: Sequence[float] = (0.5, 0.5, 0.5), + character: str = 'Spaz', + super_punch: bool = False, + powerups_expire: bool = True): + super().__init__(player=player, + color=color, + highlight=highlight, + character=character, + powerups_expire=powerups_expire) + self._super_punch = super_punch + + def handlemessage(self, msg: Any) -> Any: + from bascenev1lib.actor.spaz import PunchHitMessage + from bascenev1lib.actor.bomb import Blast + if isinstance(msg, PunchHitMessage): + super().handlemessage(msg) + node = bs.getcollision().opposingnode + if self._super_punch: + if node.getnodetype() == 'spaz': + if not node.frozen: + node.frozen = True + node.handlemessage(babase.FreezeMessage()) + bs.getsound('freeze').play() + bs.getsound('superPunch').play() + bs.getsound('punchStrong02').play() + Blast(position=node.position, + velocity=node.velocity, + blast_radius=0.0, + blast_type='normal').autoretain() + else: + return super().handlemessage(msg) + return None + + +class Player(bs.Player['Team']): + """Our player type for this game.""" + + def __init__(self) -> None: + self.icons: List[Icon] = [] + self.in_game: bool = False + self.playervs1: bool = False + self.playervs2: bool = False + self.light: bool = False + + +class Team(bs.Team[Player]): + """Our team type for this game.""" + + def __init__(self) -> None: + self.score = 0 + + +lang = bs.app.lang.language +if lang == 'Spanish': + enable_powerups = 'Habilitar Potenciadores' + night_mode = 'Modo Noche' + fight_delay = 'Tiempo entre Pelea' + very_fast = 'Muy Rápido' + fast = 'Rápido' + normal = 'Normal' + slow = 'Lento' + very_slow = 'Muy Lento' + none = 'Ninguno' + super_punch = 'Super Golpe' + box_mode = 'Modo Caja' + boxing_gloves = 'Guantes de Boxeo' +else: + enable_powerups = 'Enable Powerups' + night_mode = 'Night Mode' + fight_delay = 'Fight Delay' + very_fast = 'Very Fast' + fast = 'Fast' + normal = 'Normal' + slow = 'Slow' + very_slow = 'Very Slow' + super_punch = 'Super Punch' + box_mode = 'Box Mode' + boxing_gloves = 'Boxing Gloves' + +# ba_meta export bascenev1.GameActivity + + +class NewDuelGame(bs.TeamGameActivity[Player, Team]): + """A game type based on acquiring kills.""" + + name = 'Duel' + description = 'Kill a set number of enemies to win.' + + # Print messages when players die since it matters here. + announce_player_deaths = True + + @classmethod + def get_available_settings( + cls, sessiontype: Type[bs.Session]) -> List[babase.Setting]: + settings = [ + bs.IntSetting( + 'Kills to Win Per Player', + min_value=1, + default=5, + 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.BoolSetting(enable_powerups, default=False), + bs.BoolSetting(boxing_gloves, default=False), + bs.BoolSetting(night_mode, default=False), + bs.BoolSetting(super_punch, default=False), + bs.BoolSetting(box_mode, default=False), + bs.BoolSetting('Epic Mode', default=False), + bs.BoolSetting('Allow Negative Scores', default=False), + ] + return settings + + @classmethod + def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool: + return (issubclass(sessiontype, bs.FreeForAllSession)) + + @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) + self._scoreboard = Scoreboard() + self._score_to_win: Optional[int] = None + self._dingsound = bs.getsound('dingSmall') + self._epic_mode = bool(settings['Epic Mode']) + self._kills_to_win_per_player = int( + settings['Kills to Win Per Player']) + self._enable_powerups = bool(settings[enable_powerups]) + self._night_mode = bool(settings[night_mode]) + self._fight_delay: float = 0 + self._time_limit = float(settings['Time Limit']) + self._allow_negative_scores = bool( + settings.get('Allow Negative Scores', False)) + self._super_punch = bool(settings[super_punch]) + self._box_mode = bool(settings[box_mode]) + self._boxing_gloves = bool(settings[boxing_gloves]) + self._vs_text: Optional[bs.Actor] = None + self.spawn_order: List[Player] = [] + self._players_vs_1: bool = False + self._players_vs_2: bool = False + self._first_countdown: bool = True + self._count_1 = bs.getsound('announceOne') + self._count_2 = bs.getsound('announceTwo') + self._count_3 = bs.getsound('announceThree') + self._boxing_bell = bs.getsound('boxingBell') + + # Base class overrides. + self.slow_motion = self._epic_mode + self.default_music = (bs.MusicType.EPIC if self._epic_mode else + bs.MusicType.TO_THE_DEATH) + + def get_instance_description(self) -> Union[str, Sequence]: + return 'Crush ${ARG1} of your enemies.', self._score_to_win + + def get_instance_description_short(self) -> Union[str, Sequence]: + return 'kill ${ARG1} enemies', self._score_to_win + + def on_player_join(self, player: Player) -> None: + self.spawn_order.append(player) + self._update_order() + + def on_player_leave(self, player: Player) -> None: + super().on_player_leave(player) + player.icons = [] + if player.playervs1: + player.playervs1 = False + self._players_vs_1 = False + player.in_game = False + elif player.playervs2: + player.playervs2 = False + self._players_vs_2 = False + player.in_game = False + if player in self.spawn_order: + self.spawn_order.remove(player) + bs.timer(0.2, self._update_order) + + def on_transition_in(self) -> None: + super().on_transition_in() + if self._night_mode: + gnode = bs.getactivity().globalsnode + gnode.tint = (0.3, 0.3, 0.3) + + def on_team_join(self, team: Team) -> None: + if self.has_begun(): + self._update_scoreboard() + + def on_begin(self) -> None: + super().on_begin() + self.setup_standard_time_limit(self._time_limit) + if self._enable_powerups: + self.setup_standard_powerup_drops() + self._vs_text = bs.NodeActor( + bs.newnode('text', + attrs={ + 'position': (0, 105), + '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') + })) + + # Base kills needed to win on the size of the largest team. + self._score_to_win = (self._kills_to_win_per_player * + max(1, max(len(t.players) for t in self.teams))) + self._update_scoreboard() + bs.timer(1.0, self._update, repeat=True) + + def _update(self) -> None: + if len(self.players) == 1: + 'self.end_game()' + + def spawn_player(self, player: PlayerType) -> bs.Actor: + # pylint: disable=too-many-locals + # pylint: disable=cyclic-import + from babase import _math + from bascenev1._coopsession import CoopSession + from bascenev1lib.actor.spazfactory import SpazFactory + factory = SpazFactory.get() + name = player.getname() + color = player.color + highlight = player.highlight + + light_color = _math.normalized_color(color) + display_color = babase.safecolor(color, target_intensity=0.75) + spaz = SuperSpaz(color=color, + highlight=highlight, + character=player.character, + player=player, + super_punch=True if self._super_punch else False) + + player.actor = spaz + assert spaz.node + + # If this is co-op and we're on Courtyard or Runaround, add the + # material that allows us to collide with the player-walls. + # FIXME: Need to generalize this. + if isinstance(self.session, CoopSession) and self.map.getname() in [ + 'Courtyard', 'Tower D' + ]: + mat = self.map.preloaddata['collide_with_wall_material'] + assert isinstance(spaz.node.materials, tuple) + assert isinstance(spaz.node.roller_materials, tuple) + spaz.node.materials += (mat, ) + spaz.node.roller_materials += (mat, ) + + spaz.node.name = name + spaz.node.name_color = display_color + spaz.connect_controls_to_player() + + self._spawn_sound.play(1, position=spaz.node.position) + light = bs.newnode('light', attrs={'color': light_color}) + spaz.node.connectattr('position', light, 'position') + bs.animate(light, 'intensity', {0: 0, 0.25: 1, 0.5: 0}) + bs.timer(0.5, light.delete) + + pos1 = [self.map.get_start_position(0), 90] + pos2 = [self.map.get_start_position(1), 270] + pos3 = [] + + for x in self.players: + if x.is_alive(): + if x is player: + continue + p = x.actor.node.position + if 0.0 not in (p[0], p[2]): + if p[0] <= 0: + pos3.append(pos2[0]) + else: + pos3.append(pos1[0]) + + spaz.handlemessage(bs.StandMessage(pos1[0] if player.playervs1 else pos2[0], + pos1[1] if player.playervs1 else pos2[1])) + + if any(pos3): + spaz.handlemessage(bs.StandMessage(pos3[0])) + + if self._super_punch: + spaz._punch_power_scale = factory.punch_power_scale_gloves = 10 + spaz.equip_boxing_gloves() + lfx = bs.newnode( + 'light', + attrs={ + 'color': color, + 'radius': 0.3, + 'intensity': 0.3}) + + def sp_fx(): + if not spaz.node: + lfx.delete() + return + bs.emitfx(position=spaz.node.position, + velocity=spaz.node.velocity, + count=5, + scale=0.5, + spread=0.5, + chunk_type='spark') + bs.emitfx(position=spaz.node.position, + velocity=spaz.node.velocity, + count=2, + scale=0.8, + spread=0.3, + chunk_type='spark') + if lfx: + spaz.node.connectattr('position', lfx, 'position') + bs.timer(0.1, sp_fx, repeat=True) + + if self._box_mode: + spaz.node.color_texture = bs.gettexture('tnt') + spaz.node.color_mask_texture = bs.gettexture('tnt') + spaz.node.color = (1, 1, 1) + spaz.node.highlight = (1, 1, 1) + spaz.node.head_mesh = None + spaz.node.torso_mesh = bs.getmesh('tnt') + spaz.node.style = 'cyborg' + + if self._boxing_gloves: + spaz.equip_boxing_gloves() + + return spaz + + def _update_spawn(self) -> None: + if self._players_vs_1 or self._players_vs_2: + for player in self.players: + if player.playervs1 or player.playervs2: + if not player.is_alive(): + self.spawn_player(player) + # player.actor.disconnect_controls_from_player() + + if self._night_mode: + if not player.light: + player.light = True + light = bs.newnode( + 'light', + owner=player.node, + attrs={ + 'radius': 0.3, + 'intensity': 0.6, + 'height_attenuated': False, + 'color': player.color + }) + player.node.connectattr( + 'position', light, 'position') + else: + player.actor.disconnect_controls_from_player() + + bs.timer(0.0, self._countdown) + # bs.timer(0.1, self._clear_all_objects) + + def _countdown(self) -> None: + self._first_countdown = False + if self._fight_delay == 0: + for player in self.players: + if player.playervs1 or player.playervs2: + if not player.is_alive(): + return + else: + player.actor.connect_controls_to_player() + else: + bs.timer(self._fight_delay, self.count3) + + def start(self) -> None: + self._count_text('FIGHT') + self._boxing_bell.play() + for player in self.players: + if player.playervs1 or player.playervs2: + if not player.is_alive(): + return + else: + player.actor.connect_controls_to_player() + + def count(self) -> None: + self._count_text('1') + self._count_1.play() + bs.timer(self._fight_delay, self.start) + + def count2(self) -> None: + self._count_text('2') + self._count_2.play() + bs.timer(self._fight_delay, self.count) + + def count3(self) -> None: + self._count_text('3') + self._count_3.play() + bs.timer(self._fight_delay, self.count2) + + def _count_text(self, num: str) -> None: + self.node = bs.newnode('text', + attrs={ + 'v_attach': 'center', + 'h_attach': 'center', + 'h_align': 'center', + 'color': (1, 1, 0.5, 1), + 'flatness': 0.5, + 'shadow': 0.5, + 'position': (0, 18), + 'text': num + }) + if self._fight_delay == 0.7: + bs.animate(self.node, 'scale', + {0: 0, 0.1: 3.9, 0.64: 4.3, 0.68: 0}) + elif self._fight_delay == 0.4: + bs.animate(self.node, 'scale', + {0: 0, 0.1: 3.9, 0.34: 4.3, 0.38: 0}) + else: + bs.animate(self.node, 'scale', + {0: 0, 0.1: 3.9, 0.92: 4.3, 0.96: 0}) + cmb = bs.newnode('combine', owner=self.node, attrs={'size': 4}) + cmb.connectattr('output', self.node, 'color') + bs.animate(cmb, 'input0', {0: 1.0, 0.15: 1.0}, loop=True) + bs.animate(cmb, 'input1', {0: 1.0, 0.15: 0.5}, loop=True) + bs.animate(cmb, 'input2', {0: 0.1, 0.15: 0.0}, loop=True) + cmb.input3 = 1.0 + bs.timer(self._fight_delay, self.node.delete) + + def _update_order(self) -> None: + for player in self.spawn_order: + assert isinstance(player, Player) + if not player.is_alive(): + if not self._players_vs_1: + self._players_vs_1 = True + player.playervs1 = True + player.in_game = True + self.spawn_order.remove(player) + self._update_spawn() + elif not self._players_vs_2: + self._players_vs_2 = True + player.playervs2 = True + player.in_game = True + self.spawn_order.remove(player) + self._update_spawn() + self._update_icons() + + def _update_icons(self) -> None: + # pylint: disable=too-many-branches + + for player in self.players: + player.icons = [] + + if player.in_game: + if player.playervs1: + xval = -60 + x_offs = -78 + elif player.playervs2: + xval = 60 + x_offs = 78 + player.icons.append( + Icon(player, + position=(xval, 40), + scale=1.0, + name_maxwidth=130, + name_scale=0.8, + flatness=0.0, + shadow=0.5, + show_death=True, + show_lives=False)) + else: + xval = 125 + xval2 = -125 + x_offs = 78 + for player in self.spawn_order: + player.icons.append( + Icon(player, + position=(xval, 25), + scale=0.5, + name_maxwidth=75, + name_scale=1.0, + flatness=1.0, + shadow=1.0, + show_death=False, + show_lives=False)) + xval += x_offs * 0.56 + player.icons.append( + Icon(player, + position=(xval2, 25), + scale=0.5, + name_maxwidth=75, + name_scale=1.0, + flatness=1.0, + shadow=1.0, + show_death=False, + show_lives=False)) + xval2 -= x_offs * 0.56 + + def handlemessage(self, msg: Any) -> Any: + + if isinstance(msg, bs.PlayerDiedMessage): + + # Augment standard behavior. + super().handlemessage(msg) + + player = msg.getplayer(Player) + + if player.playervs1: + player.playervs1 = False + self._players_vs_1 = False + player.in_game = False + self.spawn_order.append(player) + elif player.playervs2: + player.playervs2 = False + self._players_vs_2 = False + player.in_game = False + self.spawn_order.append(player) + bs.timer(0.2, self._update_order) + + killer = msg.getkillerplayer(Player) + if killer is None: + return None + + # Handle team-kills. + if killer.team is player.team: + + # In free-for-all, killing yourself loses you a point. + if isinstance(self.session, bs.FreeForAllSession): + new_score = player.team.score - 1 + if not self._allow_negative_scores: + new_score = max(0, new_score) + player.team.score = new_score + + # In teams-mode it gives a point to the other team. + else: + self._dingsound.play() + for team in self.teams: + if team is not killer.team: + team.score += 1 + + # Killing someone on another team nets a kill. + else: + killer.team.score += 1 + self._dingsound.play() + + # In FFA show scores since its hard to find on the scoreboard. + if isinstance(killer.actor, PlayerSpaz) and killer.actor: + killer.actor.set_score_text(str(killer.team.score) + '/' + + str(self._score_to_win), + color=killer.team.color, + flash=True) + + self._update_scoreboard() + + # If someone has won, set a timer to end shortly. + # (allows the dust to clear and draws to occur if deaths are + # close enough) + assert self._score_to_win is not None + if any(team.score >= self._score_to_win for team in self.teams): + bs.timer(0.5, self.end_game) + else: + return super().handlemessage(msg) + return None + + def _update_scoreboard(self) -> None: + for team in self.teams: + self._scoreboard.set_team_value(team, team.score, + self._score_to_win) + + def end_game(self) -> None: + results = bs.GameResults() + for team in self.teams: + results.set_team_score(team, team.score) + self.end(results=results) diff --git a/plugins/minigames/supersmash.py b/plugins/minigames/supersmash.py new file mode 100644 index 0000000..3736360 --- /dev/null +++ b/plugins/minigames/supersmash.py @@ -0,0 +1,956 @@ +# To learn more, see https://ballistica.net/wiki/meta-tag-system +# ba_meta require api 8 + +from __future__ import annotations + +from typing import TYPE_CHECKING + +import babase +import random +import bauiv1 as bui +import bascenev1 as bs +from babase import _math +from bascenev1lib.actor.spaz import Spaz +from bascenev1lib.actor.spazfactory import SpazFactory +from bascenev1lib.actor.scoreboard import Scoreboard +from bascenev1lib.game import elimination +from bascenev1lib.game.elimination import Icon, Player, Team +from bascenev1lib.actor.bomb import Bomb, Blast +from bascenev1lib.actor.playerspaz import PlayerSpaz, PlayerSpazHurtMessage + +if TYPE_CHECKING: + from typing import Any, Type, List, Sequence, Optional + + +class Icon(Icon): + 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 > 1: + 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 + + +class PowBox(Bomb): + + def __init__(self, + position: Sequence[float] = (0.0, 1.0, 0.0), + velocity: Sequence[float] = (0.0, 0.0, 0.0)) -> None: + Bomb.__init__(self, + position, + velocity, + bomb_type='tnt', + blast_radius=2.5, + source_player=None, + owner=None) + self.set_pow_text() + + def set_pow_text(self) -> None: + m = bs.newnode('math', + owner=self.node, + attrs={'input1': (0, 0.7, 0), + 'operation': 'add'}) + self.node.connectattr('position', m, 'input2') + + self._pow_text = bs.newnode('text', + owner=self.node, + attrs={'text': 'POW!', + 'in_world': True, + 'shadow': 1.0, + 'flatness': 1.0, + 'color': (1, 1, 0.4), + 'scale': 0.0, + 'h_align': 'center'}) + m.connectattr('output', self._pow_text, 'position') + bs.animate(self._pow_text, 'scale', {0: 0.0, 1.0: 0.01}) + + def pow(self) -> None: + self.explode() + + def handlemessage(self, m: Any) -> Any: + if isinstance(m, babase.PickedUpMessage): + self._heldBy = m.node + elif isinstance(m, bs.DroppedMessage): + bs.timer(0.6, self.pow) + Bomb.handlemessage(self, m) + + +class SSPlayerSpaz(PlayerSpaz): + multiplyer = 1 + is_dead = False + + def oob_effect(self) -> None: + if self.is_dead: + return + self.is_dead = True + if self.multiplyer > 1.25: + blast_type = 'tnt' + radius = min(self.multiplyer * 5, 20) + else: + # penalty for killing people with low multiplyer + blast_type = 'ice' + radius = 7.5 + Blast(position=self.node.position, + blast_radius=radius, + blast_type=blast_type).autoretain() + + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, bs.HitMessage): + if not self.node: + return None + if self.node.invincible: + SpazFactory.get().block_sound.play(1.0, position=self.node.position) + return True + + # If we were recently hit, don't count this as another. + # (so punch flurries and bomb pileups essentially count as 1 hit) + local_time = int(bs.time() * 1000) + assert isinstance(local_time, int) + if (self._last_hit_time is None + or local_time - self._last_hit_time > 1000): + self._num_times_hit += 1 + self._last_hit_time = local_time + + mag = msg.magnitude * self.impact_scale + velocity_mag = msg.velocity_magnitude * self.impact_scale + damage_scale = 0.22 + + # If they've got a shield, deliver it to that instead. + if self.shield: + if msg.flat_damage: + damage = msg.flat_damage * self.impact_scale + else: + # Hit our spaz with an impulse but tell it to only return + # theoretical damage; not apply the impulse. + assert msg.force_direction is not None + self.node.handlemessage( + 'impulse', msg.pos[0], msg.pos[1], msg.pos[2], + msg.velocity[0], msg.velocity[1], msg.velocity[2], mag, + velocity_mag, msg.radius, 1, msg.force_direction[0], + msg.force_direction[1], msg.force_direction[2]) + damage = damage_scale * self.node.damage + + assert self.shield_hitpoints is not None + self.shield_hitpoints -= int(damage) + self.shield.hurt = ( + 1.0 - + float(self.shield_hitpoints) / self.shield_hitpoints_max) + + # Its a cleaner event if a hit just kills the shield + # without damaging the player. + # However, massive damage events should still be able to + # damage the player. This hopefully gives us a happy medium. + max_spillover = SpazFactory.get().max_shield_spillover_damage + if self.shield_hitpoints <= 0: + + # FIXME: Transition out perhaps? + self.shield.delete() + self.shield = None + SpazFactory.get().shield_down_sound.play(1.0, position=self.node.position) + + # Emit some cool looking sparks when the shield dies. + npos = self.node.position + bs.emitfx(position=(npos[0], npos[1] + 0.9, npos[2]), + velocity=self.node.velocity, + count=random.randrange(20, 30), + scale=1.0, + spread=0.6, + chunk_type='spark') + + else: + SpazFactory.get().shield_hit_sound.play(0.5, position=self.node.position) + + # Emit some cool looking sparks on shield hit. + assert msg.force_direction is not None + bs.emitfx(position=msg.pos, + velocity=(msg.force_direction[0] * 1.0, + msg.force_direction[1] * 1.0, + msg.force_direction[2] * 1.0), + count=min(30, 5 + int(damage * 0.005)), + scale=0.5, + spread=0.3, + chunk_type='spark') + + # If they passed our spillover threshold, + # pass damage along to spaz. + if self.shield_hitpoints <= -max_spillover: + leftover_damage = -max_spillover - self.shield_hitpoints + shield_leftover_ratio = leftover_damage / damage + + # Scale down the magnitudes applied to spaz accordingly. + mag *= shield_leftover_ratio + velocity_mag *= shield_leftover_ratio + else: + return True # Good job shield! + else: + shield_leftover_ratio = 1.0 + + if msg.flat_damage: + damage = int(msg.flat_damage * self.impact_scale * + shield_leftover_ratio) + else: + # Hit it with an impulse and get the resulting damage. + assert msg.force_direction is not None + self.node.handlemessage( + 'impulse', msg.pos[0], msg.pos[1], msg.pos[2], + msg.velocity[0], msg.velocity[1], msg.velocity[2], mag, + velocity_mag, msg.radius, 0, msg.force_direction[0], + msg.force_direction[1], msg.force_direction[2]) + + damage = int(damage_scale * self.node.damage) + self.node.handlemessage('hurt_sound') + + # Play punch impact sound based on damage if it was a punch. + if msg.hit_type == 'punch': + self.on_punched(damage) + + # If damage was significant, lets show it. + # if damage > 350: + # assert msg.force_direction is not None + # babase.show_damage_count('-' + str(int(damage / 10)) + '%', + # msg.pos, msg.force_direction) + + # Let's always add in a super-punch sound with boxing + # gloves just to differentiate them. + if msg.hit_subtype == 'super_punch': + SpazFactory.get().punch_sound_stronger.play(1.0, position=self.node.position) + if damage > 500: + sounds = SpazFactory.get().punch_sound_strong + sound = sounds[random.randrange(len(sounds))] + else: + sound = SpazFactory.get().punch_sound + sound.play(1.0, position=self.node.position) + + # Throw up some chunks. + assert msg.force_direction is not None + bs.emitfx(position=msg.pos, + velocity=(msg.force_direction[0] * 0.5, + msg.force_direction[1] * 0.5, + msg.force_direction[2] * 0.5), + count=min(10, 1 + int(damage * 0.0025)), + scale=0.3, + spread=0.03) + + bs.emitfx(position=msg.pos, + chunk_type='sweat', + velocity=(msg.force_direction[0] * 1.3, + msg.force_direction[1] * 1.3 + 5.0, + msg.force_direction[2] * 1.3), + count=min(30, 1 + int(damage * 0.04)), + scale=0.9, + spread=0.28) + + # Momentary flash. + hurtiness = damage * 0.003 + punchpos = (msg.pos[0] + msg.force_direction[0] * 0.02, + msg.pos[1] + msg.force_direction[1] * 0.02, + msg.pos[2] + msg.force_direction[2] * 0.02) + flash_color = (1.0, 0.8, 0.4) + light = bs.newnode( + 'light', + attrs={ + 'position': punchpos, + 'radius': 0.12 + hurtiness * 0.12, + 'intensity': 0.3 * (1.0 + 1.0 * hurtiness), + 'height_attenuated': False, + 'color': flash_color + }) + bs.timer(0.06, light.delete) + + flash = bs.newnode('flash', + attrs={ + 'position': punchpos, + 'size': 0.17 + 0.17 * hurtiness, + 'color': flash_color + }) + bs.timer(0.06, flash.delete) + + if msg.hit_type == 'impact': + assert msg.force_direction is not None + bs.emitfx(position=msg.pos, + velocity=(msg.force_direction[0] * 2.0, + msg.force_direction[1] * 2.0, + msg.force_direction[2] * 2.0), + count=min(10, 1 + int(damage * 0.01)), + scale=0.4, + spread=0.1) + if self.hitpoints > 0: + + # It's kinda crappy to die from impacts, so lets reduce + # impact damage by a reasonable amount *if* it'll keep us alive + if msg.hit_type == 'impact' and damage > self.hitpoints: + # Drop damage to whatever puts us at 10 hit points, + # or 200 less than it used to be whichever is greater + # (so it *can* still kill us if its high enough) + newdamage = max(damage - 200, self.hitpoints - 10) + damage = newdamage + self.node.handlemessage('flash') + + # If we're holding something, drop it. + if damage > 0.0 and self.node.hold_node: + self.node.hold_node = None + # self.hitpoints -= damage + self.multiplyer += min(damage / 2000, 0.15) + if damage/2000 > 0.05: + self.set_score_text(str(int((self.multiplyer-1)*100))+'%') + # self.node.hurt = 1.0 - float( + # self.hitpoints) / self.hitpoints_max + self.node.hurt = 0.0 + + # If we're cursed, *any* damage blows us up. + if self._cursed and damage > 0: + bs.timer( + 0.05, + bs.WeakCall(self.curse_explode, + msg.get_source_player(bs.Player))) + + # If we're frozen, shatter.. otherwise die if we hit zero + # if self.frozen and (damage > 200 or self.hitpoints <= 0): + # self.shatter() + # elif self.hitpoints <= 0: + # self.node.handlemessage( + # bs.DieMessage(how=babase.DeathType.IMPACT)) + + # If we're dead, take a look at the smoothed damage value + # (which gives us a smoothed average of recent damage) and shatter + # us if its grown high enough. + # if self.hitpoints <= 0: + # damage_avg = self.node.damage_smoothed * damage_scale + # if damage_avg > 1000: + # self.shatter() + + source_player = msg.get_source_player(type(self._player)) + if source_player: + self.last_player_attacked_by = source_player + self.last_attacked_time = bs.time() + self.last_attacked_type = (msg.hit_type, msg.hit_subtype) + Spaz.handlemessage(self, bs.HitMessage) # Augment standard behavior. + activity = self._activity() + if activity is not None and self._player.exists(): + activity.handlemessage(PlayerSpazHurtMessage(self)) + + elif isinstance(msg, bs.DieMessage): + self.oob_effect() + super().handlemessage(msg) + elif isinstance(msg, bs.PowerupMessage): + if msg.poweruptype == 'health': + if self.multiplyer > 2: + self.multiplyer *= 0.5 + else: + self.multiplyer *= 0.75 + self.multiplyer = max(1, self.multiplyer) + self.set_score_text(str(int((self.multiplyer-1)*100))+"%") + super().handlemessage(msg) + else: + super().handlemessage(msg) + + +class Player(bs.Player['Team']): + """Our player type for this game.""" + + +class Team(bs.Team[Player]): + """Our team type for this game.""" + + def __init__(self) -> None: + self.score = 0 + + +# ba_meta export bascenev1.GameActivity +class SuperSmash(bs.TeamGameActivity[Player, Team]): + + name = 'Super Smash' + description = 'Knock everyone off the map.' + + # Print messages when players die since it matters here. + announce_player_deaths = True + + @classmethod + def get_available_settings( + cls, sessiontype: Type[bs.Session]) -> List[babase.Setting]: + settings = [ + bs.IntSetting( + 'Kills to Win Per Player', + min_value=1, + default=5, + 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('Boxing Gloves', default=False), + bs.BoolSetting('Epic Mode', default=False), + ] + if issubclass(sessiontype, bs.FreeForAllSession): + settings.append( + bs.BoolSetting('Allow Negative Scores', default=False)) + return settings + + @classmethod + def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool: + return (issubclass(sessiontype, bs.DualTeamSession) + or issubclass(sessiontype, bs.FreeForAllSession)) + + @classmethod + def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]: + maps = bs.app.classic.getmaps('melee') + for m in ['Lake Frigid', 'Hockey Stadium', 'Football Stadium']: + # remove maps without bounds + maps.remove(m) + return maps + + def __init__(self, settings: dict): + super().__init__(settings) + self._scoreboard = Scoreboard() + self._score_to_win: int | None = None + self._dingsound = bs.getsound('dingSmall') + self._epic_mode = bool(settings['Epic Mode']) + self._kills_to_win_per_player = int( + settings['Kills to Win Per Player']) + self._time_limit = float(settings['Time Limit']) + self._allow_negative_scores = bool( + settings.get('Allow Negative Scores', False)) + self._boxing_gloves = bool(settings['Boxing Gloves']) + + # 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) -> str | Sequence: + return 'Knock everyone off the map.' + + def get_instance_description_short(self) -> str | Sequence: + return 'Knock off the map.' + + def on_begin(self) -> None: + super().on_begin() + self._start_time = bs.time() + self.setup_standard_time_limit(self._time_limit) + self.setup_standard_powerup_drops(enable_tnt=False) + self._pow = None + self._tnt_drop_timer = bs.timer(1.0 * 0.30, + bs.WeakCall(self._drop_pow_box), + repeat=True) + + # Base kills needed to win on the size of the largest team. + self._score_to_win = (self._kills_to_win_per_player * + max(1, max(len(t.players) for t in self.teams))) + self._update_scoreboard() + + def _drop_pow_box(self) -> None: + if self._pow is not None and self._pow: + return + if len(self.map.tnt_points) == 0: + return + pos = random.choice(self.map.tnt_points) + pos = (pos[0], pos[1] + 1, pos[2]) + self._pow = PowBox(position=pos, velocity=(0.0, 1.0, 0.0)) + + def spawn_player(self, player: Player) -> bs.Actor: + if isinstance(self.session, bs.DualTeamSession): + position = self.map.get_start_position(player.team.id) + else: + # otherwise do free-for-all spawn locations + position = self.map.get_ffa_start_position(self.players) + angle = None + + name = player.getname() + light_color = _math.normalized_color(player.color) + display_color = babase.safecolor(player.color, target_intensity=0.75) + + spaz = SSPlayerSpaz(color=player.color, + highlight=player.highlight, + character=player.character, + player=player) + + player.actor = spaz + assert spaz.node + + # If this is co-op and we're on Courtyard or Runaround, add the + # material that allows us to collide with the player-walls. + # FIXME: Need to generalize this. + if isinstance(self.session, bs.CoopSession) and self.map.getname() in [ + 'Courtyard', 'Tower D' + ]: + mat = self.map.preloaddata['collide_with_wall_material'] + assert isinstance(spaz.node.materials, tuple) + assert isinstance(spaz.node.roller_materials, tuple) + spaz.node.materials += (mat, ) + spaz.node.roller_materials += (mat, ) + + spaz.node.name = name + spaz.node.name_color = display_color + spaz.connect_controls_to_player() + + # Move to the stand position and add a flash of light. + spaz.handlemessage( + bs.StandMessage( + position, + angle if angle is not None else random.uniform(0, 360))) + self._spawn_sound.play(1, position=spaz.node.position) + light = bs.newnode('light', attrs={'color': light_color}) + spaz.node.connectattr('position', light, 'position') + bs.animate(light, 'intensity', {0: 0, 0.25: 1, 0.5: 0}) + bs.timer(0.5, light.delete) + + if self._boxing_gloves: + spaz.equip_boxing_gloves() + + return spaz + + 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) + + killer = msg.getkillerplayer(Player) + if killer is None: + return None + + # Handle team-kills. + if killer.team is player.team: + + # In free-for-all, killing yourself loses you a point. + if isinstance(self.session, bs.FreeForAllSession): + new_score = player.team.score - 1 + if not self._allow_negative_scores: + new_score = max(0, new_score) + player.team.score = new_score + + # In teams-mode it gives a point to the other team. + else: + self._dingsound.play() + for team in self.teams: + if team is not killer.team: + team.score += 1 + + # Killing someone on another team nets a kill. + else: + killer.team.score += 1 + self._dingsound.play() + + # In FFA show scores since its hard to find on the scoreboard. + if isinstance(killer.actor, SSPlayerSpaz) and killer.actor: + killer.actor.set_score_text(str(killer.team.score) + '/' + + str(self._score_to_win), + color=killer.team.color, + flash=True) + + self._update_scoreboard() + + # If someone has won, set a timer to end shortly. + # (allows the dust to clear and draws to occur if deaths are + # close enough) + assert self._score_to_win is not None + if any(team.score >= self._score_to_win for team in self.teams): + bs.timer(0.5, self.end_game) + + else: + return super().handlemessage(msg) + return None + + def _update_scoreboard(self) -> None: + for team in self.teams: + self._scoreboard.set_team_value(team, team.score, + self._score_to_win) + + def end_game(self) -> None: + results = bs.GameResults() + for team in self.teams: + results.set_team_score(team, team.score) + self.end(results=results) + + +class Player2(bs.Player['Team']): + """Our player type for this game.""" + + def __init__(self) -> None: + self.lives = 0 + self.icons: List[Icon] = [] + + +class Team2(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 SuperSmashElimination(bs.TeamGameActivity[Player2, Team2]): + + name = 'Super Smash Elimination' + description = 'Knock everyone off the map.' + scoreconfig = bs.ScoreConfig(label='Survived', + scoretype=bs.ScoreType.SECONDS, + none_is_winner=True) + + # Print messages when players die since it matters here. + announce_player_deaths = True + + @classmethod + def get_available_settings( + cls, sessiontype: Type[bs.Session]) -> List[babase.Setting]: + settings = [ + bs.IntSetting( + 'Lives (0 = Unlimited)', + min_value=0, + default=3, + 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('Boxing Gloves', default=False), + bs.BoolSetting('Epic Mode', default=False), + ] + return settings + + @classmethod + def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool: + return (issubclass(sessiontype, bs.DualTeamSession) + or issubclass(sessiontype, bs.FreeForAllSession)) + + @classmethod + def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]: + maps = bs.app.classic.getmaps('melee') + for m in ['Lake Frigid', 'Hockey Stadium', 'Football Stadium']: + # remove maps without bounds + maps.remove(m) + return maps + + def __init__(self, settings: dict): + super().__init__(settings) + self.lives = int(settings['Lives (0 = Unlimited)']) + self.time_limit_only = (self.lives == 0) + if self.time_limit_only: + settings['Time Limit'] = max(60, settings['Time Limit']) + + self._epic_mode = bool(settings['Epic Mode']) + self._time_limit = float(settings['Time Limit']) + + self._start_time: Optional[float] = 1.0 + + self._boxing_gloves = bool(settings['Boxing Gloves']) + self._solo_mode = bool(settings.get('Solo Mode', False)) + + # 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) -> str | Sequence: + return 'Knock everyone off the map.' + + def get_instance_description_short(self) -> str | Sequence: + return 'Knock off the map.' + + def on_begin(self) -> None: + super().on_begin() + self._start_time = bs.time() + self.setup_standard_time_limit(self._time_limit) + self.setup_standard_powerup_drops(enable_tnt=False) + self._pow = None + self._tnt_drop_timer = bs.timer(1.0 * 0.30, + bs.WeakCall(self._drop_pow_box), + repeat=True) + self._update_icons() + bs.timer(1.0, self.check_end_game, repeat=True) + + def _drop_pow_box(self) -> None: + if self._pow is not None and self._pow: + return + if len(self.map.tnt_points) == 0: + return + pos = random.choice(self.map.tnt_points) + pos = (pos[0], pos[1] + 1, pos[2]) + self._pow = PowBox(position=pos, velocity=(0.0, 1.0, 0.0)) + + def on_player_join(self, player: Player) -> None: + + if self.has_begun(): + if (all(teammate.lives == 0 for teammate in player.team.players) + 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 + # create our icon and spawn + player.icons = [Icon(player, + position=(0.0, 50), + scale=0.8)] + if player.lives > 0 or self.time_limit_only: + self.spawn_player(player) + + # dont waste time doing this until begin + if self.has_begun(): + self._update_icons() + + def on_player_leave(self, player: Player) -> None: + super().on_player_leave(player) + player.icons = None + + # update icons in a moment since our team + # will be gone from the list then + bs.timer(0.0, self._update_icons) + bs.timer(0.1, self.check_end_game, repeat=True) + + def _update_icons(self) -> None: + # pylint: disable=too-many-branches + + # In free-for-all mode, everyone is just lined up along the bottom. + if isinstance(self.session, bs.FreeForAllSession): + count = len(self.teams) + x_offs = 85 + xval = x_offs * (count - 1) * -0.5 + for team in self.teams: + if len(team.players) > 1: + print('WTF have', len(team.players), 'players in ffa team') + elif len(team.players) == 1: + player = team.players[0] + if len(player.icons) != 1: + print( + 'WTF have', + len(player.icons), + 'icons in non-solo elim') + for icon in player.icons: + icon.set_position_and_scale((xval, 30), 0.7) + icon.update_for_lives() + xval += x_offs + + # In teams mode we split up teams. + else: + if self._solo_mode: + # First off, clear out all icons. + for player in self.players: + player.icons = [] + + # 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 + is_first = True + 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, (40 if is_first else 25)), + scale=1.0 if is_first else 0.5, + name_maxwidth=130 if is_first else 75, + name_scale=0.8 if is_first else 1.0, + flatness=0.0 if is_first else 1.0, + shadow=0.5 if is_first else 1.0, + show_death=is_first, + show_lives=False)) + xval += x_offs * (0.8 if is_first else 0.56) + is_first = False + test_lives += 1 + # Non-solo mode. + else: + for team in self.teams: + if team.id == 0: + xval = -50 + x_offs = -85 + else: + xval = 50 + x_offs = 85 + for player in team.players: + if len(player.icons) != 1: + print( + 'WTF have', + len(player.icons), + 'icons in non-solo elim') + for icon in player.icons: + icon.set_position_and_scale((xval, 30), 0.7) + icon.update_for_lives() + xval += x_offs + + # overriding the default character spawning.. + def spawn_player(self, player: Player) -> bs.Actor: + if isinstance(self.session, bs.DualTeamSession): + position = self.map.get_start_position(player.team.id) + else: + # otherwise do free-for-all spawn locations + position = self.map.get_ffa_start_position(self.players) + angle = None + + name = player.getname() + light_color = _math.normalized_color(player.color) + display_color = babase.safecolor(player.color, target_intensity=0.75) + + spaz = SSPlayerSpaz(color=player.color, + highlight=player.highlight, + character=player.character, + player=player) + + player.actor = spaz + assert spaz.node + + # If this is co-op and we're on Courtyard or Runaround, add the + # material that allows us to collide with the player-walls. + # FIXME: Need to generalize this. + if isinstance(self.session, bs.CoopSession) and self.map.getname() in [ + 'Courtyard', 'Tower D' + ]: + mat = self.map.preloaddata['collide_with_wall_material'] + assert isinstance(spaz.node.materials, tuple) + assert isinstance(spaz.node.roller_materials, tuple) + spaz.node.materials += (mat, ) + spaz.node.roller_materials += (mat, ) + + spaz.node.name = name + spaz.node.name_color = display_color + spaz.connect_controls_to_player() + + # Move to the stand position and add a flash of light. + spaz.handlemessage( + bs.StandMessage( + position, + angle if angle is not None else random.uniform(0, 360))) + self._spawn_sound.play(1, position=spaz.node.position) + light = bs.newnode('light', attrs={'color': light_color}) + spaz.node.connectattr('position', light, 'position') + bs.animate(light, 'intensity', {0: 0, 0.25: 1, 0.5: 0}) + bs.timer(0.5, light.delete) + + # If we have any icons, update their state. + for icon in player.icons: + icon.handle_player_spawned() + + if self._boxing_gloves: + spaz.equip_boxing_gloves() + + return spaz + + def _get_total_team_lives(self, team: Team) -> int: + return sum(player.lives for player in team.players) + + def handlemessage(self, msg: Any) -> Any: + + if isinstance(msg, bs.PlayerDiedMessage): + # Augment standard behavior. + super().handlemessage(msg) + player: Player = msg.getplayer(Player) + + player.lives -= 1 + if player.lives < 0: + 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 in solo mode + if player.lives == 0: + SpazFactory.get().single_player_death_sound.play() + + # if we hit zero lives we're dead and the game might be over + if player.lives == 0 and not self.time_limit_only: + # 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) + # we still have lives; yay! + else: + self.respawn_player(player) + + bs.timer(0.1, self.check_end_game, repeat=True) + + else: + return super().handlemessage(msg) + return None + + def check_end_game(self) -> None: + if len(self._get_living_teams()) < 2: + 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) + ] + + 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/plugins/minigames/volleyball.py b/plugins/minigames/volleyball.py index d4aeacc..df4c19a 100644 --- a/plugins/minigames/volleyball.py +++ b/plugins/minigames/volleyball.py @@ -1,6 +1,6 @@ # Volley Ball (final) -# Made by your friend: Freaku / @[Just] Freak#4999 +# Made by your friend: Freaku # Join BCS: @@ -28,25 +28,24 @@ ## 2022 - Code cleanup -- No longer requires a plugin - More accurate Goal positions """ -# ba_meta require api 7 +# ba_meta require api 8 from __future__ import annotations from typing import TYPE_CHECKING -import _ba -import ba +import babase import random -from bastd.actor.playerspaz import PlayerSpaz -from bastd.actor.scoreboard import Scoreboard -from bastd.actor.powerupbox import PowerupBoxFactory -from bastd.actor.bomb import BombFactory -from bastd.gameutils import SharedObjects +import bascenev1 as bs +from bascenev1lib.actor.playerspaz import PlayerSpaz +from bascenev1lib.actor.scoreboard import Scoreboard +from bascenev1lib.actor.powerupbox import PowerupBoxFactory +from bascenev1lib.actor.bomb import BombFactory +from bascenev1lib.gameutils import SharedObjects if TYPE_CHECKING: from typing import Any, Sequence, Dict, Type, List, Optional, Union @@ -59,7 +58,7 @@ class PuckDiedMessage: self.puck = puck -class Puck(ba.Actor): +class Puck(bs.Actor): def __init__(self, position: Sequence[float] = (0.0, 1.0, 0.0)): super().__init__() shared = SharedObjects.get() @@ -72,16 +71,16 @@ class Puck(ba.Actor): assert activity is not None assert isinstance(activity, VolleyBallGame) pmats = [shared.object_material, activity.puck_material] - self.node = ba.newnode('prop', + self.node = bs.newnode('prop', delegate=self, attrs={ - 'model': activity.puck_model, + 'mesh': activity.puck_mesh, 'color_texture': activity.puck_tex, 'body': 'sphere', 'reflection': 'soft', 'reflection_scale': [0.2], 'shadow_size': 0.6, - 'model_scale': 0.4, + 'mesh_scale': 0.4, 'body_scale': 1.07, 'is_area_of_interest': True, 'position': self._spawn_pos, @@ -91,11 +90,11 @@ class Puck(ba.Actor): # Since it rolls on spawn, lets make gravity # to 0, and when another node (bomb/spaz) # touches it. It'll act back as our normie puck! - ba.animate(self.node, 'gravity_scale', {0: -0.1, 0.2: 1}, False) + bs.animate(self.node, 'gravity_scale', {0: -0.1, 0.2: 1}, False) # When other node touches, it realises its new gravity_scale def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, ba.DieMessage): + if isinstance(msg, bs.DieMessage): assert self.node self.node.delete() activity = self._activity() @@ -103,11 +102,11 @@ class Puck(ba.Actor): activity.handlemessage(PuckDiedMessage(self)) # If we go out of bounds, move back to where we started. - elif isinstance(msg, ba.OutOfBoundsMessage): + elif isinstance(msg, bs.OutOfBoundsMessage): assert self.node self.node.position = self._spawn_pos - elif isinstance(msg, ba.HitMessage): + elif isinstance(msg, bs.HitMessage): assert self.node assert msg.force_direction is not None self.node.handlemessage( @@ -128,29 +127,29 @@ class Puck(ba.Actor): super().handlemessage(msg) -class Player(ba.Player['Team']): +class Player(bs.Player['Team']): """Our player type for this game.""" -class Team(ba.Team[Player]): +class Team(bs.Team[Player]): """Our team type for this game.""" def __init__(self) -> None: self.score = 0 -# ba_meta export game -class VolleyBallGame(ba.TeamGameActivity[Player, Team]): +# ba_meta export bascenev1.GameActivity +class VolleyBallGame(bs.TeamGameActivity[Player, Team]): name = 'Volley Ball' description = 'Score some goals.\nby \ue048Freaku' available_settings = [ - ba.IntSetting( + bs.IntSetting( 'Score to Win', min_value=1, default=1, increment=1, ), - ba.IntChoiceSetting( + bs.IntChoiceSetting( 'Time Limit', choices=[ ('None', 0), @@ -162,7 +161,7 @@ class VolleyBallGame(ba.TeamGameActivity[Player, Team]): ], default=0, ), - ba.FloatChoiceSetting( + bs.FloatChoiceSetting( 'Respawn Times', choices=[ ('Shorter', 0.25), @@ -173,36 +172,36 @@ class VolleyBallGame(ba.TeamGameActivity[Player, Team]): ], default=1.0, ), - ba.BoolSetting('Epic Mode', True), - ba.BoolSetting('Night Mode', False), - ba.BoolSetting('Icy Floor', True), - ba.BoolSetting('Disable Punch', False), - ba.BoolSetting('Disable Bombs', False), - ba.BoolSetting('Enable Bottom Credits', True), + bs.BoolSetting('Epic Mode', True), + bs.BoolSetting('Night Mode', False), + bs.BoolSetting('Icy Floor', True), + bs.BoolSetting('Disable Punch', False), + bs.BoolSetting('Disable Bombs', False), + bs.BoolSetting('Enable Bottom Credits', True), ] - default_music = ba.MusicType.HOCKEY + default_music = bs.MusicType.HOCKEY @classmethod - def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool: - return issubclass(sessiontype, ba.DualTeamSession) + def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool: + return issubclass(sessiontype, bs.DualTeamSession) @classmethod - def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: + def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]: return ['Open Field', 'Closed Arena'] def __init__(self, settings: dict): super().__init__(settings) shared = SharedObjects.get() self._scoreboard = Scoreboard() - self._cheer_sound = ba.getsound('cheer') - self._chant_sound = ba.getsound('crowdChant') - self._foghorn_sound = ba.getsound('foghorn') - self._swipsound = ba.getsound('swip') - self._whistle_sound = ba.getsound('refWhistle') - self.puck_model = ba.getmodel('shield') - self.puck_tex = ba.gettexture('gameCircleIcon') - self._puck_sound = ba.getsound('metalHit') - self.puck_material = ba.Material() + self._cheer_sound = bs.getsound('cheer') + self._chant_sound = bs.getsound('crowdChant') + self._foghorn_sound = bs.getsound('foghorn') + self._swipsound = bs.getsound('swip') + self._whistle_sound = bs.getsound('refWhistle') + self.puck_mesh = bs.getmesh('shield') + self.puck_tex = bs.gettexture('gameCircleIcon') + self._puck_sound = bs.getsound('metalHit') + self.puck_material = bs.Material() self.puck_material.add_actions(actions=(('modify_part_collision', 'friction', 0.5))) self.puck_material.add_actions(conditions=('they_have_material', @@ -233,16 +232,16 @@ class VolleyBallGame(ba.TeamGameActivity[Player, Team]): conditions=('they_have_material', PowerupBoxFactory.get().powerup_material), actions=(('modify_part_collision', 'physical', False), - ('message', 'their_node', 'at_connect', ba.DieMessage()))) - self._score_region_material = ba.Material() + ('message', 'their_node', 'at_connect', bs.DieMessage()))) + self._score_region_material = bs.Material() self._score_region_material.add_actions( conditions=('they_have_material', self.puck_material), actions=(('modify_part_collision', 'collide', True), ('modify_part_collision', 'physical', False), ('call', 'at_connect', self._handle_score))) - self._wall_material = ba.Material() - self._fake_wall_material = ba.Material() + self._wall_material = bs.Material() + self._fake_wall_material = bs.Material() self._wall_material.add_actions( actions=( @@ -282,7 +281,7 @@ class VolleyBallGame(ba.TeamGameActivity[Player, Team]): )) self.blocks = [] - self._net_wall_material = ba.Material() + self._net_wall_material = bs.Material() self._net_wall_material.add_actions( conditions=('they_have_material', shared.player_material), actions=( @@ -309,7 +308,7 @@ class VolleyBallGame(ba.TeamGameActivity[Player, Team]): self.net_blocc = [] self._puck_spawn_pos: Optional[Sequence[float]] = None - self._score_regions: Optional[List[ba.NodeActor]] = None + self._score_regions: Optional[List[bs.NodeActor]] = None self._puck: Optional[Puck] = None self._score_to_win = int(settings['Score to Win']) self._punchie_ = bool(settings['Disable Punch']) @@ -321,8 +320,8 @@ class VolleyBallGame(ba.TeamGameActivity[Player, Team]): self._epic_mode = bool(settings['Epic Mode']) # Base class overrides. self.slow_motion = self._epic_mode - self.default_music = (ba.MusicType.EPIC if self._epic_mode else - ba.MusicType.TO_THE_DEATH) + self.default_music = (bs.MusicType.EPIC if self._epic_mode else + bs.MusicType.TO_THE_DEATH) def get_instance_description(self) -> Union[str, Sequence]: if self._score_to_win == 1: @@ -339,15 +338,15 @@ class VolleyBallGame(ba.TeamGameActivity[Player, Team]): self.setup_standard_time_limit(self._time_limit) if self._night_mode: - ba.getactivity().globalsnode.tint = (0.5, 0.7, 1) + bs.getactivity().globalsnode.tint = (0.5, 0.7, 1) self._puck_spawn_pos = self.map.get_flag_position(None) self._spawn_puck() # Set up the two score regions. self._score_regions = [] self._score_regions.append( - ba.NodeActor( - ba.newnode('region', + bs.NodeActor( + bs.newnode('region', attrs={ 'position': (5.7, 0, -0.065), 'scale': (10.7, 0.001, 8), @@ -355,8 +354,8 @@ class VolleyBallGame(ba.TeamGameActivity[Player, Team]): 'materials': [self._score_region_material] }))) self._score_regions.append( - ba.NodeActor( - ba.newnode('region', + bs.NodeActor( + bs.newnode('region', attrs={ 'position': (-5.7, 0, -0.065), 'scale': (10.7, 0.001, 8), @@ -364,9 +363,9 @@ class VolleyBallGame(ba.TeamGameActivity[Player, Team]): 'materials': [self._score_region_material] }))) self._update_scoreboard() - ba.playsound(self._chant_sound) + self._chant_sound.play() if self.credit_text: - t = ba.newnode('text', + t = bs.newnode('text', attrs={'text': "Created by Freaku\nVolleyBall", # Disable 'Enable Bottom Credits' when making playlist, No need to edit this lovely... 'scale': 0.7, 'position': (0, 0), @@ -376,23 +375,23 @@ class VolleyBallGame(ba.TeamGameActivity[Player, Team]): 'h_align': 'center', 'v_attach': 'bottom'}) shared = SharedObjects.get() - self.blocks.append(ba.NodeActor(ba.newnode('region', attrs={'position': (0, 2.4, 0), 'scale': ( + self.blocks.append(bs.NodeActor(bs.newnode('region', attrs={'position': (0, 2.4, 0), 'scale': ( 0.8, 6, 20), 'type': 'box', 'materials': (self._fake_wall_material, )}))) - self.net_blocc.append(ba.NodeActor(ba.newnode('region', attrs={'position': (0, 0, 0), 'scale': ( + self.net_blocc.append(bs.NodeActor(bs.newnode('region', attrs={'position': (0, 0, 0), 'scale': ( 0.6, 2.4, 20), 'type': 'box', 'materials': (self._net_wall_material, )}))) def on_team_join(self, team: Team) -> None: self._update_scoreboard() def _handle_puck_player_collide(self) -> None: - collision = ba.getcollision() + collision = bs.getcollision() try: puck = collision.sourcenode.getdelegate(Puck, True) player = collision.opposingnode.getdelegate(PlayerSpaz, True).getplayer( Player, True) - except ba.NotFoundError: + except bs.NotFoundError: return puck.last_players_to_touch[player.team.id] = player @@ -409,7 +408,7 @@ class VolleyBallGame(ba.TeamGameActivity[Player, Team]): if self._puck.scored: return - region = ba.getcollision().sourcenode + region = bs.getcollision().sourcenode index = 0 for index in range(len(self._score_regions)): if region == self._score_regions[index].node: @@ -431,7 +430,7 @@ class VolleyBallGame(ba.TeamGameActivity[Player, Team]): for player in team.players: if player.actor: - player.actor.handlemessage(ba.CelebrateMessage(2.0)) + player.actor.handlemessage(bs.CelebrateMessage(2.0)) # If we've got the player from the scoring team that last # touched us, give them points. @@ -446,28 +445,28 @@ class VolleyBallGame(ba.TeamGameActivity[Player, Team]): if team.score >= self._score_to_win: self.end_game() - ba.playsound(self._foghorn_sound) - ba.playsound(self._cheer_sound) + self._foghorn_sound.play() + self._cheer_sound.play() self._puck.scored = True # Kill the puck (it'll respawn itself shortly). - ba.emitfx(position=ba.getcollision().position, count=int( + bs.emitfx(position=bs.getcollision().position, count=int( 6.0 + 7.0 * 12), scale=3, spread=0.5, chunk_type='spark') - ba.timer(0.7, self._kill_puck) + bs.timer(0.7, self._kill_puck) - ba.cameraflash(duration=7.0) + bs.cameraflash(duration=7.0) self._update_scoreboard() def end_game(self) -> None: - results = ba.GameResults() + results = bs.GameResults() for team in self.teams: results.set_team_score(team, team.score) self.end(results=results) def on_transition_in(self) -> None: super().on_transition_in() - activity = ba.getactivity() + activity = bs.getactivity() if self._icy_flooor: activity.map.is_hockey = True @@ -477,7 +476,7 @@ class VolleyBallGame(ba.TeamGameActivity[Player, Team]): self._scoreboard.set_team_value(team, team.score, winscore) # overriding the default character spawning.. - def spawn_player(self, player: Player) -> ba.Actor: + def spawn_player(self, player: Player) -> bs.Actor: spaz = self.spawn_player_spaz(player) if self._bombies_: @@ -493,7 +492,7 @@ class VolleyBallGame(ba.TeamGameActivity[Player, Team]): def handlemessage(self, msg: Any) -> Any: # Respawn dead players if they're still in the game. - if isinstance(msg, ba.PlayerDiedMessage): + if isinstance(msg, bs.PlayerDiedMessage): # Augment standard behavior... super().handlemessage(msg) self.respawn_player(msg.getplayer(Player)) @@ -501,18 +500,18 @@ class VolleyBallGame(ba.TeamGameActivity[Player, Team]): # Respawn dead pucks. elif isinstance(msg, PuckDiedMessage): if not self.has_ended(): - ba.timer(2.2, self._spawn_puck) + bs.timer(2.2, self._spawn_puck) else: super().handlemessage(msg) def _flash_puck_spawn(self) -> None: # Effect >>>>>> Flashly - ba.emitfx(position=self._puck_spawn_pos, count=int( + bs.emitfx(position=self._puck_spawn_pos, count=int( 6.0 + 7.0 * 12), scale=1.7, spread=0.4, chunk_type='spark') def _spawn_puck(self) -> None: - ba.playsound(self._swipsound) - ba.playsound(self._whistle_sound) + self._swipsound.play() + self._whistle_sound.play() self._flash_puck_spawn() assert self._puck_spawn_pos is not None self._puck = Puck(position=self._puck_spawn_pos) @@ -538,7 +537,7 @@ class PointzzforH: points['spawn2'] = (6.857415055, 0.03938567998, 0.0) + (1.0, 1.0, 3.0) -class VolleyBallMap(ba.Map): +class VolleyBallMap(bs.Map): defs = Pointzz() name = "Open Field" @@ -553,10 +552,10 @@ class VolleyBallMap(ba.Map): @classmethod def on_preload(cls) -> Any: data: Dict[str, Any] = { - 'model': ba.getmodel('footballStadium'), - 'vr_fill_model': ba.getmodel('footballStadiumVRFill'), - 'collide_model': ba.getcollidemodel('footballStadiumCollide'), - 'tex': ba.gettexture('footballStadium') + 'mesh': bs.getmesh('footballStadium'), + 'vr_fill_mesh': bs.getmesh('footballStadiumVRFill'), + 'collision_mesh': bs.getcollisionmesh('footballStadiumCollide'), + 'tex': bs.gettexture('footballStadium') } return data @@ -565,60 +564,60 @@ class VolleyBallMap(ba.Map): shared = SharedObjects.get() x = -5 while x < 5: - self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (0, 0, x), + self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (0, 0, x), 'color': (1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) - self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (0, .25, x), + self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (0, .25, x), 'color': (1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) - self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (0, .5, x), + self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (0, .5, x), 'color': (1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) - self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (0, .75, x), + self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (0, .75, x), 'color': (1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) - self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (0, 1, x), + self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (0, 1, x), 'color': (1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) x = x + 0.5 y = -1 while y > -11: - self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (y, 0.01, 4), + self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (y, 0.01, 4), 'color': (0, 0, 1), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) - self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (y, 0.01, -4), + self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (y, 0.01, -4), 'color': (0, 0, 1), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) - self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (-y, 0.01, 4), + self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (-y, 0.01, 4), 'color': (1, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) - self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (-y, 0.01, -4), + self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (-y, 0.01, -4), 'color': (1, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) y -= 1 z = 0 while z < 5: - self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (11, 0.01, z), + self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (11, 0.01, z), 'color': (1, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) - self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (11, 0.01, -z), + self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (11, 0.01, -z), 'color': (1, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) - self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (-11, 0.01, z), + self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (-11, 0.01, z), 'color': (0, 0, 1), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) - self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (-11, 0.01, -z), + self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (-11, 0.01, -z), 'color': (0, 0, 1), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) z += 1 - self.node = ba.newnode( + self.node = bs.newnode( 'terrain', delegate=self, attrs={ - 'model': self.preloaddata['model'], - 'collide_model': self.preloaddata['collide_model'], + 'mesh': self.preloaddata['mesh'], + 'collision_mesh': self.preloaddata['collision_mesh'], 'color_texture': self.preloaddata['tex'], 'materials': [shared.footing_material] }) - ba.newnode('terrain', + bs.newnode('terrain', attrs={ - 'model': self.preloaddata['vr_fill_model'], + 'mesh': self.preloaddata['vr_fill_mesh'], 'lighting': False, 'vr_only': True, 'background': True, 'color_texture': self.preloaddata['tex'] }) - gnode = ba.getactivity().globalsnode + 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) @@ -627,7 +626,7 @@ class VolleyBallMap(ba.Map): gnode.vr_near_clip = 0.5 -class VolleyBallMapH(ba.Map): +class VolleyBallMapH(bs.Map): defs = PointzzforH() name = 'Closed Arena' @@ -642,13 +641,13 @@ class VolleyBallMapH(ba.Map): @classmethod def on_preload(cls) -> Any: data: Dict[str, Any] = { - 'models': (ba.getmodel('hockeyStadiumOuter'), - ba.getmodel('hockeyStadiumInner')), - 'vr_fill_model': ba.getmodel('footballStadiumVRFill'), - 'collide_model': ba.getcollidemodel('hockeyStadiumCollide'), - 'tex': ba.gettexture('hockeyStadium'), + 'meshs': (bs.getmesh('hockeyStadiumOuter'), + bs.getmesh('hockeyStadiumInner')), + 'vr_fill_mesh': bs.getmesh('footballStadiumVRFill'), + 'collision_mesh': bs.getcollisionmesh('hockeyStadiumCollide'), + 'tex': bs.gettexture('hockeyStadium'), } - mat = ba.Material() + mat = bs.Material() mat.add_actions(actions=('modify_part_collision', 'friction', 0.01)) data['ice_material'] = mat return data @@ -658,66 +657,66 @@ class VolleyBallMapH(ba.Map): shared = SharedObjects.get() x = -5 while x < 5: - self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (0, 0, x), + self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (0, 0, x), 'color': (1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) - self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (0, .25, x), + self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (0, .25, x), 'color': (1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) - self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (0, .5, x), + self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (0, .5, x), 'color': (1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) - self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (0, .75, x), + self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (0, .75, x), 'color': (1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) - self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (0, 1, x), + self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (0, 1, x), 'color': (1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) x = x + 0.5 y = -1 while y > -11: - self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (y, 0.01, 4), + self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (y, 0.01, 4), 'color': (0, 0, 1), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) - self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (y, 0.01, -4), + self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (y, 0.01, -4), 'color': (0, 0, 1), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) - self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (-y, 0.01, 4), + self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (-y, 0.01, 4), 'color': (1, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) - self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (-y, 0.01, -4), + self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (-y, 0.01, -4), 'color': (1, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) y -= 1 z = 0 while z < 5: - self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (11, 0.01, z), + self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (11, 0.01, z), 'color': (1, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) - self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (11, 0.01, -z), + self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (11, 0.01, -z), 'color': (1, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) - self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (-11, 0.01, z), + self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (-11, 0.01, z), 'color': (0, 0, 1), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) - self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (-11, 0.01, -z), + self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (-11, 0.01, -z), 'color': (0, 0, 1), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) z += 1 - self.node = ba.newnode('terrain', + self.node = bs.newnode('terrain', delegate=self, attrs={ - 'model': + 'mesh': None, - 'collide_model': + 'collision_mesh': # we dont want Goalposts... - ba.getcollidemodel('footballStadiumCollide'), + bs.getcollisionmesh('footballStadiumCollide'), 'color_texture': self.preloaddata['tex'], 'materials': [ shared.footing_material] }) - ba.newnode('terrain', + bs.newnode('terrain', attrs={ - 'model': self.preloaddata['vr_fill_model'], + 'mesh': self.preloaddata['vr_fill_mesh'], 'vr_only': True, 'lighting': False, 'background': True, }) mats = [shared.footing_material] - self.floor = ba.newnode('terrain', + self.floor = bs.newnode('terrain', attrs={ - 'model': self.preloaddata['models'][1], + 'mesh': self.preloaddata['meshs'][1], 'color_texture': self.preloaddata['tex'], 'opacity': 0.92, 'opacity_in_low_or_medium_quality': 1.0, @@ -725,16 +724,16 @@ class VolleyBallMapH(ba.Map): 'color': (0.4, 0.9, 0) }) - self.background = ba.newnode( + self.background = bs.newnode( 'terrain', attrs={ - 'model': ba.getmodel('natureBackground'), + 'mesh': bs.getmesh('natureBackground'), 'lighting': False, 'background': True, 'color': (0.5, 0.30, 0.4) }) - gnode = ba.getactivity().globalsnode + gnode = bs.getactivity().globalsnode gnode.floor_reflection = True gnode.debris_friction = 0.3 gnode.debris_kill_height = -0.3 @@ -747,5 +746,17 @@ class VolleyBallMapH(ba.Map): #self.is_hockey = True -ba._map.register_map(VolleyBallMap) -ba._map.register_map(VolleyBallMapH) +bs._map.register_map(VolleyBallMap) +bs._map.register_map(VolleyBallMapH) + + +# ba_meta export plugin +class byFreaku(babase.Plugin): + def __init__(self): + # Reason of plugin: + # To register maps. + # + # Then why not include function here? + # On server upon first launch, plugins are not activated, + # (same can be case for user if disabled auto-enable plugins) + pass diff --git a/plugins/utilities.json b/plugins/utilities.json index 7598dc9..462398b 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -293,10 +293,16 @@ { "name": "Freaku", "email": "", - "discord": "[Just] Freak#4999" + "discord": "" } ], "versions": { + "2.0.0": { + "api_version": 8, + "commit_sha": "48f9302", + "released_on": "28-07-2023", + "md5sum": "31df84f027c98e86336a420aa509e47f" + }, "1.0.0": { "api_version": 7, "commit_sha": "6beb8ddf", @@ -312,10 +318,16 @@ { "name": "Freaku", "email": "", - "discord": "[Just] Freak#4999" + "discord": "" } ], "versions": { + "2.0.0": { + "api_version": 8, + "commit_sha": "48f9302", + "released_on": "28-07-2023", + "md5sum": "ef2dbcac9190a61753e2c3c0f8afc22c" + }, "1.1.0": { "api_version": 7, "commit_sha": "383f774", @@ -505,10 +517,16 @@ { "name": "Freaku", "email": "", - "discord": "[Just] Freak#4999" + "discord": "" } ], "versions": { + "2.0.0": { + "api_version": 8, + "commit_sha": "48f9302", + "released_on": "28-07-2023", + "md5sum": "8a63ad58d24e2b61bb63645f74d876e8" + }, "1.0.0": { "api_version": 7, "commit_sha": "b581d90", diff --git a/plugins/utilities/floater.py b/plugins/utilities/floater.py index d57e593..28e943e 100644 --- a/plugins/utilities/floater.py +++ b/plugins/utilities/floater.py @@ -1,4 +1,4 @@ -# Ported by: Freaku / @[Just] Freak#4999 +# Ported by your friend: Freaku # Join BCS: # https://discord.gg/ucyaesh @@ -8,27 +8,30 @@ # https://github.com/Freaku17/BombSquad-Mods-byFreaku -# ba_meta require api 7 +# ba_meta require api 8 from __future__ import annotations from typing import TYPE_CHECKING -import _ba -import ba +import _babase +import babase import random import math -from bastd.gameutils import SharedObjects -from bastd.actor.bomb import Bomb -from bastd.actor.popuptext import PopupText +import bauiv1 as bui +import bascenev1 as bs +from bascenev1lib.gameutils import SharedObjects +from bascenev1lib.actor.bomb import Bomb +from bascenev1lib.actor.popuptext import PopupText +from bauiv1lib.party import PartyWindow if TYPE_CHECKING: from typing import Optional -class Floater(ba.Actor): +class Floater(bs.Actor): def __init__(self, bounds): super().__init__() shared = SharedObjects.get() self.controlled = False self.source_player = None - self.floaterMaterial = ba.Material() + self.floaterMaterial = bs.Material() self.floaterMaterial.add_actions( conditions=('they_have_material', shared.player_material), @@ -48,21 +51,21 @@ class Floater(ba.Actor): self.py = "random.uniform(self.pos[1],self.pos[4])" self.pz = "random.uniform(self.pos[2],self.pos[5])" - self.node = ba.newnode( + self.node = bs.newnode( 'prop', delegate=self, owner=None, attrs={ 'position': (eval(self.px), eval(self.py), eval(self.pz)), - 'model': - ba.getmodel('landMine'), - 'light_model': - ba.getmodel('landMine'), + 'mesh': + bs.getmesh('landMine'), + 'light_mesh': + bs.getmesh('landMine'), 'body': 'landMine', 'body_scale': 3, - 'model_scale': + 'mesh_scale': 3.1, 'shadow_size': 0.25, @@ -71,21 +74,21 @@ class Floater(ba.Actor): 'gravity_scale': 0.0, 'color_texture': - ba.gettexture('achievementFlawlessVictory'), + bs.gettexture('achievementFlawlessVictory'), 'reflection': 'soft', 'reflection_scale': [0.25], 'materials': [shared.footing_material, self.floaterMaterial] }) - self.node2 = ba.newnode( + self.node2 = bs.newnode( 'prop', owner=self.node, attrs={ 'position': (0, 0, 0), 'body': 'sphere', - 'model': + 'mesh': None, 'color_texture': None, @@ -96,7 +99,7 @@ class Floater(ba.Actor): 'density': 999999, 'reflection_scale': [1.0], - 'model_scale': + 'mesh_scale': 1.0, 'gravity_scale': 0, @@ -110,7 +113,7 @@ class Floater(ba.Actor): self.node.connectattr('position', self.node2, 'position') def pop(self): PopupText(text="Ported by \ue048Freaku", scale=1.3, position=( - self.node.position[0], self.node.position[1]-1, self.node.position[2]), color=(0, 1, 1)).autoretain() # Edit = YouNoob... + self.node.position[0], self.node.position[1]-1, self.node.position[2]), color=(0, 1, 1)).autoretain() def checkCanControl(self): if not self.node.exists(): @@ -172,7 +175,7 @@ class Floater(ba.Actor): if self.source_player is None: return if self.source_player.is_alive(): - ba.timer(1, self.checkPlayerDie) + bs.timer(1, self.checkPlayerDie) return else: self.dis() @@ -199,22 +202,22 @@ class Floater(ba.Actor): pn = self.node.position dist = self.distance(pn[0], pn[1], pn[2], px, py, pz) self.node.velocity = ((px - pn[0]) / dist, (py - pn[1]) / dist, (pz - pn[2]) / dist) - ba.timer(dist-1, ba.WeakCall(self.move), suppress_format_warning=True) + bs.timer(dist-1, bs.WeakCall(self.move)) # suppress_format_warning=True) def handlemessage(self, msg): - if isinstance(msg, ba.DieMessage): + if isinstance(msg, bs.DieMessage): self.node.delete() self.node2.delete() self.controlled = False - elif isinstance(msg, ba.OutOfBoundsMessage): - self.handlemessage(ba.DieMessage()) + elif isinstance(msg, bs.OutOfBoundsMessage): + self.handlemessage(bs.DieMessage()) else: super().handlemessage(msg) def assignFloInputs(clientID: int): - with ba.Context(_ba.get_foreground_host_activity()): - activity = ba.getactivity() + activity = bs.get_foreground_host_activity() + with activity.context: if not hasattr(activity, 'flo') or not activity.flo.node.exists(): try: activity.flo = Floater(activity.map.get_def_bound_box('map_bounds')) @@ -222,13 +225,13 @@ def assignFloInputs(clientID: int): return # Perhaps using in main-menu/score-screen floater = activity.flo if floater.controlled: - ba.screenmessage('Floater is already being controlled', - color=(1, 0, 0), transient=True, clients=[clientID]) + bs.broadcastmessage('Floater is already being controlled', + color=(1, 0, 0), transient=True, clients=[clientID]) return - ba.screenmessage('You Gained Control Over The Floater!\n Press Bomb to Throw Bombs and Punch to leave!', clients=[ - clientID], transient=True, color=(0, 1, 1)) + bs.broadcastmessage('You Gained Control Over The Floater!\n Press Bomb to Throw Bombs and Punch to leave!', clients=[ + clientID], transient=True, color=(0, 1, 1)) - for i in _ba.get_foreground_host_activity().players: + for i in activity.players: if i.sessionplayer.inputdevice.client_id == clientID: def dis(i, floater): i.actor.node.invincible = False @@ -238,41 +241,54 @@ def assignFloInputs(clientID: int): ps = i.actor.node.position i.actor.node.invincible = True floater.node.position = (ps[0], ps[1] + 1.0, ps[2]) - ba.timer(1, floater.pop) - i.actor.node.hold_node = ba.Node(None) + bs.timer(1, floater.pop) + i.actor.node.hold_node = bs.Node(None) i.actor.node.hold_node = floater.node2 i.actor.connect_controls_to_player() i.actor.disconnect_controls_from_player() i.resetinput() floater.source_player = i floater.con() - i.assigninput(ba.InputType.PICK_UP_PRESS, floater.up) - i.assigninput(ba.InputType.PICK_UP_RELEASE, floater.upR) - i.assigninput(ba.InputType.JUMP_PRESS, floater.down) - i.assigninput(ba.InputType.BOMB_PRESS, floater.drop) - i.assigninput(ba.InputType.PUNCH_PRESS, ba.Call(dis, i, floater)) - i.assigninput(ba.InputType.UP_DOWN, floater.updown) - i.assigninput(ba.InputType.LEFT_RIGHT, floater.leftright) + i.assigninput(babase.InputType.PICK_UP_PRESS, floater.up) + i.assigninput(babase.InputType.PICK_UP_RELEASE, floater.upR) + i.assigninput(babase.InputType.JUMP_PRESS, floater.down) + i.assigninput(babase.InputType.BOMB_PRESS, floater.drop) + i.assigninput(babase.InputType.PUNCH_PRESS, babase.Call(dis, i, floater)) + i.assigninput(babase.InputType.UP_DOWN, floater.updown) + i.assigninput(babase.InputType.LEFT_RIGHT, floater.leftright) -old_fcm = _ba.chatmessage +# Display chat icon, but if user open/close gather it may disappear +bui.set_party_icon_always_visible(True) -def new_chat_message(msg: Union[str, ba.Lstr], clients: Sequence[int] = None, sender_override: str = None): - old_fcm(msg, clients, sender_override) - if msg == '/floater': +old_piv = bui.set_party_icon_always_visible + + +def new_piv(*args, **kwargs): + # Do not let chat icon go away + old_piv(True) + + +bui.set_party_icon_always_visible = new_piv + + +old_fcm = bs.chatmessage + + +def new_chat_message(*args, **kwargs): + old_fcm(*args, **kwargs) + if args[0] == '/floater': try: assignFloInputs(-1) except: pass -_ba.chatmessage = new_chat_message -if not _ba.is_party_icon_visible(): - _ba.set_party_icon_always_visible(True) +bs.chatmessage = new_chat_message # ba_meta export plugin -class byFreaku(ba.Plugin): +class byFreaku(babase.Plugin): def __init__(self): pass diff --git a/plugins/utilities/icons_keyboard.py b/plugins/utilities/icons_keyboard.py index 3033bd4..7447660 100644 --- a/plugins/utilities/icons_keyboard.py +++ b/plugins/utilities/icons_keyboard.py @@ -1,4 +1,4 @@ -# Made by: Freaku / @[Just] Freak#4999 +# Made by your friend: Freaku # • Icon Keyboard • # Make your chats look even more cooler! @@ -6,51 +6,52 @@ # Double tap the space to change between keyboards... -# ba_meta require api 7 +# ba_meta require api 8 from __future__ import annotations from typing import TYPE_CHECKING -import ba -from _ba import charstr as uwu +import babase +import bascenev1 as bs +from babase import charstr as uwu if TYPE_CHECKING: from typing import Any, Optional, Dict, List, Tuple, Type, Iterable # ba_meta export keyboard -class IconKeyboard_byFreaku(ba.Keyboard): +class IconKeyboard_byFreaku(babase.Keyboard): """Keyboard go brrrrrrr""" name = 'Icons by \ue048Freaku' - chars = [(uwu(ba.SpecialChar.TICKET), - uwu(ba.SpecialChar.CROWN), - uwu(ba.SpecialChar.DRAGON), - uwu(ba.SpecialChar.SKULL), - uwu(ba.SpecialChar.HEART), - uwu(ba.SpecialChar.FEDORA), - uwu(ba.SpecialChar.HAL), - uwu(ba.SpecialChar.YIN_YANG), - uwu(ba.SpecialChar.EYE_BALL), - uwu(ba.SpecialChar.HELMET), - uwu(ba.SpecialChar.OUYA_BUTTON_U)), - (uwu(ba.SpecialChar.MUSHROOM), - uwu(ba.SpecialChar.NINJA_STAR), - uwu(ba.SpecialChar.VIKING_HELMET), - uwu(ba.SpecialChar.MOON), - uwu(ba.SpecialChar.SPIDER), - uwu(ba.SpecialChar.FIREBALL), - uwu(ba.SpecialChar.MIKIROG), - uwu(ba.SpecialChar.OUYA_BUTTON_O), - uwu(ba.SpecialChar.LOCAL_ACCOUNT), - uwu(ba.SpecialChar.LOGO)), - (uwu(ba.SpecialChar.TICKET), - uwu(ba.SpecialChar.FLAG_INDIA), - uwu(ba.SpecialChar.OCULUS_LOGO), - uwu(ba.SpecialChar.STEAM_LOGO), - uwu(ba.SpecialChar.NVIDIA_LOGO), - uwu(ba.SpecialChar.GAME_CENTER_LOGO), - uwu(ba.SpecialChar.GOOGLE_PLAY_GAMES_LOGO), - uwu(ba.SpecialChar.ALIBABA_LOGO))] + chars = [(uwu(babase.SpecialChar.TICKET), + uwu(babase.SpecialChar.CROWN), + uwu(babase.SpecialChar.DRAGON), + uwu(babase.SpecialChar.SKULL), + uwu(babase.SpecialChar.HEART), + uwu(babase.SpecialChar.FEDORA), + uwu(babase.SpecialChar.HAL), + uwu(babase.SpecialChar.YIN_YANG), + uwu(babase.SpecialChar.EYE_BALL), + uwu(babase.SpecialChar.HELMET), + uwu(babase.SpecialChar.OUYA_BUTTON_U)), + (uwu(babase.SpecialChar.MUSHROOM), + uwu(babase.SpecialChar.NINJA_STAR), + uwu(babase.SpecialChar.VIKING_HELMET), + uwu(babase.SpecialChar.MOON), + uwu(babase.SpecialChar.SPIDER), + uwu(babase.SpecialChar.FIREBALL), + uwu(babase.SpecialChar.MIKIROG), + uwu(babase.SpecialChar.OUYA_BUTTON_O), + uwu(babase.SpecialChar.LOCAL_ACCOUNT), + uwu(babase.SpecialChar.LOGO)), + (uwu(babase.SpecialChar.TICKET), + uwu(babase.SpecialChar.FLAG_INDIA), + uwu(babase.SpecialChar.OCULUS_LOGO), + uwu(babase.SpecialChar.STEAM_LOGO), + uwu(babase.SpecialChar.NVIDIA_LOGO), + uwu(babase.SpecialChar.GAME_CENTER_LOGO), + uwu(babase.SpecialChar.GOOGLE_PLAY_GAMES_LOGO), + uwu(babase.SpecialChar.EXPLODINARY_LOGO))] nums = [] pages: Dict[str, Tuple[str, ...]] = {} diff --git a/plugins/utilities/unlock_TowerD.py b/plugins/utilities/unlock_TowerD.py index e6d29b4..172e8c0 100644 --- a/plugins/utilities/unlock_TowerD.py +++ b/plugins/utilities/unlock_TowerD.py @@ -1,8 +1,9 @@ -# By Freaku / @[Just] Freak#4999 +# Made by your friend: Freaku -import ba -from bastd.maps import TowerD +import babase +import bascenev1 as bs +from bascenev1lib.maps import TowerD @classmethod @@ -11,8 +12,8 @@ def new_play_types(cls): return ['melee', 'keep_away', 'team_flag', 'king_of_the_hill'] -# ba_meta require api 7 +# ba_meta require api 8 # ba_meta export plugin -class byFreaku(ba.Plugin): +class byFreaku(babase.Plugin): def on_app_running(self): TowerD.get_play_types = new_play_types