From e01840c83d35766a2ddb5e90a6715d56cd785785 Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Wed, 24 Jan 2024 14:17:05 +0300 Subject: [PATCH 01/36] Update request from bombsquaders --- plugins/minigames.json | 98 ++ plugins/minigames/Avalanche.py | 143 +++ plugins/minigames/EggGame.py | 491 ++++++++ plugins/minigames/HYPER_RACE.py | 1239 ++++++++++++++++++++ plugins/minigames/SnowBallFight.py | 643 ++++++++++ plugins/minigames/meteorshowerdeluxe.py | 67 ++ plugins/minigames/ofuuuAttack.py | 340 ++++++ plugins/minigames/safe_zone.py | 720 ++++++++++++ plugins/utilities.json | 58 +- plugins/utilities/InfinityShield.py | 81 ++ plugins/utilities/OnlyNight.py | 50 + plugins/utilities/Tag.py | 565 +++++++++ plugins/utilities/disable_friendly_fire.py | 108 ++ 13 files changed, 4602 insertions(+), 1 deletion(-) create mode 100644 plugins/minigames/Avalanche.py create mode 100644 plugins/minigames/EggGame.py create mode 100644 plugins/minigames/HYPER_RACE.py create mode 100644 plugins/minigames/SnowBallFight.py create mode 100644 plugins/minigames/meteorshowerdeluxe.py create mode 100644 plugins/minigames/ofuuuAttack.py create mode 100644 plugins/minigames/safe_zone.py create mode 100644 plugins/utilities/InfinityShield.py create mode 100644 plugins/utilities/OnlyNight.py create mode 100644 plugins/utilities/Tag.py create mode 100644 plugins/utilities/disable_friendly_fire.py diff --git a/plugins/minigames.json b/plugins/minigames.json index 5f3b9e2..01a7b96 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -877,6 +877,104 @@ "md5sum": "1cbe5b3e85b5dfcee1eb322f33568fd4" } } + }, + "Avalanche": { + "description": "Dodge the falling ice bombs", + "external_url": "", + "authors": [ + { + "name": "", + "email": "", + "discord": "" + } + ], + "versions": { + "1.0.0": null + } + }, + "HYPER_RACE": { + "description": "Race and avoid the obsatacles", + "external_url": "", + "authors": [ + { + "name": "JoseAng3l", + "email": "", + "discord": "joseang3l" + } + ], + "versions": { + "1.0.0": null + } + }, + "meteorshowerdeluxe": { + "description": "Meteor shower on all maps support", + "external_url": "", + "authors": [ + { + "name": "EraOSBeta", + "email": "", + "discord": "3ra0" + } + ], + "versions": { + "1.0.0": null + } + }, + "ofuuuAttack": { + "description": "Dodge the falling bombs.", + "external_url": "", + "authors": [ + { + "name": "Riyukii", + "email": "", + "discord": "" + } + ], + "versions": { + "1.0.0": null + } + }, + "safe_zone": { + "description": "Stay in the safe zone", + "external_url": "", + "authors": [ + { + "name": "SEBASTIAN2059", + "email": "", + "discord": "sebastian2059" + } + ], + "versions": { + "1.0.0": null + } + }, + "SnowBallFight": { + "description": "Throw snoballs and dominate", + "external_url": "https://youtu.be/uXyb_meBjGI?si=D_N_OXZT5BFh8R5C", + "authors": [ + { + "name": "JoseAng3l", + "email": "", + "discord": "joseang3l" + } + ], + "versions": { + "1.0.0": null + } + }, + "EggGame": { + "description": "Throw Egg as far u can", + "external_url": "https://youtu.be/82vLp9ceCcw?si=OSC5Hu3Ns7PevlwP", + "authors": [ + { + "name": "Mr.Smoothy", + "email": "", + "discord": "mr.smoothy" + } + ], + "versions": { + "1.0.0": null + } } } } \ No newline at end of file diff --git a/plugins/minigames/Avalanche.py b/plugins/minigames/Avalanche.py new file mode 100644 index 0000000..1e36208 --- /dev/null +++ b/plugins/minigames/Avalanche.py @@ -0,0 +1,143 @@ +# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport) +"""Avalancha mini-game.""" + +# ba_meta require api 8 +# (see https://ballistica.net/wiki/meta-tag-system) + +from __future__ import annotations +import random +from typing import TYPE_CHECKING + +import babase +import bauiv1 as bui +import bascenev1 as bs +from bascenev1lib.actor.bomb import Bomb +from bascenev1lib.actor.onscreentimer import OnScreenTimer +from bascenev1lib.game.meteorshower import * +from bascenev1lib.actor.spazbot import * +from bascenev1lib.actor.spaz import PunchHitMessage +from bascenev1lib.gameutils import SharedObjects + +if TYPE_CHECKING: + from typing import Any, Sequence, Optional, List, Dict, Type, Type + +## MoreMinigames.py support ## +randomPic = ["lakeFrigidPreview", "hockeyStadiumPreview"] + + +def ba_get_api_version(): + return 6 + + +def ba_get_levels(): + return [ + babase._level.Level( + "Icy Emits", + gametype=IcyEmitsGame, + settings={}, + preview_texture_name=random.choice(randomPic), + ) + ] + + +## MoreMinigames.py support ## + + +class PascalBot(BrawlerBot): + color = (0, 0, 3) + highlight = (0.2, 0.2, 1) + character = "Pascal" + bouncy = True + punchiness = 0.7 + + def handlemessage(self, msg: Any) -> Any: + assert not self.expired + if isinstance(msg, bs.FreezeMessage): + return + else: + super().handlemessage(msg) + + +# ba_meta export bascenev1.GameActivity +class AvalanchaGame(MeteorShowerGame): + """Minigame involving dodging falling bombs.""" + + name = "Avalanche" + description = "Dodge the ice-bombs." + available_settings = [ + bs.BoolSetting("Epic Mode", default=False), + bs.IntSetting("Difficulty", default=1, min_value=1, max_value=3, increment=1), + ] + scoreconfig = bs.ScoreConfig( + label="Survived", scoretype=bs.ScoreType.MILLISECONDS, version="B" + ) + + announce_player_deaths = True + + @classmethod + def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]: + return ["Tip Top"] + + def __init__(self, settings: dict): + super().__init__(settings) + + self._epic_mode = settings.get("Epic Mode", False) + self._last_player_death_time: Optional[float] = None + self._meteor_time = 2.0 + if settings["Difficulty"] == 1: + self._min_delay = 0.4 + elif settings["Difficulty"] == 2: + self._min_delay = 0.3 + else: + self._min_delay = 0.1 + + self._timer: Optional[OnScreenTimer] = None + self._bots = SpazBotSet() + + self.default_music = ( + bs.MusicType.EPIC if self._epic_mode else bs.MusicType.SURVIVAL + ) + if self._epic_mode: + self.slow_motion = True + + def on_transition_in(self) -> None: + super().on_transition_in() + gnode = bs.getactivity().globalsnode + gnode.tint = (0.5, 0.5, 1) + + act = bs.getactivity().map + shared = SharedObjects.get() + mat = bs.Material() + mat.add_actions(actions=("modify_part_collision", "friction", 0.18)) + + act.node.color = act.bottom.color = (1, 1, 1.2) + act.node.reflection = act.bottom.reflection = "soft" + act.node.materials = [shared.footing_material, mat] + + def _set_meteor_timer(self) -> None: + bs.timer( + (1.0 + 0.2 * random.random()) * self._meteor_time, self._drop_bomb_cluster + ) + + def _drop_bomb_cluster(self) -> None: + defs = self.map.defs + delay = 0.0 + for _i in range(random.randrange(1, 3)): + pos = defs.points["flag_default"] + pos = (pos[0], pos[1] + 0.4, pos[2]) + dropdir = -1.0 if pos[0] > 0 else 1.0 + vel = (random.randrange(-4, 4), 7.0, random.randrange(0, 4)) + bs.timer(delay, babase.Call(self._drop_bomb, pos, vel)) + delay += 0.1 + self._set_meteor_timer() + + def _drop_bomb(self, position: Sequence[float], velocity: Sequence[float]) -> None: + Bomb(position=position, velocity=velocity, bomb_type="ice").autoretain() + + def _decrement_meteor_time(self) -> None: + if self._meteor_time < self._min_delay: + return + self._meteor_time = max(0.01, self._meteor_time * 0.9) + if random.choice([0, 0, 1]) == 1: + pos = self.map.defs.points["flag_default"] + self._bots.spawn_bot(PascalBot, pos=pos, spawn_time=2) diff --git a/plugins/minigames/EggGame.py b/plugins/minigames/EggGame.py new file mode 100644 index 0000000..e2d2030 --- /dev/null +++ b/plugins/minigames/EggGame.py @@ -0,0 +1,491 @@ +# Ported by brostos to api 8 +# Tool used to make porting easier.(https://github.com/bombsquad-community/baport) +# Released under the MIT License. See LICENSE for details. + +"""Egg game and support classes.""" +# The Egg Game - throw egg as far as you can +# created in BCS (Bombsquad Consultancy Service) - opensource bombsquad mods for all +# discord.gg/ucyaesh join now and give your contribution +# The Egg game by mr.smoothy +# 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 +from bascenev1lib.actor.flag import Flag +import math +import random +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 + + +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 =None + self.scored = False + self.egg_mesh = bs.getmesh('egg') + self.egg_tex_1 = bs.gettexture('eggTex1') + self.egg_tex_2 = bs.gettexture('eggTex2') + self.egg_tex_3 = bs.gettexture('eggTex3') + self.eggtx=[self.egg_tex_1,self.egg_tex_2,self.egg_tex_3] + regg=random.randrange(0,3) + assert activity is not None + assert isinstance(activity, EggGame) + pmats = [shared.object_material, activity.puck_material] + self.node = bs.newnode('prop', + delegate=self, + attrs={ + 'mesh': self.egg_mesh, + 'color_texture': self.eggtx[regg], + 'body': 'capsule', + 'reflection': 'soft', + 'reflection_scale': [0.2], + 'shadow_size': 0.5, + 'body_scale':0.7, + 'is_area_of_interest': True, + 'position': self._spawn_pos, + 'materials': pmats + }) + bs.animate(self.node, 'mesh_scale', {0: 0, 0.2: 0.7, 0.26: 0.6}) + + 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 + 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 on_app_running(self) -> None: + self.score = 0 + + +# ba_meta export bascenev1.GameActivity +class EggGame(bs.TeamGameActivity[Player, Team]): + """Egg game.""" + + name = 'Epic Egg Game' + 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), + ('40 Seconds', 40), + ('1 Minute', 60), + ('2 Minutes', 120), + ('5 Minutes', 300), + ('10 Minutes', 600), + ('20 Minutes', 1200), + ], + default=0, + ), + bs.FloatChoiceSetting( + 'Respawn Times', + choices=[ + ('Shorter', 0.1), + ('Short', 0.5), + ('Normal', 1.0), + ('Long', 2.0), + ('Longer', 4.0), + ], + default=1.0, + ), + ] + 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('football') + + def __init__(self, settings: dict): + super().__init__(settings) + shared = SharedObjects.get() + self.slow_motion = True + self._scoreboard = Scoreboard() + 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_mesh = bs.getmesh('bomb') + self.puck_tex = bs.gettexture('landMine') + self.puck_scored_tex = bs.gettexture('landMineLit') + self._puck_sound = bui.getsound('metalHit') + self.puck_material = bs.Material() + self._fake_wall_material=bs.Material() + self.HIGHEST=0 + self._fake_wall_material.add_actions( + conditions=('they_have_material', shared.player_material), + actions=( + ('modify_part_collision', 'collide', True), + ('modify_part_collision', 'physical', True) + + )) + 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.puck_material.add_actions( + # conditions=('they_have_material',shared.footing_material) + # actions=(('modify_part_collision', 'collide', + # True), ('modify_part_collision', 'physical', True), + # ('call', 'at_connect', self._handle_egg_collision)) + # ) + 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.main_ground_material= bs.Material() + + self.main_ground_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_egg_collision))) + + self._puck_spawn_pos: Optional[Sequence[float]] = None + self._score_regions: Optional[List[bs.NodeActor]] = None + self._puck: Optional[Puck] = None + self._pucks=[] + self._score_to_win = int(settings['Score to Win']) + self._time_limit = float(settings['Time Limit']) + + def get_instance_description(self) -> Union[str, Sequence]: + return "Throw Egg as far u can" + + def get_instance_description_short(self) -> Union[str, Sequence]: + return "Throw Egg as far u can" + + def on_begin(self) -> None: + super().on_begin() + if self._time_limit==0.0: + self._time_limit=60 + 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() + self._spawn_puck() + self._spawn_puck() + self._spawn_puck() + self._spawn_puck() + + # Set up the two score regions. + defs = self.map.defs + self._score_regions = [] + pos=(11.88630542755127, 0.3009839951992035, 1.33331298828125) + # mat=bs.Material() + # mat.add_actions( + + # actions=( ('modify_part_collision','physical',True), + # ('modify_part_collision','collide',True)) + # ) + # self._score_regions.append( + # bs.NodeActor( + # bs.newnode('region', + # attrs={ + # 'position': pos, + # 'scale': (2,3,5), + # 'type': 'box', + # 'materials': [self._score_region_material] + # }))) + # pos=(-11.88630542755127, 0.3009839951992035, 1.33331298828125) + # self._score_regions.append( + # bs.NodeActor( + # bs.newnode('region', + # attrs={ + # 'position': pos, + # 'scale': (2,3,5), + # 'type': 'box', + # 'materials': [self._score_region_material] + # }))) + self._score_regions.append( + bs.NodeActor( + bs.newnode('region', + attrs={ + 'position': (-9.21,defs.boxes['goal2'][0:3][1],defs.boxes['goal2'][0:3][2]), + 'scale': defs.boxes['goal2'][6:9], + 'type': 'box', + 'materials': (self._fake_wall_material, ) + }))) + pos=(0,0.1,-5) + self.main_ground=bs.newnode('region',attrs={'position': pos,'scale': (25,0.001,22),'type': 'box','materials': [self.main_ground_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 + + def _kill_puck(self) -> None: + self._puck = None + def _handle_egg_collision(self) -> None: + + no=bs.getcollision().opposingnode + pos=no.position + egg=no.getdelegate(Puck) + source_player=egg.last_players_to_touch + if source_player==None or pos[0]< -8 or not source_player.node.exists() : + return + + + try: + col=source_player.team.color + self.flagg=Flag(pos,touchable=False,color=col).autoretain() + self.flagg.is_area_of_interest=True + player_pos=source_player.node.position + + distance = math.sqrt( pow(player_pos[0]-pos[0],2) + pow(player_pos[2]-pos[2],2)) + + + dis_mark=bs.newnode('text', + + attrs={ + 'text':str(round(distance,2))+"m", + 'in_world':True, + 'scale':0.02, + 'h_align':'center', + 'position':(pos[0],1.6,pos[2]), + 'color':col + }) + bs.animate(dis_mark,'scale',{ + 0.0:0, 0.5:0.01 + }) + if distance > self.HIGHEST: + self.HIGHEST=distance + self.stats.player_scored( + source_player, + 10, + big_message=False) + + no.delete() + bs.timer(2,self._spawn_puck) + source_player.team.score=int(distance) + + except(): + pass + def spawn_player(self, player: Player) -> bs.Actor: + + + zoo=random.randrange(-4,5) + pos=(-11.204887390136719, 0.2998693287372589, zoo) + spaz = self.spawn_player_spaz( + player, position=pos, angle=90 ) + assert spaz.node + + # Prevent controlling of characters before the start of the race. + + return spaz + 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 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], + 20, + 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 + + # Change puck texture to something cool + # self._puck.node.color_texture = self.puck_scored_tex + # 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) + pass + def _spawn_puck(self) -> None: + # self._swipsound.play() + # self._whistle_sound.play() + self._flash_puck_spawn() + assert self._puck_spawn_pos is not None + zoo=random.randrange(-5,6) + pos=(-11.204887390136719, 0.2998693287372589, zoo) + self._pucks.append (Puck(position=pos)) diff --git a/plugins/minigames/HYPER_RACE.py b/plugins/minigames/HYPER_RACE.py new file mode 100644 index 0000000..e09478c --- /dev/null +++ b/plugins/minigames/HYPER_RACE.py @@ -0,0 +1,1239 @@ +# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport) +# ba_meta require api 8 + +from __future__ import annotations + +import random +from typing import TYPE_CHECKING +from dataclasses import dataclass + +import babase +import bauiv1 as bui +import bascenev1 as bs +from bascenev1 import _map +from bascenev1lib.actor.bomb import Bomb, Blast, BombFactory +from bascenev1lib.actor.powerupbox import PowerupBox +from bascenev1lib.actor.playerspaz import PlayerSpaz +from bascenev1lib.actor.scoreboard import Scoreboard +from bascenev1lib.gameutils import SharedObjects + +if TYPE_CHECKING: + from typing import (Any, Type, Tuple, List, Sequence, Optional, Dict, + Union) + from bascenev1lib.actor.onscreentimer import OnScreenTimer + + +class ThePadDefs: + points = {} + boxes = {} + points['race_mine1'] = (0, 5, 12) + points['race_point1'] = (0.2, 5, 2.86308) + (0.507, 4.673, 1.1) + points['race_point2'] = (6.9301, 5.04988, 2.82066) + (0.911, 4.577, 1.073) + points['race_point3'] = (6.98857, 4.5011, -8.88703) + (1.083, 4.673, 1.076) + points['race_point4'] = (-6.4441, 4.5011, -8.88703) + (1.083, 4.673, 1.076) + points['race_point5'] = (-6.31128, 4.5011, 2.82669) + (0.894, 4.673, 0.941) + boxes['area_of_interest_bounds'] = ( + 0.3544110667, 4.493562578, -2.518391331) + ( + 0.0, 0.0, 0.0) + (16.64754831, 8.06138989, 18.5029888) + points['ffa_spawn1'] = (-0, 5, 2.5) + points['flag1'] = (-7.026110145, 4.308759233, -6.302807727) + points['flag2'] = (7.632557137, 4.366002373, -6.287969342) + points['flagDefault'] = (0.4611826686, 4.382076338, 3.680881802) + boxes['map_bounds'] = (0.2608783669, 4.899663734, -3.543675157) + ( + 0.0, 0.0, 0.0) + (29.23565494, 14.19991443, 29.92689344) + points['powerup_spawn1'] = (-4.166594349, 5.281834349, -6.427493781) + points['powerup_spawn2'] = (4.426873526, 5.342460464, -6.329745237) + points['powerup_spawn3'] = (-4.201686731, 5.123385835, 0.4400721376) + points['powerup_spawn4'] = (4.758924722, 5.123385835, 0.3494054559) + points['shadow_lower_bottom'] = (-0.2912522507, 2.020798381, 5.341226521) + points['shadow_lower_top'] = (-0.2912522507, 3.206066063, 5.341226521) + points['shadow_upper_bottom'] = (-0.2912522507, 6.062361813, 5.341226521) + points['shadow_upper_top'] = (-0.2912522507, 9.827201965, 5.341226521) + points['spawn1'] = (-0, 5, 2.5) + points['tnt1'] = (0.4599593402, 4.044276501, -6.573537395) + + +class ThePadMapb(bs.Map): + defs = ThePadDefs() + name = 'Racing' + + @classmethod + def get_play_types(cls) -> List[str]: + """Return valid play types for this map.""" + return ['hyper'] + + @classmethod + def get_preview_texture_name(cls) -> str: + return 'thePadPreview' + + @classmethod + def on_preload(cls) -> Any: + data: Dict[str, Any] = { + 'mesh': bs.getmesh('thePadLevel'), + 'bottom_mesh': bs.getmesh('thePadLevelBottom'), + 'collision_mesh': bs.getcollisionmesh('thePadLevelCollide'), + 'tex': bs.gettexture('thePadLevelColor'), + 'bgtex': bs.gettexture('black'), + 'bgmesh': bs.getmesh('thePadBG'), + 'railing_collision_mesh': bs.getcollisionmesh('thePadLevelBumper'), + 'vr_fill_mound_mesh': bs.getmesh('thePadVRFillMound'), + 'vr_fill_mound_tex': bs.gettexture('vrFillMound') + } + # fixme should chop this into vr/non-vr sections for efficiency + return data + + def __init__(self) -> None: + super().__init__() + shared = SharedObjects.get() + self.node = bs.newnode( + 'terrain', + delegate=self, + attrs={ + 'collision_mesh': self.preloaddata['collision_mesh'], + 'mesh': self.preloaddata['mesh'], + 'color_texture': self.preloaddata['tex'], + 'materials': [shared.footing_material] + }) + self.bottom = bs.newnode('terrain', + attrs={ + 'mesh': self.preloaddata['bottom_mesh'], + 'lighting': False, + 'color_texture': self.preloaddata['tex'] + }) + self.background = bs.newnode( + 'terrain', + attrs={ + 'mesh': self.preloaddata['bgmesh'], + 'lighting': False, + 'background': True, + 'color_texture': self.preloaddata['bgtex'] + }) + self.railing = bs.newnode( + 'terrain', + attrs={ + 'collision_mesh': self.preloaddata['railing_collision_mesh'], + 'materials': [shared.railing_material], + 'bumper': True + }) + bs.newnode('terrain', + attrs={ + 'mesh': self.preloaddata['vr_fill_mound_mesh'], + 'lighting': False, + 'vr_only': True, + 'color': (0.56, 0.55, 0.47), + 'background': True, + 'color_texture': self.preloaddata['vr_fill_mound_tex'] + }) + gnode = bs.getactivity().globalsnode + gnode.tint = (1.1, 1.1, 1.0) + gnode.ambient_color = (1.1, 1.1, 1.0) + gnode.vignette_outer = (0.7, 0.65, 0.75) + gnode.vignette_inner = (0.95, 0.95, 0.93) + + +# ba_meta export plugin +class NewMap(babase.Plugin): + """My first ballistica plugin!""" + + def on_app_running(self) -> None: + _map.register_map(ThePadMapb) + + +class NewBlast(Blast): + + def __init__(self, + position: Sequence[float] = (0.0, 1.0, 0.0), + velocity: Sequence[float] = (0.0, 0.0, 0.0), + blast_radius: float = 2.0, + blast_type: str = 'normal', + source_player: bs.Player = None, + hit_type: str = 'explosion', + hit_subtype: str = 'normal'): + bs.Actor.__init__(self) + + shared = SharedObjects.get() + factory = BombFactory.get() + + self.blast_type = blast_type + self._source_player = source_player + self.hit_type = hit_type + self.hit_subtype = hit_subtype + self.radius = blast_radius + + # Set our position a bit lower so we throw more things upward. + rmats = (factory.blast_material, shared.attack_material) + self.node = bs.newnode( + 'region', + delegate=self, + attrs={ + 'position': (position[0], position[1] - 0.1, position[2]), + 'scale': (self.radius, self.radius, self.radius), + 'type': 'sphere', + 'materials': rmats + }, + ) + + bs.timer(0.05, self.node.delete) + + # Throw in an explosion and flash. + evel = (velocity[0], max(-1.0, velocity[1]), velocity[2]) + explosion = bs.newnode('explosion', + attrs={ + 'position': position, + 'velocity': evel, + 'radius': self.radius, + 'big': (self.blast_type == 'tnt') + }) + if self.blast_type == 'ice': + explosion.color = (0, 0.05, 0.4) + + bs.timer(1.0, explosion.delete) + + if self.blast_type != 'ice': + bs.emitfx(position=position, + velocity=velocity, + count=int(1.0 + random.random() * 4), + emit_type='tendrils', + tendril_type='thin_smoke') + bs.emitfx(position=position, + velocity=velocity, + count=int(4.0 + random.random() * 4), + emit_type='tendrils', + tendril_type='ice' if self.blast_type == 'ice' else 'smoke') + bs.emitfx(position=position, + emit_type='distortion', + spread=1.0 if self.blast_type == 'tnt' else 2.0) + + # And emit some shrapnel. + if self.blast_type == 'ice': + + def emit() -> None: + bs.emitfx(position=position, + velocity=velocity, + count=30, + spread=2.0, + scale=0.4, + chunk_type='ice', + emit_type='stickers') + + # It looks better if we delay a bit. + bs.timer(0.05, emit) + + elif self.blast_type == 'sticky': + + def emit() -> None: + bs.emitfx(position=position, + velocity=velocity, + count=int(4.0 + random.random() * 8), + spread=0.7, + chunk_type='slime') + bs.emitfx(position=position, + velocity=velocity, + count=int(4.0 + random.random() * 8), + scale=0.5, + spread=0.7, + chunk_type='slime') + bs.emitfx(position=position, + velocity=velocity, + count=15, + scale=0.6, + chunk_type='slime', + emit_type='stickers') + bs.emitfx(position=position, + velocity=velocity, + count=20, + scale=0.7, + chunk_type='spark', + emit_type='stickers') + bs.emitfx(position=position, + velocity=velocity, + count=int(6.0 + random.random() * 12), + scale=0.8, + spread=1.5, + chunk_type='spark') + + # It looks better if we delay a bit. + bs.timer(0.05, emit) + + elif self.blast_type == 'impact': + + def emit() -> None: + bs.emitfx(position=position, + velocity=velocity, + count=int(4.0 + random.random() * 8), + scale=0.8, + chunk_type='metal') + bs.emitfx(position=position, + velocity=velocity, + count=int(4.0 + random.random() * 8), + scale=0.4, + chunk_type='metal') + bs.emitfx(position=position, + velocity=velocity, + count=20, + scale=0.7, + chunk_type='spark', + emit_type='stickers') + bs.emitfx(position=position, + velocity=velocity, + count=int(8.0 + random.random() * 15), + scale=0.8, + spread=1.5, + chunk_type='spark') + + # It looks better if we delay a bit. + bs.timer(0.05, emit) + + else: # Regular or land mine bomb shrapnel. + + def emit() -> None: + if self.blast_type != 'tnt': + bs.emitfx(position=position, + velocity=velocity, + count=int(4.0 + random.random() * 8), + chunk_type='rock') + bs.emitfx(position=position, + velocity=velocity, + count=int(4.0 + random.random() * 8), + scale=0.5, + chunk_type='rock') + bs.emitfx(position=position, + velocity=velocity, + count=30, + scale=1.0 if self.blast_type == 'tnt' else 0.7, + chunk_type='spark', + emit_type='stickers') + bs.emitfx(position=position, + velocity=velocity, + count=int(18.0 + random.random() * 20), + scale=1.0 if self.blast_type == 'tnt' else 0.8, + spread=1.5, + chunk_type='spark') + + # TNT throws splintery chunks. + if self.blast_type == 'tnt': + + def emit_splinters() -> None: + bs.emitfx(position=position, + velocity=velocity, + count=int(20.0 + random.random() * 25), + scale=0.8, + spread=1.0, + chunk_type='splinter') + + bs.timer(0.01, emit_splinters) + + # Every now and then do a sparky one. + if self.blast_type == 'tnt' or random.random() < 0.1: + + def emit_extra_sparks() -> None: + bs.emitfx(position=position, + velocity=velocity, + count=int(10.0 + random.random() * 20), + scale=0.8, + spread=1.5, + chunk_type='spark') + + bs.timer(0.02, emit_extra_sparks) + + # It looks better if we delay a bit. + bs.timer(0.05, emit) + + lcolor = ((0.6, 0.6, 1.0) if self.blast_type == 'ice' else + (1, 0.3, 0.1)) + light = bs.newnode('light', + attrs={ + 'position': position, + 'volume_intensity_scale': 10.0, + 'color': lcolor + }) + + scl = random.uniform(0.6, 0.9) + scorch_radius = light_radius = self.radius + if self.blast_type == 'tnt': + light_radius *= 1.4 + scorch_radius *= 1.15 + scl *= 3.0 + + iscale = 1.6 + bs.animate( + light, 'intensity', { + 0: 2.0 * iscale, + scl * 0.02: 0.1 * iscale, + scl * 0.025: 0.2 * iscale, + scl * 0.05: 17.0 * iscale, + scl * 0.06: 5.0 * iscale, + scl * 0.08: 4.0 * iscale, + scl * 0.2: 0.6 * iscale, + scl * 2.0: 0.00 * iscale, + scl * 3.0: 0.0 + }) + bs.animate( + light, 'radius', { + 0: light_radius * 0.2, + scl * 0.05: light_radius * 0.55, + scl * 0.1: light_radius * 0.3, + scl * 0.3: light_radius * 0.15, + scl * 1.0: light_radius * 0.05 + }) + bs.timer(scl * 3.0, light.delete) + + # Make a scorch that fades over time. + scorch = bs.newnode('scorch', + attrs={ + 'position': position, + 'size': scorch_radius * 0.5, + 'big': (self.blast_type == 'tnt') + }) + if self.blast_type == 'ice': + scorch.color = (1, 1, 1.5) + + bs.animate(scorch, 'presence', {3.000: 1, 13.000: 0}) + bs.timer(13.0, scorch.delete) + + if self.blast_type == 'ice': + factory.hiss_sound.play(position=light.position) + + lpos = light.position + factory.random_explode_sound().play(position=lpos) + factory.debris_fall_sound.play(position=lpos) + + bs.camerashake(0.0) + + # TNT is more epic. + if self.blast_type == 'tnt': + factory.random_explode_sound().play(position=lpos) + + def _extra_boom() -> None: + factory.random_explode_sound().play(position=lpos) + + bs.timer(0.25, _extra_boom) + + def _extra_debris_sound() -> None: + factory.debris_fall_sound.play(position=lpos) + factory.wood_debris_fall_sound.play(position=lpos) + + bs.timer(0.4, _extra_debris_sound) + + +class NewBomb(Bomb): + + def explode(self) -> None: + """Blows up the bomb if it has not yet done so.""" + if self._exploded: + return + self._exploded = True + if self.node: + blast = NewBlast(position=self.node.position, + velocity=self.node.velocity, + blast_radius=self.blast_radius, + blast_type=self.bomb_type, + source_player=babase.existing(self._source_player), + hit_type=self.hit_type, + hit_subtype=self.hit_subtype).autoretain() + for callback in self._explode_callbacks: + callback(self, blast) + + # We blew up so we need to go away. + # NOTE TO SELF: do we actually need this delay? + bs.timer(0.001, bs.WeakCall(self.handlemessage, bs.DieMessage())) + + +class TNT(bs.Actor): + + def __init__(self, + position: Sequence[float] = (0.0, 1.0, 0.0), + velocity: Sequence[float] = (0.0, 0.0, 0.0), + tnt_scale: float = 1.0, + teleport: bool = True): + super().__init__() + self.position = position + self.teleport = teleport + + self._no_collide_material = bs.Material() + self._no_collide_material.add_actions( + actions=('modify_part_collision', 'collide', False), + ) + self._collide_material = bs.Material() + self._collide_material.add_actions( + actions=('modify_part_collision', 'collide', True), + ) + + if teleport: + collide = self._collide_material + else: + collide = self._no_collide_material + self.node = bs.newnode( + 'prop', + delegate=self, + attrs={ + 'position': position, + 'velocity': velocity, + 'mesh': bs.getmesh('tnt'), + 'color_texture': bs.gettexture('tnt'), + 'body': 'crate', + 'mesh_scale': tnt_scale, + 'body_scale': tnt_scale, + 'density': 2.0, + 'gravity_scale': 2.0, + 'materials': [collide] + } + ) + if not teleport: + bs.timer(0.1, self._collide) + + def _collide(self) -> None: + self.node.materials += (self._collide_material,) + + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, bs.OutOfBoundsMessage): + if self.teleport: + self.node.position = self.position + self.node.velocity = (0, 0, 0) + else: + self.node.delete() + else: + super().handlemessage(msg) + + +class RaceRegion(bs.Actor): + """Region used to track progress during a race.""" + + def __init__(self, pt: Sequence[float], index: int): + super().__init__() + activity = self.activity + assert isinstance(activity, RaceGame) + self.pos = pt + self.index = index + self.node = bs.newnode( + 'region', + delegate=self, + attrs={ + 'position': pt[:3], + 'scale': (pt[3] * 2.0, pt[4] * 2.0, pt[5] * 2.0), + 'type': 'box', + 'materials': [activity.race_region_material] + }) + + +# MINIGAME +class Player(bs.Player['Team']): + """Our player type for this game.""" + + def __init__(self) -> None: + self.distance_txt: Optional[bs.Node] = None + self.last_region = 0 + self.lap = 0 + self.distance = 0.0 + self.finished = False + self.rank: Optional[int] = None + + +class Team(bs.Team[Player]): + """Our team type for this game.""" + + def __init__(self) -> None: + self.time: Optional[float] = None + self.lap = 0 + self.finished = False + + +# ba_meta export bascenev1.GameActivity +class RaceGame(bs.TeamGameActivity[Player, Team]): + """Game of racing around a track.""" + + name = 'Hyper Race' + description = 'Creado Por Cebolla!!' + scoreconfig = bs.ScoreConfig(label='Time', + lower_is_better=True, + scoretype=bs.ScoreType.MILLISECONDS) + + @classmethod + def get_available_settings( + cls, sessiontype: Type[bs.Session]) -> List[babase.Setting]: + settings = [ + bs.IntSetting('Laps', min_value=1, default=3, increment=1), + bs.IntChoiceSetting( + 'Time Limit', + default=0, + choices=[ + ('None', 0), + ('1 Minute', 60), + ('2 Minutes', 120), + ('5 Minutes', 300), + ('10 Minutes', 600), + ('20 Minutes', 1200), + ], + ), + bs.BoolSetting('Epic Mode', default=False), + ] + + # We have some specific settings in teams mode. + if issubclass(sessiontype, bs.DualTeamSession): + settings.append( + bs.BoolSetting('Entire Team Must Finish', default=False)) + return settings + + @classmethod + def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool: + return issubclass(sessiontype, bs.MultiTeamSession) + + @classmethod + def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]: + return bs.app.classic.getmaps('hyper') + + def __init__(self, settings: dict): + self._race_started = False + super().__init__(settings) + self.factory = factory = BombFactory.get() + self.shared = shared = SharedObjects.get() + self._scoreboard = Scoreboard() + self._score_sound = bs.getsound('score') + self._swipsound = bs.getsound('swip') + self._last_team_time: Optional[float] = None + self._front_race_region: Optional[int] = None + self._nub_tex = bs.gettexture('nub') + self._beep_1_sound = bs.getsound('raceBeep1') + self._beep_2_sound = bs.getsound('raceBeep2') + self.race_region_material: Optional[bs.Material] = None + self._regions: List[RaceRegion] = [] + self._team_finish_pts: Optional[int] = None + self._time_text: Optional[bs.Actor] = None + self._timer: Optional[OnScreenTimer] = None + self._scoreboard_timer: Optional[bs.Timer] = None + self._player_order_update_timer: Optional[bs.Timer] = None + self._start_lights: Optional[List[bs.Node]] = None + self._laps = int(settings['Laps']) + self._entire_team_must_finish = bool( + settings.get('Entire Team Must Finish', False)) + self._time_limit = float(settings['Time Limit']) + self._epic_mode = bool(settings['Epic Mode']) + + # Base class overrides. + self.slow_motion = self._epic_mode + self.default_music = (bs.MusicType.EPIC_RACE + if self._epic_mode else bs.MusicType.RACE) + + self._safe_region_material = bs.Material() + self._safe_region_material.add_actions( + conditions=('they_have_material', shared.player_material), + actions=(('modify_part_collision', 'collide', True), + ('modify_part_collision', 'physical', True)) + ) + + def get_instance_description(self) -> Union[str, Sequence]: + if (isinstance(self.session, bs.DualTeamSession) + and self._entire_team_must_finish): + t_str = ' Your entire team has to finish.' + else: + t_str = '' + + if self._laps > 1: + return 'Run ${ARG1} laps.' + t_str, self._laps + return 'Run 1 lap.' + t_str + + def get_instance_description_short(self) -> Union[str, Sequence]: + if self._laps > 1: + return 'run ${ARG1} laps', self._laps + return 'run 1 lap' + + def on_transition_in(self) -> None: + super().on_transition_in() + shared = SharedObjects.get() + pts = self.map.get_def_points('race_point') + mat = self.race_region_material = bs.Material() + mat.add_actions(conditions=('they_have_material', + shared.player_material), + actions=( + ('modify_part_collision', 'collide', True), + ('modify_part_collision', 'physical', False), + ('call', 'at_connect', + self._handle_race_point_collide), + )) + for rpt in pts: + self._regions.append(RaceRegion(rpt, len(self._regions))) + + bs.newnode( + 'region', + attrs={ + 'position': (0.3, 4.044276501, -2.9), + 'scale': (11.7, 15, 9.5), + 'type': 'box', + 'materials': [self._safe_region_material] + } + ) + + def _flash_player(self, player: Player, scale: float) -> None: + assert isinstance(player.actor, PlayerSpaz) + assert player.actor.node + pos = player.actor.node.position + light = bs.newnode('light', + attrs={ + 'position': pos, + 'color': (1, 1, 0), + 'height_attenuated': False, + 'radius': 0.4 + }) + bs.timer(0.5, light.delete) + bs.animate(light, 'intensity', {0: 0, 0.1: 1.0 * scale, 0.5: 0}) + + def _handle_race_point_collide(self) -> None: + # FIXME: Tidy this up. + # pylint: disable=too-many-statements + # pylint: disable=too-many-branches + # pylint: disable=too-many-nested-blocks + collision = bs.getcollision() + try: + region = collision.sourcenode.getdelegate(RaceRegion, True) + spaz = collision.opposingnode.getdelegate(PlayerSpaz,True) + except bs.NotFoundError: + return + + if not spaz.is_alive(): + return + + try: + player = spaz.getplayer(Player, True) + except bs.NotFoundError: + return + + last_region = player.last_region + this_region = region.index + + if last_region != this_region: + + # If a player tries to skip regions, smite them. + # Allow a one region leeway though (its plausible players can get + # blown over a region, etc). + if this_region > last_region + 2: + if player.is_alive(): + assert player.actor + player.actor.handlemessage(bs.DieMessage()) + bs.broadcastmessage(babase.Lstr( + translate=('statements', 'Killing ${NAME} for' + ' skipping part of the track!'), + subs=[('${NAME}', player.getname(full=True))]), + color=(1, 0, 0)) + else: + # If this player is in first, note that this is the + # front-most race-point. + if player.rank == 0: + self._front_race_region = this_region + + player.last_region = this_region + if last_region >= len(self._regions) - 2 and this_region == 0: + team = player.team + player.lap = min(self._laps, player.lap + 1) + + # In teams mode with all-must-finish on, the team lap + # value is the min of all team players. + # Otherwise its the max. + if isinstance(self.session, bs.DualTeamSession + ) and self._entire_team_must_finish: + team.lap = min([p.lap for p in team.players]) + else: + team.lap = max([p.lap for p in team.players]) + + # A player is finishing. + if player.lap == self._laps: + + # In teams mode, hand out points based on the order + # players come in. + if isinstance(self.session, bs.DualTeamSession): + assert self._team_finish_pts is not None + if self._team_finish_pts > 0: + self.stats.player_scored(player, + self._team_finish_pts, + screenmessage=False) + self._team_finish_pts -= 25 + + # Flash where the player is. + self._flash_player(player, 1.0) + player.finished = True + assert player.actor + player.actor.handlemessage( + bs.DieMessage(immediate=True)) + + # Makes sure noone behind them passes them in rank + # while finishing. + player.distance = 9999.0 + + # If the whole team has finished the race. + if team.lap == self._laps: + self._score_sound.play() + player.team.finished = True + assert self._timer is not None + elapsed = bs.time() - self._timer.getstarttime() + self._last_team_time = player.team.time = elapsed + self._check_end_game() + + # Team has yet to finish. + else: + self._swipsound.play() + + # They've just finished a lap but not the race. + else: + self._swipsound.play() + self._flash_player(player, 0.3) + + # Print their lap number over their head. + try: + assert isinstance(player.actor, PlayerSpaz) + mathnode = bs.newnode('math', + owner=player.actor.node, + attrs={ + 'input1': (0, 1.9, 0), + 'operation': 'add' + }) + player.actor.node.connectattr( + 'torso_position', mathnode, 'input2') + tstr = babase.Lstr(resource='lapNumberText', + subs=[('${CURRENT}', + str(player.lap + 1)), + ('${TOTAL}', str(self._laps)) + ]) + txtnode = bs.newnode('text', + owner=mathnode, + attrs={ + 'text': tstr, + 'in_world': True, + 'color': (1, 1, 0, 1), + 'scale': 0.015, + 'h_align': 'center' + }) + mathnode.connectattr('output', txtnode, 'position') + bs.animate(txtnode, 'scale', { + 0.0: 0, + 0.2: 0.019, + 2.0: 0.019, + 2.2: 0 + }) + bs.timer(2.3, mathnode.delete) + except Exception: + babase.print_exception('Error printing lap.') + + def on_team_join(self, team: Team) -> None: + self._update_scoreboard() + + def on_player_leave(self, player: Player) -> None: + super().on_player_leave(player) + + # A player leaving disqualifies the team if 'Entire Team Must Finish' + # is on (otherwise in teams mode everyone could just leave except the + # leading player to win). + if (isinstance(self.session, bs.DualTeamSession) + and self._entire_team_must_finish): + bs.broadcastmessage(babase.Lstr( + translate=('statements', + '${TEAM} is disqualified because ${PLAYER} left'), + subs=[('${TEAM}', player.team.name), + ('${PLAYER}', player.getname(full=True))]), + color=(1, 1, 0)) + player.team.finished = True + player.team.time = None + player.team.lap = 0 + bs.getsound('boo').play() + for otherplayer in player.team.players: + otherplayer.lap = 0 + otherplayer.finished = True + try: + if otherplayer.actor is not None: + otherplayer.actor.handlemessage(bs.DieMessage()) + except Exception: + babase.print_exception('Error sending DieMessage.') + + # Defer so team/player lists will be updated. + babase.pushcall(self._check_end_game) + + def _update_scoreboard(self) -> None: + for team in self.teams: + distances = [player.distance for player in team.players] + if not distances: + teams_dist = 0.0 + else: + if (isinstance(self.session, bs.DualTeamSession) + and self._entire_team_must_finish): + teams_dist = min(distances) + else: + teams_dist = max(distances) + self._scoreboard.set_team_value( + team, + teams_dist, + self._laps, + flash=(teams_dist >= float(self._laps)), + show_value=False) + + def on_begin(self) -> None: + from bascenev1lib.actor.onscreentimer import OnScreenTimer + super().on_begin() + self.setup_standard_time_limit(self._time_limit) + # self.setup_standard_powerup_drops() + self._team_finish_pts = 100 + + # Throw a timer up on-screen. + self._time_text = bs.NodeActor( + 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, -50), + 'scale': 1.4, + 'text': '' + })) + self._timer = OnScreenTimer() + + self._scoreboard_timer = bs.Timer(0.25, + self._update_scoreboard, + repeat=True) + self._player_order_update_timer = bs.Timer(0.25, + self._update_player_order, + repeat=True) + + if self.slow_motion: + t_scale = 0.4 + light_y = 50 + else: + t_scale = 1.0 + light_y = 150 + lstart = 7.1 * t_scale + inc = 1.25 * t_scale + + bs.timer(lstart, self._do_light_1) + bs.timer(lstart + inc, self._do_light_2) + bs.timer(lstart + 2 * inc, self._do_light_3) + bs.timer(lstart + 3 * inc, self._start_race) + + self._start_lights = [] + for i in range(4): + lnub = bs.newnode('image', + attrs={ + 'texture': bs.gettexture('nub'), + 'opacity': 1.0, + 'absolute_scale': True, + 'position': (-75 + i * 50, light_y), + 'scale': (50, 50), + 'attach': 'center' + }) + bs.animate( + lnub, 'opacity', { + 4.0 * t_scale: 0, + 5.0 * t_scale: 1.0, + 12.0 * t_scale: 1.0, + 12.5 * t_scale: 0.0 + }) + bs.timer(13.0 * t_scale, lnub.delete) + self._start_lights.append(lnub) + + self._obstacles() + + pts = self.map.get_def_points('race_point') + for rpt in pts: + bs.newnode( + 'locator', + attrs={ + 'shape': 'circle', + 'position': (rpt[0], 4.382076338, rpt[2]), + 'size': (rpt[3] * 2.0, 0, rpt[5] * 2.0), + 'color': (0, 1, 0), + 'opacity': 1.0, + 'draw_beauty': False, + 'additive': True + } + ) + + def _obstacles(self) -> None: + self._start_lights[0].color = (0.2, 0, 0) + self._start_lights[1].color = (0.2, 0, 0) + self._start_lights[2].color = (0.2, 0.05, 0) + self._start_lights[3].color = (0.0, 0.3, 0) + + self._tnt((1.5, 5, 2.3), (0, 0, 0), 1.0) + self._tnt((1.5, 5, 3.3), (0, 0, 0), 1.0) + + self._tnt((3.5, 5, 2.3), (0, 0, 0), 1.0) + self._tnt((3.5, 5, 3.3), (0, 0, 0), 1.0) + + self._tnt((5.5, 5, 2.3), (0, 0, 0), 1.0) + self._tnt((5.5, 5, 3.3), (0, 0, 0), 1.0) + + self._tnt((-6, 5, -7), (0, 0, 0), 1.3) + self._tnt((-7, 5, -5), (0, 0, 0), 1.3) + self._tnt((-6, 5, -3), (0, 0, 0), 1.3) + self._tnt((-7, 5, -1), (0, 0, 0), 1.3) + self._tnt((-6, 5, 1), (0, 0, 0), 1.3) + + bs.timer(0.1, bs.WeakCall(self._tnt, (-3.2, 5, 1), + (0, 0, 0), 1.0, (0, 20, 60)), repeat=True) + + bs.timer(1.6, bs.WeakCall(self._bomb, 'impact', + (6, 7, 1), (0, 0, 0), 1.0, 1.0), repeat=True) + bs.timer(1.6, bs.WeakCall(self._bomb, 'impact', + (6.8, 7, 1), (0, 0, 0), 1.0, 1.0), repeat=True) + bs.timer(1.6, bs.WeakCall(self._bomb, 'impact', + (7.6, 7, 1), (0, 0, 0), 1.0, 1.0), repeat=True) + + bs.timer(1.6, bs.WeakCall(self._bomb, 'impact', + (6, 7, -2.2), (0, 0, 0), 1.0, 1.0), repeat=True) + bs.timer(1.6, bs.WeakCall(self._bomb, 'impact', + (6.8, 7, -2.2), (0, 0, 0), 1.0, 1.0), repeat=True) + bs.timer(1.6, bs.WeakCall(self._bomb, 'impact', + (7.6, 7, -2.2), (0, 0, 0), 1.0, 1.0), repeat=True) + + bs.timer(1.6, bs.WeakCall(self._bomb, 'impact', + (6, 7, -5.2), (0, 0, 0), 1.0, 1.0), repeat=True) + bs.timer(1.6, bs.WeakCall(self._bomb, 'impact', + (6.8, 7, -5.2), (0, 0, 0), 1.0, 1.0), repeat=True) + bs.timer(1.6, bs.WeakCall(self._bomb, 'impact', + (7.6, 7, -5.2), (0, 0, 0), 1.0, 1.0), repeat=True) + + bs.timer(1.6, bs.WeakCall(self._bomb, 'impact', + (6, 7, -8), (0, 0, 0), 1.0, 1.0), repeat=True) + bs.timer(1.6, bs.WeakCall(self._bomb, 'impact', + (6.8, 7, -8), (0, 0, 0), 1.0, 1.0), repeat=True) + bs.timer(1.6, bs.WeakCall(self._bomb, 'impact', + (7.6, 7, -8), (0, 0, 0), 1.0, 1.0), repeat=True) + + bs.timer(1.6, bs.WeakCall(self._bomb, 'impact', + (-5, 5, 0), (0, 0, 0), 1.0, 1.0, (0, 20, 3)), repeat=True) + bs.timer(1.6, bs.WeakCall(self._bomb, 'impact', + (-1.5, 5, 0), (0, 0, 0), 1.0, 1.0, (0, 20, 3)), repeat=True) + + + bs.timer(1.6, bs.WeakCall(self._bomb, 'sticky', + (-1, 5, -8), (0, 10, 0), 1.0, 1.0), repeat=True) + bs.timer(1.6, bs.WeakCall(self._bomb, 'sticky', + (-1, 5, -9), (0, 10, 0), 1.0, 1.0), repeat=True) + bs.timer(1.6, bs.WeakCall(self._bomb, 'sticky', + (-1, 5, -10), (0, 10, 0), 1.0, 1.0), repeat=True) + + bs.timer(1.6, bs.WeakCall(self._bomb, 'sticky', + (-4.6, 5, -8), (0, 10, 0), 1.0, 1.0), repeat=True) + bs.timer(1.6, bs.WeakCall(self._bomb, 'sticky', + (-4.6, 5, -9), (0, 10, 0), 1.0, 1.0), repeat=True) + bs.timer(1.6, bs.WeakCall(self._bomb, 'sticky', + (-4.6, 5, -10), (0, 10, 0), 1.0, 1.0), repeat=True) + + bs.timer(1.6, bs.WeakCall( + self._powerup, (2, 5, -5), 'curse', (0, 20, -3)), repeat=True) + bs.timer(1.6, bs.WeakCall( + self._powerup, (4, 5, -5), 'curse', (0, 20, -3)), repeat=True) + + def _tnt(self, + position: float, + velocity: float, + tnt_scale: float, + extra_acceleration: float = None) -> None: + if extra_acceleration: + TNT(position, velocity, tnt_scale, False).autoretain( + ).node.extra_acceleration = extra_acceleration + else: + TNT(position, velocity, tnt_scale).autoretain() + + def _bomb(self, + type: str, + position: float, + velocity: float, + mesh_scale: float, + body_scale: float, + extra_acceleration: float = None) -> None: + if extra_acceleration: + NewBomb(position=position, + velocity=velocity, + bomb_type=type).autoretain( + ).node.extra_acceleration = extra_acceleration + else: + NewBomb(position=position, + velocity=velocity, + bomb_type=type).autoretain() + + def _powerup(self, + position: float, + poweruptype: str, + extra_acceleration: float = None) -> None: + if extra_acceleration: + PowerupBox(position=position, + poweruptype=poweruptype).autoretain( + ).node.extra_acceleration = extra_acceleration + else: + PowerupBox(position=position, poweruptype=poweruptype).autoretain() + + def _do_light_1(self) -> None: + assert self._start_lights is not None + self._start_lights[0].color = (1.0, 0, 0) + self._beep_1_sound.play() + + def _do_light_2(self) -> None: + assert self._start_lights is not None + self._start_lights[1].color = (1.0, 0, 0) + self._beep_1_sound.play() + + def _do_light_3(self) -> None: + assert self._start_lights is not None + self._start_lights[2].color = (1.0, 0.3, 0) + self._beep_1_sound.play() + + def _start_race(self) -> None: + assert self._start_lights is not None + self._start_lights[3].color = (0.0, 1.0, 0) + self._beep_2_sound.play() + for player in self.players: + if player.actor is not None: + try: + assert isinstance(player.actor, PlayerSpaz) + player.actor.connect_controls_to_player() + except Exception: + babase.print_exception('Error in race player connects.') + assert self._timer is not None + self._timer.start() + + self._race_started = True + + def _update_player_order(self) -> None: + + # Calc all player distances. + for player in self.players: + pos: Optional[babase.Vec3] + try: + pos = player.position + except bs.NotFoundError: + pos = None + if pos is not None: + r_index = player.last_region + rg1 = self._regions[r_index] + r1pt = babase.Vec3(rg1.pos[:3]) + rg2 = self._regions[0] if r_index == len( + self._regions) - 1 else self._regions[r_index + 1] + r2pt = babase.Vec3(rg2.pos[:3]) + r2dist = (pos - r2pt).length() + amt = 1.0 - (r2dist / (r2pt - r1pt).length()) + amt = player.lap + (r_index + amt) * (1.0 / len(self._regions)) + player.distance = amt + + # Sort players by distance and update their ranks. + p_list = [(player.distance, player) for player in self.players] + + p_list.sort(reverse=True, key=lambda x: x[0]) + for i, plr in enumerate(p_list): + plr[1].rank = i + if plr[1].actor: + node = plr[1].distance_txt + if node: + node.text = str(i + 1) if plr[1].is_alive() else '' + + def spawn_player(self, player: Player) -> bs.Actor: + if player.team.finished: + # FIXME: This is not type-safe! + # This call is expected to always return an Actor! + # Perhaps we need something like can_spawn_player()... + # noinspection PyTypeChecker + return None # type: ignore + pos = self._regions[player.last_region].pos + + # Don't use the full region so we're less likely to spawn off a cliff. + region_scale = 0.8 + x_range = ((-0.5, 0.5) if pos[3] == 0 else + (-region_scale * pos[3], region_scale * pos[3])) + z_range = ((-0.5, 0.5) if pos[5] == 0 else + (-region_scale * pos[5], region_scale * pos[5])) + pos = (pos[0] + random.uniform(*x_range), pos[1], + pos[2] + random.uniform(*z_range)) + spaz = self.spawn_player_spaz( + player, position=pos, angle=90 if not self._race_started else None) + assert spaz.node + + # Prevent controlling of characters before the start of the race. + if not self._race_started: + spaz.disconnect_controls_from_player() + + mathnode = bs.newnode('math', + owner=spaz.node, + attrs={ + 'input1': (0, 1.4, 0), + 'operation': 'add' + }) + spaz.node.connectattr('torso_position', mathnode, 'input2') + + distance_txt = bs.newnode('text', + owner=spaz.node, + attrs={ + 'text': '', + 'in_world': True, + 'color': (1, 1, 0.4), + 'scale': 0.02, + 'h_align': 'center' + }) + player.distance_txt = distance_txt + mathnode.connectattr('output', distance_txt, 'position') + return spaz + + def _check_end_game(self) -> None: + + # If there's no teams left racing, finish. + teams_still_in = len([t for t in self.teams if not t.finished]) + if teams_still_in == 0: + self.end_game() + return + + # Count the number of teams that have completed the race. + teams_completed = len( + [t for t in self.teams if t.finished and t.time is not None]) + + if teams_completed > 0: + session = self.session + + # In teams mode its over as soon as any team finishes the race + + # FIXME: The get_ffa_point_awards code looks dangerous. + if isinstance(session, bs.DualTeamSession): + self.end_game() + else: + # In ffa we keep the race going while there's still any points + # to be handed out. Find out how many points we have to award + # and how many teams have finished, and once that matches + # we're done. + assert isinstance(session, bs.FreeForAllSession) + points_to_award = len(session.get_ffa_point_awards()) + if teams_completed >= points_to_award - teams_completed: + self.end_game() + return + + def end_game(self) -> None: + + # Stop updating our time text, and set it to show the exact last + # finish time if we have one. (so users don't get upset if their + # final time differs from what they see onscreen by a tiny amount) + assert self._timer is not None + if self._timer.has_started(): + self._timer.stop( + endtime=None if self._last_team_time is None else ( + self._timer.getstarttime() + self._last_team_time)) + + results = bs.GameResults() + + for team in self.teams: + if team.time is not None: + # We store time in seconds, but pass a score in milliseconds. + results.set_team_score(team, int(team.time * 1000.0)) + else: + results.set_team_score(team, None) + + # We don't announce a winner in ffa mode since its probably been a + # while since the first place guy crossed the finish line so it seems + # odd to be announcing that now. + self.end(results=results, + announce_winning_team=isinstance(self.session, + bs.DualTeamSession)) + + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, bs.PlayerDiedMessage): + # Augment default behavior. + super().handlemessage(msg) + player = msg.getplayer(Player) + if not player.finished: + self.respawn_player(player, respawn_time=1) + else: + super().handlemessage(msg) diff --git a/plugins/minigames/SnowBallFight.py b/plugins/minigames/SnowBallFight.py new file mode 100644 index 0000000..29afe38 --- /dev/null +++ b/plugins/minigames/SnowBallFight.py @@ -0,0 +1,643 @@ +# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport) +# 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.bomb import Blast +from bascenev1lib.gameutils import SharedObjects +from bascenev1lib.actor.spaz import PunchHitMessage +from bascenev1lib.actor.playerspaz import PlayerSpaz +from bascenev1lib.actor.scoreboard import Scoreboard +from bascenev1lib.actor.spazfactory import SpazFactory + +if TYPE_CHECKING: + from typing import Any, Sequence + + +lang = bs.app.lang.language + +if lang == 'Spanish': + name = 'Guerra de Nieve' + snowball_rate = 'Intervalo de Ataque' + snowball_slowest = 'Más Lento' + snowball_slow = 'Lento' + snowball_fast = 'Rápido' + snowball_lagcity = 'Más Rápido' + snowball_scale = 'Tamaño de Bola de Nieve' + snowball_smallest = 'Más Pequeño' + snowball_small = 'Pequeño' + snowball_big = 'Grande' + snowball_biggest = 'Más Grande' + snowball_insane = 'Insano' + snowball_melt = 'Derretir Bola de Nieve' + snowball_bust = 'Rebotar Bola de Nieve' + snowball_explode = 'Explotar al Impactar' + snowball_snow = 'Modo Nieve' +else: + name = 'Snowball Fight' + snowball_rate = 'Snowball Rate' + snowball_slowest = 'Slowest' + snowball_slow = 'Slow' + snowball_fast = 'Fast' + snowball_lagcity = 'Lag City' + snowball_scale = 'Snowball Scale' + snowball_smallest = 'Smallest' + snowball_small = 'Small' + snowball_big = 'Big' + snowball_biggest = 'Biggest' + snowball_insane = 'Insane' + snowball_melt = 'Snowballs Melt' + snowball_bust = 'Snowballs Bust' + snowball_explode = 'Snowballs Explode' + snowball_snow = 'Snow Mode' + + +class Snowball(bs.Actor): + + def __init__(self, + position: Sequence[float] = (0.0, 1.0, 0.0), + velocity: Sequence[float] = (0.0, 0.0, 0.0), + blast_radius: float = 0.7, + bomb_scale: float = 0.8, + source_player: bs.Player | None = None, + owner: bs.Node | None = None, + melt: bool = True, + bounce: bool = True, + explode: bool = False): + super().__init__() + shared = SharedObjects.get() + self._exploded = False + self.scale = bomb_scale + self.blast_radius = blast_radius + self._source_player = source_player + self.owner = owner + self._hit_nodes = set() + self.snowball_melt = melt + self.snowball_bounce = bounce + self.snowball_explode = explode + self.radius = bomb_scale * 0.1 + if bomb_scale <= 1.0: + shadow_size = 0.6 + elif bomb_scale <= 2.0: + shadow_size = 0.4 + elif bomb_scale <= 3.0: + shadow_size = 0.2 + else: + shadow_size = 0.1 + + self.snowball_material = bs.Material() + self.snowball_material.add_actions( + conditions=( + ( + ('we_are_younger_than', 5), + 'or', + ('they_are_younger_than', 100), + ), + 'and', + ('they_have_material', shared.object_material), + ), + actions=('modify_node_collision', 'collide', False), + ) + + self.snowball_material.add_actions( + conditions=('they_have_material', shared.pickup_material), + actions=('modify_part_collision', 'use_node_collide', False), + ) + + self.snowball_material.add_actions(actions=('modify_part_collision', + 'friction', 0.3)) + + self.snowball_material.add_actions( + conditions=('they_have_material', shared.player_material), + actions=(('modify_part_collision', 'physical', False), + ('call', 'at_connect', self.hit))) + + self.snowball_material.add_actions( + conditions=(('they_dont_have_material', shared.player_material), + 'and', + ('they_have_material', shared.object_material), + 'or', + ('they_have_material', shared.footing_material)), + actions=('call', 'at_connect', self.bounce)) + + self.node = bs.newnode( + 'prop', + delegate=self, + attrs={ + 'position': position, + 'velocity': velocity, + 'body': 'sphere', + 'body_scale': self.scale, + 'mesh': bs.getmesh('frostyPelvis'), + 'shadow_size': shadow_size, + 'color_texture': bs.gettexture('bunnyColor'), + 'reflection': 'soft', + 'reflection_scale': [0.15], + 'density': 1.0, + 'materials': [self.snowball_material] + }) + self.light = bs.newnode( + 'light', + owner=self.node, + attrs={ + 'color': (0.6, 0.6, 1.0), + 'intensity': 0.8, + 'radius': self.radius + }) + self.node.connectattr('position', self.light, 'position') + bs.animate(self.node, 'mesh_scale', { + 0: 0, + 0.2: 1.3 * self.scale, + 0.26: self.scale + }) + bs.animate(self.light, 'radius', { + 0: 0, + 0.2: 1.3 * self.radius, + 0.26: self.radius + }) + if self.snowball_melt: + bs.timer(1.5, bs.WeakCall(self._disappear)) + + def hit(self) -> None: + if not self.node: + return + if self._exploded: + return + if self.snowball_explode: + self._exploded = True + self.do_explode() + bs.timer(0.001, bs.WeakCall(self.handlemessage, bs.DieMessage())) + else: + self.do_hit() + + def do_hit(self) -> None: + v = self.node.velocity + if babase.Vec3(*v).length() > 5.0: + node = bs.getcollision().opposingnode + if node is not None and node and not ( + node in self._hit_nodes): + t = self.node.position + hitdir = self.node.velocity + self._hit_nodes.add(node) + node.handlemessage( + bs.HitMessage( + pos=t, + velocity=v, + magnitude=babase.Vec3(*v).length()*0.5, + velocity_magnitude=babase.Vec3(*v).length()*0.5, + radius=0, + srcnode=self.node, + source_player=self._source_player, + force_direction=hitdir, + hit_type='snoBall', + hit_subtype='default')) + + if not self.snowball_bounce: + bs.timer(0.05, bs.WeakCall(self.do_bounce)) + + def do_explode(self) -> None: + Blast(position=self.node.position, + velocity=self.node.velocity, + blast_radius=self.blast_radius, + source_player=babase.existing(self._source_player), + blast_type='impact', + hit_subtype='explode').autoretain() + + def bounce(self) -> None: + if not self.node: + return + if self._exploded: + return + if not self.snowball_bounce: + vel = self.node.velocity + bs.timer(0.01, bs.WeakCall(self.calc_bounce, vel)) + else: + return + + def calc_bounce(self, vel) -> None: + if not self.node: + return + ospd = babase.Vec3(*vel).length() + dot = sum(x*y for x, y in zip(vel, self.node.velocity)) + if ospd*ospd - dot > 50.0: + bs.timer(0.05, bs.WeakCall(self.do_bounce)) + + def do_bounce(self) -> None: + if not self.node: + return + if not self._exploded: + self.do_effect() + + def do_effect(self) -> None: + self._exploded = True + bs.emitfx(position=self.node.position, + velocity=[v*0.1 for v in self.node.velocity], + count=10, + spread=0.1, + scale=0.4, + chunk_type='ice') + sound = bs.getsound('impactMedium') + sound.play(1.0, position=self.node.position) + scl = self.node.mesh_scale + bs.animate(self.node, 'mesh_scale', { + 0.0: scl*1.0, + 0.02: scl*0.5, + 0.05: 0.0 + }) + lr = self.light.radius + bs.animate(self.light, 'radius', { + 0.0: lr*1.0, + 0.02: lr*0.5, + 0.05: 0.0 + }) + bs.timer(0.08, + bs.WeakCall(self.handlemessage, bs.DieMessage())) + + def _disappear(self) -> None: + self._exploded = True + if self.node: + scl = self.node.mesh_scale + bs.animate(self.node, 'mesh_scale', { + 0.0: scl*1.0, + 0.3: scl*0.5, + 0.5: 0.0 + }) + lr = self.light.radius + bs.animate(self.light, 'radius', { + 0.0: lr*1.0, + 0.3: lr*0.5, + 0.5: 0.0 + }) + bs.timer(0.55, + bs.WeakCall(self.handlemessage, bs.DieMessage())) + + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, bs.DieMessage): + if self.node: + self.node.delete() + elif isinstance(msg, bs.OutOfBoundsMessage): + self.handlemessage(bs.DieMessage()) + else: + super().handlemessage(msg) + + +class NewPlayerSpaz(PlayerSpaz): + + def __init__(self, *args: Any, **kwds: Any): + super().__init__(*args, **kwds) + self.snowball_scale = 1.0 + self.snowball_melt = True + self.snowball_bounce = True + self.snowball_explode = False + + def on_punch_press(self) -> None: + if not self.node or self.frozen or self.node.knockout > 0.0: + return + t_ms = bs.time() * 1000 + assert isinstance(t_ms, int) + if t_ms - self.last_punch_time_ms >= self._punch_cooldown: + if self.punch_callback is not None: + self.punch_callback(self) + + # snowball + pos = self.node.position + p1 = self.node.position_center + p2 = self.node.position_forward + direction = [p1[0]-p2[0],p2[1]-p1[1],p1[2]-p2[2]] + direction[1] = 0.03 + mag = 20.0/babase.Vec3(*direction).length() + vel = [v * mag for v in direction] + Snowball(position=(pos[0], pos[1] + 0.1, pos[2]), + velocity=vel, + blast_radius=self.blast_radius, + bomb_scale=self.snowball_scale, + source_player=self.source_player, + owner=self.node, + melt=self.snowball_melt, + bounce=self.snowball_bounce, + explode=self.snowball_explode).autoretain() + + self._punched_nodes = set() # Reset this. + self.last_punch_time_ms = t_ms + self.node.punch_pressed = True + if not self.node.hold_node: + bs.timer( + 0.1, + bs.WeakCall(self._safe_play_sound, + SpazFactory.get().swish_sound, 0.8)) + self._turbo_filter_add_press('punch') + + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, PunchHitMessage): + pass + else: + return super().handlemessage(msg) + return None + + +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 SnowballFightGame(bs.TeamGameActivity[Player, Team]): + """A game type based on acquiring kills.""" + + name = name + 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.FloatChoiceSetting( + 'Respawn Times', + choices=[ + ('Shorter', 0.25), + ('Short', 0.5), + ('Normal', 1.0), + ('Long', 2.0), + ('Longer', 4.0), + ], + default=1.0, + ), + bs.IntChoiceSetting( + snowball_rate, + choices=[ + (snowball_slowest, 500), + (snowball_slow, 400), + ('Normal', 300), + (snowball_fast, 200), + (snowball_lagcity, 100), + ], + default=300, + ), + bs.FloatChoiceSetting( + snowball_scale, + choices=[ + (snowball_smallest, 0.4), + (snowball_small, 0.6), + ('Normal', 0.8), + (snowball_big, 1.4), + (snowball_biggest, 3.0), + (snowball_insane, 6.0), + ], + default=0.8, + ), + bs.BoolSetting(snowball_melt, default=True), + bs.BoolSetting(snowball_bust, default=True), + bs.BoolSetting(snowball_explode, default=False), + bs.BoolSetting(snowball_snow, default=True), + bs.BoolSetting('Epic Mode', default=False), + ] + + # In teams mode, a suicide gives a point to the other team, but in + # free-for-all it subtracts from your own score. By default we clamp + # 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, 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]: + return bs.app.classic.getmaps('melee') + + 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._snowball_rate = int(settings[snowball_rate]) + self._snowball_scale = float(settings[snowball_scale]) + self._snowball_melt = bool(settings[snowball_melt]) + self._snowball_bounce = bool(settings[snowball_bust]) + self._snowball_explode = bool(settings[snowball_explode]) + self._snow_mode = bool(settings[snowball_snow]) + + # 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) -> 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_transition_in(self) -> None: + super().on_transition_in() + if self._snow_mode: + gnode = bs.getactivity().globalsnode + gnode.tint = (0.8, 0.8, 1.3) + bs.timer(0.02, self.emit_snowball, repeat=True) + + def on_begin(self) -> None: + super().on_begin() + self.setup_standard_time_limit(self._time_limit) + # self.setup_standard_powerup_drops() + + # 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 emit_snowball(self) -> None: + pos = (-10 + (random.random() * 30), 15, + -10 + (random.random() * 30)) + vel = ((-5.0 + random.random() * 30.0) * (-1.0 if pos[0] > 0 else 1.0), + -50.0, (-5.0 + random.random() * 30.0) * ( + -1.0 if pos[0] > 0 else 1.0)) + bs.emitfx(position=pos, + velocity=vel, + count=10, + scale=1.0 + random.random(), + spread=0.0, + chunk_type='spark') + + def spawn_player_spaz(self, + player: Player, + position: Sequence[float] = (0, 0, 0), + angle: float | None = None) -> PlayerSpaz: + from babase import _math + from bascenev1._gameutils import animate + from bascenev1._coopsession import CoopSession + + 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) + + 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 = NewPlayerSpaz(color=color, + highlight=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, 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( + enable_pickup=False, enable_bomb=False) + + # 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') + animate(light, 'intensity', {0: 0, 0.25: 1, 0.5: 0}) + bs.timer(0.5, light.delete) + + # custom + spaz._punch_cooldown = self._snowball_rate + spaz.snowball_scale = self._snowball_scale + spaz.snowball_melt = self._snowball_melt + spaz.snowball_bounce = self._snowball_bounce + spaz.snowball_explode = self._snowball_explode + + 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, 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/meteorshowerdeluxe.py b/plugins/minigames/meteorshowerdeluxe.py new file mode 100644 index 0000000..296c8dc --- /dev/null +++ b/plugins/minigames/meteorshowerdeluxe.py @@ -0,0 +1,67 @@ +# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport) +# ba_meta require api 8 +""" +GNU AFFERO GENERAL PUBLIC LICENSE +Version 3, 19 November 2007 + +Copyright (C) 2007 Free Software Foundation, Inc. <[1](https://fsf.org/)> + +Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. + +This license is designed to ensure cooperation with the community in the case of network server software. It is a free, copyleft license for software and other kinds of works. The license guarantees your freedom to share and change all versions of a program, to make sure it remains free software for all its users. + +The license identifier refers to the choice to use code under AGPL-3.0-or-later (i.e., AGPL-3.0 or some later version), as distinguished from use of code under AGPL-3.0-only. The license notice states which of these applies the code in the file. + + +""" +import random +import babase +import bauiv1 as bui +import bascenev1 as bs +from bascenev1lib.game.meteorshower import MeteorShowerGame +from bascenev1lib.actor.bomb import Bomb + + +class NewMeteorShowerGame(MeteorShowerGame): + @classmethod + def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]: + return bs.app.classic.getmaps("melee") + + def _drop_bomb_cluster(self) -> None: + # Drop several bombs in series. + delay = 0.0 + bounds = list(self._map.get_def_bound_box("map_bounds")) + for _i in range(random.randrange(1, 3)): + # Drop them somewhere within our bounds with velocity pointing + # toward the opposite side. + pos = ( + random.uniform(bounds[0], bounds[3]), + bounds[4], + random.uniform(bounds[2], bounds[5]), + ) + dropdirx = -1 if pos[0] > 0 else 1 + dropdirz = -1 if pos[2] > 0 else 1 + forcex = ( + bounds[0] - bounds[3] + if bounds[0] - bounds[3] > 0 + else -(bounds[0] - bounds[3]) + ) + forcez = ( + bounds[2] - bounds[5] + if bounds[2] - bounds[5] > 0 + else -(bounds[2] - bounds[5]) + ) + vel = ( + (-5 + random.random() * forcex) * dropdirx, + random.uniform(-3.066, -4.12), + (-5 + random.random() * forcez) * dropdirz, + ) + bs.timer(delay, babase.Call(self._drop_bomb, pos, vel)) + delay += 0.1 + self._set_meteor_timer() + + +# ba_meta export plugin +class byEra0S(babase.Plugin): + MeteorShowerGame.get_supported_maps = NewMeteorShowerGame.get_supported_maps + MeteorShowerGame._drop_bomb_cluster = NewMeteorShowerGame._drop_bomb_cluster diff --git a/plugins/minigames/ofuuuAttack.py b/plugins/minigames/ofuuuAttack.py new file mode 100644 index 0000000..49b2afb --- /dev/null +++ b/plugins/minigames/ofuuuAttack.py @@ -0,0 +1,340 @@ +# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport) +# 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.bomb import BombFactory, Bomb +from bascenev1lib.gameutils import SharedObjects +from bascenev1lib.actor.onscreentimer import OnScreenTimer + +if TYPE_CHECKING: + from typing import Any, Sequence, Optional, List, Dict, Type, Type + +class _GotTouched(): + pass + +class UFO(bs.Actor): + + def __init__(self, pos: float = (0,0,0)): + super().__init__() + shared = SharedObjects.get() + self.r: Optional[int] = 0 + self.dis: Optional[List] = [] + self.target: float = (0.0, 0.0, 0.0) + self.regs: List[bs.NodeActor] = [] + self.node = bs.newnode('prop', + delegate=self, + attrs={'body':'landMine', + 'position': pos, + 'mesh':bs.getmesh('landMine'), + 'mesh_scale': 1.5, + 'body_scale': 0.01, + 'shadow_size': 0.000001, + 'gravity_scale': 0.0, + 'color_texture': bs.gettexture("achievementCrossHair"), + 'materials': [shared.object_material]}) + self.ufo_collide = None + + def create_target(self): + if not self.node.exists(): return + self.dis = [] + shared = SharedObjects.get() + try: + def pass_(): + self.regs.clear() + bs.timer(3875*0.001, self.move) + try: bs.timer(3277*0.001, lambda: Bomb(velocity=(0,0,0), position=(self.target[0], self.node.position[1]-0.43999, self.target[2]), bomb_type='impact').autoretain().arm()) + except: pass + key = bs.Material() + key.add_actions( + conditions=('they_have_material', shared.object_material), + actions=( + ('modify_part_collision', 'collide', True), + ('modify_part_collision', 'physical', False), + ('call', 'at_connect', pass_()), + )) + except: pass + self.regs.append(bs.NodeActor(bs.newnode('region', + attrs={ + 'position': self.target, + 'scale': (0.04, 22, 0.04), + 'type': 'sphere', + 'materials':[key]}))) + + def move(self): + if not self.node.exists(): return + try: + self.create_target() + for j in bs.getnodes(): + n = j.getdelegate(object) + if j.getnodetype() == 'prop' and isinstance(n, TileFloor): + if n.node.exists(): self.dis.append(n.node) + self.r = random.randint(0,len(self.dis)-1) + self.target = (self.dis[self.r].position[0], self.node.position[1], self.dis[self.r].position[2]) + bs.animate_array(self.node, 'position', 3, { + 0:self.node.position, + 3.0:self.target}) + except: pass + def handlemessage(self, msg): + + if isinstance(msg, bs.DieMessage): + self.node.delete() + elif isinstance(msg ,bs.OutOfBoundsMessage): self.handlemessage(bs.DieMessage()) + else: super().handlemessage(msg) + + +class TileFloor(bs.Actor): + def __init__(self, + pos: float = (0, 0, 0)): + super().__init__() + get_mat = SharedObjects.get() + self.pos = pos + self.scale = 1.5 + self.mat, self.mat2, self.test = bs.Material(), bs.Material(), bs.Material() + self.mat.add_actions(conditions=('we_are_older_than', 1), actions=(('modify_part_collision', 'collide', False))) + self.mat2.add_actions(conditions=('we_are_older_than', 1), actions=(('modify_part_collision', 'collide', True))) + self.test.add_actions( + conditions=('they_have_material', BombFactory.get().bomb_material), + actions=( + ('modify_part_collision', 'collide', True), + ('modify_part_collision', 'physical', False), + ('message', 'our_node', 'at_connect', _GotTouched()))) + self.node = bs.newnode('prop', + delegate=self, + attrs={'body':'puck', + 'position': self.pos, + 'mesh':bs.getmesh('buttonSquareOpaque'), + 'mesh_scale': self.scale*1.16, + 'body_scale': self.scale, + 'shadow_size': 0.0002, + 'gravity_scale': 0.0, + 'color_texture': bs.gettexture("tnt"), + 'is_area_of_interest': True, + 'materials': [self.mat, self.test]}) + self.node_support = bs.newnode('region', + attrs={ + 'position': self.pos, + 'scale': (self.scale*0.8918, 0.1, self.scale*0.8918), + 'type': 'box', + 'materials':[get_mat.footing_material, self.mat2] + }) + def handlemessage(self, msg): + if isinstance(msg, bs.DieMessage): + self.node.delete() + self.node_support.delete() + elif isinstance(msg, _GotTouched): + def do(): self.handlemessage(bs.DieMessage()) + bs.timer(0.1, do) + else: super().handlemessage(msg) + +class defs(): + points = boxes = {} + boxes['area_of_interest_bounds'] = (-1.3440, 1.185751251, 3.7326226188) + ( + 0.0, 0.0, 0.0) + (29.8180273, 15.57249038, 22.93859993) + boxes['map_bounds'] = (0.0, 2.585751251, 0.4326226188) + (0.0, 0.0, 0.0) + (29.09506485, 15.81173179, 33.76723155) + +class DummyMapForGame(bs.Map): + defs, name = defs(), 'Tile Lands' + @classmethod + def get_play_types(cls) -> List[str]: + return [] + @classmethod + def get_preview_texture_name(cls) -> str: + return 'achievementCrossHair' + @classmethod + def on_preload(cls) -> Any: + data: Dict[str, Any] = {'bg_1': bs.gettexture('rampageBGColor'),'bg_2': bs.gettexture('rampageBGColor2'),'bg_mesh_1': bs.getmesh('rampageBG'),'bg_mesh_2': bs.getmesh('rampageBG2'),} + return data + def __init__(self) -> None: + super().__init__() + self.bg1 = bs.newnode('terrain',attrs={'mesh': self.preloaddata['bg_mesh_1'],'lighting': False,'background': True,'color_texture': self.preloaddata['bg_2']}) + self.bg2 = bs.newnode('terrain',attrs={ 'mesh': self.preloaddata['bg_mesh_2'], 'lighting': False,'background': True, 'color_texture': self.preloaddata['bg_2']}) + a = bs.getactivity().globalsnode + a.tint, a.ambient_color, a.vignette_outer, a.vignette_inner = (1.2, 1.1, 0.97), (1.3, 1.2, 1.03), (0.62, 0.64, 0.69), (0.97, 0.95, 0.93) + +class DummyMapForGame2(bs.Map): + defs, name = defs(), 'Tile Lands Night' + @classmethod + def get_play_types(cls) -> List[str]: + return [] + @classmethod + def get_preview_texture_name(cls) -> str: + return 'achievementCrossHair' + @classmethod + def on_preload(cls) -> Any: + data: Dict[str, Any] = {'bg_1': bs.gettexture('menuBG'),'bg_2': bs.gettexture('menuBG'),'bg_mesh_1': bs.getmesh('thePadBG'),'bg_mesh_2': bs.getmesh('thePadBG'),} + return data + def __init__(self) -> None: + super().__init__() + self.bg1 = bs.newnode('terrain',attrs={'mesh': self.preloaddata['bg_mesh_1'],'lighting': False,'background': True,'color_texture': self.preloaddata['bg_2']}) + self.bg2 = bs.newnode('terrain',attrs={ 'mesh': self.preloaddata['bg_mesh_2'], 'lighting': False,'background': True, 'color_texture': self.preloaddata['bg_2']}) + a = bs.getactivity().globalsnode + a.tint, a.ambient_color, a.vignette_outer, a.vignette_inner = (0.5, 0.7, 1.27), (2.5, 2.5, 2.5), (0.62, 0.64, 0.69), (0.97, 0.95, 0.93) + +bs._map.register_map(DummyMapForGame) +bs._map.register_map(DummyMapForGame2) + + + + +class Player(bs.Player['Team']): + """Our player type for this game.""" + + def __init__(self) -> None: + super().__init__() + self.death_time: Optional[float] = None + + +class Team(bs.Team[Player]): + """Our team type for this game.""" + + +# ba_meta export bascenev1.GameActivity +class UFOAttackGame(bs.TeamGameActivity[Player, Team]): + + name = 'UFO Attack' + description = 'Dodge the falling bombs.' + available_settings = [ + bs.BoolSetting('Epic Mode', default=False), + bs.BoolSetting('Enable Run', default=True), + bs.BoolSetting('Enable Jump', default=True), + bs.BoolSetting('Display Map Area Dimension', default=False), + bs.IntSetting('No. of Rows' + u' →',max_value=13, min_value=1, default=8, increment=1), + bs.IntSetting('No. of Columns' + u' ↓', max_value=12, min_value=1, default=6, increment=1) + ] + scoreconfig = bs.ScoreConfig(label='Survived', + scoretype=bs.ScoreType.SECONDS, + version='B') + + # Print messages when players die (since its meaningful in this game). + announce_player_deaths = True + @classmethod + def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]: + return ['Tile Lands', 'Tile Lands Night'] + @classmethod + def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool: + return (issubclass(sessiontype, bs.DualTeamSession) + or issubclass(sessiontype, bs.FreeForAllSession)) + + def __init__(self, settings: dict): + super().__init__(settings) + + self.col = int(settings['No. of Columns' + u' ↓']) + self.row = int(settings['No. of Rows' + u' →']) + self.bool1 = bool(settings['Enable Run']) + self.bool2 = bool(settings['Enable Jump']) + self._epic_mode = settings.get('Epic Mode', False) + self._last_player_death_time: Optional[float] = None + self._timer: Optional[OnScreenTimer] = None + self.default_music = (bs.MusicType.EPIC + if self._epic_mode else bs.MusicType.SURVIVAL) + if bool(settings["Display Map Area Dimension"]): + self.game_name = "UFO Attack " + "(" + str(self.col) + "x" + str(self.row) + ")" + else: self.game_name = "UFO Attack" + if self._epic_mode: + self.slow_motion = True + + def get_instance_display_string(self) -> babase.Lstr: + return self.game_name + + def on_begin(self) -> None: + super().on_begin() + self._timer = OnScreenTimer() + self._timer.start() + #bs.timer(5.0, self._check_end_game) + for r in range(self.col): + for j in range(self.row): + tile = TileFloor(pos=(-6.204283+(j*1.399), 3.425666, + -1.3538+(r*1.399))).autoretain() + self.ufo = UFO(pos=(-5.00410667, 6.616383286, -2.503472)).autoretain() + bs.timer(7000*0.001, lambda: self.ufo.move()) + for t in self.players: + self.spawn_player(t) + + def on_player_join(self, player: Player) -> None: + if self.has_begun(): + bs.broadcastmessage( + babase.Lstr(resource='playerDelayedJoinText', + subs=[('${PLAYER}', player.getname(full=True))]), + color=(0, 1, 0), + ) + assert self._timer is not None + player.death_time = self._timer.getstarttime() + return + + def on_player_leave(self, player: Player) -> None: + super().on_player_leave(player) + self._check_end_game() + + def spawn_player(self, player: Player) -> bs.Actor: + dis = [] + for a in bs.getnodes(): + g = a.getdelegate(object) + if a.getnodetype() == 'prop' and isinstance(g, TileFloor): + dis.append(g.node) + r = random.randint(0, len(dis)-1) + spaz = self.spawn_player_spaz(player, position=(dis[r].position[0], dis[r].position[1]+1.005958, dis[r].position[2])) + spaz.connect_controls_to_player(enable_punch=False, + enable_bomb=False, + enable_run=self.bool1, + enable_jump=self.bool2, + enable_pickup=False) + spaz.play_big_death_sound = True + return spaz + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, bs.PlayerDiedMessage): + super().handlemessage(msg) + + curtime = bs.time() + msg.getplayer(Player).death_time = curtime + bs.timer(1.0, self._check_end_game) + + else: + return super().handlemessage(msg) + return None + + def _check_end_game(self) -> None: + living_team_count = 0 + for team in self.teams: + for player in team.players: + if player.is_alive(): + living_team_count += 1 + break + if living_team_count <= 1: + self.end_game() + + def end_game(self) -> None: + self.ufo.handlemessage(bs.DieMessage()) + cur_time = bs.time() + assert self._timer is not None + start_time = self._timer.getstarttime() + for team in self.teams: + for player in team.players: + survived = False + if player.death_time is None: + survived = True + player.death_time = cur_time + 1 + score = int(player.death_time - self._timer.getstarttime()) + if survived: + score += 2 + self.stats.player_scored(player, score, screenmessage=False) + self._timer.stop(endtime=self._last_player_death_time) + results = bs.GameResults() + for team in self.teams: + longest_life = 0.0 + for player in team.players: + assert player.death_time is not None + longest_life = max(longest_life, + player.death_time - start_time) + + # Submit the score value in milliseconds. + results.set_team_score(team, int(longest_life)) + + self.end(results=results) \ No newline at end of file diff --git a/plugins/minigames/safe_zone.py b/plugins/minigames/safe_zone.py new file mode 100644 index 0000000..4c2620f --- /dev/null +++ b/plugins/minigames/safe_zone.py @@ -0,0 +1,720 @@ +# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport) +# Released under the MIT License. See LICENSE for details. +# +"""Elimination mini-game.""" + +# Maded by Froshlee14 +# Update by SEBASTIAN2059 + +# 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 _babase +import random +from bascenev1lib.actor.spazfactory import SpazFactory +from bascenev1lib.actor.scoreboard import Scoreboard +from bascenev1lib.actor import spazbot as stdbot +from bascenev1lib.gameutils import SharedObjects as so + +if TYPE_CHECKING: + from typing import (Any, Tuple, Dict, Type, List, Sequence, Optional, + Union) + + +class Icon(bs.Actor): + """Creates in in-game icon on screen.""" + + def __init__(self, + player: Player, + position: Tuple[float, float], + scale: float, + show_lives: bool = True, + show_death: bool = True, + name_scale: float = 1.0, + name_maxwidth: float = 115.0, + flatness: float = 1.0, + shadow: float = 1.0): + super().__init__() + + self._player = player + self._show_lives = show_lives + self._show_death = show_death + self._name_scale = name_scale + self._outline_tex = bs.gettexture('characterIconMask') + + icon = player.get_icon() + self.node = bs.newnode('image', + delegate=self, + attrs={ + 'texture': icon['texture'], + 'tint_texture': icon['tint_texture'], + 'tint_color': icon['tint_color'], + 'vr_depth': 400, + 'tint2_color': icon['tint2_color'], + 'mask_texture': self._outline_tex, + 'opacity': 1.0, + 'absolute_scale': True, + 'attach': 'bottomCenter' + }) + self._name_text = bs.newnode( + 'text', + owner=self.node, + attrs={ + 'text': babase.Lstr(value=player.getname()), + 'color': babase.safecolor(player.team.color), + 'h_align': 'center', + 'v_align': 'center', + 'vr_depth': 410, + 'maxwidth': name_maxwidth, + 'shadow': shadow, + 'flatness': flatness, + 'h_attach': 'center', + 'v_attach': 'bottom' + }) + if self._show_lives: + self._lives_text = bs.newnode('text', + owner=self.node, + attrs={ + 'text': 'x0', + 'color': (1, 1, 0.5), + 'h_align': 'left', + 'vr_depth': 430, + 'shadow': 1.0, + 'flatness': 1.0, + 'h_attach': 'center', + 'v_attach': 'bottom' + }) + self.set_position_and_scale(position, scale) + + def set_position_and_scale(self, position: Tuple[float, float], + scale: float) -> None: + """(Re)position the icon.""" + assert self.node + self.node.position = position + self.node.scale = [70.0 * scale] + self._name_text.position = (position[0], position[1] + scale * 52.0) + self._name_text.scale = 1.0 * scale * self._name_scale + if self._show_lives: + self._lives_text.position = (position[0] + scale * 10.0, + position[1] - scale * 43.0) + self._lives_text.scale = 1.0 * scale + + def update_for_lives(self) -> None: + """Update for the target player's current lives.""" + if self._player: + lives = self._player.lives + else: + lives = 0 + if self._show_lives: + if lives > 0: + self._lives_text.text = 'x' + str(lives - 1) + else: + self._lives_text.text = '' + if lives == 0: + self._name_text.opacity = 0.2 + assert self.node + self.node.color = (0.7, 0.3, 0.3) + self.node.opacity = 0.2 + + def handle_player_spawned(self) -> None: + """Our player spawned; hooray!""" + if not self.node: + return + self.node.opacity = 1.0 + self.update_for_lives() + + def handle_player_died(self) -> None: + """Well poo; our player died.""" + if not self.node: + return + if self._show_death: + bs.animate( + self.node, 'opacity', { + 0.00: 1.0, + 0.05: 0.0, + 0.10: 1.0, + 0.15: 0.0, + 0.20: 1.0, + 0.25: 0.0, + 0.30: 1.0, + 0.35: 0.0, + 0.40: 1.0, + 0.45: 0.0, + 0.50: 1.0, + 0.55: 0.2 + }) + lives = self._player.lives + if lives == 0: + bs.timer(0.6, self.update_for_lives) + + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, bs.DieMessage): + self.node.delete() + return None + return super().handlemessage(msg) + + +class Player(bs.Player['Team']): + """Our player type for this game.""" + + def __init__(self) -> None: + self.lives = 0 + self.icons: List[Icon] = [] + + +class Team(bs.Team[Player]): + """Our team type for this game.""" + + def __init__(self) -> None: + self.survival_seconds: Optional[int] = None + self.spawn_order: List[Player] = [] + +lang = bs.app.lang.language +if lang == 'Spanish': + description = 'Mantente en la zona segura.' + join_description = 'Corre hacia la zona segura.' + kill_timer = 'Kill timer: ' +else: + description = 'Stay in the safe zone.' + join_description = 'Run into the safe zone' + kill_timer = 'Kill timer: ' + +# ba_meta export bascenev1.GameActivity +class SafeZoneGame(bs.TeamGameActivity[Player, Team]): + """Game type where last player(s) left alive win.""" + + name = 'Safe Zone' + description = description + 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 + + @classmethod + def get_available_settings( + cls, sessiontype: Type[bs.Session]) -> List[babase.Setting]: + settings = [ + bs.IntSetting( + 'Lives Per Player', + default=2, + min_value=1, + max_value=10, + increment=1, + ), + bs.IntChoiceSetting( + 'Time Limit', + choices=[ + ('None', 0), + ('1 Minute', 60), + ('2 Minutes', 120), + ('5 Minutes', 300), + ('10 Minutes', 600), + ('20 Minutes', 1200), + ], + default=0, + ), + bs.FloatChoiceSetting( + 'Respawn Times', + choices=[ + ('Short', 0.25), + ('Normal', 0.5), + ], + default=0.5, + ), + bs.BoolSetting('Epic Mode', default=False), + ] + if issubclass(sessiontype, bs.DualTeamSession): + settings.append(bs.BoolSetting('Solo Mode', default=False)) + settings.append( + bs.BoolSetting('Balance Total Lives', default=False)) + return settings + + @classmethod + def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool: + return (issubclass(sessiontype, bs.DualTeamSession) + or issubclass(sessiontype, bs.FreeForAllSession)) + + @classmethod + def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]: + return ['Football Stadium','Hockey Stadium'] + + def __init__(self, settings: dict): + super().__init__(settings) + self._scoreboard = Scoreboard() + self._start_time: Optional[float] = None + self._vs_text: Optional[bs.Actor] = None + self._round_end_timer: Optional[bs.Timer] = None + self._epic_mode = bool(settings['Epic Mode']) + self._lives_per_player = int(settings['Lives Per Player']) + self._time_limit = float(settings['Time Limit']) + self._balance_total_lives = bool( + settings.get('Balance Total Lives', False)) + self._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) + + self._tick_sound = bs.getsound('tick') + + def get_instance_description(self) -> Union[str, Sequence]: + return join_description + + def get_instance_description_short(self) -> Union[str, Sequence]: + return 'last team standing wins' if isinstance( + self.session, bs.DualTeamSession) else 'last one standing wins' + + def on_player_join(self, player: Player) -> None: + + # No longer allowing mid-game joiners here; too easy to exploit. + if self.has_begun(): + + # Make sure their team has survival seconds set if they're all dead + # (otherwise blocked new ffa players are considered 'still alive' + # in score tallying). + if (self._get_total_team_lives(player.team) == 0 + and player.team.survival_seconds is None): + player.team.survival_seconds = 0 + bs.broadcastmessage( + babase.Lstr(resource='playerDelayedJoinText', + subs=[('${PLAYER}', player.getname(full=True))]), + color=(0, 1, 0), + ) + return + + player.lives = self._lives_per_player + + if self._solo_mode: + player.team.spawn_order.append(player) + self._update_solo_mode() + else: + # Create our icon and spawn. + player.icons = [Icon(player, position=(0, 50), scale=0.8)] + if player.lives > 0: + self.spawn_player(player) + + # Don't waste time doing this until begin. + if self.has_begun(): + self._update_icons() + + 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() + + bs.timer(5,self.spawn_zone) + self._bots = stdbot.SpazBotSet() + bs.timer(3,babase.Call(self.add_bot,'left')) + bs.timer(3,babase.Call(self.add_bot,'right')) + if len(self.initialplayerinfos) > 4: + bs.timer(5,babase.Call(self.add_bot,'right')) + bs.timer(5,babase.Call(self.add_bot,'left')) + + if self._solo_mode: + 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') + })) + + # If balance-team-lives is on, add lives to the smaller team until + # total lives match. + if (isinstance(self.session, bs.DualTeamSession) + and self._balance_total_lives and self.teams[0].players + and self.teams[1].players): + if self._get_total_team_lives( + self.teams[0]) < self._get_total_team_lives(self.teams[1]): + lesser_team = self.teams[0] + greater_team = self.teams[1] + else: + lesser_team = self.teams[1] + greater_team = self.teams[0] + add_index = 0 + while (self._get_total_team_lives(lesser_team) < + self._get_total_team_lives(greater_team)): + lesser_team.players[add_index].lives += 1 + add_index = (add_index + 1) % len(lesser_team.players) + + self._update_icons() + + # We could check game-over conditions at explicit trigger points, + # but lets just do the simple thing and poll it. + bs.timer(1.0, self._update, repeat=True) + + def spawn_zone(self): + self.zone_pos = (random.randrange(-10,10),0.05,random.randrange(-5,5)) + self.zone = bs.newnode('locator',attrs={'shape':'circle','position':self.zone_pos,'color':(1, 1, 0),'opacity':0.8,'draw_beauty':True,'additive':False,'drawShadow':False}) + self.zone_limit = bs.newnode('locator',attrs={'shape':'circleOutline','position':self.zone_pos,'color':(1, 0.2, 0.2),'opacity':0.8,'draw_beauty':True,'additive':False,'drawShadow':False}) + bs.animate_array(self.zone, 'size', 1,{0:[0], 0.3:[self.get_players_count()*0.85], 0.35:[self.get_players_count()*0.8]}) + bs.animate_array(self.zone_limit, 'size', 1,{0:[0], 0.3:[self.get_players_count()*1.2], 0.35:[self.get_players_count()*0.95]}) + self.last_players_count = self.get_players_count() + bs.getsound('laserReverse').play() + self.start_timer() + self.move_zone() + + def delete_zone(self): + self.zone.delete() + self.zone = None + self.zone_limit.delete() + self.zone_limit = None + bs.getsound('shieldDown').play() + bs.timer(1,self.spawn_zone) + + def move_zone(self): + if self.zone_pos[0] > 0: x = random.randrange(0,10) + else: x = random.randrange(-10,0) + + if self.zone_pos[2] > 0: y = random.randrange(0,5) + else: y = random.randrange(-5,0) + + new_pos = (x,0.05,y) + bs.animate_array(self.zone, 'position', 3,{0:self.zone.position, 8:new_pos}) + bs.animate_array(self.zone_limit, 'position', 3,{0:self.zone_limit.position,8:new_pos}) + + def start_timer(self): + count = self.get_players_count() + self._time_remaining = 10 if count > 9 else count-1 if count > 6 else count if count > 2 else count*2 + self._timer_x = bs.Timer(1.0,bs.WeakCall(self.tick),repeat=True) + # gnode = bs.getactivity().globalsnode + # tint = gnode.tint + # bs.animate_array(gnode,'tint',3,{0:tint,self._time_remaining*1.5:(1.0,0.5,0.5),self._time_remaining*1.55:tint}) + + def stop_timer(self): + self._time = None + self._timer_x = None + + def tick(self): + self.check_players() + self._time = bs.NodeActor(bs.newnode('text', + attrs={'v_attach':'top','h_attach':'center', + 'text':kill_timer+str(self._time_remaining)+'s', + 'opacity':0.8,'maxwidth':100,'h_align':'center', + 'v_align':'center','shadow':1.0,'flatness':1.0, + 'color':(1,1,1),'scale':1.5,'position':(0,-50)} + ) + ) + self._time_remaining -= 1 + self._tick_sound.play() + + def check_players(self): + if self._time_remaining <= 0: + self.stop_timer() + bs.animate_array(self.zone, 'size', 1,{0:[self.last_players_count*0.8], 1.4:[self.last_players_count*0.8],1.5:[0]}) + bs.animate_array(self.zone_limit, 'size', 1,{0:[self.last_players_count*0.95], 1.45:[self.last_players_count*0.95],1.5:[0]}) + bs.timer(1.5,self.delete_zone) + for player in self.players: + if not player.actor is None: + if player.actor.is_alive(): + p1 = player.actor.node.position + p2 = self.zone.position + diff = (babase.Vec3(p1[0]-p2[0],0.0,p1[2]-p2[2])) + dist = (diff.length()) + if dist > (self.get_players_count()*0.7): + player.actor.handlemessage(bs.DieMessage()) + + def get_players_count(self): + count = 0 + for player in self.players: + if not player.actor is None: + if player.actor.is_alive(): + count += 1 + return count + + def _update_solo_mode(self) -> None: + # For both teams, find the first player on the spawn order list with + # lives remaining and spawn them if they're not alive. + for team in self.teams: + # Prune dead players from the spawn order. + team.spawn_order = [p for p in team.spawn_order if p] + for player in team.spawn_order: + assert isinstance(player, Player) + if player.lives > 0: + if not player.is_alive(): + self.spawn_player(player) + break + + 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: + player = team.players[0] + 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: + for icon in player.icons: + icon.set_position_and_scale((xval, 30), 0.7) + icon.update_for_lives() + xval += x_offs + + def _get_spawn_point(self, player: Player) -> Optional[babase.Vec3]: + del player # Unused. + + # In solo-mode, if there's an existing live player on the map, spawn at + # whichever spot is farthest from them (keeps the action spread out). + if self._solo_mode: + living_player = None + living_player_pos = None + for team in self.teams: + for tplayer in team.players: + if tplayer.is_alive(): + assert tplayer.node + ppos = tplayer.node.position + living_player = tplayer + living_player_pos = ppos + break + if living_player: + assert living_player_pos is not None + player_pos = babase.Vec3(living_player_pos) + points: List[Tuple[float, babase.Vec3]] = [] + for team in self.teams: + start_pos = babase.Vec3(self.map.get_start_position(team.id)) + points.append( + ((start_pos - player_pos).length(), start_pos)) + # Hmm.. we need to sorting vectors too? + points.sort(key=lambda x: x[0]) + return points[-1][1] + return None + + def spawn_player(self, player: Player) -> bs.Actor: + actor = self.spawn_player_spaz(player, self._get_spawn_point(player)) + if not self._solo_mode: + bs.timer(0.3, babase.Call(self._print_lives, player)) + + # spaz but *without* the ability to attack or pick stuff up. + actor.connect_controls_to_player(enable_punch=False, + enable_bomb=False, + enable_pickup=False) + + # If we have any icons, update their state. + for icon in player.icons: + icon.handle_player_spawned() + return actor + + def _print_lives(self, player: Player) -> None: + from bascenev1lib.actor import popuptext + + # We get called in a timer so it's possible our player has left/etc. + if not player or not player.is_alive() or not player.node: + return + + popuptext.PopupText('x' + str(player.lives - 1), + color=(1, 1, 0, 1), + offset=(0, -0.8, 0), + random_offset=0.0, + scale=1.8, + position=player.node.position).autoretain() + + def on_player_leave(self, player: Player) -> None: + super().on_player_leave(player) + player.icons = [] + + # Remove us from spawn-order. + if self._solo_mode: + if player in player.team.spawn_order: + player.team.spawn_order.remove(player) + + # Update icons in a moment since our team will be gone from the + # list then. + bs.timer(0, self._update_icons) + + # If the player to leave was the last in spawn order and had + # their final turn currently in-progress, mark the survival time + # for their team. + if self._get_total_team_lives(player.team) == 0: + assert self._start_time is not None + player.team.survival_seconds = int(bs.time() - self._start_time) + + def _get_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: + babase.print_error( + "Got lives < 0 in Elim; this shouldn't happen. solo:" + + str(self._solo_mode)) + 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 self._solo_mode or player.lives == 0: + SpazFactory.get().single_player_death_sound.play() + + # If we hit zero lives, we're dead (and our team might be too). + if player.lives == 0: + # If the whole team is now dead, mark their survival time. + if self._get_total_team_lives(player.team) == 0: + assert self._start_time is not None + player.team.survival_seconds = int(bs.time() - + self._start_time) + else: + # Otherwise, in regular mode, respawn. + if not self._solo_mode: + self.respawn_player(player) + + # In solo, put ourself at the back of the spawn order. + if self._solo_mode: + player.team.spawn_order.remove(player) + player.team.spawn_order.append(player) + elif isinstance(msg,stdbot.SpazBotDiedMessage): + self._on_spaz_bot_died(msg) + + def _on_spaz_bot_died(self,die_msg): + bs.timer(1,babase.Call(self.add_bot,die_msg.spazbot.node.position)) + + def _on_bot_spawn(self,spaz): + spaz.update_callback = self.move_bot + spaz_type = type(spaz) + spaz._charge_speed = self._get_bot_speed(spaz_type) + + def add_bot(self,pos=None): + if pos == 'left': position = (-11,0,random.randrange(-5,5)) + elif pos == 'right': position = (11,0,random.randrange(-5,5)) + else: position = pos + self._bots.spawn_bot(self.get_random_bot(),pos=position,spawn_time=1,on_spawn_call=babase.Call(self._on_bot_spawn)) + + def move_bot(self,bot): + p = bot.node.position + speed = -bot._charge_speed if(p[0]>=-11 and p[0]<0) else bot._charge_speed + + if (p[0]>=-11) and (p[0]<=11): + bot.node.move_left_right = speed + bot.node.move_up_down = 0.0 + bot.node.run = 0.0 + return True + return False + + def get_random_bot(self): + bots = [stdbot.BomberBotStatic, stdbot.TriggerBotStatic] + return (random.choice(bots)) + + def _get_bot_speed(self, bot_type): + if bot_type == stdbot.BomberBotStatic: + return 0.48 + elif bot_type == stdbot.TriggerBotStatic: + return 0.73 + else: + raise Exception('Invalid bot type to _getBotSpeed(): '+str(bot_type)) + + def _update(self) -> None: + if self._solo_mode: + # For both teams, find the first player on the spawn order + # list with lives remaining and spawn them if they're not alive. + for team in self.teams: + # Prune dead players from the spawn order. + team.spawn_order = [p for p in team.spawn_order if p] + for player in team.spawn_order: + assert isinstance(player, Player) + if player.lives > 0: + if not player.is_alive(): + self.spawn_player(player) + self._update_icons() + break + + # If we're down to 1 or fewer living teams, start a timer to end + # the game (allows the dust to settle and draws to occur if deaths + # are close enough). + if len(self._get_living_teams()) < 2: + self._round_end_timer = bs.Timer(0.5, self.end_game) + + def _get_living_teams(self) -> List[Team]: + return [ + team for team in self.teams + if len(team.players) > 0 and any(player.lives > 0 + for player in team.players) + ] + + 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/utilities.json b/plugins/utilities.json index 5404ffd..0b16c15 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -986,6 +986,62 @@ "md5sum": "5fa8706f36d618f8302551dd2a0403a0" } } - } + }, + "disable_friendly_fire": { + "description": "Disables friendly fire", + "external_url": "", + "authors": [ + { + "name": "EmperoR", + "email": "", + "discord": "EmperoR#4098" + } + ], + "versions": { + "1.0.0": null + } + }, + "infinityShield": { + "description": "Gives you unbreakable shield", + "external_url": "https://youtu.be/hp7vbB-hUPg?si=i7Th0NP5xDPLN2P_", + "authors": [ + { + "name": "JoseAng3l", + "email": "", + "discord": "joseang3l" + } + ], + "versions": { + "1.0.0": null + } + }, + "OnlyNight": { + "description": "Night Mode", + "external_url": "", + "authors": [ + { + "name": "", + "email": "", + "discord": "" + } + ], + "versions": { + "1.0.0": null + } + }, + "Tag": { + "description": "Get a tag", + "external_url": "", + "authors": [ + { + "name": "pranav", + "email": "", + "discord": "" + } + ], + "versions": { + "2.0.1": null + } + } } } \ No newline at end of file diff --git a/plugins/utilities/InfinityShield.py b/plugins/utilities/InfinityShield.py new file mode 100644 index 0000000..a224ba3 --- /dev/null +++ b/plugins/utilities/InfinityShield.py @@ -0,0 +1,81 @@ +# Ported to api 8 by brostos using baport.(https://github.com/bombsquad-community/baport) +# 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.spaz import Spaz +from bascenev1lib.actor.spazfactory import SpazFactory + +if TYPE_CHECKING: + pass + + +Spaz._old_init = Spaz.__init__ +def __init__(self, + color: Sequence[float] = (1.0, 1.0, 1.0), + highlight: Sequence[float] = (0.5, 0.5, 0.5), + character: str = 'Spaz', + source_player: bs.Player = None, + start_invincible: bool = True, + can_accept_powerups: bool = True, + powerups_expire: bool = False, + demo_mode: bool = False): + self._old_init(color,highlight,character,source_player,start_invincible, + can_accept_powerups,powerups_expire,demo_mode) + if self.source_player: + self.equip_shields() + def animate_shield(): + if not self.shield: + return + bs.animate_array(self.shield, 'color', 3, { + 0.0: self.shield.color, + 0.2: (random.random(), random.random(), random.random()) + }) + bs.timer(0.2, animate_shield, repeat=True) + self.impact_scale = 0 + +def equip_shields(self, decay: bool = False) -> None: + """ + Give this spaz a nice energy shield. + """ + + if not self.node: + babase.print_error('Can\'t equip shields; no node.') + return + + factory = SpazFactory.get() + if self.shield is None: + self.shield = bs.newnode('shield', + owner=self.node, + attrs={ + 'color': (0.3, 0.2, 2.0), + 'radius': 1.3 + }) + self.node.connectattr('position_center', self.shield, 'position') + self.shield_hitpoints = self.shield_hitpoints_max = 650 + self.shield_decay_rate = factory.shield_decay_rate if decay else 0 + self.shield.hurt = 0 + factory.shield_up_sound.play(1.0, position=self.node.position) + + if self.impact_scale == 0: + return + + if self.shield_decay_rate > 0: + self.shield_decay_timer = bs.Timer(0.5, + bs.WeakCall(self.shield_decay), + repeat=True) + # So user can see the decay. + self.shield.always_show_health_bar = True + + +# ba_meta export plugin +class InfinityShieldPlugin(babase.Plugin): + Spaz.__init__ = __init__ + Spaz.equip_shields = equip_shields diff --git a/plugins/utilities/OnlyNight.py b/plugins/utilities/OnlyNight.py new file mode 100644 index 0000000..b337647 --- /dev/null +++ b/plugins/utilities/OnlyNight.py @@ -0,0 +1,50 @@ +# Ported by brostos to api 8 +# Tool used to make porting easier.(https://github.com/bombsquad-community/baport) +"""Only Night.""" + +# ba_meta require api 8 + +from __future__ import annotations + +from typing import TYPE_CHECKING + +import babase +import bascenev1 as bs +from bascenev1._gameactivity import GameActivity + +if TYPE_CHECKING: + pass + + +# ba_meta export plugin +class OnlyNight(babase.Plugin): + GameActivity.old_on_transition_in = GameActivity.on_transition_in + + def new_on_transition_in(self) -> None: + self.old_on_transition_in() + gnode = bs.getactivity().globalsnode + if self.map.getname() in [ + "Monkey Face", + "Rampage", + "Roundabout", + "Step Right Up", + "Tip Top", + "Zigzag", + "The Pad", + ]: + gnode.tint = (0.4, 0.4, 0.4) + elif self.map.getname() in [ + "Big G", + "Bridgit", + "Courtyard", + "Crag Castle", + "Doom Shroom", + "Football Stadium", + "Happy Thoughts", + "Hockey Stadium", + ]: + gnode.tint = (0.5, 0.5, 0.5) + else: + gnode.tint = (0.3, 0.3, 0.3) + + GameActivity.on_transition_in = new_on_transition_in diff --git a/plugins/utilities/Tag.py b/plugins/utilities/Tag.py new file mode 100644 index 0000000..4ec9a9d --- /dev/null +++ b/plugins/utilities/Tag.py @@ -0,0 +1,565 @@ +# Ported by brostos to api 8 +# Tool used to make porting easier.(https://github.com/bombsquad-community/baport) +""" +I apreciate any kind of modification. So feel free to use or edit code or change credit string.... no problem. + +really awsome servers: + Bombsquad Consultancy Service - https://discord.gg/2RKd9QQdQY + bombspot - https://discord.gg/ucyaesh + cyclones - https://discord.gg/pJXxkbQ7kH + +how to use: + Account -> PlayerProfile -> Edit(new profile -> edit) + Open profile you like (every profile has dirrent tags, settings (Configs)) + enable tag for profile you like, edit tag you want. enable cool flashy animation +""" + +from __future__ import annotations +from bauiv1lib.profile.edit import EditProfileWindow +from bauiv1lib.colorpicker import ColorPicker +from bauiv1lib.popup import PopupMenu +from bascenev1lib.actor.playerspaz import PlayerSpaz +from baenv import TARGET_BALLISTICA_BUILD as build_number +import babase +import bauiv1 as bui +import bascenev1 as bs +import _babase + +from typing import ( + Tuple, + Optional, + Sequence, + Union, + Callable, + Any, + List, + cast +) + +__version__ = 2.0 +__author__ = "pranav1711#2006" + + +# Default Confings/Settings +Configs = { + "enabletag": False, + "tag": "", + "scale": "medium", + "opacity": 1.0, + "shadow": 0.0, + "animtag": False, + "frequency": 0.5 +} + +# Useful global fucntions +def setconfigs() -> None: + """ + Set required defualt configs for mod + """ + cnfg = babase.app.config + profiles = cnfg['Player Profiles'] + if not "TagConf" in cnfg: cnfg["TagConf"] = {} + for p in profiles: + if not p in cnfg["TagConf"]: + cnfg["TagConf"][str(p)] = Configs + babase.app.config.apply_and_commit() + +def getanimcolor(name: str) -> dict: + """ + Returns dictnary of colors with prefective time -> {seconds: (r, g, b)} + """ + freq = babase.app.config['TagConf'][str(name)]['frequency'] + s1 = 0.0 + s2 = s1 + freq + s3 = s2 + freq + + animcolor = { + s1: (1,0,0), + s2: (0,1,0), + s3: (0,0,1) + } + return animcolor + +def gethostname() -> str: + """ + Return player name, by using -1 only host can use tags. + """ + session = bs.get_foreground_host_session() + with session.context: + for player in session.sessionplayers: + if player.inputdevice.client_id == -1: + name = player.getname(full=True, icon=False) + break + if name == bui.app.plus.get_v1_account_name: + return '__account__' + return name + +# Dummy functions for extend functionality for class object +PlayerSpaz.init = PlayerSpaz.__init__ +EditProfileWindow.init = EditProfileWindow.__init__ + +# PlayerSpaz object at -> bascenev1lib.actor.playerspaz +def NewPlayerSzapInit(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', + powerups_expire: bool = True) -> None: + self.init(player, color, highlight, character, powerups_expire) + self.curname = gethostname() + + try: + cnfg = babase.app.config["TagConf"] + if cnfg[str(self.curname)]["enabletag"]: + # Tag node + self.mnode = bs.newnode('math', owner=self.node, attrs={'input1': (0, 1.5, 0),'operation': 'add'}) + self.node.connectattr('torso_position', self.mnode, 'input2') + + tagtext = cnfg[str(self.curname)]["tag"] + opacity = cnfg[str(self.curname)]["opacity"] + shadow = cnfg[str(self.curname)]["shadow"] + sl = cnfg[str(self.curname)]["scale"] + scale = 0.01 if sl == 'mediam' else 0.009 if not sl == 'large' else 0.02 + + self.Tag = bs.newnode( + type='text', + owner=self.node, + attrs={ + 'text': str(tagtext), + 'in_world': True, + 'shadow': shadow, + 'color': (0,0,0), + 'scale': scale, + 'opacity': opacity, + 'flatness': 1.0, + 'h_align': 'center'}) + self.mnode.connectattr('output', self.Tag, 'position') + + if cnfg[str(self.curname)]["animtag"]: + kys = getanimcolor(self.curname) + bs.animate_array(node=self.Tag, attr='color', size=3, keys=kys, loop=True) + except Exception: pass + + +def NewEditProfileWindowInit(self, + existing_profile: Optional[str], + in_main_menu: bool, + transition: str = 'in_right') -> None: + """ + New boilerplate for editprofilewindow, addeds button to call TagSettings window + """ + self.existing_profile = existing_profile + self.in_main_menu = in_main_menu + self.init(existing_profile, in_main_menu, transition) + + v = self._height - 115.0 + x_inset = self._x_inset + b_width = 50 + b_height = 30 + + self.tagwinbtn = bui.buttonwidget( + parent=self._root_widget, + autoselect=True, + position=(505 + x_inset, v - 38 - 15), + size=(b_width, b_height), + color=(0.6, 0.5, 0.6), + label='Tag', + button_type='square', + text_scale=1.2, + on_activate_call=babase.Call(_on_tagwinbtn_press, self)) + +def _on_tagwinbtn_press(self): + """ + Calls tag config window passes all paramisters + """ + bui.containerwidget(edit=self._root_widget, transition='out_scale') + bui.app.ui_v1.set_main_menu_window( + TagWindow(self.existing_profile, + self.in_main_menu, + self._name, + transition='in_right').get_root_widget(), from_window=self._root_widget) + + +# ba_meta require api 8 +# ba_meta export plugin +class Tag(babase.Plugin): + def __init__(self) -> None: + """ + Tag above actor player head, replacing PlayerSpaz class for getting actor, + using EditProfileWindow for UI. + """ + if _babase.env().get("build_number",0) >= 20327: + setconfigs() + self.Replace() + + def Replace(self) -> None: + """ + Replacing bolierplates no harm to relative funtionality only extending + """ + PlayerSpaz.__init__ = NewPlayerSzapInit + EditProfileWindow.__init__ = NewEditProfileWindowInit + + +class TagWindow(bui.Window): + + def __init__(self, + existing_profile: Optional[str], + in_main_menu: bool, + profilename: str, + transition: Optional[str] = 'in_right'): + self.existing_profile = existing_profile + self.in_main_menu = in_main_menu + self.profilename = profilename + + uiscale = bui.app.ui_v1.uiscale + self._width = 870.0 if uiscale is babase.UIScale.SMALL else 670.0 + self._height = (390.0 if uiscale is babase.UIScale.SMALL else + 450.0 if uiscale is babase.UIScale.MEDIUM else 520.0) + extra_x = 100 if uiscale is babase.UIScale.SMALL else 0 + self.extra_x = extra_x + top_extra = 20 if uiscale is babase.UIScale.SMALL else 0 + + super().__init__( + root_widget=bui.containerwidget( + size=(self._width, self._height), + transition=transition, + scale=(2.06 if uiscale is babase.UIScale.SMALL else + 1.4 if uiscale is babase.UIScale.MEDIUM else 1.0))) + + self._back_button = bui.buttonwidget( + parent=self._root_widget, + autoselect=True, + selectable=False, # FIXME: when press a in text field it selets to button + position=(52 + self.extra_x, self._height - 60), + size=(60, 60), + scale=0.8, + label=babase.charstr(babase.SpecialChar.BACK), + button_type='backSmall', + on_activate_call=self._back) + bui.containerwidget(edit=self._root_widget, cancel_button=self._back_button) + + self._save_button = bui.buttonwidget( + parent=self._root_widget, + position=(self._width - (177 + extra_x), + self._height - 60), + size=(155, 60), + color=(0, 0.7, 0.5), + autoselect=True, + selectable=False, # FIXME: when press a in text field it selets to button + scale=0.8, + label=babase.Lstr(resource='saveText'), + on_activate_call=self.on_save) + bui.widget(edit=self._save_button, left_widget=self._back_button) + bui.widget(edit=self._back_button, right_widget=self._save_button) + bui.containerwidget(edit=self._root_widget, start_button=self._save_button) + + self._title_text = bui.textwidget( + parent=self._root_widget, + position=(0, self._height - 52 - top_extra), + size=(self._width, 25), + text='Tag', + color=bui.app.ui_v1.title_color, + scale=1.5, + h_align='center', + v_align='top') + + self._scroll_width = self._width - (100 + 2 * extra_x) + self._scroll_height = self._height - 115.0 + self._sub_width = self._scroll_width * 0.95 + self._sub_height = 724.0 + self._spacing = 32 + self._extra_button_spacing = self._spacing * 2.5 + + self._scrollwidget = bui.scrollwidget( + parent=self._root_widget, + position=(50 + extra_x, 50), + simple_culling_v=20.0, + highlight=False, + size=(self._scroll_width, + self._scroll_height), + selection_loops_to_parent=True) + bui.widget(edit=self._scrollwidget, right_widget=self._scrollwidget) + + self._subcontainer = bui.containerwidget( + parent=self._scrollwidget, + size=(self._sub_width, + self._sub_height), + background=False, + selection_loops_to_parent=True) + + v = self._sub_height - 35 + v -= self._spacing * 1.2 + + self._prof = babase.app.config["TagConf"][self.profilename] + self.enabletagcb = bui.checkboxwidget( + parent=self._subcontainer, + autoselect=False, + position=(10.0, v + 30), + size=(10, 10), + text='Enable Tag', + textcolor=(0.8, 0.8, 0.8), + value=self._prof['enabletag'], + on_value_change_call=babase.Call(self.change_val, [f'{self.profilename}', 'enabletag']), + scale=1.1 if uiscale is babase.UIScale.SMALL else 1.5, + maxwidth=430) + + self.tag_text = bui.textwidget( + parent=self._subcontainer, + text='Tag', + position=(25.0, v - 30), + flatness=1.0, + scale=1.55, + maxwidth=430, + h_align='center', + v_align='center', + color=(0.8, 0.8, 0.8)) + + self.tagtextfield = bui.textwidget( + parent=self._subcontainer, + position=(100.0, v - 45), + size=(350, 50), + text=self._prof["tag"], + h_align='center', + v_align='center', + max_chars=16, + autoselect=True, + editable=True, + padding=4, + color=(0.9, 0.9, 0.9, 1.0)) + + self.tag_color_text = bui.textwidget( + parent=self._subcontainer, + text='Color', + position=(40.0, v - 80), + flatness=1.0, + scale=1.25, + maxwidth=430, + h_align='center', + v_align='center', + color=(0.8, 0.8, 0.8)) + + self.tag_scale_text = bui.textwidget( + parent=self._subcontainer, + text='Scale', + position=(40.0, v - 130), + flatness=1.0, + scale=1.25, + maxwidth=430, + h_align='center', + v_align='center', + color=(0.8, 0.8, 0.8)) + + self.tag_scale_button = PopupMenu( + parent=self._subcontainer, + position=(330.0, v - 145), + width=150, + autoselect=True, + on_value_change_call=bs.WeakCall(self._on_menu_choice), + choices=['large', 'medium', 'small'], + button_size=(150, 50), + #choices_display=('large', 'medium', 'small'), + current_choice=self._prof["scale"]) + + CustomConfigNumberEdit( + parent=self._subcontainer, + position=(40.0, v - 180), + xoffset=65, + displayname='Opacity', + configkey=['TagConf', f'{self.profilename}', 'opacity'], + changesound=False, + minval=0.5, + maxval=2.0, + increment=0.1, + textscale=1.25) + + CustomConfigNumberEdit( + parent=self._subcontainer, + position=(40.0, v - 230), + xoffset=65, + displayname='Shadow', + configkey=['TagConf', f'{self.profilename}', 'shadow'], + changesound=False, + minval=0.0, + maxval=2.0, + increment=0.1, + textscale=1.25) + + self.enabletaganim = bui.checkboxwidget( + parent=self._subcontainer, + autoselect=True, + position=(10.0, v - 280), + size=(10, 10), + text='Animate tag', + textcolor=(0.8, 0.8, 0.8), + value=self._prof['enabletag'], + on_value_change_call=babase.Call(self.change_val, [f'{self.profilename}', 'animtag']), + scale=1.1 if uiscale is babase.UIScale.SMALL else 1.5, + maxwidth=430) + + CustomConfigNumberEdit( + parent=self._subcontainer, + position=(40.0, v - 330), + xoffset=65, + displayname='Frequency', + configkey=['TagConf', f'{self.profilename}', 'frequency'], + changesound=False, + minval=0.1, + maxval=5.0, + increment=0.1, + textscale=1.25) + + def _back(self) -> None: + """ + transit window into back window + """ + bui.containerwidget(edit=self._root_widget, + transition='out_scale') + bui.app.ui_v1.set_main_menu_window(EditProfileWindow( + self.existing_profile, + self.in_main_menu, + transition='in_left').get_root_widget(), from_window=self._root_widget) + + def change_val(self, config: List[str], val: bool) -> None: + """ + chamges the value of check boxes + """ + cnfg = babase.app.config["TagConf"] + try: + cnfg[config[0]][config[1]] = val + bui.getsound('gunCocking').play() + except Exception: + bui.screenmessage("error", color=(1,0,0)) + bui.getsound('error').play() + babase.app.config.apply_and_commit() + + def _on_menu_choice(self, choice: str): + """ + Changes the given choice in configs + """ + cnfg = babase.app.config["TagConf"][self.profilename] + cnfg["scale"] = choice + babase.app.config.apply_and_commit() + + def on_save(self): + """ + Gets the text in text field of tag and then save it + """ + text: str = cast(str, bui.textwidget(query=self.tagtextfield)) + profile = babase.app.config["TagConf"][self.profilename] + if not text == "" or not text.strip(): + profile['tag'] = text + babase.app.config.apply_and_commit() + bui.getsound('gunCocking').play() + else: + bui.screenmessage(f"please define tag", color=(1,0,0)) + bui.getsound('error').play() + + bui.containerwidget(edit=self._root_widget, + transition='out_scale') + bui.app.ui_v1.set_main_menu_window(EditProfileWindow( + self.existing_profile, + self.in_main_menu, + transition='in_left').get_root_widget(), from_window=self._root_widget) + + +class CustomConfigNumberEdit: + """A set of controls for editing a numeric config value. + + It will automatically save and apply the config when its + value changes. + + Attributes: + + nametext + The text widget displaying the name. + + valuetext + The text widget displaying the current value. + + minusbutton + The button widget used to reduce the value. + + plusbutton + The button widget used to increase the value. + """ + + def __init__(self, + parent: bui.Widget, + configkey: List[str], + position: Tuple[float, float], + minval: float = 0.0, + maxval: float = 100.0, + increment: float = 1.0, + callback: Callable[[float], Any] = None, + xoffset: float = 0.0, + displayname: Union[str, babase.Lstr] = None, + changesound: bool = True, + textscale: float = 1.0): + self._minval = minval + self._maxval = maxval + self._increment = increment + self._callback = callback + self._configkey = configkey + self._value = babase.app.config[configkey[0]][configkey[1]][configkey[2]] + + self.nametext = bui.textwidget( + parent=parent, + position=position, + size=(100, 30), + text=displayname, + maxwidth=160 + xoffset, + color=(0.8, 0.8, 0.8, 1.0), + h_align='left', + v_align='center', + scale=textscale) + + self.valuetext = bui.textwidget( + parent=parent, + position=(246 + xoffset, position[1]), + size=(60, 28), + editable=False, + color=(0.3, 1.0, 0.3, 1.0), + h_align='right', + v_align='center', + text=str(self._value), + padding=2) + + self.minusbutton = bui.buttonwidget( + parent=parent, + position=(330 + xoffset, position[1]), + size=(28, 28), + label='-', + autoselect=True, + on_activate_call=babase.Call(self._down), + repeat=True, + enable_sound=changesound) + + self.plusbutton = bui.buttonwidget(parent=parent, + position=(380 + xoffset, position[1]), + size=(28, 28), + label='+', + autoselect=True, + on_activate_call=babase.Call(self._up), + repeat=True, + enable_sound=changesound) + + bui.uicleanupcheck(self, self.nametext) + self._update_display() + + def _up(self) -> None: + self._value = min(self._maxval, self._value + self._increment) + self._changed() + + def _down(self) -> None: + self._value = max(self._minval, self._value - self._increment) + self._changed() + + def _changed(self) -> None: + self._update_display() + if self._callback: + self._callback(self._value) + babase.app.config[self._configkey[0]][self._configkey[1]][self._configkey[2]] = float(str(f'{self._value:.1f}')) + babase.app.config.apply_and_commit() + + def _update_display(self) -> None: + bui.textwidget(edit=self.valuetext, text=f'{self._value:.1f}') \ No newline at end of file diff --git a/plugins/utilities/disable_friendly_fire.py b/plugins/utilities/disable_friendly_fire.py new file mode 100644 index 0000000..0771cfe --- /dev/null +++ b/plugins/utilities/disable_friendly_fire.py @@ -0,0 +1,108 @@ +# Ported to api 8 by brostos using baport.(https://github.com/bombsquad-community/baport) +# 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 bascenev1lib +from bascenev1lib.gameutils import SharedObjects + +if TYPE_CHECKING: + pass + +class BombPickupMessage: + """ message says that someone pick up the dropped bomb """ + +# for bs.FreezeMessage +freeze: bool = True + +# ba_meta export plugin +class Plugin(babase.Plugin): + + # there are two ways to ignore our team player hits + # either change playerspaz handlemessage or change spaz handlemessage + def playerspaz_new_handlemessage(func: fuction) -> fuction: + def wrapper(*args, **kwargs): + global freeze + + # only run if session is dual team + if isinstance(args[0].activity.session, bs.DualTeamSession): + # when spaz got hurt by any reason this statement is runs. + if isinstance(args[1], bs.HitMessage): + our_team_players: list[type(args[0]._player)] + + # source_player + attacker = args[1].get_source_player(type(args[0]._player)) + + # our team payers + our_team_players = args[0]._player.team.players.copy() + + if len(our_team_players) > 0: + + # removing our self + our_team_players.remove(args[0]._player) + + # if we honding teammate or if we have a shield, do hit. + for player in our_team_players: + if player.actor.exists() and args[0]._player.actor.exists(): + if args[0]._player.actor.node.hold_node == player.actor.node or args[0]._player.actor.shield: + our_team_players.remove(player) + break + + if attacker in our_team_players: + freeze = False + return None + else: + freeze = True + + # if ice_bomb blast hits any spaz this statement runs. + elif isinstance(args[1], bs.FreezeMessage): + if not freeze: + freeze = True # use it and reset it + return None + + # orignal unchanged code goes here + func(*args, **kwargs) + + return wrapper + + # replace original fuction to modified function + bascenev1lib.actor.playerspaz.PlayerSpaz.handlemessage = playerspaz_new_handlemessage( + bascenev1lib.actor.playerspaz.PlayerSpaz.handlemessage) + + # let's add a message when bomb is pick by player + def bombfact_new_init(func: function) -> function: + def wrapper(*args): + + func(*args) # original code + + args[0].bomb_material.add_actions( + conditions=('they_have_material', SharedObjects.get().pickup_material), + actions=('message', 'our_node', 'at_connect', BombPickupMessage()), + ) + return wrapper + + # you get the idea + bascenev1lib.actor.bomb.BombFactory.__init__ = bombfact_new_init( + bascenev1lib.actor.bomb.BombFactory.__init__) + + def bomb_new_handlemessage(func: function) -> function: + def wrapper(*args, **kwargs): + # only run if session is dual team + if isinstance(args[0].activity.session, bs.DualTeamSession): + if isinstance(args[1], BombPickupMessage): + # get the pickuper and assign the pickuper to the source_player(attacker) of bomb blast + for player in args[0].activity.players: + if player.actor.exists(): + if player.actor.node.hold_node == args[0].node: + args[0]._source_player = player + break + + func(*args, **kwargs) # original + + return wrapper + + bascenev1lib.actor.bomb.Bomb.handlemessage = bomb_new_handlemessage( + bascenev1lib.actor.bomb.Bomb.handlemessage) \ No newline at end of file From 36673fc3683f0a1f87232862e518592128bc0730 Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Wed, 24 Jan 2024 11:26:19 +0000 Subject: [PATCH 02/36] [ci] auto-format --- plugins/minigames/EggGame.py | 128 +-- plugins/minigames/HYPER_RACE.py | 85 +- plugins/minigames/SnowBallFight.py | 1072 ++++++++++---------- plugins/minigames/ofuuuAttack.py | 298 +++--- plugins/minigames/safe_zone.py | 157 +-- plugins/utilities/InfinityShield.py | 8 +- plugins/utilities/Tag.py | 502 ++++----- plugins/utilities/disable_friendly_fire.py | 78 +- 8 files changed, 1204 insertions(+), 1124 deletions(-) diff --git a/plugins/minigames/EggGame.py b/plugins/minigames/EggGame.py index e2d2030..4c0ffc1 100644 --- a/plugins/minigames/EggGame.py +++ b/plugins/minigames/EggGame.py @@ -4,8 +4,8 @@ """Egg game and support classes.""" # The Egg Game - throw egg as far as you can -# created in BCS (Bombsquad Consultancy Service) - opensource bombsquad mods for all -# discord.gg/ucyaesh join now and give your contribution +# created in BCS (Bombsquad Consultancy Service) - opensource bombsquad mods for all +# discord.gg/ucyaesh join now and give your contribution # The Egg game by mr.smoothy # ba_meta require api 8 # (see https://ballistica.net/wiki/meta-tag-system) @@ -45,14 +45,14 @@ class Puck(bs.Actor): # Spawn just above the provided point. self._spawn_pos = (position[0], position[1] + 1.0, position[2]) - self.last_players_to_touch =None + self.last_players_to_touch = None self.scored = False self.egg_mesh = bs.getmesh('egg') self.egg_tex_1 = bs.gettexture('eggTex1') self.egg_tex_2 = bs.gettexture('eggTex2') self.egg_tex_3 = bs.gettexture('eggTex3') - self.eggtx=[self.egg_tex_1,self.egg_tex_2,self.egg_tex_3] - regg=random.randrange(0,3) + self.eggtx = [self.egg_tex_1, self.egg_tex_2, self.egg_tex_3] + regg = random.randrange(0, 3) assert activity is not None assert isinstance(activity, EggGame) pmats = [shared.object_material, activity.puck_material] @@ -65,7 +65,7 @@ class Puck(bs.Actor): 'reflection': 'soft', 'reflection_scale': [0.2], 'shadow_size': 0.5, - 'body_scale':0.7, + 'body_scale': 0.7, 'is_area_of_interest': True, 'position': self._spawn_pos, 'materials': pmats @@ -180,14 +180,14 @@ class EggGame(bs.TeamGameActivity[Player, Team]): self.puck_scored_tex = bs.gettexture('landMineLit') self._puck_sound = bui.getsound('metalHit') self.puck_material = bs.Material() - self._fake_wall_material=bs.Material() - self.HIGHEST=0 + self._fake_wall_material = bs.Material() + self.HIGHEST = 0 self._fake_wall_material.add_actions( conditions=('they_have_material', shared.player_material), actions=( ('modify_part_collision', 'collide', True), ('modify_part_collision', 'physical', True) - + )) self.puck_material.add_actions(actions=(('modify_part_collision', 'friction', 0.5))) @@ -232,8 +232,8 @@ class EggGame(bs.TeamGameActivity[Player, Team]): actions=(('modify_part_collision', 'collide', True), ('modify_part_collision', 'physical', False), ('call', 'at_connect', self._handle_score))) - self.main_ground_material= bs.Material() - + self.main_ground_material = bs.Material() + self.main_ground_material.add_actions( conditions=('they_have_material', self.puck_material), actions=(('modify_part_collision', 'collide', @@ -243,7 +243,7 @@ class EggGame(bs.TeamGameActivity[Player, Team]): self._puck_spawn_pos: Optional[Sequence[float]] = None self._score_regions: Optional[List[bs.NodeActor]] = None self._puck: Optional[Puck] = None - self._pucks=[] + self._pucks = [] self._score_to_win = int(settings['Score to Win']) self._time_limit = float(settings['Time Limit']) @@ -255,8 +255,8 @@ class EggGame(bs.TeamGameActivity[Player, Team]): def on_begin(self) -> None: super().on_begin() - if self._time_limit==0.0: - self._time_limit=60 + if self._time_limit == 0.0: + self._time_limit = 60 self.setup_standard_time_limit(self._time_limit) # self.setup_standard_powerup_drops() self._puck_spawn_pos = self.map.get_flag_position(None) @@ -269,10 +269,10 @@ class EggGame(bs.TeamGameActivity[Player, Team]): # Set up the two score regions. defs = self.map.defs self._score_regions = [] - pos=(11.88630542755127, 0.3009839951992035, 1.33331298828125) + pos = (11.88630542755127, 0.3009839951992035, 1.33331298828125) # mat=bs.Material() # mat.add_actions( - + # actions=( ('modify_part_collision','physical',True), # ('modify_part_collision','collide',True)) # ) @@ -299,13 +299,14 @@ class EggGame(bs.TeamGameActivity[Player, Team]): bs.NodeActor( bs.newnode('region', attrs={ - 'position': (-9.21,defs.boxes['goal2'][0:3][1],defs.boxes['goal2'][0:3][2]), + 'position': (-9.21, defs.boxes['goal2'][0:3][1], defs.boxes['goal2'][0:3][2]), 'scale': defs.boxes['goal2'][6:9], 'type': 'box', 'materials': (self._fake_wall_material, ) }))) - pos=(0,0.1,-5) - self.main_ground=bs.newnode('region',attrs={'position': pos,'scale': (25,0.001,22),'type': 'box','materials': [self.main_ground_material]}) + pos = (0, 0.1, -5) + self.main_ground = bs.newnode('region', attrs={'position': pos, 'scale': ( + 25, 0.001, 22), 'type': 'box', 'materials': [self.main_ground_material]}) self._update_scoreboard() self._chant_sound.play() @@ -326,63 +327,63 @@ class EggGame(bs.TeamGameActivity[Player, Team]): def _kill_puck(self) -> None: self._puck = None + def _handle_egg_collision(self) -> None: - no=bs.getcollision().opposingnode - pos=no.position - egg=no.getdelegate(Puck) - source_player=egg.last_players_to_touch - if source_player==None or pos[0]< -8 or not source_player.node.exists() : + no = bs.getcollision().opposingnode + pos = no.position + egg = no.getdelegate(Puck) + source_player = egg.last_players_to_touch + if source_player == None or pos[0] < -8 or not source_player.node.exists(): return - try: - col=source_player.team.color - self.flagg=Flag(pos,touchable=False,color=col).autoretain() - self.flagg.is_area_of_interest=True - player_pos=source_player.node.position - - distance = math.sqrt( pow(player_pos[0]-pos[0],2) + pow(player_pos[2]-pos[2],2)) - - - dis_mark=bs.newnode('text', - - attrs={ - 'text':str(round(distance,2))+"m", - 'in_world':True, - 'scale':0.02, - 'h_align':'center', - 'position':(pos[0],1.6,pos[2]), - 'color':col - }) - bs.animate(dis_mark,'scale',{ - 0.0:0, 0.5:0.01 + col = source_player.team.color + self.flagg = Flag(pos, touchable=False, color=col).autoretain() + self.flagg.is_area_of_interest = True + player_pos = source_player.node.position + + distance = math.sqrt(pow(player_pos[0]-pos[0], 2) + pow(player_pos[2]-pos[2], 2)) + + dis_mark = bs.newnode('text', + + attrs={ + 'text': str(round(distance, 2))+"m", + 'in_world': True, + 'scale': 0.02, + 'h_align': 'center', + 'position': (pos[0], 1.6, pos[2]), + 'color': col + }) + bs.animate(dis_mark, 'scale', { + 0.0: 0, 0.5: 0.01 }) if distance > self.HIGHEST: - self.HIGHEST=distance + self.HIGHEST = distance self.stats.player_scored( - source_player, - 10, - big_message=False) - + source_player, + 10, + big_message=False) + no.delete() - bs.timer(2,self._spawn_puck) - source_player.team.score=int(distance) - - except(): + bs.timer(2, self._spawn_puck) + source_player.team.score = int(distance) + + except (): pass + def spawn_player(self, player: Player) -> bs.Actor: - - - zoo=random.randrange(-4,5) - pos=(-11.204887390136719, 0.2998693287372589, zoo) + + zoo = random.randrange(-4, 5) + pos = (-11.204887390136719, 0.2998693287372589, zoo) spaz = self.spawn_player_spaz( - player, position=pos, angle=90 ) + player, position=pos, angle=90) assert spaz.node # Prevent controlling of characters before the start of the race. - + return spaz + def _handle_score(self) -> None: """A point has been scored.""" @@ -481,11 +482,12 @@ class EggGame(bs.TeamGameActivity[Player, Team]): # bs.animate(light, 'intensity', {0.0: 0, 0.25: 1, 0.5: 0}, loop=True) # bs.timer(1.0, light.delete) pass + def _spawn_puck(self) -> None: # self._swipsound.play() # self._whistle_sound.play() self._flash_puck_spawn() assert self._puck_spawn_pos is not None - zoo=random.randrange(-5,6) - pos=(-11.204887390136719, 0.2998693287372589, zoo) - self._pucks.append (Puck(position=pos)) + zoo = random.randrange(-5, 6) + pos = (-11.204887390136719, 0.2998693287372589, zoo) + self._pucks.append(Puck(position=pos)) diff --git a/plugins/minigames/HYPER_RACE.py b/plugins/minigames/HYPER_RACE.py index e09478c..c5f5aaa 100644 --- a/plugins/minigames/HYPER_RACE.py +++ b/plugins/minigames/HYPER_RACE.py @@ -425,12 +425,12 @@ class NewBomb(Bomb): self._exploded = True if self.node: blast = NewBlast(position=self.node.position, - velocity=self.node.velocity, - blast_radius=self.blast_radius, - blast_type=self.bomb_type, - source_player=babase.existing(self._source_player), - hit_type=self.hit_type, - hit_subtype=self.hit_subtype).autoretain() + velocity=self.node.velocity, + blast_radius=self.blast_radius, + blast_type=self.bomb_type, + source_player=babase.existing(self._source_player), + hit_type=self.hit_type, + hit_subtype=self.hit_subtype).autoretain() for callback in self._explode_callbacks: callback(self, blast) @@ -458,7 +458,7 @@ class TNT(bs.Actor): self._collide_material.add_actions( actions=('modify_part_collision', 'collide', True), ) - + if teleport: collide = self._collide_material else: @@ -649,7 +649,7 @@ class RaceGame(bs.TeamGameActivity[Player, Team]): ('modify_part_collision', 'physical', False), ('call', 'at_connect', self._handle_race_point_collide), - )) + )) for rpt in pts: self._regions.append(RaceRegion(rpt, len(self._regions))) @@ -685,18 +685,18 @@ class RaceGame(bs.TeamGameActivity[Player, Team]): collision = bs.getcollision() try: region = collision.sourcenode.getdelegate(RaceRegion, True) - spaz = collision.opposingnode.getdelegate(PlayerSpaz,True) + spaz = collision.opposingnode.getdelegate(PlayerSpaz, True) except bs.NotFoundError: return - + if not spaz.is_alive(): return - + try: player = spaz.getplayer(Player, True) except bs.NotFoundError: return - + last_region = player.last_region this_region = region.index @@ -713,7 +713,7 @@ class RaceGame(bs.TeamGameActivity[Player, Team]): translate=('statements', 'Killing ${NAME} for' ' skipping part of the track!'), subs=[('${NAME}', player.getname(full=True))]), - color=(1, 0, 0)) + color=(1, 0, 0)) else: # If this player is in first, note that this is the # front-most race-point. @@ -788,10 +788,10 @@ class RaceGame(bs.TeamGameActivity[Player, Team]): player.actor.node.connectattr( 'torso_position', mathnode, 'input2') tstr = babase.Lstr(resource='lapNumberText', - subs=[('${CURRENT}', - str(player.lap + 1)), - ('${TOTAL}', str(self._laps)) - ]) + subs=[('${CURRENT}', + str(player.lap + 1)), + ('${TOTAL}', str(self._laps)) + ]) txtnode = bs.newnode('text', owner=mathnode, attrs={ @@ -828,7 +828,7 @@ class RaceGame(bs.TeamGameActivity[Player, Team]): '${TEAM} is disqualified because ${PLAYER} left'), subs=[('${TEAM}', player.team.name), ('${PLAYER}', player.getname(full=True))]), - color=(1, 1, 0)) + color=(1, 1, 0)) player.team.finished = True player.team.time = None player.team.lap = 0 @@ -967,55 +967,54 @@ class RaceGame(bs.TeamGameActivity[Player, Team]): self._tnt((-6, 5, 1), (0, 0, 0), 1.3) bs.timer(0.1, bs.WeakCall(self._tnt, (-3.2, 5, 1), - (0, 0, 0), 1.0, (0, 20, 60)), repeat=True) + (0, 0, 0), 1.0, (0, 20, 60)), repeat=True) bs.timer(1.6, bs.WeakCall(self._bomb, 'impact', - (6, 7, 1), (0, 0, 0), 1.0, 1.0), repeat=True) + (6, 7, 1), (0, 0, 0), 1.0, 1.0), repeat=True) bs.timer(1.6, bs.WeakCall(self._bomb, 'impact', - (6.8, 7, 1), (0, 0, 0), 1.0, 1.0), repeat=True) + (6.8, 7, 1), (0, 0, 0), 1.0, 1.0), repeat=True) bs.timer(1.6, bs.WeakCall(self._bomb, 'impact', - (7.6, 7, 1), (0, 0, 0), 1.0, 1.0), repeat=True) + (7.6, 7, 1), (0, 0, 0), 1.0, 1.0), repeat=True) bs.timer(1.6, bs.WeakCall(self._bomb, 'impact', - (6, 7, -2.2), (0, 0, 0), 1.0, 1.0), repeat=True) + (6, 7, -2.2), (0, 0, 0), 1.0, 1.0), repeat=True) bs.timer(1.6, bs.WeakCall(self._bomb, 'impact', - (6.8, 7, -2.2), (0, 0, 0), 1.0, 1.0), repeat=True) + (6.8, 7, -2.2), (0, 0, 0), 1.0, 1.0), repeat=True) bs.timer(1.6, bs.WeakCall(self._bomb, 'impact', - (7.6, 7, -2.2), (0, 0, 0), 1.0, 1.0), repeat=True) + (7.6, 7, -2.2), (0, 0, 0), 1.0, 1.0), repeat=True) bs.timer(1.6, bs.WeakCall(self._bomb, 'impact', - (6, 7, -5.2), (0, 0, 0), 1.0, 1.0), repeat=True) + (6, 7, -5.2), (0, 0, 0), 1.0, 1.0), repeat=True) bs.timer(1.6, bs.WeakCall(self._bomb, 'impact', - (6.8, 7, -5.2), (0, 0, 0), 1.0, 1.0), repeat=True) + (6.8, 7, -5.2), (0, 0, 0), 1.0, 1.0), repeat=True) bs.timer(1.6, bs.WeakCall(self._bomb, 'impact', - (7.6, 7, -5.2), (0, 0, 0), 1.0, 1.0), repeat=True) + (7.6, 7, -5.2), (0, 0, 0), 1.0, 1.0), repeat=True) bs.timer(1.6, bs.WeakCall(self._bomb, 'impact', - (6, 7, -8), (0, 0, 0), 1.0, 1.0), repeat=True) + (6, 7, -8), (0, 0, 0), 1.0, 1.0), repeat=True) bs.timer(1.6, bs.WeakCall(self._bomb, 'impact', - (6.8, 7, -8), (0, 0, 0), 1.0, 1.0), repeat=True) + (6.8, 7, -8), (0, 0, 0), 1.0, 1.0), repeat=True) bs.timer(1.6, bs.WeakCall(self._bomb, 'impact', - (7.6, 7, -8), (0, 0, 0), 1.0, 1.0), repeat=True) + (7.6, 7, -8), (0, 0, 0), 1.0, 1.0), repeat=True) bs.timer(1.6, bs.WeakCall(self._bomb, 'impact', - (-5, 5, 0), (0, 0, 0), 1.0, 1.0, (0, 20, 3)), repeat=True) + (-5, 5, 0), (0, 0, 0), 1.0, 1.0, (0, 20, 3)), repeat=True) bs.timer(1.6, bs.WeakCall(self._bomb, 'impact', - (-1.5, 5, 0), (0, 0, 0), 1.0, 1.0, (0, 20, 3)), repeat=True) - + (-1.5, 5, 0), (0, 0, 0), 1.0, 1.0, (0, 20, 3)), repeat=True) bs.timer(1.6, bs.WeakCall(self._bomb, 'sticky', - (-1, 5, -8), (0, 10, 0), 1.0, 1.0), repeat=True) + (-1, 5, -8), (0, 10, 0), 1.0, 1.0), repeat=True) bs.timer(1.6, bs.WeakCall(self._bomb, 'sticky', - (-1, 5, -9), (0, 10, 0), 1.0, 1.0), repeat=True) + (-1, 5, -9), (0, 10, 0), 1.0, 1.0), repeat=True) bs.timer(1.6, bs.WeakCall(self._bomb, 'sticky', - (-1, 5, -10), (0, 10, 0), 1.0, 1.0), repeat=True) + (-1, 5, -10), (0, 10, 0), 1.0, 1.0), repeat=True) bs.timer(1.6, bs.WeakCall(self._bomb, 'sticky', - (-4.6, 5, -8), (0, 10, 0), 1.0, 1.0), repeat=True) + (-4.6, 5, -8), (0, 10, 0), 1.0, 1.0), repeat=True) bs.timer(1.6, bs.WeakCall(self._bomb, 'sticky', - (-4.6, 5, -9), (0, 10, 0), 1.0, 1.0), repeat=True) + (-4.6, 5, -9), (0, 10, 0), 1.0, 1.0), repeat=True) bs.timer(1.6, bs.WeakCall(self._bomb, 'sticky', - (-4.6, 5, -10), (0, 10, 0), 1.0, 1.0), repeat=True) + (-4.6, 5, -10), (0, 10, 0), 1.0, 1.0), repeat=True) bs.timer(1.6, bs.WeakCall( self._powerup, (2, 5, -5), 'curse', (0, 20, -3)), repeat=True) @@ -1029,7 +1028,7 @@ class RaceGame(bs.TeamGameActivity[Player, Team]): extra_acceleration: float = None) -> None: if extra_acceleration: TNT(position, velocity, tnt_scale, False).autoretain( - ).node.extra_acceleration = extra_acceleration + ).node.extra_acceleration = extra_acceleration else: TNT(position, velocity, tnt_scale).autoretain() @@ -1044,7 +1043,7 @@ class RaceGame(bs.TeamGameActivity[Player, Team]): NewBomb(position=position, velocity=velocity, bomb_type=type).autoretain( - ).node.extra_acceleration = extra_acceleration + ).node.extra_acceleration = extra_acceleration else: NewBomb(position=position, velocity=velocity, @@ -1057,7 +1056,7 @@ class RaceGame(bs.TeamGameActivity[Player, Team]): if extra_acceleration: PowerupBox(position=position, poweruptype=poweruptype).autoretain( - ).node.extra_acceleration = extra_acceleration + ).node.extra_acceleration = extra_acceleration else: PowerupBox(position=position, poweruptype=poweruptype).autoretain() diff --git a/plugins/minigames/SnowBallFight.py b/plugins/minigames/SnowBallFight.py index 29afe38..0bffe2d 100644 --- a/plugins/minigames/SnowBallFight.py +++ b/plugins/minigames/SnowBallFight.py @@ -18,626 +18,626 @@ from bascenev1lib.actor.scoreboard import Scoreboard from bascenev1lib.actor.spazfactory import SpazFactory if TYPE_CHECKING: - from typing import Any, Sequence + from typing import Any, Sequence lang = bs.app.lang.language if lang == 'Spanish': - name = 'Guerra de Nieve' - snowball_rate = 'Intervalo de Ataque' - snowball_slowest = 'Más Lento' - snowball_slow = 'Lento' - snowball_fast = 'Rápido' - snowball_lagcity = 'Más Rápido' - snowball_scale = 'Tamaño de Bola de Nieve' - snowball_smallest = 'Más Pequeño' - snowball_small = 'Pequeño' - snowball_big = 'Grande' - snowball_biggest = 'Más Grande' - snowball_insane = 'Insano' - snowball_melt = 'Derretir Bola de Nieve' - snowball_bust = 'Rebotar Bola de Nieve' - snowball_explode = 'Explotar al Impactar' - snowball_snow = 'Modo Nieve' + name = 'Guerra de Nieve' + snowball_rate = 'Intervalo de Ataque' + snowball_slowest = 'Más Lento' + snowball_slow = 'Lento' + snowball_fast = 'Rápido' + snowball_lagcity = 'Más Rápido' + snowball_scale = 'Tamaño de Bola de Nieve' + snowball_smallest = 'Más Pequeño' + snowball_small = 'Pequeño' + snowball_big = 'Grande' + snowball_biggest = 'Más Grande' + snowball_insane = 'Insano' + snowball_melt = 'Derretir Bola de Nieve' + snowball_bust = 'Rebotar Bola de Nieve' + snowball_explode = 'Explotar al Impactar' + snowball_snow = 'Modo Nieve' else: - name = 'Snowball Fight' - snowball_rate = 'Snowball Rate' - snowball_slowest = 'Slowest' - snowball_slow = 'Slow' - snowball_fast = 'Fast' - snowball_lagcity = 'Lag City' - snowball_scale = 'Snowball Scale' - snowball_smallest = 'Smallest' - snowball_small = 'Small' - snowball_big = 'Big' - snowball_biggest = 'Biggest' - snowball_insane = 'Insane' - snowball_melt = 'Snowballs Melt' - snowball_bust = 'Snowballs Bust' - snowball_explode = 'Snowballs Explode' - snowball_snow = 'Snow Mode' + name = 'Snowball Fight' + snowball_rate = 'Snowball Rate' + snowball_slowest = 'Slowest' + snowball_slow = 'Slow' + snowball_fast = 'Fast' + snowball_lagcity = 'Lag City' + snowball_scale = 'Snowball Scale' + snowball_smallest = 'Smallest' + snowball_small = 'Small' + snowball_big = 'Big' + snowball_biggest = 'Biggest' + snowball_insane = 'Insane' + snowball_melt = 'Snowballs Melt' + snowball_bust = 'Snowballs Bust' + snowball_explode = 'Snowballs Explode' + snowball_snow = 'Snow Mode' class Snowball(bs.Actor): - def __init__(self, - position: Sequence[float] = (0.0, 1.0, 0.0), - velocity: Sequence[float] = (0.0, 0.0, 0.0), - blast_radius: float = 0.7, - bomb_scale: float = 0.8, - source_player: bs.Player | None = None, - owner: bs.Node | None = None, - melt: bool = True, - bounce: bool = True, - explode: bool = False): - super().__init__() - shared = SharedObjects.get() - self._exploded = False - self.scale = bomb_scale - self.blast_radius = blast_radius - self._source_player = source_player - self.owner = owner - self._hit_nodes = set() - self.snowball_melt = melt - self.snowball_bounce = bounce - self.snowball_explode = explode - self.radius = bomb_scale * 0.1 - if bomb_scale <= 1.0: - shadow_size = 0.6 - elif bomb_scale <= 2.0: - shadow_size = 0.4 - elif bomb_scale <= 3.0: - shadow_size = 0.2 - else: - shadow_size = 0.1 + def __init__(self, + position: Sequence[float] = (0.0, 1.0, 0.0), + velocity: Sequence[float] = (0.0, 0.0, 0.0), + blast_radius: float = 0.7, + bomb_scale: float = 0.8, + source_player: bs.Player | None = None, + owner: bs.Node | None = None, + melt: bool = True, + bounce: bool = True, + explode: bool = False): + super().__init__() + shared = SharedObjects.get() + self._exploded = False + self.scale = bomb_scale + self.blast_radius = blast_radius + self._source_player = source_player + self.owner = owner + self._hit_nodes = set() + self.snowball_melt = melt + self.snowball_bounce = bounce + self.snowball_explode = explode + self.radius = bomb_scale * 0.1 + if bomb_scale <= 1.0: + shadow_size = 0.6 + elif bomb_scale <= 2.0: + shadow_size = 0.4 + elif bomb_scale <= 3.0: + shadow_size = 0.2 + else: + shadow_size = 0.1 - self.snowball_material = bs.Material() - self.snowball_material.add_actions( - conditions=( - ( - ('we_are_younger_than', 5), - 'or', - ('they_are_younger_than', 100), - ), - 'and', - ('they_have_material', shared.object_material), - ), - actions=('modify_node_collision', 'collide', False), - ) + self.snowball_material = bs.Material() + self.snowball_material.add_actions( + conditions=( + ( + ('we_are_younger_than', 5), + 'or', + ('they_are_younger_than', 100), + ), + 'and', + ('they_have_material', shared.object_material), + ), + actions=('modify_node_collision', 'collide', False), + ) - self.snowball_material.add_actions( - conditions=('they_have_material', shared.pickup_material), - actions=('modify_part_collision', 'use_node_collide', False), - ) + self.snowball_material.add_actions( + conditions=('they_have_material', shared.pickup_material), + actions=('modify_part_collision', 'use_node_collide', False), + ) - self.snowball_material.add_actions(actions=('modify_part_collision', - 'friction', 0.3)) + self.snowball_material.add_actions(actions=('modify_part_collision', + 'friction', 0.3)) - self.snowball_material.add_actions( - conditions=('they_have_material', shared.player_material), - actions=(('modify_part_collision', 'physical', False), - ('call', 'at_connect', self.hit))) + self.snowball_material.add_actions( + conditions=('they_have_material', shared.player_material), + actions=(('modify_part_collision', 'physical', False), + ('call', 'at_connect', self.hit))) - self.snowball_material.add_actions( - conditions=(('they_dont_have_material', shared.player_material), - 'and', - ('they_have_material', shared.object_material), - 'or', - ('they_have_material', shared.footing_material)), - actions=('call', 'at_connect', self.bounce)) + self.snowball_material.add_actions( + conditions=(('they_dont_have_material', shared.player_material), + 'and', + ('they_have_material', shared.object_material), + 'or', + ('they_have_material', shared.footing_material)), + actions=('call', 'at_connect', self.bounce)) - self.node = bs.newnode( - 'prop', - delegate=self, - attrs={ - 'position': position, - 'velocity': velocity, - 'body': 'sphere', - 'body_scale': self.scale, - 'mesh': bs.getmesh('frostyPelvis'), - 'shadow_size': shadow_size, - 'color_texture': bs.gettexture('bunnyColor'), - 'reflection': 'soft', - 'reflection_scale': [0.15], - 'density': 1.0, - 'materials': [self.snowball_material] - }) - self.light = bs.newnode( - 'light', - owner=self.node, - attrs={ - 'color': (0.6, 0.6, 1.0), - 'intensity': 0.8, - 'radius': self.radius - }) - self.node.connectattr('position', self.light, 'position') - bs.animate(self.node, 'mesh_scale', { - 0: 0, - 0.2: 1.3 * self.scale, - 0.26: self.scale - }) - bs.animate(self.light, 'radius', { - 0: 0, - 0.2: 1.3 * self.radius, - 0.26: self.radius - }) - if self.snowball_melt: - bs.timer(1.5, bs.WeakCall(self._disappear)) + self.node = bs.newnode( + 'prop', + delegate=self, + attrs={ + 'position': position, + 'velocity': velocity, + 'body': 'sphere', + 'body_scale': self.scale, + 'mesh': bs.getmesh('frostyPelvis'), + 'shadow_size': shadow_size, + 'color_texture': bs.gettexture('bunnyColor'), + 'reflection': 'soft', + 'reflection_scale': [0.15], + 'density': 1.0, + 'materials': [self.snowball_material] + }) + self.light = bs.newnode( + 'light', + owner=self.node, + attrs={ + 'color': (0.6, 0.6, 1.0), + 'intensity': 0.8, + 'radius': self.radius + }) + self.node.connectattr('position', self.light, 'position') + bs.animate(self.node, 'mesh_scale', { + 0: 0, + 0.2: 1.3 * self.scale, + 0.26: self.scale + }) + bs.animate(self.light, 'radius', { + 0: 0, + 0.2: 1.3 * self.radius, + 0.26: self.radius + }) + if self.snowball_melt: + bs.timer(1.5, bs.WeakCall(self._disappear)) - def hit(self) -> None: - if not self.node: - return - if self._exploded: - return - if self.snowball_explode: - self._exploded = True - self.do_explode() - bs.timer(0.001, bs.WeakCall(self.handlemessage, bs.DieMessage())) - else: - self.do_hit() + def hit(self) -> None: + if not self.node: + return + if self._exploded: + return + if self.snowball_explode: + self._exploded = True + self.do_explode() + bs.timer(0.001, bs.WeakCall(self.handlemessage, bs.DieMessage())) + else: + self.do_hit() - def do_hit(self) -> None: - v = self.node.velocity - if babase.Vec3(*v).length() > 5.0: - node = bs.getcollision().opposingnode - if node is not None and node and not ( - node in self._hit_nodes): - t = self.node.position - hitdir = self.node.velocity - self._hit_nodes.add(node) - node.handlemessage( - bs.HitMessage( - pos=t, - velocity=v, - magnitude=babase.Vec3(*v).length()*0.5, - velocity_magnitude=babase.Vec3(*v).length()*0.5, - radius=0, - srcnode=self.node, - source_player=self._source_player, - force_direction=hitdir, - hit_type='snoBall', - hit_subtype='default')) + def do_hit(self) -> None: + v = self.node.velocity + if babase.Vec3(*v).length() > 5.0: + node = bs.getcollision().opposingnode + if node is not None and node and not ( + node in self._hit_nodes): + t = self.node.position + hitdir = self.node.velocity + self._hit_nodes.add(node) + node.handlemessage( + bs.HitMessage( + pos=t, + velocity=v, + magnitude=babase.Vec3(*v).length()*0.5, + velocity_magnitude=babase.Vec3(*v).length()*0.5, + radius=0, + srcnode=self.node, + source_player=self._source_player, + force_direction=hitdir, + hit_type='snoBall', + hit_subtype='default')) - if not self.snowball_bounce: - bs.timer(0.05, bs.WeakCall(self.do_bounce)) + if not self.snowball_bounce: + bs.timer(0.05, bs.WeakCall(self.do_bounce)) - def do_explode(self) -> None: - Blast(position=self.node.position, - velocity=self.node.velocity, - blast_radius=self.blast_radius, - source_player=babase.existing(self._source_player), - blast_type='impact', - hit_subtype='explode').autoretain() + def do_explode(self) -> None: + Blast(position=self.node.position, + velocity=self.node.velocity, + blast_radius=self.blast_radius, + source_player=babase.existing(self._source_player), + blast_type='impact', + hit_subtype='explode').autoretain() - def bounce(self) -> None: - if not self.node: - return - if self._exploded: - return - if not self.snowball_bounce: - vel = self.node.velocity - bs.timer(0.01, bs.WeakCall(self.calc_bounce, vel)) - else: - return + def bounce(self) -> None: + if not self.node: + return + if self._exploded: + return + if not self.snowball_bounce: + vel = self.node.velocity + bs.timer(0.01, bs.WeakCall(self.calc_bounce, vel)) + else: + return - def calc_bounce(self, vel) -> None: - if not self.node: - return - ospd = babase.Vec3(*vel).length() - dot = sum(x*y for x, y in zip(vel, self.node.velocity)) - if ospd*ospd - dot > 50.0: - bs.timer(0.05, bs.WeakCall(self.do_bounce)) + def calc_bounce(self, vel) -> None: + if not self.node: + return + ospd = babase.Vec3(*vel).length() + dot = sum(x*y for x, y in zip(vel, self.node.velocity)) + if ospd*ospd - dot > 50.0: + bs.timer(0.05, bs.WeakCall(self.do_bounce)) - def do_bounce(self) -> None: - if not self.node: - return - if not self._exploded: - self.do_effect() + def do_bounce(self) -> None: + if not self.node: + return + if not self._exploded: + self.do_effect() - def do_effect(self) -> None: - self._exploded = True - bs.emitfx(position=self.node.position, - velocity=[v*0.1 for v in self.node.velocity], - count=10, - spread=0.1, - scale=0.4, - chunk_type='ice') - sound = bs.getsound('impactMedium') - sound.play(1.0, position=self.node.position) - scl = self.node.mesh_scale - bs.animate(self.node, 'mesh_scale', { - 0.0: scl*1.0, - 0.02: scl*0.5, - 0.05: 0.0 - }) - lr = self.light.radius - bs.animate(self.light, 'radius', { - 0.0: lr*1.0, - 0.02: lr*0.5, - 0.05: 0.0 - }) - bs.timer(0.08, - bs.WeakCall(self.handlemessage, bs.DieMessage())) + def do_effect(self) -> None: + self._exploded = True + bs.emitfx(position=self.node.position, + velocity=[v*0.1 for v in self.node.velocity], + count=10, + spread=0.1, + scale=0.4, + chunk_type='ice') + sound = bs.getsound('impactMedium') + sound.play(1.0, position=self.node.position) + scl = self.node.mesh_scale + bs.animate(self.node, 'mesh_scale', { + 0.0: scl*1.0, + 0.02: scl*0.5, + 0.05: 0.0 + }) + lr = self.light.radius + bs.animate(self.light, 'radius', { + 0.0: lr*1.0, + 0.02: lr*0.5, + 0.05: 0.0 + }) + bs.timer(0.08, + bs.WeakCall(self.handlemessage, bs.DieMessage())) - def _disappear(self) -> None: - self._exploded = True - if self.node: - scl = self.node.mesh_scale - bs.animate(self.node, 'mesh_scale', { - 0.0: scl*1.0, - 0.3: scl*0.5, - 0.5: 0.0 - }) - lr = self.light.radius - bs.animate(self.light, 'radius', { - 0.0: lr*1.0, - 0.3: lr*0.5, - 0.5: 0.0 - }) - bs.timer(0.55, - bs.WeakCall(self.handlemessage, bs.DieMessage())) + def _disappear(self) -> None: + self._exploded = True + if self.node: + scl = self.node.mesh_scale + bs.animate(self.node, 'mesh_scale', { + 0.0: scl*1.0, + 0.3: scl*0.5, + 0.5: 0.0 + }) + lr = self.light.radius + bs.animate(self.light, 'radius', { + 0.0: lr*1.0, + 0.3: lr*0.5, + 0.5: 0.0 + }) + bs.timer(0.55, + bs.WeakCall(self.handlemessage, bs.DieMessage())) - def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, bs.DieMessage): - if self.node: - self.node.delete() - elif isinstance(msg, bs.OutOfBoundsMessage): - self.handlemessage(bs.DieMessage()) - else: - super().handlemessage(msg) + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, bs.DieMessage): + if self.node: + self.node.delete() + elif isinstance(msg, bs.OutOfBoundsMessage): + self.handlemessage(bs.DieMessage()) + else: + super().handlemessage(msg) class NewPlayerSpaz(PlayerSpaz): - def __init__(self, *args: Any, **kwds: Any): - super().__init__(*args, **kwds) - self.snowball_scale = 1.0 - self.snowball_melt = True - self.snowball_bounce = True - self.snowball_explode = False + def __init__(self, *args: Any, **kwds: Any): + super().__init__(*args, **kwds) + self.snowball_scale = 1.0 + self.snowball_melt = True + self.snowball_bounce = True + self.snowball_explode = False - def on_punch_press(self) -> None: - if not self.node or self.frozen or self.node.knockout > 0.0: - return - t_ms = bs.time() * 1000 - assert isinstance(t_ms, int) - if t_ms - self.last_punch_time_ms >= self._punch_cooldown: - if self.punch_callback is not None: - self.punch_callback(self) + def on_punch_press(self) -> None: + if not self.node or self.frozen or self.node.knockout > 0.0: + return + t_ms = bs.time() * 1000 + assert isinstance(t_ms, int) + if t_ms - self.last_punch_time_ms >= self._punch_cooldown: + if self.punch_callback is not None: + self.punch_callback(self) - # snowball - pos = self.node.position - p1 = self.node.position_center - p2 = self.node.position_forward - direction = [p1[0]-p2[0],p2[1]-p1[1],p1[2]-p2[2]] - direction[1] = 0.03 - mag = 20.0/babase.Vec3(*direction).length() - vel = [v * mag for v in direction] - Snowball(position=(pos[0], pos[1] + 0.1, pos[2]), - velocity=vel, - blast_radius=self.blast_radius, - bomb_scale=self.snowball_scale, - source_player=self.source_player, - owner=self.node, - melt=self.snowball_melt, - bounce=self.snowball_bounce, - explode=self.snowball_explode).autoretain() + # snowball + pos = self.node.position + p1 = self.node.position_center + p2 = self.node.position_forward + direction = [p1[0]-p2[0], p2[1]-p1[1], p1[2]-p2[2]] + direction[1] = 0.03 + mag = 20.0/babase.Vec3(*direction).length() + vel = [v * mag for v in direction] + Snowball(position=(pos[0], pos[1] + 0.1, pos[2]), + velocity=vel, + blast_radius=self.blast_radius, + bomb_scale=self.snowball_scale, + source_player=self.source_player, + owner=self.node, + melt=self.snowball_melt, + bounce=self.snowball_bounce, + explode=self.snowball_explode).autoretain() - self._punched_nodes = set() # Reset this. - self.last_punch_time_ms = t_ms - self.node.punch_pressed = True - if not self.node.hold_node: - bs.timer( - 0.1, - bs.WeakCall(self._safe_play_sound, - SpazFactory.get().swish_sound, 0.8)) - self._turbo_filter_add_press('punch') + self._punched_nodes = set() # Reset this. + self.last_punch_time_ms = t_ms + self.node.punch_pressed = True + if not self.node.hold_node: + bs.timer( + 0.1, + bs.WeakCall(self._safe_play_sound, + SpazFactory.get().swish_sound, 0.8)) + self._turbo_filter_add_press('punch') - def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, PunchHitMessage): - pass - else: - return super().handlemessage(msg) - return None + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, PunchHitMessage): + pass + else: + return super().handlemessage(msg) + return None class Player(bs.Player['Team']): - """Our player type for this game.""" + """Our player type for this game.""" class Team(bs.Team[Player]): - """Our team type for this game.""" + """Our team type for this game.""" - def __init__(self) -> None: - self.score = 0 + def __init__(self) -> None: + self.score = 0 # ba_meta export bascenev1.GameActivity class SnowballFightGame(bs.TeamGameActivity[Player, Team]): - """A game type based on acquiring kills.""" + """A game type based on acquiring kills.""" - name = name - description = 'Kill a set number of enemies to win.' + name = name + description = 'Kill a set number of enemies to win.' - # Print messages when players die since it matters here. - announce_player_deaths = 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( - '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( - snowball_rate, - choices=[ - (snowball_slowest, 500), - (snowball_slow, 400), - ('Normal', 300), - (snowball_fast, 200), - (snowball_lagcity, 100), - ], - default=300, - ), - bs.FloatChoiceSetting( - snowball_scale, - choices=[ - (snowball_smallest, 0.4), - (snowball_small, 0.6), - ('Normal', 0.8), - (snowball_big, 1.4), - (snowball_biggest, 3.0), - (snowball_insane, 6.0), - ], - default=0.8, - ), - bs.BoolSetting(snowball_melt, default=True), - bs.BoolSetting(snowball_bust, default=True), - bs.BoolSetting(snowball_explode, default=False), - bs.BoolSetting(snowball_snow, default=True), - bs.BoolSetting('Epic Mode', default=False), - ] + @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( + snowball_rate, + choices=[ + (snowball_slowest, 500), + (snowball_slow, 400), + ('Normal', 300), + (snowball_fast, 200), + (snowball_lagcity, 100), + ], + default=300, + ), + bs.FloatChoiceSetting( + snowball_scale, + choices=[ + (snowball_smallest, 0.4), + (snowball_small, 0.6), + ('Normal', 0.8), + (snowball_big, 1.4), + (snowball_biggest, 3.0), + (snowball_insane, 6.0), + ], + default=0.8, + ), + bs.BoolSetting(snowball_melt, default=True), + bs.BoolSetting(snowball_bust, default=True), + bs.BoolSetting(snowball_explode, default=False), + bs.BoolSetting(snowball_snow, default=True), + bs.BoolSetting('Epic Mode', default=False), + ] - # In teams mode, a suicide gives a point to the other team, but in - # free-for-all it subtracts from your own score. By default we clamp - # 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, bs.FreeForAllSession): - settings.append( - bs.BoolSetting('Allow Negative Scores', default=False)) + # In teams mode, a suicide gives a point to the other team, but in + # free-for-all it subtracts from your own score. By default we clamp + # 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, bs.FreeForAllSession): + settings.append( + bs.BoolSetting('Allow Negative Scores', default=False)) - return settings + 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 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 bs.app.classic.getmaps('melee') + @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: 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._snowball_rate = int(settings[snowball_rate]) - self._snowball_scale = float(settings[snowball_scale]) - self._snowball_melt = bool(settings[snowball_melt]) - self._snowball_bounce = bool(settings[snowball_bust]) - self._snowball_explode = bool(settings[snowball_explode]) - self._snow_mode = bool(settings[snowball_snow]) + 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._snowball_rate = int(settings[snowball_rate]) + self._snowball_scale = float(settings[snowball_scale]) + self._snowball_melt = bool(settings[snowball_melt]) + self._snowball_bounce = bool(settings[snowball_bust]) + self._snowball_explode = bool(settings[snowball_explode]) + self._snow_mode = bool(settings[snowball_snow]) - # 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) + # 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) -> str | Sequence: - return 'Crush ${ARG1} of your enemies.', self._score_to_win + 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 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_team_join(self, team: Team) -> None: + if self.has_begun(): + self._update_scoreboard() - def on_transition_in(self) -> None: - super().on_transition_in() - if self._snow_mode: - gnode = bs.getactivity().globalsnode - gnode.tint = (0.8, 0.8, 1.3) - bs.timer(0.02, self.emit_snowball, repeat=True) + def on_transition_in(self) -> None: + super().on_transition_in() + if self._snow_mode: + gnode = bs.getactivity().globalsnode + gnode.tint = (0.8, 0.8, 1.3) + bs.timer(0.02, self.emit_snowball, repeat=True) - def on_begin(self) -> None: - super().on_begin() - self.setup_standard_time_limit(self._time_limit) - # self.setup_standard_powerup_drops() + def on_begin(self) -> None: + super().on_begin() + self.setup_standard_time_limit(self._time_limit) + # self.setup_standard_powerup_drops() - # 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() + # 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 emit_snowball(self) -> None: - pos = (-10 + (random.random() * 30), 15, - -10 + (random.random() * 30)) - vel = ((-5.0 + random.random() * 30.0) * (-1.0 if pos[0] > 0 else 1.0), - -50.0, (-5.0 + random.random() * 30.0) * ( - -1.0 if pos[0] > 0 else 1.0)) - bs.emitfx(position=pos, - velocity=vel, - count=10, - scale=1.0 + random.random(), - spread=0.0, - chunk_type='spark') + def emit_snowball(self) -> None: + pos = (-10 + (random.random() * 30), 15, + -10 + (random.random() * 30)) + vel = ((-5.0 + random.random() * 30.0) * (-1.0 if pos[0] > 0 else 1.0), + -50.0, (-5.0 + random.random() * 30.0) * ( + -1.0 if pos[0] > 0 else 1.0)) + bs.emitfx(position=pos, + velocity=vel, + count=10, + scale=1.0 + random.random(), + spread=0.0, + chunk_type='spark') - def spawn_player_spaz(self, - player: Player, - position: Sequence[float] = (0, 0, 0), - angle: float | None = None) -> PlayerSpaz: - from babase import _math - from bascenev1._gameutils import animate - from bascenev1._coopsession import CoopSession + def spawn_player_spaz(self, + player: Player, + position: Sequence[float] = (0, 0, 0), + angle: float | None = None) -> PlayerSpaz: + from babase import _math + from bascenev1._gameutils import animate + from bascenev1._coopsession import CoopSession - 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) + 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) - name = player.getname() - color = player.color - highlight = player.highlight + name = player.getname() + color = player.color + highlight = player.highlight - light_color = _math.normalized_color(color) - display_color = babase.safecolor(color, target_intensity=0.75) + light_color = _math.normalized_color(color) + display_color = babase.safecolor(color, target_intensity=0.75) - spaz = NewPlayerSpaz(color=color, - highlight=highlight, - character=player.character, - player=player) + spaz = NewPlayerSpaz(color=color, + highlight=highlight, + character=player.character, + player=player) - player.actor = spaz - assert spaz.node + 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, ) + # 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( - enable_pickup=False, enable_bomb=False) + spaz.node.name = name + spaz.node.name_color = display_color + spaz.connect_controls_to_player( + enable_pickup=False, enable_bomb=False) - # 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') - animate(light, 'intensity', {0: 0, 0.25: 1, 0.5: 0}) - bs.timer(0.5, light.delete) + # 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') + animate(light, 'intensity', {0: 0, 0.25: 1, 0.5: 0}) + bs.timer(0.5, light.delete) - # custom - spaz._punch_cooldown = self._snowball_rate - spaz.snowball_scale = self._snowball_scale - spaz.snowball_melt = self._snowball_melt - spaz.snowball_bounce = self._snowball_bounce - spaz.snowball_explode = self._snowball_explode + # custom + spaz._punch_cooldown = self._snowball_rate + spaz.snowball_scale = self._snowball_scale + spaz.snowball_melt = self._snowball_melt + spaz.snowball_bounce = self._snowball_bounce + spaz.snowball_explode = self._snowball_explode - return spaz + return spaz - def handlemessage(self, msg: Any) -> Any: + def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, bs.PlayerDiedMessage): + if isinstance(msg, bs.PlayerDiedMessage): - # Augment standard behavior. - super().handlemessage(msg) + # Augment standard behavior. + super().handlemessage(msg) - player = msg.getplayer(Player) - self.respawn_player(player) + player = msg.getplayer(Player) + self.respawn_player(player) - killer = msg.getkillerplayer(Player) - if killer is None: - return None + killer = msg.getkillerplayer(Player) + if killer is None: + return None - # Handle team-kills. - if killer.team is player.team: + # 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 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 + # 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() + # 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) + # 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() + 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) + # 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 + 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 _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) + 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/ofuuuAttack.py b/plugins/minigames/ofuuuAttack.py index 49b2afb..1e5b6d4 100644 --- a/plugins/minigames/ofuuuAttack.py +++ b/plugins/minigames/ofuuuAttack.py @@ -17,173 +17,210 @@ from bascenev1lib.actor.onscreentimer import OnScreenTimer if TYPE_CHECKING: from typing import Any, Sequence, Optional, List, Dict, Type, Type + class _GotTouched(): - pass + pass + class UFO(bs.Actor): - def __init__(self, pos: float = (0,0,0)): - super().__init__() - shared = SharedObjects.get() - self.r: Optional[int] = 0 - self.dis: Optional[List] = [] - self.target: float = (0.0, 0.0, 0.0) - self.regs: List[bs.NodeActor] = [] - self.node = bs.newnode('prop', - delegate=self, - attrs={'body':'landMine', - 'position': pos, - 'mesh':bs.getmesh('landMine'), - 'mesh_scale': 1.5, - 'body_scale': 0.01, - 'shadow_size': 0.000001, - 'gravity_scale': 0.0, - 'color_texture': bs.gettexture("achievementCrossHair"), - 'materials': [shared.object_material]}) - self.ufo_collide = None + def __init__(self, pos: float = (0, 0, 0)): + super().__init__() + shared = SharedObjects.get() + self.r: Optional[int] = 0 + self.dis: Optional[List] = [] + self.target: float = (0.0, 0.0, 0.0) + self.regs: List[bs.NodeActor] = [] + self.node = bs.newnode('prop', + delegate=self, + attrs={'body': 'landMine', + 'position': pos, + 'mesh': bs.getmesh('landMine'), + 'mesh_scale': 1.5, + 'body_scale': 0.01, + 'shadow_size': 0.000001, + 'gravity_scale': 0.0, + 'color_texture': bs.gettexture("achievementCrossHair"), + 'materials': [shared.object_material]}) + self.ufo_collide = None - def create_target(self): - if not self.node.exists(): return - self.dis = [] - shared = SharedObjects.get() - try: - def pass_(): - self.regs.clear() - bs.timer(3875*0.001, self.move) - try: bs.timer(3277*0.001, lambda: Bomb(velocity=(0,0,0), position=(self.target[0], self.node.position[1]-0.43999, self.target[2]), bomb_type='impact').autoretain().arm()) - except: pass - key = bs.Material() - key.add_actions( - conditions=('they_have_material', shared.object_material), - actions=( - ('modify_part_collision', 'collide', True), - ('modify_part_collision', 'physical', False), - ('call', 'at_connect', pass_()), - )) - except: pass - self.regs.append(bs.NodeActor(bs.newnode('region', - attrs={ - 'position': self.target, - 'scale': (0.04, 22, 0.04), - 'type': 'sphere', - 'materials':[key]}))) + def create_target(self): + if not self.node.exists(): + return + self.dis = [] + shared = SharedObjects.get() + try: + def pass_(): + self.regs.clear() + bs.timer(3875*0.001, self.move) + try: + bs.timer(3277*0.001, lambda: Bomb(velocity=(0, 0, 0), position=( + self.target[0], self.node.position[1]-0.43999, self.target[2]), bomb_type='impact').autoretain().arm()) + except: + pass + key = bs.Material() + key.add_actions( + conditions=('they_have_material', shared.object_material), + actions=( + ('modify_part_collision', 'collide', True), + ('modify_part_collision', 'physical', False), + ('call', 'at_connect', pass_()), + )) + except: + pass + self.regs.append(bs.NodeActor(bs.newnode('region', + attrs={ + 'position': self.target, + 'scale': (0.04, 22, 0.04), + 'type': 'sphere', + 'materials': [key]}))) - def move(self): - if not self.node.exists(): return - try: - self.create_target() - for j in bs.getnodes(): - n = j.getdelegate(object) - if j.getnodetype() == 'prop' and isinstance(n, TileFloor): - if n.node.exists(): self.dis.append(n.node) - self.r = random.randint(0,len(self.dis)-1) - self.target = (self.dis[self.r].position[0], self.node.position[1], self.dis[self.r].position[2]) - bs.animate_array(self.node, 'position', 3, { - 0:self.node.position, - 3.0:self.target}) - except: pass - def handlemessage(self, msg): + def move(self): + if not self.node.exists(): + return + try: + self.create_target() + for j in bs.getnodes(): + n = j.getdelegate(object) + if j.getnodetype() == 'prop' and isinstance(n, TileFloor): + if n.node.exists(): + self.dis.append(n.node) + self.r = random.randint(0, len(self.dis)-1) + self.target = (self.dis[self.r].position[0], + self.node.position[1], self.dis[self.r].position[2]) + bs.animate_array(self.node, 'position', 3, { + 0: self.node.position, + 3.0: self.target}) + except: + pass - if isinstance(msg, bs.DieMessage): - self.node.delete() - elif isinstance(msg ,bs.OutOfBoundsMessage): self.handlemessage(bs.DieMessage()) - else: super().handlemessage(msg) + def handlemessage(self, msg): + + if isinstance(msg, bs.DieMessage): + self.node.delete() + elif isinstance(msg, bs.OutOfBoundsMessage): + self.handlemessage(bs.DieMessage()) + else: + super().handlemessage(msg) class TileFloor(bs.Actor): - def __init__(self, - pos: float = (0, 0, 0)): - super().__init__() - get_mat = SharedObjects.get() - self.pos = pos - self.scale = 1.5 - self.mat, self.mat2, self.test = bs.Material(), bs.Material(), bs.Material() - self.mat.add_actions(conditions=('we_are_older_than', 1), actions=(('modify_part_collision', 'collide', False))) - self.mat2.add_actions(conditions=('we_are_older_than', 1), actions=(('modify_part_collision', 'collide', True))) - self.test.add_actions( + def __init__(self, + pos: float = (0, 0, 0)): + super().__init__() + get_mat = SharedObjects.get() + self.pos = pos + self.scale = 1.5 + self.mat, self.mat2, self.test = bs.Material(), bs.Material(), bs.Material() + self.mat.add_actions(conditions=('we_are_older_than', 1), + actions=(('modify_part_collision', 'collide', False))) + self.mat2.add_actions(conditions=('we_are_older_than', 1), + actions=(('modify_part_collision', 'collide', True))) + self.test.add_actions( conditions=('they_have_material', BombFactory.get().bomb_material), actions=( ('modify_part_collision', 'collide', True), ('modify_part_collision', 'physical', False), ('message', 'our_node', 'at_connect', _GotTouched()))) - self.node = bs.newnode('prop', - delegate=self, - attrs={'body':'puck', - 'position': self.pos, - 'mesh':bs.getmesh('buttonSquareOpaque'), - 'mesh_scale': self.scale*1.16, - 'body_scale': self.scale, - 'shadow_size': 0.0002, - 'gravity_scale': 0.0, - 'color_texture': bs.gettexture("tnt"), - 'is_area_of_interest': True, - 'materials': [self.mat, self.test]}) - self.node_support = bs.newnode('region', - attrs={ - 'position': self.pos, - 'scale': (self.scale*0.8918, 0.1, self.scale*0.8918), - 'type': 'box', - 'materials':[get_mat.footing_material, self.mat2] - }) - def handlemessage(self, msg): - if isinstance(msg, bs.DieMessage): - self.node.delete() - self.node_support.delete() - elif isinstance(msg, _GotTouched): - def do(): self.handlemessage(bs.DieMessage()) - bs.timer(0.1, do) - else: super().handlemessage(msg) + self.node = bs.newnode('prop', + delegate=self, + attrs={'body': 'puck', + 'position': self.pos, + 'mesh': bs.getmesh('buttonSquareOpaque'), + 'mesh_scale': self.scale*1.16, + 'body_scale': self.scale, + 'shadow_size': 0.0002, + 'gravity_scale': 0.0, + 'color_texture': bs.gettexture("tnt"), + 'is_area_of_interest': True, + 'materials': [self.mat, self.test]}) + self.node_support = bs.newnode('region', + attrs={ + 'position': self.pos, + 'scale': (self.scale*0.8918, 0.1, self.scale*0.8918), + 'type': 'box', + 'materials': [get_mat.footing_material, self.mat2] + }) + + def handlemessage(self, msg): + if isinstance(msg, bs.DieMessage): + self.node.delete() + self.node_support.delete() + elif isinstance(msg, _GotTouched): + def do(): self.handlemessage(bs.DieMessage()) + bs.timer(0.1, do) + else: + super().handlemessage(msg) + class defs(): points = boxes = {} boxes['area_of_interest_bounds'] = (-1.3440, 1.185751251, 3.7326226188) + ( - 0.0, 0.0, 0.0) + (29.8180273, 15.57249038, 22.93859993) - boxes['map_bounds'] = (0.0, 2.585751251, 0.4326226188) + (0.0, 0.0, 0.0) + (29.09506485, 15.81173179, 33.76723155) + 0.0, 0.0, 0.0) + (29.8180273, 15.57249038, 22.93859993) + boxes['map_bounds'] = (0.0, 2.585751251, 0.4326226188) + (0.0, 0.0, + 0.0) + (29.09506485, 15.81173179, 33.76723155) + class DummyMapForGame(bs.Map): defs, name = defs(), 'Tile Lands' + @classmethod def get_play_types(cls) -> List[str]: return [] + @classmethod def get_preview_texture_name(cls) -> str: return 'achievementCrossHair' + @classmethod def on_preload(cls) -> Any: - data: Dict[str, Any] = {'bg_1': bs.gettexture('rampageBGColor'),'bg_2': bs.gettexture('rampageBGColor2'),'bg_mesh_1': bs.getmesh('rampageBG'),'bg_mesh_2': bs.getmesh('rampageBG2'),} + data: Dict[str, Any] = {'bg_1': bs.gettexture('rampageBGColor'), 'bg_2': bs.gettexture( + 'rampageBGColor2'), 'bg_mesh_1': bs.getmesh('rampageBG'), 'bg_mesh_2': bs.getmesh('rampageBG2'), } return data + def __init__(self) -> None: super().__init__() - self.bg1 = bs.newnode('terrain',attrs={'mesh': self.preloaddata['bg_mesh_1'],'lighting': False,'background': True,'color_texture': self.preloaddata['bg_2']}) - self.bg2 = bs.newnode('terrain',attrs={ 'mesh': self.preloaddata['bg_mesh_2'], 'lighting': False,'background': True, 'color_texture': self.preloaddata['bg_2']}) + self.bg1 = bs.newnode('terrain', attrs={ + 'mesh': self.preloaddata['bg_mesh_1'], 'lighting': False, 'background': True, 'color_texture': self.preloaddata['bg_2']}) + self.bg2 = bs.newnode('terrain', attrs={ + 'mesh': self.preloaddata['bg_mesh_2'], 'lighting': False, 'background': True, 'color_texture': self.preloaddata['bg_2']}) a = bs.getactivity().globalsnode - a.tint, a.ambient_color, a.vignette_outer, a.vignette_inner = (1.2, 1.1, 0.97), (1.3, 1.2, 1.03), (0.62, 0.64, 0.69), (0.97, 0.95, 0.93) + a.tint, a.ambient_color, a.vignette_outer, a.vignette_inner = ( + 1.2, 1.1, 0.97), (1.3, 1.2, 1.03), (0.62, 0.64, 0.69), (0.97, 0.95, 0.93) + class DummyMapForGame2(bs.Map): defs, name = defs(), 'Tile Lands Night' + @classmethod def get_play_types(cls) -> List[str]: return [] + @classmethod def get_preview_texture_name(cls) -> str: return 'achievementCrossHair' + @classmethod def on_preload(cls) -> Any: - data: Dict[str, Any] = {'bg_1': bs.gettexture('menuBG'),'bg_2': bs.gettexture('menuBG'),'bg_mesh_1': bs.getmesh('thePadBG'),'bg_mesh_2': bs.getmesh('thePadBG'),} + data: Dict[str, Any] = {'bg_1': bs.gettexture('menuBG'), 'bg_2': bs.gettexture( + 'menuBG'), 'bg_mesh_1': bs.getmesh('thePadBG'), 'bg_mesh_2': bs.getmesh('thePadBG'), } return data + def __init__(self) -> None: super().__init__() - self.bg1 = bs.newnode('terrain',attrs={'mesh': self.preloaddata['bg_mesh_1'],'lighting': False,'background': True,'color_texture': self.preloaddata['bg_2']}) - self.bg2 = bs.newnode('terrain',attrs={ 'mesh': self.preloaddata['bg_mesh_2'], 'lighting': False,'background': True, 'color_texture': self.preloaddata['bg_2']}) + self.bg1 = bs.newnode('terrain', attrs={ + 'mesh': self.preloaddata['bg_mesh_1'], 'lighting': False, 'background': True, 'color_texture': self.preloaddata['bg_2']}) + self.bg2 = bs.newnode('terrain', attrs={ + 'mesh': self.preloaddata['bg_mesh_2'], 'lighting': False, 'background': True, 'color_texture': self.preloaddata['bg_2']}) a = bs.getactivity().globalsnode - a.tint, a.ambient_color, a.vignette_outer, a.vignette_inner = (0.5, 0.7, 1.27), (2.5, 2.5, 2.5), (0.62, 0.64, 0.69), (0.97, 0.95, 0.93) + a.tint, a.ambient_color, a.vignette_outer, a.vignette_inner = ( + 0.5, 0.7, 1.27), (2.5, 2.5, 2.5), (0.62, 0.64, 0.69), (0.97, 0.95, 0.93) + bs._map.register_map(DummyMapForGame) bs._map.register_map(DummyMapForGame2) - - class Player(bs.Player['Team']): """Our player type for this game.""" @@ -202,12 +239,12 @@ class UFOAttackGame(bs.TeamGameActivity[Player, Team]): name = 'UFO Attack' description = 'Dodge the falling bombs.' available_settings = [ - bs.BoolSetting('Epic Mode', default=False), - bs.BoolSetting('Enable Run', default=True), - bs.BoolSetting('Enable Jump', default=True), - bs.BoolSetting('Display Map Area Dimension', default=False), - bs.IntSetting('No. of Rows' + u' →',max_value=13, min_value=1, default=8, increment=1), - bs.IntSetting('No. of Columns' + u' ↓', max_value=12, min_value=1, default=6, increment=1) + bs.BoolSetting('Epic Mode', default=False), + bs.BoolSetting('Enable Run', default=True), + bs.BoolSetting('Enable Jump', default=True), + bs.BoolSetting('Display Map Area Dimension', default=False), + bs.IntSetting('No. of Rows' + u' →', max_value=13, min_value=1, default=8, increment=1), + bs.IntSetting('No. of Columns' + u' ↓', max_value=12, min_value=1, default=6, increment=1) ] scoreconfig = bs.ScoreConfig(label='Survived', scoretype=bs.ScoreType.SECONDS, @@ -215,9 +252,11 @@ class UFOAttackGame(bs.TeamGameActivity[Player, Team]): # Print messages when players die (since its meaningful in this game). announce_player_deaths = True + @classmethod def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]: return ['Tile Lands', 'Tile Lands Night'] + @classmethod def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool: return (issubclass(sessiontype, bs.DualTeamSession) @@ -225,7 +264,7 @@ class UFOAttackGame(bs.TeamGameActivity[Player, Team]): def __init__(self, settings: dict): super().__init__(settings) - + self.col = int(settings['No. of Columns' + u' ↓']) self.row = int(settings['No. of Rows' + u' →']) self.bool1 = bool(settings['Enable Run']) @@ -237,7 +276,8 @@ class UFOAttackGame(bs.TeamGameActivity[Player, Team]): if self._epic_mode else bs.MusicType.SURVIVAL) if bool(settings["Display Map Area Dimension"]): self.game_name = "UFO Attack " + "(" + str(self.col) + "x" + str(self.row) + ")" - else: self.game_name = "UFO Attack" + else: + self.game_name = "UFO Attack" if self._epic_mode: self.slow_motion = True @@ -248,11 +288,11 @@ class UFOAttackGame(bs.TeamGameActivity[Player, Team]): super().on_begin() self._timer = OnScreenTimer() self._timer.start() - #bs.timer(5.0, self._check_end_game) + # bs.timer(5.0, self._check_end_game) for r in range(self.col): for j in range(self.row): tile = TileFloor(pos=(-6.204283+(j*1.399), 3.425666, - -1.3538+(r*1.399))).autoretain() + -1.3538+(r*1.399))).autoretain() self.ufo = UFO(pos=(-5.00410667, 6.616383286, -2.503472)).autoretain() bs.timer(7000*0.001, lambda: self.ufo.move()) for t in self.players: @@ -262,7 +302,7 @@ class UFOAttackGame(bs.TeamGameActivity[Player, Team]): if self.has_begun(): bs.broadcastmessage( babase.Lstr(resource='playerDelayedJoinText', - subs=[('${PLAYER}', player.getname(full=True))]), + subs=[('${PLAYER}', player.getname(full=True))]), color=(0, 1, 0), ) assert self._timer is not None @@ -278,9 +318,10 @@ class UFOAttackGame(bs.TeamGameActivity[Player, Team]): for a in bs.getnodes(): g = a.getdelegate(object) if a.getnodetype() == 'prop' and isinstance(g, TileFloor): - dis.append(g.node) + dis.append(g.node) r = random.randint(0, len(dis)-1) - spaz = self.spawn_player_spaz(player, position=(dis[r].position[0], dis[r].position[1]+1.005958, dis[r].position[2])) + spaz = self.spawn_player_spaz(player, position=( + dis[r].position[0], dis[r].position[1]+1.005958, dis[r].position[2])) spaz.connect_controls_to_player(enable_punch=False, enable_bomb=False, enable_run=self.bool1, @@ -288,6 +329,7 @@ class UFOAttackGame(bs.TeamGameActivity[Player, Team]): enable_pickup=False) spaz.play_big_death_sound = True return spaz + def handlemessage(self, msg: Any) -> Any: if isinstance(msg, bs.PlayerDiedMessage): super().handlemessage(msg) @@ -308,7 +350,7 @@ class UFOAttackGame(bs.TeamGameActivity[Player, Team]): living_team_count += 1 break if living_team_count <= 1: - self.end_game() + self.end_game() def end_game(self) -> None: self.ufo.handlemessage(bs.DieMessage()) @@ -337,4 +379,4 @@ class UFOAttackGame(bs.TeamGameActivity[Player, Team]): # Submit the score value in milliseconds. results.set_team_score(team, int(longest_life)) - self.end(results=results) \ No newline at end of file + self.end(results=results) diff --git a/plugins/minigames/safe_zone.py b/plugins/minigames/safe_zone.py index 4c2620f..5680877 100644 --- a/plugins/minigames/safe_zone.py +++ b/plugins/minigames/safe_zone.py @@ -176,6 +176,7 @@ class Team(bs.Team[Player]): self.survival_seconds: Optional[int] = None self.spawn_order: List[Player] = [] + lang = bs.app.lang.language if lang == 'Spanish': description = 'Mantente en la zona segura.' @@ -187,6 +188,8 @@ else: kill_timer = 'Kill timer: ' # ba_meta export bascenev1.GameActivity + + class SafeZoneGame(bs.TeamGameActivity[Player, Team]): """Game type where last player(s) left alive win.""" @@ -244,7 +247,7 @@ class SafeZoneGame(bs.TeamGameActivity[Player, Team]): @classmethod def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]: - return ['Football Stadium','Hockey Stadium'] + return ['Football Stadium', 'Hockey Stadium'] def __init__(self, settings: dict): super().__init__(settings) @@ -263,7 +266,7 @@ class SafeZoneGame(bs.TeamGameActivity[Player, Team]): self.slow_motion = self._epic_mode self.default_music = (bs.MusicType.EPIC if self._epic_mode else bs.MusicType.SURVIVAL) - + self._tick_sound = bs.getsound('tick') def get_instance_description(self) -> Union[str, Sequence]: @@ -286,7 +289,7 @@ class SafeZoneGame(bs.TeamGameActivity[Player, Team]): player.team.survival_seconds = 0 bs.broadcastmessage( babase.Lstr(resource='playerDelayedJoinText', - subs=[('${PLAYER}', player.getname(full=True))]), + subs=[('${PLAYER}', player.getname(full=True))]), color=(0, 1, 0), ) return @@ -305,21 +308,21 @@ class SafeZoneGame(bs.TeamGameActivity[Player, Team]): # Don't waste time doing this until begin. if self.has_begun(): self._update_icons() - + 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() - - bs.timer(5,self.spawn_zone) + # self.setup_standard_powerup_drops() + + bs.timer(5, self.spawn_zone) self._bots = stdbot.SpazBotSet() - bs.timer(3,babase.Call(self.add_bot,'left')) - bs.timer(3,babase.Call(self.add_bot,'right')) + bs.timer(3, babase.Call(self.add_bot, 'left')) + bs.timer(3, babase.Call(self.add_bot, 'right')) if len(self.initialplayerinfos) > 4: - bs.timer(5,babase.Call(self.add_bot,'right')) - bs.timer(5,babase.Call(self.add_bot,'left')) - + bs.timer(5, babase.Call(self.add_bot, 'right')) + bs.timer(5, babase.Call(self.add_bot, 'left')) + if self._solo_mode: self._vs_text = bs.NodeActor( bs.newnode('text', @@ -359,78 +362,88 @@ class SafeZoneGame(bs.TeamGameActivity[Player, Team]): # We could check game-over conditions at explicit trigger points, # but lets just do the simple thing and poll it. bs.timer(1.0, self._update, repeat=True) - + def spawn_zone(self): - self.zone_pos = (random.randrange(-10,10),0.05,random.randrange(-5,5)) - self.zone = bs.newnode('locator',attrs={'shape':'circle','position':self.zone_pos,'color':(1, 1, 0),'opacity':0.8,'draw_beauty':True,'additive':False,'drawShadow':False}) - self.zone_limit = bs.newnode('locator',attrs={'shape':'circleOutline','position':self.zone_pos,'color':(1, 0.2, 0.2),'opacity':0.8,'draw_beauty':True,'additive':False,'drawShadow':False}) - bs.animate_array(self.zone, 'size', 1,{0:[0], 0.3:[self.get_players_count()*0.85], 0.35:[self.get_players_count()*0.8]}) - bs.animate_array(self.zone_limit, 'size', 1,{0:[0], 0.3:[self.get_players_count()*1.2], 0.35:[self.get_players_count()*0.95]}) + self.zone_pos = (random.randrange(-10, 10), 0.05, random.randrange(-5, 5)) + self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': self.zone_pos, 'color': ( + 1, 1, 0), 'opacity': 0.8, 'draw_beauty': True, 'additive': False, 'drawShadow': False}) + self.zone_limit = bs.newnode('locator', attrs={'shape': 'circleOutline', 'position': self.zone_pos, 'color': ( + 1, 0.2, 0.2), 'opacity': 0.8, 'draw_beauty': True, 'additive': False, 'drawShadow': False}) + bs.animate_array(self.zone, 'size', 1, {0: [0], 0.3: [ + self.get_players_count()*0.85], 0.35: [self.get_players_count()*0.8]}) + bs.animate_array(self.zone_limit, 'size', 1, {0: [0], 0.3: [ + self.get_players_count()*1.2], 0.35: [self.get_players_count()*0.95]}) self.last_players_count = self.get_players_count() bs.getsound('laserReverse').play() self.start_timer() self.move_zone() - + def delete_zone(self): self.zone.delete() self.zone = None self.zone_limit.delete() self.zone_limit = None bs.getsound('shieldDown').play() - bs.timer(1,self.spawn_zone) - + bs.timer(1, self.spawn_zone) + def move_zone(self): - if self.zone_pos[0] > 0: x = random.randrange(0,10) - else: x = random.randrange(-10,0) - - if self.zone_pos[2] > 0: y = random.randrange(0,5) - else: y = random.randrange(-5,0) - - new_pos = (x,0.05,y) - bs.animate_array(self.zone, 'position', 3,{0:self.zone.position, 8:new_pos}) - bs.animate_array(self.zone_limit, 'position', 3,{0:self.zone_limit.position,8:new_pos}) - + if self.zone_pos[0] > 0: + x = random.randrange(0, 10) + else: + x = random.randrange(-10, 0) + + if self.zone_pos[2] > 0: + y = random.randrange(0, 5) + else: + y = random.randrange(-5, 0) + + new_pos = (x, 0.05, y) + bs.animate_array(self.zone, 'position', 3, {0: self.zone.position, 8: new_pos}) + bs.animate_array(self.zone_limit, 'position', 3, {0: self.zone_limit.position, 8: new_pos}) + def start_timer(self): count = self.get_players_count() - self._time_remaining = 10 if count > 9 else count-1 if count > 6 else count if count > 2 else count*2 - self._timer_x = bs.Timer(1.0,bs.WeakCall(self.tick),repeat=True) + self._time_remaining = 10 if count > 9 else count-1 if count > 6 else count if count > 2 else count*2 + self._timer_x = bs.Timer(1.0, bs.WeakCall(self.tick), repeat=True) # gnode = bs.getactivity().globalsnode # tint = gnode.tint # bs.animate_array(gnode,'tint',3,{0:tint,self._time_remaining*1.5:(1.0,0.5,0.5),self._time_remaining*1.55:tint}) - + def stop_timer(self): self._time = None self._timer_x = None - + def tick(self): self.check_players() self._time = bs.NodeActor(bs.newnode('text', - attrs={'v_attach':'top','h_attach':'center', - 'text':kill_timer+str(self._time_remaining)+'s', - 'opacity':0.8,'maxwidth':100,'h_align':'center', - 'v_align':'center','shadow':1.0,'flatness':1.0, - 'color':(1,1,1),'scale':1.5,'position':(0,-50)} - ) - ) + attrs={'v_attach': 'top', 'h_attach': 'center', + 'text': kill_timer+str(self._time_remaining)+'s', + 'opacity': 0.8, 'maxwidth': 100, 'h_align': 'center', + 'v_align': 'center', 'shadow': 1.0, 'flatness': 1.0, + 'color': (1, 1, 1), 'scale': 1.5, 'position': (0, -50)} + ) + ) self._time_remaining -= 1 self._tick_sound.play() - + def check_players(self): if self._time_remaining <= 0: self.stop_timer() - bs.animate_array(self.zone, 'size', 1,{0:[self.last_players_count*0.8], 1.4:[self.last_players_count*0.8],1.5:[0]}) - bs.animate_array(self.zone_limit, 'size', 1,{0:[self.last_players_count*0.95], 1.45:[self.last_players_count*0.95],1.5:[0]}) - bs.timer(1.5,self.delete_zone) + bs.animate_array(self.zone, 'size', 1, { + 0: [self.last_players_count*0.8], 1.4: [self.last_players_count*0.8], 1.5: [0]}) + bs.animate_array(self.zone_limit, 'size', 1, { + 0: [self.last_players_count*0.95], 1.45: [self.last_players_count*0.95], 1.5: [0]}) + bs.timer(1.5, self.delete_zone) for player in self.players: if not player.actor is None: if player.actor.is_alive(): p1 = player.actor.node.position p2 = self.zone.position - diff = (babase.Vec3(p1[0]-p2[0],0.0,p1[2]-p2[2])) + diff = (babase.Vec3(p1[0]-p2[0], 0.0, p1[2]-p2[2])) dist = (diff.length()) if dist > (self.get_players_count()*0.7): player.actor.handlemessage(bs.DieMessage()) - + def get_players_count(self): count = 0 for player in self.players: @@ -438,7 +451,7 @@ class SafeZoneGame(bs.TeamGameActivity[Player, Team]): if player.actor.is_alive(): count += 1 return count - + def _update_solo_mode(self) -> None: # For both teams, find the first player on the spawn order list with # lives remaining and spawn them if they're not alive. @@ -558,9 +571,9 @@ class SafeZoneGame(bs.TeamGameActivity[Player, Team]): # spaz but *without* the ability to attack or pick stuff up. actor.connect_controls_to_player(enable_punch=False, - enable_bomb=False, - enable_pickup=False) - + enable_bomb=False, + enable_pickup=False) + # If we have any icons, update their state. for icon in player.icons: icon.handle_player_spawned() @@ -642,38 +655,42 @@ class SafeZoneGame(bs.TeamGameActivity[Player, Team]): if self._solo_mode: player.team.spawn_order.remove(player) player.team.spawn_order.append(player) - elif isinstance(msg,stdbot.SpazBotDiedMessage): + elif isinstance(msg, stdbot.SpazBotDiedMessage): self._on_spaz_bot_died(msg) - - def _on_spaz_bot_died(self,die_msg): - bs.timer(1,babase.Call(self.add_bot,die_msg.spazbot.node.position)) - - def _on_bot_spawn(self,spaz): + + def _on_spaz_bot_died(self, die_msg): + bs.timer(1, babase.Call(self.add_bot, die_msg.spazbot.node.position)) + + def _on_bot_spawn(self, spaz): spaz.update_callback = self.move_bot spaz_type = type(spaz) spaz._charge_speed = self._get_bot_speed(spaz_type) - def add_bot(self,pos=None): - if pos == 'left': position = (-11,0,random.randrange(-5,5)) - elif pos == 'right': position = (11,0,random.randrange(-5,5)) - else: position = pos - self._bots.spawn_bot(self.get_random_bot(),pos=position,spawn_time=1,on_spawn_call=babase.Call(self._on_bot_spawn)) + def add_bot(self, pos=None): + if pos == 'left': + position = (-11, 0, random.randrange(-5, 5)) + elif pos == 'right': + position = (11, 0, random.randrange(-5, 5)) + else: + position = pos + self._bots.spawn_bot(self.get_random_bot(), pos=position, spawn_time=1, + on_spawn_call=babase.Call(self._on_bot_spawn)) - def move_bot(self,bot): + def move_bot(self, bot): p = bot.node.position - speed = -bot._charge_speed if(p[0]>=-11 and p[0]<0) else bot._charge_speed - - if (p[0]>=-11) and (p[0]<=11): + speed = -bot._charge_speed if (p[0] >= -11 and p[0] < 0) else bot._charge_speed + + if (p[0] >= -11) and (p[0] <= 11): bot.node.move_left_right = speed bot.node.move_up_down = 0.0 bot.node.run = 0.0 return True return False - + def get_random_bot(self): bots = [stdbot.BomberBotStatic, stdbot.TriggerBotStatic] return (random.choice(bots)) - + def _get_bot_speed(self, bot_type): if bot_type == stdbot.BomberBotStatic: return 0.48 @@ -681,7 +698,7 @@ class SafeZoneGame(bs.TeamGameActivity[Player, Team]): return 0.73 else: raise Exception('Invalid bot type to _getBotSpeed(): '+str(bot_type)) - + def _update(self) -> None: if self._solo_mode: # For both teams, find the first player on the spawn order diff --git a/plugins/utilities/InfinityShield.py b/plugins/utilities/InfinityShield.py index a224ba3..9510452 100644 --- a/plugins/utilities/InfinityShield.py +++ b/plugins/utilities/InfinityShield.py @@ -18,6 +18,8 @@ if TYPE_CHECKING: Spaz._old_init = Spaz.__init__ + + def __init__(self, color: Sequence[float] = (1.0, 1.0, 1.0), highlight: Sequence[float] = (0.5, 0.5, 0.5), @@ -27,10 +29,11 @@ def __init__(self, can_accept_powerups: bool = True, powerups_expire: bool = False, demo_mode: bool = False): - self._old_init(color,highlight,character,source_player,start_invincible, - can_accept_powerups,powerups_expire,demo_mode) + self._old_init(color, highlight, character, source_player, start_invincible, + can_accept_powerups, powerups_expire, demo_mode) if self.source_player: self.equip_shields() + def animate_shield(): if not self.shield: return @@ -41,6 +44,7 @@ def __init__(self, bs.timer(0.2, animate_shield, repeat=True) self.impact_scale = 0 + def equip_shields(self, decay: bool = False) -> None: """ Give this spaz a nice energy shield. diff --git a/plugins/utilities/Tag.py b/plugins/utilities/Tag.py index 4ec9a9d..24139ae 100644 --- a/plugins/utilities/Tag.py +++ b/plugins/utilities/Tag.py @@ -29,7 +29,7 @@ from typing import ( Tuple, Optional, Sequence, - Union, + Union, Callable, Any, List, @@ -52,18 +52,22 @@ Configs = { } # Useful global fucntions + + def setconfigs() -> None: """ Set required defualt configs for mod """ cnfg = babase.app.config profiles = cnfg['Player Profiles'] - if not "TagConf" in cnfg: cnfg["TagConf"] = {} + if not "TagConf" in cnfg: + cnfg["TagConf"] = {} for p in profiles: if not p in cnfg["TagConf"]: cnfg["TagConf"][str(p)] = Configs babase.app.config.apply_and_commit() + def getanimcolor(name: str) -> dict: """ Returns dictnary of colors with prefective time -> {seconds: (r, g, b)} @@ -72,14 +76,15 @@ def getanimcolor(name: str) -> dict: s1 = 0.0 s2 = s1 + freq s3 = s2 + freq - + animcolor = { - s1: (1,0,0), - s2: (0,1,0), - s3: (0,0,1) + s1: (1, 0, 0), + s2: (0, 1, 0), + s3: (0, 0, 1) } return animcolor + def gethostname() -> str: """ Return player name, by using -1 only host can use tags. @@ -94,17 +99,20 @@ def gethostname() -> str: return '__account__' return name + # Dummy functions for extend functionality for class object PlayerSpaz.init = PlayerSpaz.__init__ EditProfileWindow.init = EditProfileWindow.__init__ # PlayerSpaz object at -> bascenev1lib.actor.playerspaz + + def NewPlayerSzapInit(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', - powerups_expire: bool = True) -> None: + player: bs.Player, + color: Sequence[float] = (1.0, 1.0, 1.0), + highlight: Sequence[float] = (0.5, 0.5, 0.5), + character: str = 'Spaz', + powerups_expire: bool = True) -> None: self.init(player, color, highlight, character, powerups_expire) self.curname = gethostname() @@ -112,7 +120,8 @@ def NewPlayerSzapInit(self, cnfg = babase.app.config["TagConf"] if cnfg[str(self.curname)]["enabletag"]: # Tag node - self.mnode = bs.newnode('math', owner=self.node, attrs={'input1': (0, 1.5, 0),'operation': 'add'}) + self.mnode = bs.newnode('math', owner=self.node, attrs={ + 'input1': (0, 1.5, 0), 'operation': 'add'}) self.node.connectattr('torso_position', self.mnode, 'input2') tagtext = cnfg[str(self.curname)]["tag"] @@ -120,7 +129,7 @@ def NewPlayerSzapInit(self, shadow = cnfg[str(self.curname)]["shadow"] sl = cnfg[str(self.curname)]["scale"] scale = 0.01 if sl == 'mediam' else 0.009 if not sl == 'large' else 0.02 - + self.Tag = bs.newnode( type='text', owner=self.node, @@ -128,7 +137,7 @@ def NewPlayerSzapInit(self, 'text': str(tagtext), 'in_world': True, 'shadow': shadow, - 'color': (0,0,0), + 'color': (0, 0, 0), 'scale': scale, 'opacity': opacity, 'flatness': 1.0, @@ -138,13 +147,14 @@ def NewPlayerSzapInit(self, if cnfg[str(self.curname)]["animtag"]: kys = getanimcolor(self.curname) bs.animate_array(node=self.Tag, attr='color', size=3, keys=kys, loop=True) - except Exception: pass + except Exception: + pass def NewEditProfileWindowInit(self, - existing_profile: Optional[str], - in_main_menu: bool, - transition: str = 'in_right') -> None: + existing_profile: Optional[str], + in_main_menu: bool, + transition: str = 'in_right') -> None: """ New boilerplate for editprofilewindow, addeds button to call TagSettings window """ @@ -156,17 +166,18 @@ def NewEditProfileWindowInit(self, x_inset = self._x_inset b_width = 50 b_height = 30 - + self.tagwinbtn = bui.buttonwidget( - parent=self._root_widget, - autoselect=True, - position=(505 + x_inset, v - 38 - 15), - size=(b_width, b_height), - color=(0.6, 0.5, 0.6), - label='Tag', - button_type='square', - text_scale=1.2, - on_activate_call=babase.Call(_on_tagwinbtn_press, self)) + parent=self._root_widget, + autoselect=True, + position=(505 + x_inset, v - 38 - 15), + size=(b_width, b_height), + color=(0.6, 0.5, 0.6), + label='Tag', + button_type='square', + text_scale=1.2, + on_activate_call=babase.Call(_on_tagwinbtn_press, self)) + def _on_tagwinbtn_press(self): """ @@ -174,10 +185,10 @@ def _on_tagwinbtn_press(self): """ bui.containerwidget(edit=self._root_widget, transition='out_scale') bui.app.ui_v1.set_main_menu_window( - TagWindow(self.existing_profile, - self.in_main_menu, - self._name, - transition='in_right').get_root_widget(), from_window=self._root_widget) + TagWindow(self.existing_profile, + self.in_main_menu, + self._name, + transition='in_right').get_root_widget(), from_window=self._root_widget) # ba_meta require api 8 @@ -188,10 +199,10 @@ class Tag(babase.Plugin): Tag above actor player head, replacing PlayerSpaz class for getting actor, using EditProfileWindow for UI. """ - if _babase.env().get("build_number",0) >= 20327: + if _babase.env().get("build_number", 0) >= 20327: setconfigs() self.Replace() - + def Replace(self) -> None: """ Replacing bolierplates no harm to relative funtionality only extending @@ -203,10 +214,10 @@ class Tag(babase.Plugin): class TagWindow(bui.Window): def __init__(self, - existing_profile: Optional[str], - in_main_menu: bool, - profilename: str, - transition: Optional[str] = 'in_right'): + existing_profile: Optional[str], + in_main_menu: bool, + profilename: str, + transition: Optional[str] = 'in_right'): self.existing_profile = existing_profile self.in_main_menu = in_main_menu self.profilename = profilename @@ -220,205 +231,205 @@ class TagWindow(bui.Window): top_extra = 20 if uiscale is babase.UIScale.SMALL else 0 super().__init__( - root_widget=bui.containerwidget( + root_widget=bui.containerwidget( size=(self._width, self._height), transition=transition, scale=(2.06 if uiscale is babase.UIScale.SMALL else - 1.4 if uiscale is babase.UIScale.MEDIUM else 1.0))) - + 1.4 if uiscale is babase.UIScale.MEDIUM else 1.0))) + self._back_button = bui.buttonwidget( - parent=self._root_widget, - autoselect=True, - selectable=False, # FIXME: when press a in text field it selets to button - position=(52 + self.extra_x, self._height - 60), - size=(60, 60), - scale=0.8, - label=babase.charstr(babase.SpecialChar.BACK), - button_type='backSmall', - on_activate_call=self._back) + parent=self._root_widget, + autoselect=True, + selectable=False, # FIXME: when press a in text field it selets to button + position=(52 + self.extra_x, self._height - 60), + size=(60, 60), + scale=0.8, + label=babase.charstr(babase.SpecialChar.BACK), + button_type='backSmall', + on_activate_call=self._back) bui.containerwidget(edit=self._root_widget, cancel_button=self._back_button) self._save_button = bui.buttonwidget( - parent=self._root_widget, - position=(self._width - (177 + extra_x), - self._height - 60), - size=(155, 60), - color=(0, 0.7, 0.5), - autoselect=True, - selectable=False, # FIXME: when press a in text field it selets to button - scale=0.8, - label=babase.Lstr(resource='saveText'), - on_activate_call=self.on_save) + parent=self._root_widget, + position=(self._width - (177 + extra_x), + self._height - 60), + size=(155, 60), + color=(0, 0.7, 0.5), + autoselect=True, + selectable=False, # FIXME: when press a in text field it selets to button + scale=0.8, + label=babase.Lstr(resource='saveText'), + on_activate_call=self.on_save) bui.widget(edit=self._save_button, left_widget=self._back_button) bui.widget(edit=self._back_button, right_widget=self._save_button) bui.containerwidget(edit=self._root_widget, start_button=self._save_button) self._title_text = bui.textwidget( - parent=self._root_widget, - position=(0, self._height - 52 - top_extra), - size=(self._width, 25), - text='Tag', - color=bui.app.ui_v1.title_color, - scale=1.5, - h_align='center', - v_align='top') - + parent=self._root_widget, + position=(0, self._height - 52 - top_extra), + size=(self._width, 25), + text='Tag', + color=bui.app.ui_v1.title_color, + scale=1.5, + h_align='center', + v_align='top') + self._scroll_width = self._width - (100 + 2 * extra_x) self._scroll_height = self._height - 115.0 self._sub_width = self._scroll_width * 0.95 self._sub_height = 724.0 self._spacing = 32 self._extra_button_spacing = self._spacing * 2.5 - + self._scrollwidget = bui.scrollwidget( - parent=self._root_widget, - position=(50 + extra_x, 50), - simple_culling_v=20.0, - highlight=False, - size=(self._scroll_width, - self._scroll_height), - selection_loops_to_parent=True) + parent=self._root_widget, + position=(50 + extra_x, 50), + simple_culling_v=20.0, + highlight=False, + size=(self._scroll_width, + self._scroll_height), + selection_loops_to_parent=True) bui.widget(edit=self._scrollwidget, right_widget=self._scrollwidget) - + self._subcontainer = bui.containerwidget( - parent=self._scrollwidget, - size=(self._sub_width, - self._sub_height), - background=False, - selection_loops_to_parent=True) - + parent=self._scrollwidget, + size=(self._sub_width, + self._sub_height), + background=False, + selection_loops_to_parent=True) + v = self._sub_height - 35 v -= self._spacing * 1.2 - + self._prof = babase.app.config["TagConf"][self.profilename] self.enabletagcb = bui.checkboxwidget( - parent=self._subcontainer, - autoselect=False, - position=(10.0, v + 30), - size=(10, 10), - text='Enable Tag', - textcolor=(0.8, 0.8, 0.8), - value=self._prof['enabletag'], - on_value_change_call=babase.Call(self.change_val, [f'{self.profilename}', 'enabletag']), - scale=1.1 if uiscale is babase.UIScale.SMALL else 1.5, - maxwidth=430) - + parent=self._subcontainer, + autoselect=False, + position=(10.0, v + 30), + size=(10, 10), + text='Enable Tag', + textcolor=(0.8, 0.8, 0.8), + value=self._prof['enabletag'], + on_value_change_call=babase.Call(self.change_val, [f'{self.profilename}', 'enabletag']), + scale=1.1 if uiscale is babase.UIScale.SMALL else 1.5, + maxwidth=430) + self.tag_text = bui.textwidget( - parent=self._subcontainer, - text='Tag', - position=(25.0, v - 30), - flatness=1.0, - scale=1.55, - maxwidth=430, - h_align='center', - v_align='center', - color=(0.8, 0.8, 0.8)) - + parent=self._subcontainer, + text='Tag', + position=(25.0, v - 30), + flatness=1.0, + scale=1.55, + maxwidth=430, + h_align='center', + v_align='center', + color=(0.8, 0.8, 0.8)) + self.tagtextfield = bui.textwidget( - parent=self._subcontainer, - position=(100.0, v - 45), - size=(350, 50), - text=self._prof["tag"], - h_align='center', - v_align='center', - max_chars=16, - autoselect=True, - editable=True, - padding=4, - color=(0.9, 0.9, 0.9, 1.0)) - + parent=self._subcontainer, + position=(100.0, v - 45), + size=(350, 50), + text=self._prof["tag"], + h_align='center', + v_align='center', + max_chars=16, + autoselect=True, + editable=True, + padding=4, + color=(0.9, 0.9, 0.9, 1.0)) + self.tag_color_text = bui.textwidget( - parent=self._subcontainer, - text='Color', - position=(40.0, v - 80), - flatness=1.0, - scale=1.25, - maxwidth=430, - h_align='center', - v_align='center', - color=(0.8, 0.8, 0.8)) - + parent=self._subcontainer, + text='Color', + position=(40.0, v - 80), + flatness=1.0, + scale=1.25, + maxwidth=430, + h_align='center', + v_align='center', + color=(0.8, 0.8, 0.8)) + self.tag_scale_text = bui.textwidget( - parent=self._subcontainer, - text='Scale', - position=(40.0, v - 130), - flatness=1.0, - scale=1.25, - maxwidth=430, - h_align='center', - v_align='center', - color=(0.8, 0.8, 0.8)) - + parent=self._subcontainer, + text='Scale', + position=(40.0, v - 130), + flatness=1.0, + scale=1.25, + maxwidth=430, + h_align='center', + v_align='center', + color=(0.8, 0.8, 0.8)) + self.tag_scale_button = PopupMenu( - parent=self._subcontainer, - position=(330.0, v - 145), - width=150, - autoselect=True, - on_value_change_call=bs.WeakCall(self._on_menu_choice), - choices=['large', 'medium', 'small'], - button_size=(150, 50), - #choices_display=('large', 'medium', 'small'), - current_choice=self._prof["scale"]) - + parent=self._subcontainer, + position=(330.0, v - 145), + width=150, + autoselect=True, + on_value_change_call=bs.WeakCall(self._on_menu_choice), + choices=['large', 'medium', 'small'], + button_size=(150, 50), + # choices_display=('large', 'medium', 'small'), + current_choice=self._prof["scale"]) + CustomConfigNumberEdit( - parent=self._subcontainer, - position=(40.0, v - 180), - xoffset=65, - displayname='Opacity', - configkey=['TagConf', f'{self.profilename}', 'opacity'], - changesound=False, - minval=0.5, - maxval=2.0, - increment=0.1, - textscale=1.25) - + parent=self._subcontainer, + position=(40.0, v - 180), + xoffset=65, + displayname='Opacity', + configkey=['TagConf', f'{self.profilename}', 'opacity'], + changesound=False, + minval=0.5, + maxval=2.0, + increment=0.1, + textscale=1.25) + CustomConfigNumberEdit( - parent=self._subcontainer, - position=(40.0, v - 230), - xoffset=65, - displayname='Shadow', - configkey=['TagConf', f'{self.profilename}', 'shadow'], - changesound=False, - minval=0.0, - maxval=2.0, - increment=0.1, - textscale=1.25) - + parent=self._subcontainer, + position=(40.0, v - 230), + xoffset=65, + displayname='Shadow', + configkey=['TagConf', f'{self.profilename}', 'shadow'], + changesound=False, + minval=0.0, + maxval=2.0, + increment=0.1, + textscale=1.25) + self.enabletaganim = bui.checkboxwidget( - parent=self._subcontainer, - autoselect=True, - position=(10.0, v - 280), - size=(10, 10), - text='Animate tag', - textcolor=(0.8, 0.8, 0.8), - value=self._prof['enabletag'], - on_value_change_call=babase.Call(self.change_val, [f'{self.profilename}', 'animtag']), - scale=1.1 if uiscale is babase.UIScale.SMALL else 1.5, - maxwidth=430) - + parent=self._subcontainer, + autoselect=True, + position=(10.0, v - 280), + size=(10, 10), + text='Animate tag', + textcolor=(0.8, 0.8, 0.8), + value=self._prof['enabletag'], + on_value_change_call=babase.Call(self.change_val, [f'{self.profilename}', 'animtag']), + scale=1.1 if uiscale is babase.UIScale.SMALL else 1.5, + maxwidth=430) + CustomConfigNumberEdit( - parent=self._subcontainer, - position=(40.0, v - 330), - xoffset=65, - displayname='Frequency', - configkey=['TagConf', f'{self.profilename}', 'frequency'], - changesound=False, - minval=0.1, - maxval=5.0, - increment=0.1, - textscale=1.25) - + parent=self._subcontainer, + position=(40.0, v - 330), + xoffset=65, + displayname='Frequency', + configkey=['TagConf', f'{self.profilename}', 'frequency'], + changesound=False, + minval=0.1, + maxval=5.0, + increment=0.1, + textscale=1.25) + def _back(self) -> None: """ transit window into back window """ bui.containerwidget(edit=self._root_widget, - transition='out_scale') + transition='out_scale') bui.app.ui_v1.set_main_menu_window(EditProfileWindow( - self.existing_profile, - self.in_main_menu, - transition='in_left').get_root_widget(), from_window=self._root_widget) - + self.existing_profile, + self.in_main_menu, + transition='in_left').get_root_widget(), from_window=self._root_widget) + def change_val(self, config: List[str], val: bool) -> None: """ chamges the value of check boxes @@ -428,10 +439,10 @@ class TagWindow(bui.Window): cnfg[config[0]][config[1]] = val bui.getsound('gunCocking').play() except Exception: - bui.screenmessage("error", color=(1,0,0)) + bui.screenmessage("error", color=(1, 0, 0)) bui.getsound('error').play() babase.app.config.apply_and_commit() - + def _on_menu_choice(self, choice: str): """ Changes the given choice in configs @@ -439,7 +450,7 @@ class TagWindow(bui.Window): cnfg = babase.app.config["TagConf"][self.profilename] cnfg["scale"] = choice babase.app.config.apply_and_commit() - + def on_save(self): """ Gets the text in text field of tag and then save it @@ -451,15 +462,15 @@ class TagWindow(bui.Window): babase.app.config.apply_and_commit() bui.getsound('gunCocking').play() else: - bui.screenmessage(f"please define tag", color=(1,0,0)) + bui.screenmessage(f"please define tag", color=(1, 0, 0)) bui.getsound('error').play() - + bui.containerwidget(edit=self._root_widget, - transition='out_scale') + transition='out_scale') bui.app.ui_v1.set_main_menu_window(EditProfileWindow( - self.existing_profile, - self.in_main_menu, - transition='in_left').get_root_widget(), from_window=self._root_widget) + self.existing_profile, + self.in_main_menu, + transition='in_left').get_root_widget(), from_window=self._root_widget) class CustomConfigNumberEdit: @@ -503,46 +514,46 @@ class CustomConfigNumberEdit: self._value = babase.app.config[configkey[0]][configkey[1]][configkey[2]] self.nametext = bui.textwidget( - parent=parent, - position=position, - size=(100, 30), - text=displayname, - maxwidth=160 + xoffset, - color=(0.8, 0.8, 0.8, 1.0), - h_align='left', - v_align='center', - scale=textscale) - + parent=parent, + position=position, + size=(100, 30), + text=displayname, + maxwidth=160 + xoffset, + color=(0.8, 0.8, 0.8, 1.0), + h_align='left', + v_align='center', + scale=textscale) + self.valuetext = bui.textwidget( - parent=parent, - position=(246 + xoffset, position[1]), - size=(60, 28), - editable=False, - color=(0.3, 1.0, 0.3, 1.0), - h_align='right', - v_align='center', - text=str(self._value), - padding=2) - + parent=parent, + position=(246 + xoffset, position[1]), + size=(60, 28), + editable=False, + color=(0.3, 1.0, 0.3, 1.0), + h_align='right', + v_align='center', + text=str(self._value), + padding=2) + self.minusbutton = bui.buttonwidget( - parent=parent, - position=(330 + xoffset, position[1]), - size=(28, 28), - label='-', - autoselect=True, - on_activate_call=babase.Call(self._down), - repeat=True, - enable_sound=changesound) - + parent=parent, + position=(330 + xoffset, position[1]), + size=(28, 28), + label='-', + autoselect=True, + on_activate_call=babase.Call(self._down), + repeat=True, + enable_sound=changesound) + self.plusbutton = bui.buttonwidget(parent=parent, - position=(380 + xoffset, position[1]), - size=(28, 28), - label='+', - autoselect=True, - on_activate_call=babase.Call(self._up), - repeat=True, - enable_sound=changesound) - + position=(380 + xoffset, position[1]), + size=(28, 28), + label='+', + autoselect=True, + on_activate_call=babase.Call(self._up), + repeat=True, + enable_sound=changesound) + bui.uicleanupcheck(self, self.nametext) self._update_display() @@ -558,8 +569,9 @@ class CustomConfigNumberEdit: self._update_display() if self._callback: self._callback(self._value) - babase.app.config[self._configkey[0]][self._configkey[1]][self._configkey[2]] = float(str(f'{self._value:.1f}')) + babase.app.config[self._configkey[0]][self._configkey[1] + ][self._configkey[2]] = float(str(f'{self._value:.1f}')) babase.app.config.apply_and_commit() def _update_display(self) -> None: - bui.textwidget(edit=self.valuetext, text=f'{self._value:.1f}') \ No newline at end of file + bui.textwidget(edit=self.valuetext, text=f'{self._value:.1f}') diff --git a/plugins/utilities/disable_friendly_fire.py b/plugins/utilities/disable_friendly_fire.py index 0771cfe..e8bf84e 100644 --- a/plugins/utilities/disable_friendly_fire.py +++ b/plugins/utilities/disable_friendly_fire.py @@ -12,85 +12,89 @@ from bascenev1lib.gameutils import SharedObjects if TYPE_CHECKING: pass + class BombPickupMessage: """ message says that someone pick up the dropped bomb """ + # for bs.FreezeMessage freeze: bool = True # ba_meta export plugin + + class Plugin(babase.Plugin): - + # there are two ways to ignore our team player hits # either change playerspaz handlemessage or change spaz handlemessage def playerspaz_new_handlemessage(func: fuction) -> fuction: def wrapper(*args, **kwargs): global freeze - - # only run if session is dual team + + # only run if session is dual team if isinstance(args[0].activity.session, bs.DualTeamSession): # when spaz got hurt by any reason this statement is runs. if isinstance(args[1], bs.HitMessage): our_team_players: list[type(args[0]._player)] - + # source_player attacker = args[1].get_source_player(type(args[0]._player)) - + # our team payers our_team_players = args[0]._player.team.players.copy() - + if len(our_team_players) > 0: - - # removing our self - our_team_players.remove(args[0]._player) - - # if we honding teammate or if we have a shield, do hit. - for player in our_team_players: - if player.actor.exists() and args[0]._player.actor.exists(): - if args[0]._player.actor.node.hold_node == player.actor.node or args[0]._player.actor.shield: - our_team_players.remove(player) - break - - if attacker in our_team_players: - freeze = False - return None - else: - freeze = True - + + # removing our self + our_team_players.remove(args[0]._player) + + # if we honding teammate or if we have a shield, do hit. + for player in our_team_players: + if player.actor.exists() and args[0]._player.actor.exists(): + if args[0]._player.actor.node.hold_node == player.actor.node or args[0]._player.actor.shield: + our_team_players.remove(player) + break + + if attacker in our_team_players: + freeze = False + return None + else: + freeze = True + # if ice_bomb blast hits any spaz this statement runs. elif isinstance(args[1], bs.FreezeMessage): if not freeze: - freeze = True # use it and reset it + freeze = True # use it and reset it return None # orignal unchanged code goes here func(*args, **kwargs) - + return wrapper - + # replace original fuction to modified function bascenev1lib.actor.playerspaz.PlayerSpaz.handlemessage = playerspaz_new_handlemessage( bascenev1lib.actor.playerspaz.PlayerSpaz.handlemessage) - + # let's add a message when bomb is pick by player def bombfact_new_init(func: function) -> function: def wrapper(*args): - - func(*args) # original code - + + func(*args) # original code + args[0].bomb_material.add_actions( conditions=('they_have_material', SharedObjects.get().pickup_material), actions=('message', 'our_node', 'at_connect', BombPickupMessage()), ) return wrapper - + # you get the idea bascenev1lib.actor.bomb.BombFactory.__init__ = bombfact_new_init( bascenev1lib.actor.bomb.BombFactory.__init__) - + def bomb_new_handlemessage(func: function) -> function: def wrapper(*args, **kwargs): - # only run if session is dual team + # only run if session is dual team if isinstance(args[0].activity.session, bs.DualTeamSession): if isinstance(args[1], BombPickupMessage): # get the pickuper and assign the pickuper to the source_player(attacker) of bomb blast @@ -99,10 +103,10 @@ class Plugin(babase.Plugin): if player.actor.node.hold_node == args[0].node: args[0]._source_player = player break - - func(*args, **kwargs) # original - + + func(*args, **kwargs) # original + return wrapper bascenev1lib.actor.bomb.Bomb.handlemessage = bomb_new_handlemessage( - bascenev1lib.actor.bomb.Bomb.handlemessage) \ No newline at end of file + bascenev1lib.actor.bomb.Bomb.handlemessage) From f744c41d7d59efe3bf61c77d2c0f5f7137a7a9f0 Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Wed, 24 Jan 2024 14:28:11 +0300 Subject: [PATCH 03/36] i -> I --- plugins/utilities.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 2c5f025..d48ee7b 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -1086,7 +1086,7 @@ "1.0.0": null } }, - "infinityShield": { + "InfinityShield": { "description": "Gives you unbreakable shield", "external_url": "https://youtu.be/hp7vbB-hUPg?si=i7Th0NP5xDPLN2P_", "authors": [ From 6de5f5f3a7fcc0e82c61d40493fedd38b9426f8b Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Wed, 24 Jan 2024 11:29:20 +0000 Subject: [PATCH 04/36] [ci] apply-version-metadata --- plugins/minigames.json | 49 ++++++++++++++++++++++++++++++++++++------ plugins/utilities.json | 30 +++++++++++++++++++++----- 2 files changed, 67 insertions(+), 12 deletions(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index d9d5323..06a4091 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -979,7 +979,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "f744c41", + "released_on": "24-01-2024", + "md5sum": "c1c96450fbdb6e5b2f0d26bb4e797236" + } } }, "HYPER_RACE": { @@ -993,7 +998,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "f744c41", + "released_on": "24-01-2024", + "md5sum": "8b423bdae256bd411489528b550b8bd9" + } } }, "meteorshowerdeluxe": { @@ -1007,7 +1017,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "f744c41", + "released_on": "24-01-2024", + "md5sum": "7e86bbc8e3ebb26a66602068950adfbf" + } } }, "ofuuuAttack": { @@ -1021,7 +1036,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "f744c41", + "released_on": "24-01-2024", + "md5sum": "982c72f2d2cb3d50280f50b022e7865f" + } } }, "safe_zone": { @@ -1035,7 +1055,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "f744c41", + "released_on": "24-01-2024", + "md5sum": "862fab0c26947c70397542742fb82635" + } } }, "SnowBallFight": { @@ -1049,7 +1074,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "f744c41", + "released_on": "24-01-2024", + "md5sum": "ef6bd7cd0404674f65e8f8d4da3ab8c8" + } } }, "EggGame": { @@ -1063,7 +1093,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "f744c41", + "released_on": "24-01-2024", + "md5sum": "e1d401ec8f2d06dec741d713d6602710" + } } } } diff --git a/plugins/utilities.json b/plugins/utilities.json index d48ee7b..8a7d763 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -1083,7 +1083,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "f744c41", + "released_on": "24-01-2024", + "md5sum": "203ecefa1c1eb9894cfb0d87e2d7fe09" + } } }, "InfinityShield": { @@ -1097,7 +1102,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "f744c41", + "released_on": "24-01-2024", + "md5sum": "eb917ca19d206dfd19667181dacc1df5" + } } }, "OnlyNight": { @@ -1111,7 +1121,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "f744c41", + "released_on": "24-01-2024", + "md5sum": "255d3d6694008cc2f73d115182100b52" + } } }, "Tag": { @@ -1125,8 +1140,13 @@ } ], "versions": { - "2.0.1": null + "2.0.1": { + "api_version": 8, + "commit_sha": "f744c41", + "released_on": "24-01-2024", + "md5sum": "01cf9e10ab0e1bf51c07d80ff842c632" + } } - } + } } } \ No newline at end of file From fcd4cc8169fbee92d183d6294d93a78ea91bd2c1 Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Wed, 24 Jan 2024 21:14:55 +0300 Subject: [PATCH 05/36] =?UTF-8?q?=F0=9F=90=8D=F0=9F=92=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- plugins/minigames.json | 73 +-- plugins/minigames/{EggGame.py => egg_game.py} | 0 ...howerdeluxe.py => meteor_shower_deluxe.py} | 0 .../{ofuuuAttack.py => ofuuu_attack.py} | 0 .../{SnowBallFight.py => snow_ball_fight.py} | 0 plugins/minigames/you_vs_bombsquad.py | 486 ++++++++++++++++++ plugins/utilities.json | 27 +- .../{InfinityShield.py => infinity_shield.py} | 0 .../utilities/{OnlyNight.py => only_night.py} | 0 9 files changed, 518 insertions(+), 68 deletions(-) rename plugins/minigames/{EggGame.py => egg_game.py} (100%) rename plugins/minigames/{meteorshowerdeluxe.py => meteor_shower_deluxe.py} (100%) rename plugins/minigames/{ofuuuAttack.py => ofuuu_attack.py} (100%) rename plugins/minigames/{SnowBallFight.py => snow_ball_fight.py} (100%) create mode 100644 plugins/minigames/you_vs_bombsquad.py rename plugins/utilities/{InfinityShield.py => infinity_shield.py} (100%) rename plugins/utilities/{OnlyNight.py => only_night.py} (100%) diff --git a/plugins/minigames.json b/plugins/minigames.json index 06a4091..44e1e93 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -968,7 +968,7 @@ } } }, - "Avalanche": { + "avalanche": { "description": "Dodge the falling ice bombs", "external_url": "", "authors": [ @@ -979,15 +979,10 @@ } ], "versions": { - "1.0.0": { - "api_version": 8, - "commit_sha": "f744c41", - "released_on": "24-01-2024", - "md5sum": "c1c96450fbdb6e5b2f0d26bb4e797236" - } + "1.0.0": null } }, - "HYPER_RACE": { + "hyper_race": { "description": "Race and avoid the obsatacles", "external_url": "", "authors": [ @@ -998,15 +993,10 @@ } ], "versions": { - "1.0.0": { - "api_version": 8, - "commit_sha": "f744c41", - "released_on": "24-01-2024", - "md5sum": "8b423bdae256bd411489528b550b8bd9" - } + "1.0.0": null } }, - "meteorshowerdeluxe": { + "meteor_shower_deluxe": { "description": "Meteor shower on all maps support", "external_url": "", "authors": [ @@ -1017,15 +1007,10 @@ } ], "versions": { - "1.0.0": { - "api_version": 8, - "commit_sha": "f744c41", - "released_on": "24-01-2024", - "md5sum": "7e86bbc8e3ebb26a66602068950adfbf" - } + "1.0.0": null } }, - "ofuuuAttack": { + "ofuuu_attack": { "description": "Dodge the falling bombs.", "external_url": "", "authors": [ @@ -1036,12 +1021,7 @@ } ], "versions": { - "1.0.0": { - "api_version": 8, - "commit_sha": "f744c41", - "released_on": "24-01-2024", - "md5sum": "982c72f2d2cb3d50280f50b022e7865f" - } + "1.0.0": null } }, "safe_zone": { @@ -1055,15 +1035,10 @@ } ], "versions": { - "1.0.0": { - "api_version": 8, - "commit_sha": "f744c41", - "released_on": "24-01-2024", - "md5sum": "862fab0c26947c70397542742fb82635" - } + "1.0.0": null } }, - "SnowBallFight": { + "snow_ball_fight": { "description": "Throw snoballs and dominate", "external_url": "https://youtu.be/uXyb_meBjGI?si=D_N_OXZT5BFh8R5C", "authors": [ @@ -1074,15 +1049,10 @@ } ], "versions": { - "1.0.0": { - "api_version": 8, - "commit_sha": "f744c41", - "released_on": "24-01-2024", - "md5sum": "ef6bd7cd0404674f65e8f8d4da3ab8c8" - } + "1.0.0": null } }, - "EggGame": { + "egg_game": { "description": "Throw Egg as far u can", "external_url": "https://youtu.be/82vLp9ceCcw?si=OSC5Hu3Ns7PevlwP", "authors": [ @@ -1093,12 +1063,21 @@ } ], "versions": { - "1.0.0": { - "api_version": 8, - "commit_sha": "f744c41", - "released_on": "24-01-2024", - "md5sum": "e1d401ec8f2d06dec741d713d6602710" + "1.0.0": null + } + }, + "you_vs_bombsquad": { + "description": "You against bombsquad solo or with friends", + "external_url": "", + "authors": [ + { + "name": "JoseAng3l", + "email": "", + "discord": "joseang3l" } + ], + "versions": { + "1.0.0": null } } } diff --git a/plugins/minigames/EggGame.py b/plugins/minigames/egg_game.py similarity index 100% rename from plugins/minigames/EggGame.py rename to plugins/minigames/egg_game.py diff --git a/plugins/minigames/meteorshowerdeluxe.py b/plugins/minigames/meteor_shower_deluxe.py similarity index 100% rename from plugins/minigames/meteorshowerdeluxe.py rename to plugins/minigames/meteor_shower_deluxe.py diff --git a/plugins/minigames/ofuuuAttack.py b/plugins/minigames/ofuuu_attack.py similarity index 100% rename from plugins/minigames/ofuuuAttack.py rename to plugins/minigames/ofuuu_attack.py diff --git a/plugins/minigames/SnowBallFight.py b/plugins/minigames/snow_ball_fight.py similarity index 100% rename from plugins/minigames/SnowBallFight.py rename to plugins/minigames/snow_ball_fight.py diff --git a/plugins/minigames/you_vs_bombsquad.py b/plugins/minigames/you_vs_bombsquad.py new file mode 100644 index 0000000..5d662d1 --- /dev/null +++ b/plugins/minigames/you_vs_bombsquad.py @@ -0,0 +1,486 @@ +# Ported to api 8 by brostos using baport.(https://github.com/bombsquad-community/baport) +"""you vs BombSquad / 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 _babase +import random +from bascenev1lib.actor.spazbot import SpazBotSet, BrawlerBot, SpazBotDiedMessage +from bascenev1lib.actor.onscreentimer import OnScreenTimer + +if TYPE_CHECKING: + from typing import Any, Optional + +lang = bs.app.lang.language +if lang == 'Spanish': + name = 'Tu vs BombSquad' + name_easy = 'Tu vs BS Fácil' + name_easy_epic = 'Tu vs BS Fácil Épico' + name_hard = 'Tu vs BS Difícil' + name_hard_epic = 'Tu vs BS Difícil Épico' +else: + name = 'You vs BombSquad' + name_easy = 'You vs BS Easy' + name_easy_epic = 'You vs BS Easy Epic' + name_hard = 'You vs BS Hard' + name_hard_epic = 'You vs BS Hard Epic' + +# def ba_get_api_version(): +# return 6 + +def ba_get_levels(): + return [babase._level.Level( + name_easy, + gametype=TUvsBombSquad, + settings={}, + preview_texture_name='footballStadiumPreview'), + babase._level.Level( + name_easy_epic, + gametype=TUvsBombSquad, + settings={'Epic Mode': True}, + preview_texture_name='footballStadiumPreview'), + + babase._level.Level( + name_hard, + gametype=TUvsBombSquad, + settings={'Hard Mode': True}, + preview_texture_name='footballStadiumPreview'), + babase._level.Level( + name_hard_epic, + gametype=TUvsBombSquad, + settings={'Hard Mode': True, + 'Epic Mode': True}, + preview_texture_name='footballStadiumPreview')] + +#### BOTS #### +class SpazBot(BrawlerBot): + character = 'Spaz' + color=(0.1,0.35,0.1) + highlight=(1,0.15,0.15) + +class ZoeBot(BrawlerBot): + character = 'Zoe' + color=(0.6,0.6,0.6) + highlight=(0,1,0) + +class SnakeBot(BrawlerBot): + character = 'Snake Shadow' + color=(1,1,1) + highlight=(0.55,0.8,0.55) + +class MelBot(BrawlerBot): + character = 'Mel' + color=(1,1,1) + highlight=(0.1,0.6,0.1) + +class JackBot(BrawlerBot): + character = 'Jack Morgan' + color=(1,0.2,0.1) + highlight=(1,1,0) + +class SantaBot(BrawlerBot): + character = 'Santa Claus' + color=(1,0,0) + highlight=(1,1,1) + +class FrostyBot(BrawlerBot): + character = 'Frosty' + color=(0.5,0.5,1) + highlight=(1,0.5,0) + +class BonesBot(BrawlerBot): + character = 'Bones' + color=(0.6,0.9,1) + highlight=(0.6,0.9,1) + +class BernardBot(BrawlerBot): + character = 'Bernard' + color=(0.7,0.5,0.0) + highlight=(0.6,0.5,0.8) + +class PascalBot(BrawlerBot): + character = 'Pascal' + color=(0.3,0.5,0.8) + highlight=(1,0,0) + +class TaobaoBot(BrawlerBot): + character = 'Taobao Mascot' + color=(1,0.5,0) + highlight=(1,1,1) + +class BBot(BrawlerBot): + character = 'B-9000' + color=(0.5,0.5,0.5) + highlight=(1,0,0) + +class AgentBot(BrawlerBot): + character = 'Agent Johnson' + color=(0.3,0.3,0.33) + highlight=(1,0.5,0.3) + +class GrumbledorfBot(BrawlerBot): + character = 'Grumbledorf' + color=(0.2,0.4,1.0) + highlight=(0.06,0.15,0.4) + +class PixelBot(BrawlerBot): + character = 'Pixel' + color=(0,1,0.7) + highlight=(0.65,0.35,0.75) + +class BunnyBot(BrawlerBot): + character = 'Easter Bunny' + color=(1,1,1) + highlight=(1,0.5,0.5) + +class Player(bs.Player['Team']): + """Our player type for this game.""" + + +class Team(bs.Team[Player]): + """Our team type for this game.""" + + +# ba_meta export bascenev1.GameActivity +class TUvsBombSquad(bs.TeamGameActivity[Player, Team]): + """A game type based on acquiring kills.""" + + name = name + description = 'Defeat all enemies.' + scoreconfig = bs.ScoreConfig(label='Time', + scoretype=bs.ScoreType.MILLISECONDS, + lower_is_better=True) + + @classmethod + def get_available_settings( + cls, sessiontype: Type[bs.Session]) -> List[babase.Setting]: + settings = [ + bs.BoolSetting('Hard Mode', 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.CoopSession) + or issubclass(sessiontype, bs.MultiTeamSession)) + + @classmethod + def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]: + return ['Football Stadium'] + + def __init__(self, settings: dict): + super().__init__(settings) + self._winsound = bs.getsound('score') + self._won = False + self._timer: Optional[OnScreenTimer] = None + self._bots = SpazBotSet() + self._hard_mode = bool(settings['Hard Mode']) + self._epic_mode = bool(settings['Epic Mode']) + + # Base class overrides. + self.slow_motion = self._epic_mode + self.default_music = (bs.MusicType.EPIC if self._epic_mode else + bs.MusicType.SURVIVAL) + + self._spaz_easy: list = [[(-5.4146, 0.9515, -3.0379), 23.0], + [(-5.4146, 0.9515, 1.0379), 23.0]] + self._spaz_hard: list = [[(11.4146, 0.9515, -5.0379), 3.0], + [(-8.4146, 0.9515, -5.0379), 5.0], + [(5.4146, 0.9515, -3.0379), 8.0], + [(5.4146, 0.9515, 1.0379), 8.0]] + self._zoe_easy: list = [[(5.4146, 0.9515, -1.0379), 23.0], + [(-5.4146, 0.9515, 5.0379), 23.0]] + self._zoe_hard: list = [[(-11.4146, 0.9515, -5.0379), 3.0], + [(8.4146, 0.9515, -3.0379), 5.0], + [(-5.4146, 0.9515, -3.0379), 8.0], + [(-5.4146, 0.9515, 1.0379), 8.0]] + self._snake_easy: list = [[(-5.4146, 0.9515, -1.0379), 23.0], + [(5.4146, 0.9515, -5.0379), 23.0]] + self._snake_hard: list = [[(11.4146, 0.9515, -3.0379), 3.0], + [(-8.4146, 0.9515, -3.0379), 5.0], + [(5.4146, 0.9515, -1.0379), 8.0], + [(5.4146, 0.9515, 1.0379), 8.0]] + self._kronk_easy: list = [[(8.4146, 0.9515, 1.0379), 10.0], + [(5.4146, 0.9515, 3.0379), 23.0]] + self._kronk_hard: list = [[(-11.4146, 0.9515, -3.0379), 3.0], + [(8.4146, 0.9515, -1.0379), 5.0], + [(-5.4146, 0.9515, -1.0379), 8.0], + [(5.4146, 0.9515, 1.0379), 8.0]] + self._mel_easy: list = [[(5.4146, 0.9515, 1.0379), 23.0], + [(-11.4146, 0.9515, 1.0379), 3.0]] + self._mel_hard: list = [[(11.4146, 0.9515, -1.0379), 3.0], + [(-8.4146, 0.9515, -1.0379), 5.0], + [(5.4146, 0.9515, 1.0379), 8.0], + [(5.4146, 0.9515, 5.0379), 8.0]] + self._jack_easy: list = [[(-8.4146, 0.9515, 1.0379), 10.0], + [(5.4146, 0.9515, 1.0379), 23.0]] + self._jack_hard: list = [[(-11.4146, 0.9515, -1.0379), 3.0], + [(8.4146, 0.9515, 1.0379), 5.0], + [(-5.4146, 0.9515, 1.0379), 8.0], + [(-5.4146, 0.9515, 5.0379), 8.0], + [(5.4146, 0.9515, -5.0379), 8.0]] + self._frosty_easy: list = [[(8.4146, 0.9515, 1.0379), 10.0], + [(8.4146, 0.9515, -5.0379), 10.0]] + self._frosty_hard: list = [[(-11.4146, 0.9515, 1.0379), 3.0], + [(-5.4146, 0.9515, 3.0379), 8.0], + [(-5.4146, 0.9515, -5.0379), 8.0], + [(5.4146, 0.9515, 3.0379), 8.0]] + self._bunny_easy: list = [[(-8.4146, 0.9515, 3.0379), 10.0], + [(5.4146, 0.9515, 5.0379), 23.0]] + self._bunny_hard: list = [[(8.4146, 0.9515, -5.0379), 5.0], + [(-5.4146, 0.9515, -5.0379), 8.0], + [(-5.4146, 0.9515, 3.0379), 8.0], + [(8.4146, 0.9515, 3.0379), 5.0]] + self._bones_easy: list = [[(11.4146, 0.9515, -5.0379), 3.0], + [(-8.4146, 0.9515, -5.0379), 10.0]] + self._bones_hard: list = [[(5.4146, 0.9515, -3.0379), 8.0], + [(-5.4146, 0.9515, 3.0379), 8.0], + [(5.4146, 0.9515, 1.0379), 8.0], + [(8.4146, 0.9515, 3.0379), 5.0]] + self._bernard_easy: list = [[(-11.4146, 0.9515, -5.0379), 3.0], + [(8.4146, 0.9515, -3.0379), 10.0]] + self._bernard_hard: list = [[(-5.4146, 0.9515, -3.0379), 8.0], + [(5.4146, 0.9515, 1.0379), 8.0], + [(-5.4146, 0.9515, 1.0379), 8.0], + [(-8.4146, 0.9515, 3.0379), 5.0]] + self._pascal_easy: list = [[(11.4146, 0.9515, -3.0379), 3.0], + [(-8.4146, 0.9515, -3.0379), 10.0]] + self._pascal_hard: list = [[(5.4146, 0.9515, -1.0379), 8.0], + [(-5.4146, 0.9515, 1.0379), 8.0], + [(5.4146, 0.9515, 1.0379), 8.0], + [(8.4146, 0.9515, 1.0379), 5.0]] + self._taobao_easy: list = [[(-11.4146, 0.9515, -3.0379), 3.0], + [(8.4146, 0.9515, -1.0379), 10.0]] + self._taobao_hard: list = [[(-5.4146, 0.9515, -1.0379), 8.0], + [(5.4146, 0.9515, 1.0379), 8.0], + [(-5.4146, 0.9515, 1.0379), 8.0], + [(-5.4146, 0.9515, 1.0379), 8.0]] + self._bbot_easy: list = [[(11.4146, 0.9515, -1.0379), 3.0], + [(-8.4146, 0.9515, -1.0379), 10.0]] + self._bbot_hard: list = [[(-5.4146, 0.9515, 1.0379), 8.0], + [(8.4146, 0.9515, 1.0379), 5.0], + [(-5.4146, 0.9515, 1.0379), 8.0], + [(-5.4146, 0.9515, 1.0379), 8.0]] + self._agent_easy: list = [[(-11.4146, 0.9515, -1.0379), 3.0], + [(8.4146, 0.9515, 1.0379), 10.0]] + self._agent_hard: list = [[(5.4146, 0.9515, 5.0379), 8.0], + [(-8.4146, 0.9515, 1.0379), 5.0], + [(-11.4146, 0.9515, 1.0379), 3.0], + [(-11.4146, 0.9515, 1.0379), 3.0]] + self._wizard_easy: list = [[(11.4146, 0.9515, 1.0379), 3.0], + [(-8.4146, 0.9515, 1.0379), 10.0]] + self._wizard_hard: list = [[(-5.4146, 0.9515, 5.0379), 8.0], + [(8.4146, 0.9515, 5.0379), 5.0], + [(-5.4146, 0.9515, 1.0379), 8.0], + [(11.4146, 0.9515, 1.0379), 3.0]] + self._pixel_easy: list = [[(-5.4146, 0.9515, -5.0379), 23.0]] + self._pixel_hard: list = [[(5.4146, 0.9515, -5.0379), 8.0], + [(5.4146, 0.9515, 3.0379), 5.0], + [(-8.4146, 0.9515, 5.0379), 5.0]] + self._santa_easy: list = [[(-8.4146, 0.9515, 5.0379), 23.0]] + self._santa_hard: list = [[(-8.4146, 0.9515, 1.0379), 5.0], + [(-8.4146, 0.9515, 5.0379), 5.0], + [(5.4146, 0.9515, 1.0379), 8.0]] + + def on_begin(self) -> None: + super().on_begin() + self.setup_standard_powerup_drops() + self._timer = OnScreenTimer() + bs.timer(4.0, self._timer.start) + + for i in range(len(self._spaz_easy)): + self._spawn_bots(4.0, SpazBot, + self._spaz_easy[i][0], self._spaz_easy[i][1]) + for i in range(len(self._zoe_easy)): + self._spawn_bots(4.0, ZoeBot, + self._zoe_easy[i][0], self._zoe_easy[i][1]) + for i in range(len(self._snake_easy)): + self._spawn_bots(4.0, SnakeBot, + self._snake_easy[i][0], self._snake_easy[i][1]) + for i in range(len(self._kronk_easy)): + self._spawn_bots(4.0, BrawlerBot, + self._kronk_easy[i][0], self._kronk_easy[i][1]) + for i in range(len(self._mel_easy)): + self._spawn_bots(4.0, MelBot, + self._mel_easy[i][0], self._mel_easy[i][1]) + for i in range(len(self._jack_easy)): + self._spawn_bots(4.0, JackBot, + self._jack_easy[i][0], self._jack_easy[i][1]) + for i in range(len(self._santa_easy)): + self._spawn_bots(4.0, SantaBot, + self._santa_easy[i][0], self._santa_easy[i][1]) + for i in range(len(self._frosty_easy)): + self._spawn_bots(4.0, FrostyBot, + self._frosty_easy[i][0], self._frosty_easy[i][1]) + for i in range(len(self._bunny_easy)): + self._spawn_bots(4.0, BunnyBot, + self._bunny_easy[i][0], self._bunny_easy[i][1]) + for i in range(len(self._bones_easy)): + self._spawn_bots(4.0, BonesBot, + self._bones_easy[i][0], self._bones_easy[i][1]) + for i in range(len(self._bernard_easy)): + self._spawn_bots(4.0, BernardBot, + self._bernard_easy[i][0], self._bernard_easy[i][1]) + for i in range(len(self._pascal_easy)): + self._spawn_bots(4.0, PascalBot, + self._pascal_easy[i][0], self._pascal_easy[i][1]) + for i in range(len(self._taobao_easy)): + self._spawn_bots(4.0, TaobaoBot, + self._taobao_easy[i][0], self._taobao_easy[i][1]) + for i in range(len(self._bbot_easy)): + self._spawn_bots(4.0, BBot, + self._bbot_easy[i][0], self._bbot_easy[i][1]) + for i in range(len(self._agent_easy)): + self._spawn_bots(4.0, AgentBot, + self._agent_easy[i][0], self._agent_easy[i][1]) + for i in range(len(self._wizard_easy)): + self._spawn_bots(4.0, GrumbledorfBot, + self._wizard_easy[i][0], self._wizard_easy[i][1]) + for i in range(len(self._pixel_easy)): + self._spawn_bots(4.0, PixelBot, + self._pixel_easy[i][0], self._pixel_easy[i][1]) + + if self._hard_mode: + for i in range(len(self._spaz_hard)): + self._spawn_bots(4.0, SpazBot, + self._spaz_hard[i][0], self._spaz_hard[i][1]) + for i in range(len(self._zoe_hard)): + self._spawn_bots(4.0, ZoeBot, + self._zoe_hard[i][0], self._zoe_hard[i][1]) + for i in range(len(self._snake_hard)): + self._spawn_bots(4.0, SnakeBot, + self._snake_hard[i][0], self._snake_hard[i][1]) + for i in range(len(self._kronk_hard)): + self._spawn_bots(4.0, BrawlerBot, + self._kronk_hard[i][0], self._kronk_hard[i][1]) + for i in range(len(self._mel_hard)): + self._spawn_bots(4.0, MelBot, + self._mel_hard[i][0], self._mel_hard[i][1]) + for i in range(len(self._jack_hard)): + self._spawn_bots(4.0, JackBot, + self._jack_hard[i][0], self._jack_hard[i][1]) + for i in range(len(self._santa_hard)): + self._spawn_bots(4.0, SantaBot, + self._santa_hard[i][0], self._santa_hard[i][1]) + for i in range(len(self._frosty_hard)): + self._spawn_bots(4.0, FrostyBot, + self._frosty_hard[i][0], self._frosty_hard[i][1]) + for i in range(len(self._bunny_hard)): + self._spawn_bots(4.0, BunnyBot, + self._bunny_hard[i][0], self._bunny_hard[i][1]) + for i in range(len(self._bones_hard)): + self._spawn_bots(4.0, BonesBot, + self._bones_hard[i][0], self._bones_hard[i][1]) + for i in range(len(self._bernard_hard)): + self._spawn_bots(4.0, BernardBot, + self._bernard_hard[i][0], self._bernard_hard[i][1]) + for i in range(len(self._pascal_hard)): + self._spawn_bots(4.0, PascalBot, + self._pascal_hard[i][0], self._pascal_hard[i][1]) + for i in range(len(self._taobao_hard)): + self._spawn_bots(4.0, TaobaoBot, + self._taobao_hard[i][0], self._taobao_hard[i][1]) + for i in range(len(self._bbot_hard)): + self._spawn_bots(4.0, BBot, + self._bbot_hard[i][0], self._bbot_hard[i][1]) + for i in range(len(self._agent_hard)): + self._spawn_bots(4.0, AgentBot, + self._agent_hard[i][0], self._agent_hard[i][1]) + for i in range(len(self._wizard_hard)): + self._spawn_bots(4.0, GrumbledorfBot, + self._wizard_hard[i][0], self._wizard_hard[i][1]) + for i in range(len(self._pixel_hard)): + self._spawn_bots(4.0, PixelBot, + self._pixel_hard[i][0], self._pixel_hard[i][1]) + + def _spawn_bots(self, time: float, bot: Any, + pos: float, spawn_time: float) -> None: + bs.timer(time, lambda: self._bots.spawn_bot( + bot, pos=pos, spawn_time=spawn_time)) + + def on_player_join(self, player: Player) -> None: + if self.has_begun(): + bs.broadcastmessage( + babase.Lstr(resource='playerDelayedJoinText', + subs=[('${PLAYER}', player.getname(full=True))]), + color=(0, 1, 0), + ) + return + self.spawn_player(player) + + # Called for each spawning player. + def spawn_player(self, player: Player) -> bs.Actor: + + # Let's spawn close to the center. + spawn_center = (0.0728, 0.0227, -1.9888) + pos = (spawn_center[0] + random.uniform(-0.5, 0.5), spawn_center[1], + spawn_center[2] + random.uniform(-0.5, 0.5)) + return self.spawn_player_spaz(player, position=pos) + + def _check_if_won(self) -> None: + # Simply end the game if there's no living bots. + # FIXME: Should also make sure all bots have been spawned; + # if spawning is spread out enough that we're able to kill + # all living bots before the next spawns, it would incorrectly + # count as a win. + if not self._bots.have_living_bots(): + self._won = True + self.end_game() + + # Called for miscellaneous messages. + def handlemessage(self, msg: Any) -> Any: + + # A player has died. + if isinstance(msg, bs.PlayerDiedMessage): + super().handlemessage(msg) # Augment standard behavior. + self.respawn_player(msg.getplayer(Player)) + + # A spaz-bot has died. + elif isinstance(msg, SpazBotDiedMessage): + # Unfortunately the bot-set will always tell us there are living + # bots if we ask here (the currently-dying bot isn't officially + # marked dead yet) ..so lets push a call into the event loop to + # check once this guy has finished dying. + babase.pushcall(self._check_if_won) + + # Let the base class handle anything we don't. + else: + return super().handlemessage(msg) + return None + + # When this is called, we should fill out results and end the game + # *regardless* of whether is has been won. (this may be called due + # to a tournament ending or other external reason). + def end_game(self) -> None: + + # Stop our on-screen timer so players can see what they got. + assert self._timer is not None + self._timer.stop() + + results = bs.GameResults() + + # If we won, set our score to the elapsed time in milliseconds. + # (there should just be 1 team here since this is co-op). + # ..if we didn't win, leave scores as default (None) which means + # we lost. + if self._won: + elapsed_time_ms = int((bs.time() - self._timer.starttime) * 1000.0) + bs.cameraflash() + self._winsound.play() + for team in self.teams: + for player in team.players: + if player.actor: + player.actor.handlemessage(bs.CelebrateMessage()) + results.set_team_score(team, elapsed_time_ms) + + # Ends the activity. + self.end(results) diff --git a/plugins/utilities.json b/plugins/utilities.json index 8a7d763..743c372 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -1091,7 +1091,7 @@ } } }, - "InfinityShield": { + "infinity_shield": { "description": "Gives you unbreakable shield", "external_url": "https://youtu.be/hp7vbB-hUPg?si=i7Th0NP5xDPLN2P_", "authors": [ @@ -1102,15 +1102,10 @@ } ], "versions": { - "1.0.0": { - "api_version": 8, - "commit_sha": "f744c41", - "released_on": "24-01-2024", - "md5sum": "eb917ca19d206dfd19667181dacc1df5" - } + "1.0.0": null } }, - "OnlyNight": { + "0nly_night": { "description": "Night Mode", "external_url": "", "authors": [ @@ -1121,15 +1116,10 @@ } ], "versions": { - "1.0.0": { - "api_version": 8, - "commit_sha": "f744c41", - "released_on": "24-01-2024", - "md5sum": "255d3d6694008cc2f73d115182100b52" - } + "1.0.0": null } }, - "Tag": { + "tag": { "description": "Get a tag", "external_url": "", "authors": [ @@ -1140,12 +1130,7 @@ } ], "versions": { - "2.0.1": { - "api_version": 8, - "commit_sha": "f744c41", - "released_on": "24-01-2024", - "md5sum": "01cf9e10ab0e1bf51c07d80ff842c632" - } + "2.0.1": null } } } diff --git a/plugins/utilities/InfinityShield.py b/plugins/utilities/infinity_shield.py similarity index 100% rename from plugins/utilities/InfinityShield.py rename to plugins/utilities/infinity_shield.py diff --git a/plugins/utilities/OnlyNight.py b/plugins/utilities/only_night.py similarity index 100% rename from plugins/utilities/OnlyNight.py rename to plugins/utilities/only_night.py From 89295db5cc107ba2d4f3d90ccda9b79b5a0cc843 Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Wed, 24 Jan 2024 18:17:42 +0000 Subject: [PATCH 06/36] [ci] auto-format --- plugins/minigames/you_vs_bombsquad.py | 197 ++++++++++++++------------ 1 file changed, 108 insertions(+), 89 deletions(-) diff --git a/plugins/minigames/you_vs_bombsquad.py b/plugins/minigames/you_vs_bombsquad.py index 5d662d1..c28a539 100644 --- a/plugins/minigames/you_vs_bombsquad.py +++ b/plugins/minigames/you_vs_bombsquad.py @@ -36,110 +36,129 @@ else: # def ba_get_api_version(): # return 6 -def ba_get_levels(): - return [babase._level.Level( - name_easy, - gametype=TUvsBombSquad, - settings={}, - preview_texture_name='footballStadiumPreview'), - babase._level.Level( - name_easy_epic, - gametype=TUvsBombSquad, - settings={'Epic Mode': True}, - preview_texture_name='footballStadiumPreview'), - babase._level.Level( - name_hard, - gametype=TUvsBombSquad, - settings={'Hard Mode': True}, - preview_texture_name='footballStadiumPreview'), - babase._level.Level( - name_hard_epic, - gametype=TUvsBombSquad, - settings={'Hard Mode': True, - 'Epic Mode': True}, - preview_texture_name='footballStadiumPreview')] +def ba_get_levels(): + return [babase._level.Level( + name_easy, + gametype=TUvsBombSquad, + settings={}, + preview_texture_name='footballStadiumPreview'), + babase._level.Level( + name_easy_epic, + gametype=TUvsBombSquad, + settings={'Epic Mode': True}, + preview_texture_name='footballStadiumPreview'), + + babase._level.Level( + name_hard, + gametype=TUvsBombSquad, + settings={'Hard Mode': True}, + preview_texture_name='footballStadiumPreview'), + babase._level.Level( + name_hard_epic, + gametype=TUvsBombSquad, + settings={'Hard Mode': True, + 'Epic Mode': True}, + preview_texture_name='footballStadiumPreview')] #### BOTS #### + + class SpazBot(BrawlerBot): character = 'Spaz' - color=(0.1,0.35,0.1) - highlight=(1,0.15,0.15) + color = (0.1, 0.35, 0.1) + highlight = (1, 0.15, 0.15) + class ZoeBot(BrawlerBot): character = 'Zoe' - color=(0.6,0.6,0.6) - highlight=(0,1,0) + color = (0.6, 0.6, 0.6) + highlight = (0, 1, 0) + class SnakeBot(BrawlerBot): character = 'Snake Shadow' - color=(1,1,1) - highlight=(0.55,0.8,0.55) + color = (1, 1, 1) + highlight = (0.55, 0.8, 0.55) + class MelBot(BrawlerBot): character = 'Mel' - color=(1,1,1) - highlight=(0.1,0.6,0.1) + color = (1, 1, 1) + highlight = (0.1, 0.6, 0.1) + class JackBot(BrawlerBot): character = 'Jack Morgan' - color=(1,0.2,0.1) - highlight=(1,1,0) + color = (1, 0.2, 0.1) + highlight = (1, 1, 0) + class SantaBot(BrawlerBot): character = 'Santa Claus' - color=(1,0,0) - highlight=(1,1,1) + color = (1, 0, 0) + highlight = (1, 1, 1) + class FrostyBot(BrawlerBot): character = 'Frosty' - color=(0.5,0.5,1) - highlight=(1,0.5,0) + color = (0.5, 0.5, 1) + highlight = (1, 0.5, 0) + class BonesBot(BrawlerBot): character = 'Bones' - color=(0.6,0.9,1) - highlight=(0.6,0.9,1) + color = (0.6, 0.9, 1) + highlight = (0.6, 0.9, 1) + class BernardBot(BrawlerBot): character = 'Bernard' - color=(0.7,0.5,0.0) - highlight=(0.6,0.5,0.8) + color = (0.7, 0.5, 0.0) + highlight = (0.6, 0.5, 0.8) + class PascalBot(BrawlerBot): character = 'Pascal' - color=(0.3,0.5,0.8) - highlight=(1,0,0) + color = (0.3, 0.5, 0.8) + highlight = (1, 0, 0) + class TaobaoBot(BrawlerBot): character = 'Taobao Mascot' - color=(1,0.5,0) - highlight=(1,1,1) + color = (1, 0.5, 0) + highlight = (1, 1, 1) + class BBot(BrawlerBot): character = 'B-9000' - color=(0.5,0.5,0.5) - highlight=(1,0,0) + color = (0.5, 0.5, 0.5) + highlight = (1, 0, 0) + class AgentBot(BrawlerBot): character = 'Agent Johnson' - color=(0.3,0.3,0.33) - highlight=(1,0.5,0.3) + color = (0.3, 0.3, 0.33) + highlight = (1, 0.5, 0.3) + class GrumbledorfBot(BrawlerBot): character = 'Grumbledorf' - color=(0.2,0.4,1.0) - highlight=(0.06,0.15,0.4) + color = (0.2, 0.4, 1.0) + highlight = (0.06, 0.15, 0.4) + class PixelBot(BrawlerBot): character = 'Pixel' - color=(0,1,0.7) - highlight=(0.65,0.35,0.75) + color = (0, 1, 0.7) + highlight = (0.65, 0.35, 0.75) + class BunnyBot(BrawlerBot): character = 'Easter Bunny' - color=(1,1,1) - highlight=(1,0.5,0.5) + color = (1, 1, 1) + highlight = (1, 0.5, 0.5) + class Player(bs.Player['Team']): """Our player type for this game.""" @@ -299,108 +318,108 @@ class TUvsBombSquad(bs.TeamGameActivity[Player, Team]): for i in range(len(self._spaz_easy)): self._spawn_bots(4.0, SpazBot, - self._spaz_easy[i][0], self._spaz_easy[i][1]) + self._spaz_easy[i][0], self._spaz_easy[i][1]) for i in range(len(self._zoe_easy)): self._spawn_bots(4.0, ZoeBot, - self._zoe_easy[i][0], self._zoe_easy[i][1]) + self._zoe_easy[i][0], self._zoe_easy[i][1]) for i in range(len(self._snake_easy)): self._spawn_bots(4.0, SnakeBot, - self._snake_easy[i][0], self._snake_easy[i][1]) + self._snake_easy[i][0], self._snake_easy[i][1]) for i in range(len(self._kronk_easy)): self._spawn_bots(4.0, BrawlerBot, - self._kronk_easy[i][0], self._kronk_easy[i][1]) + self._kronk_easy[i][0], self._kronk_easy[i][1]) for i in range(len(self._mel_easy)): self._spawn_bots(4.0, MelBot, - self._mel_easy[i][0], self._mel_easy[i][1]) + self._mel_easy[i][0], self._mel_easy[i][1]) for i in range(len(self._jack_easy)): self._spawn_bots(4.0, JackBot, - self._jack_easy[i][0], self._jack_easy[i][1]) + self._jack_easy[i][0], self._jack_easy[i][1]) for i in range(len(self._santa_easy)): self._spawn_bots(4.0, SantaBot, - self._santa_easy[i][0], self._santa_easy[i][1]) + self._santa_easy[i][0], self._santa_easy[i][1]) for i in range(len(self._frosty_easy)): self._spawn_bots(4.0, FrostyBot, - self._frosty_easy[i][0], self._frosty_easy[i][1]) + self._frosty_easy[i][0], self._frosty_easy[i][1]) for i in range(len(self._bunny_easy)): self._spawn_bots(4.0, BunnyBot, - self._bunny_easy[i][0], self._bunny_easy[i][1]) + self._bunny_easy[i][0], self._bunny_easy[i][1]) for i in range(len(self._bones_easy)): self._spawn_bots(4.0, BonesBot, - self._bones_easy[i][0], self._bones_easy[i][1]) + self._bones_easy[i][0], self._bones_easy[i][1]) for i in range(len(self._bernard_easy)): self._spawn_bots(4.0, BernardBot, - self._bernard_easy[i][0], self._bernard_easy[i][1]) + self._bernard_easy[i][0], self._bernard_easy[i][1]) for i in range(len(self._pascal_easy)): self._spawn_bots(4.0, PascalBot, - self._pascal_easy[i][0], self._pascal_easy[i][1]) + self._pascal_easy[i][0], self._pascal_easy[i][1]) for i in range(len(self._taobao_easy)): self._spawn_bots(4.0, TaobaoBot, - self._taobao_easy[i][0], self._taobao_easy[i][1]) + self._taobao_easy[i][0], self._taobao_easy[i][1]) for i in range(len(self._bbot_easy)): self._spawn_bots(4.0, BBot, - self._bbot_easy[i][0], self._bbot_easy[i][1]) + self._bbot_easy[i][0], self._bbot_easy[i][1]) for i in range(len(self._agent_easy)): self._spawn_bots(4.0, AgentBot, - self._agent_easy[i][0], self._agent_easy[i][1]) + self._agent_easy[i][0], self._agent_easy[i][1]) for i in range(len(self._wizard_easy)): self._spawn_bots(4.0, GrumbledorfBot, - self._wizard_easy[i][0], self._wizard_easy[i][1]) + self._wizard_easy[i][0], self._wizard_easy[i][1]) for i in range(len(self._pixel_easy)): self._spawn_bots(4.0, PixelBot, - self._pixel_easy[i][0], self._pixel_easy[i][1]) + self._pixel_easy[i][0], self._pixel_easy[i][1]) if self._hard_mode: for i in range(len(self._spaz_hard)): self._spawn_bots(4.0, SpazBot, - self._spaz_hard[i][0], self._spaz_hard[i][1]) + self._spaz_hard[i][0], self._spaz_hard[i][1]) for i in range(len(self._zoe_hard)): self._spawn_bots(4.0, ZoeBot, - self._zoe_hard[i][0], self._zoe_hard[i][1]) + self._zoe_hard[i][0], self._zoe_hard[i][1]) for i in range(len(self._snake_hard)): self._spawn_bots(4.0, SnakeBot, - self._snake_hard[i][0], self._snake_hard[i][1]) + self._snake_hard[i][0], self._snake_hard[i][1]) for i in range(len(self._kronk_hard)): self._spawn_bots(4.0, BrawlerBot, - self._kronk_hard[i][0], self._kronk_hard[i][1]) + self._kronk_hard[i][0], self._kronk_hard[i][1]) for i in range(len(self._mel_hard)): self._spawn_bots(4.0, MelBot, - self._mel_hard[i][0], self._mel_hard[i][1]) + self._mel_hard[i][0], self._mel_hard[i][1]) for i in range(len(self._jack_hard)): self._spawn_bots(4.0, JackBot, - self._jack_hard[i][0], self._jack_hard[i][1]) + self._jack_hard[i][0], self._jack_hard[i][1]) for i in range(len(self._santa_hard)): self._spawn_bots(4.0, SantaBot, - self._santa_hard[i][0], self._santa_hard[i][1]) + self._santa_hard[i][0], self._santa_hard[i][1]) for i in range(len(self._frosty_hard)): self._spawn_bots(4.0, FrostyBot, - self._frosty_hard[i][0], self._frosty_hard[i][1]) + self._frosty_hard[i][0], self._frosty_hard[i][1]) for i in range(len(self._bunny_hard)): self._spawn_bots(4.0, BunnyBot, - self._bunny_hard[i][0], self._bunny_hard[i][1]) + self._bunny_hard[i][0], self._bunny_hard[i][1]) for i in range(len(self._bones_hard)): self._spawn_bots(4.0, BonesBot, - self._bones_hard[i][0], self._bones_hard[i][1]) + self._bones_hard[i][0], self._bones_hard[i][1]) for i in range(len(self._bernard_hard)): self._spawn_bots(4.0, BernardBot, - self._bernard_hard[i][0], self._bernard_hard[i][1]) + self._bernard_hard[i][0], self._bernard_hard[i][1]) for i in range(len(self._pascal_hard)): self._spawn_bots(4.0, PascalBot, - self._pascal_hard[i][0], self._pascal_hard[i][1]) + self._pascal_hard[i][0], self._pascal_hard[i][1]) for i in range(len(self._taobao_hard)): self._spawn_bots(4.0, TaobaoBot, - self._taobao_hard[i][0], self._taobao_hard[i][1]) + self._taobao_hard[i][0], self._taobao_hard[i][1]) for i in range(len(self._bbot_hard)): self._spawn_bots(4.0, BBot, - self._bbot_hard[i][0], self._bbot_hard[i][1]) + self._bbot_hard[i][0], self._bbot_hard[i][1]) for i in range(len(self._agent_hard)): self._spawn_bots(4.0, AgentBot, - self._agent_hard[i][0], self._agent_hard[i][1]) + self._agent_hard[i][0], self._agent_hard[i][1]) for i in range(len(self._wizard_hard)): self._spawn_bots(4.0, GrumbledorfBot, - self._wizard_hard[i][0], self._wizard_hard[i][1]) + self._wizard_hard[i][0], self._wizard_hard[i][1]) for i in range(len(self._pixel_hard)): self._spawn_bots(4.0, PixelBot, - self._pixel_hard[i][0], self._pixel_hard[i][1]) + self._pixel_hard[i][0], self._pixel_hard[i][1]) def _spawn_bots(self, time: float, bot: Any, pos: float, spawn_time: float) -> None: @@ -411,7 +430,7 @@ class TUvsBombSquad(bs.TeamGameActivity[Player, Team]): if self.has_begun(): bs.broadcastmessage( babase.Lstr(resource='playerDelayedJoinText', - subs=[('${PLAYER}', player.getname(full=True))]), + subs=[('${PLAYER}', player.getname(full=True))]), color=(0, 1, 0), ) return From 1c15e5b59dfa77023089773679c3b09ebb5344aa Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Wed, 24 Jan 2024 21:18:36 +0300 Subject: [PATCH 07/36] O -> o --- plugins/utilities.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 743c372..2f17edf 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -1105,7 +1105,7 @@ "1.0.0": null } }, - "0nly_night": { + "only_night": { "description": "Night Mode", "external_url": "", "authors": [ From c31f77a882efedcee1ce6ac1e334d103235679eb Mon Sep 17 00:00:00 2001 From: brostos <67740566+brostosjoined@users.noreply.github.com> Date: Wed, 24 Jan 2024 21:25:53 +0300 Subject: [PATCH 08/36] Rename Avalanche.py to avalanche.py --- plugins/minigames/{Avalanche.py => avalanche.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename plugins/minigames/{Avalanche.py => avalanche.py} (100%) diff --git a/plugins/minigames/Avalanche.py b/plugins/minigames/avalanche.py similarity index 100% rename from plugins/minigames/Avalanche.py rename to plugins/minigames/avalanche.py From 7b765e759501a37c9462389b3f7a178c9335a896 Mon Sep 17 00:00:00 2001 From: brostos <67740566+brostosjoined@users.noreply.github.com> Date: Wed, 24 Jan 2024 21:26:15 +0300 Subject: [PATCH 09/36] Rename HYPER_RACE.py to hyper_race.py --- plugins/minigames/{HYPER_RACE.py => hyper_race.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename plugins/minigames/{HYPER_RACE.py => hyper_race.py} (100%) diff --git a/plugins/minigames/HYPER_RACE.py b/plugins/minigames/hyper_race.py similarity index 100% rename from plugins/minigames/HYPER_RACE.py rename to plugins/minigames/hyper_race.py From 718039bf67f969b6b2957bf9bbb6f20475bf3479 Mon Sep 17 00:00:00 2001 From: brostos <67740566+brostosjoined@users.noreply.github.com> Date: Wed, 24 Jan 2024 21:27:20 +0300 Subject: [PATCH 10/36] Rename Tag.py to tag.py --- plugins/utilities/{Tag.py => tag.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename plugins/utilities/{Tag.py => tag.py} (100%) diff --git a/plugins/utilities/Tag.py b/plugins/utilities/tag.py similarity index 100% rename from plugins/utilities/Tag.py rename to plugins/utilities/tag.py From 4c25646aed2f1136498fad8be3a2e3fbc05401a7 Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Wed, 24 Jan 2024 18:27:47 +0000 Subject: [PATCH 11/36] [ci] apply-version-metadata --- plugins/minigames.json | 56 ++++++++++++++++++++++++++++++++++++------ plugins/utilities.json | 21 +++++++++++++--- 2 files changed, 66 insertions(+), 11 deletions(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index 44e1e93..4e7d0e2 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -979,7 +979,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "718039b", + "released_on": "24-01-2024", + "md5sum": "c1c96450fbdb6e5b2f0d26bb4e797236" + } } }, "hyper_race": { @@ -993,7 +998,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "718039b", + "released_on": "24-01-2024", + "md5sum": "8b423bdae256bd411489528b550b8bd9" + } } }, "meteor_shower_deluxe": { @@ -1007,7 +1017,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "718039b", + "released_on": "24-01-2024", + "md5sum": "7e86bbc8e3ebb26a66602068950adfbf" + } } }, "ofuuu_attack": { @@ -1021,7 +1036,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "718039b", + "released_on": "24-01-2024", + "md5sum": "982c72f2d2cb3d50280f50b022e7865f" + } } }, "safe_zone": { @@ -1035,7 +1055,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "718039b", + "released_on": "24-01-2024", + "md5sum": "862fab0c26947c70397542742fb82635" + } } }, "snow_ball_fight": { @@ -1049,7 +1074,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "718039b", + "released_on": "24-01-2024", + "md5sum": "ef6bd7cd0404674f65e8f8d4da3ab8c8" + } } }, "egg_game": { @@ -1063,7 +1093,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "718039b", + "released_on": "24-01-2024", + "md5sum": "e1d401ec8f2d06dec741d713d6602710" + } } }, "you_vs_bombsquad": { @@ -1077,7 +1112,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "718039b", + "released_on": "24-01-2024", + "md5sum": "451daeabbd628ec70fa31b80a0999f35" + } } } } diff --git a/plugins/utilities.json b/plugins/utilities.json index 2f17edf..fa71aa4 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -1102,7 +1102,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "718039b", + "released_on": "24-01-2024", + "md5sum": "eb917ca19d206dfd19667181dacc1df5" + } } }, "only_night": { @@ -1116,7 +1121,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "718039b", + "released_on": "24-01-2024", + "md5sum": "255d3d6694008cc2f73d115182100b52" + } } }, "tag": { @@ -1130,7 +1140,12 @@ } ], "versions": { - "2.0.1": null + "2.0.1": { + "api_version": 8, + "commit_sha": "718039b", + "released_on": "24-01-2024", + "md5sum": "01cf9e10ab0e1bf51c07d80ff842c632" + } } } } From 177b8ea93f73f074dca927d1a8db4435efb52d63 Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Wed, 24 Jan 2024 21:28:29 +0300 Subject: [PATCH 12/36] Some bug --- plugins/minigames/egg_game.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/minigames/egg_game.py b/plugins/minigames/egg_game.py index 4c0ffc1..09ef244 100644 --- a/plugins/minigames/egg_game.py +++ b/plugins/minigames/egg_game.py @@ -113,7 +113,7 @@ class Player(bs.Player['Team']): class Team(bs.Team[Player]): """Our team type for this game.""" - def on_app_running(self) -> None: + def __init__(self) -> None: self.score = 0 From ef7d79e93bad8bece36301055669abeaa2573128 Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Fri, 26 Jan 2024 05:00:06 +0300 Subject: [PATCH 13/36] More --- .vscode/settings.json | 5 + plugins/minigames.json | 70 ++ plugins/minigames/ba_dark_fields.py | 291 +++++++ plugins/minigames/gravity_falls.py | 34 + plugins/minigames/infinite_ninjas.py | 134 +++ plugins/minigames/lame_fight.py | 158 ++++ plugins/minigames/onslaught_football.py | 1023 +++++++++++++++++++++++ 7 files changed, 1715 insertions(+) create mode 100644 .vscode/settings.json create mode 100644 plugins/minigames/ba_dark_fields.py create mode 100644 plugins/minigames/gravity_falls.py create mode 100644 plugins/minigames/infinite_ninjas.py create mode 100644 plugins/minigames/lame_fight.py create mode 100644 plugins/minigames/onslaught_football.py diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..b242572 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "githubPullRequests.ignoredPullRequestBranches": [ + "main" + ] +} \ No newline at end of file diff --git a/plugins/minigames.json b/plugins/minigames.json index 44e1e93..52ea068 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -1079,6 +1079,76 @@ "versions": { "1.0.0": null } + }, + "ba_dark_fileds": { + "description": "Get to the other side and watch your step", + "external_url": "", + "authors": [ + { + "name": "Froshlee24", + "email": "", + "discord": "froshlee24" + } + ], + "versions": { + "1.0.0": null + } + }, + "onslaught_football": { + "description": "Onslaught but in football map", + "external_url": "", + "authors": [ + { + "name": "", + "email": "", + "discord": "" + } + ], + "versions": { + "1.0.0": null + } + }, + "lame_fight": { + "description": "Save World With Super Powers", + "external_url": "", + "authors": [ + { + "name": "", + "email": "", + "discord": "" + } + ], + "versions": { + "1.0.0": null + } + }, + "infinite_ninjas": { + "description": "How long can you survive from Ninjas??", + "external_url": "", + "authors": [ + { + "name": "", + "email": "", + "discord": "" + } + ], + "versions": { + "1.0.0": null + } + }, + "gravity_falls": { + "description": "Trip to the moon", + "external_url": "", + "authors": [ + { + "name": "", + "email": "", + "discord": "" + } + ], + "versions": { + "1.0.0": null + } } } } \ No newline at end of file diff --git a/plugins/minigames/ba_dark_fields.py b/plugins/minigames/ba_dark_fields.py new file mode 100644 index 0000000..2a82005 --- /dev/null +++ b/plugins/minigames/ba_dark_fields.py @@ -0,0 +1,291 @@ +# Ported to api 8 by brostos using baport.(https://github.com/bombsquad-community/baport) +"""Dark fields mini-game.""" + +# Minigame by Froshlee24 +# ba_meta require api 8 +# (see https://ballistica.net/wiki/meta-tag-system) + +from __future__ import annotations +import random +from typing import TYPE_CHECKING + +import _babase +import babase +import bauiv1 as bui +import bascenev1 as bs +from bascenev1lib.actor import bomb +from bascenev1._music import setmusic +from bascenev1lib.actor.scoreboard import Scoreboard +from bascenev1._gameutils import animate_array +from bascenev1lib.gameutils import SharedObjects +from bascenev1lib.actor.playerspaz import PlayerSpaz + +if TYPE_CHECKING: + from typing import Any, Sequence, Optional, List, Dict, Type, Type + +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 DarkFieldsGame(bs.TeamGameActivity[Player, Team]): + + name = 'Dark Fields' + description = 'Get to the other side.' + available_settings = [ + bs.IntSetting('Score to Win', + min_value=1, + default=3, + ), + 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), + bs.BoolSetting('Players as center of interest', default=True), + ] + + @classmethod + def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]: + return bs.app.classic.getmaps('football') + + @classmethod + def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool: + return (issubclass(sessiontype, bs.DualTeamSession) + or issubclass(sessiontype, bs.FreeForAllSession)) + + def __init__(self, settings: dict): + super().__init__(settings) + self._epic_mode = bool(settings['Epic Mode']) + self._center_of_interest = bool(settings['Players as center of interest']) + self._score_to_win_per_player = int(settings['Score to Win']) + self._time_limit = float(settings['Time Limit']) + + self._scoreboard = Scoreboard() + + shared = SharedObjects.get() + + self._scoreRegionMaterial = bs.Material() + self._scoreRegionMaterial.add_actions( + conditions=("they_have_material",shared.player_material), + actions=(("modify_part_collision","collide",True), + ("modify_part_collision","physical",False), + ("call","at_connect", self._onPlayerScores))) + + self.slow_motion = self._epic_mode + self.default_music = (bs.MusicType.EPIC if self._epic_mode else None) + + + def on_transition_in(self) -> None: + super().on_transition_in() + gnode = bs.getactivity().globalsnode + gnode.tint = (0.5,0.5,0.5) + + a = bs.newnode('locator',attrs={'shape':'box','position':(12.2,0,.1087926362), + 'color':(5,0,0),'opacity':1,'draw_beauty':True,'additive':False,'size':[2.5,0.1,12.8]}) + + b = bs.newnode('locator',attrs={'shape':'box','position':(-12.1,0,.1087926362), + 'color':(0,0,5),'opacity':1,'draw_beauty':True,'additive':False,'size':[2.5,0.1,12.8]}) + + def on_begin(self) -> None: + # self._has_begun = False + super().on_begin() + + self.setup_standard_time_limit(self._time_limit) + self._score_to_win = (self._score_to_win_per_player * + max(1, max(len(t.players) for t in self.teams))) + self._update_scoreboard() + + self.isUpdatingMines = False + self._scoreSound = bs.getsound('dingSmall') + + for p in self.players: + if p.actor is not None: + try: + p.actor.disconnect_controls_from_player() + except Exception: + print('Can\'t connect to player') + + self._scoreRegions = [] + defs = bs.getactivity().map.defs + self._scoreRegions.append(bs.NodeActor(bs.newnode('region', + attrs={'position':defs.boxes['goal1'][0:3], + 'scale':defs.boxes['goal1'][6:9], + 'type': 'box', + 'materials':(self._scoreRegionMaterial,)}))) + self.mines = [] + self.spawnMines() + bs.timer(0.8 if self.slow_motion else 1.7,self.start) + + def start(self): + # self._has_begun = True + self._show_info() + bs.timer(random.randrange(3,7),self.doRandomLighting) + if not self._epic_mode: + setmusic(bs.MusicType.SCARY) + animate_array(bs.getactivity().globalsnode,'tint',3,{0:(0.5,0.5,0.5),2:(0.2,0.2,0.2)}) + + for p in self.players: + self.doPlayer(p) + + def spawn_player(self, player): + if not self.has_begun(): + return + else: + self.doPlayer(player) + + def doPlayer(self,player): + pos = (-12.4,1,random.randrange(-5,5)) + player = self.spawn_player_spaz(player,pos) + player.connect_controls_to_player(enable_punch=False,enable_bomb=False) + player.node.is_area_of_interest = self._center_of_interest + + def _show_info(self) -> None: + if self.has_begun(): + super()._show_info() + + def on_team_join(self, team: Team) -> None: + if self.has_begun(): + self._update_scoreboard() + + def _update_scoreboard(self) -> None: + for team in self.teams: + self._scoreboard.set_team_value(team, team.score, self._score_to_win) + + def doRandomLighting(self): + bs.timer(random.randrange(3,7),self.doRandomLighting) + if self.isUpdatingMines: return + + delay = 0 + for mine in self.mines: + if mine.node.exists(): + pos = mine.node.position + bs.timer(delay,babase.Call(self.do_light,pos)) + delay += 0.005 if self._epic_mode else 0.01 + + def do_light(self,pos): + light = bs.newnode('light',attrs={ + 'position': pos, + 'volume_intensity_scale': 1.0, + 'radius':0.1, + 'color': (1,0,0) + }) + bs.animate(light, 'intensity', { 0: 2.0, 3.0: 0.0}) + bs.timer(3.0, light.delete) + + def spawnMines(self): + delay = 0 + h_range = [10,8,6,4,2,0,-2,-4,-6,-8,-10] + for h in h_range: + for i in range(random.randint(3,4)): + x = h+random.random() + y = random.randrange(-5,6)+(random.random()) + pos = (x,1,y) + bs.timer(delay,babase.Call(self.doMine,pos)) + delay += 0.015 if self._epic_mode else 0.04 + bs.timer(5.0,self.stopUpdateMines) + + def stopUpdateMines(self): + self.isUpdatingMines = False + + def updateMines(self): + if self.isUpdatingMines: return + self.isUpdatingMines = True + for m in self.mines: + m.node.delete() + self.mines = [] + self.spawnMines() + + + def doMine(self,pos): + b = bomb.Bomb(position=pos,bomb_type='land_mine').autoretain() + b.add_explode_callback(self._on_bomb_exploded) + b.arm() + self.mines.append(b) + + def _on_bomb_exploded(self, bomb: Bomb, blast: Blast) -> None: + assert blast.node + p = blast.node.position + pos = (p[0],p[1]+1,p[2]) + bs.timer(0.5,babase.Call(self.doMine,pos)) + + def _onPlayerScores(self): + player: Optional[Player] + try: + spaz = bs.getcollision().opposingnode.getdelegate(PlayerSpaz, True) + except bs.NotFoundError: + return + + if not spaz.is_alive(): + return + + try: + player = spaz.getplayer(Player, True) + except bs.NotFoundError: + return + + if player.exists() and player.is_alive(): + player.team.score += 1 + self._scoreSound.play() + pos = player.actor.node.position + + animate_array(bs.getactivity().globalsnode,'tint',3,{0:(0.5,0.5,0.5),2.8:(0.2,0.2,0.2)}) + self._update_scoreboard() + + light = bs.newnode('light', + attrs={ + 'position': pos, + 'radius': 0.5, + 'color': (1, 0, 0) + }) + bs.animate(light, 'intensity', {0.0: 0, 0.1: 1, 0.5: 0}, loop=False) + bs.timer(1.0, light.delete) + + player.actor.handlemessage(bs.DieMessage( how=bs.DeathType.REACHED_GOAL)) + self.updateMines() + + if any(team.score >= self._score_to_win for team in self.teams): + bs.timer(0.5, self.end_game) + + 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) + + else: + return super().handlemessage(msg) + return None + + def end_game(self) -> None: + results = bs.GameResults() + for team in self.teams: + results.set_team_score(team, team.score) + self.end(results=results) \ No newline at end of file diff --git a/plugins/minigames/gravity_falls.py b/plugins/minigames/gravity_falls.py new file mode 100644 index 0000000..f24b591 --- /dev/null +++ b/plugins/minigames/gravity_falls.py @@ -0,0 +1,34 @@ +# Ported to api 8 by brostos using baport.(https://github.com/bombsquad-community/baport) +## Made by MattZ45986 on GitHub +## Ported by: Freaku / @[Just] Freak#4999 + + +import babase +import bauiv1 as bui +import bascenev1 as bs +from bascenev1lib.game.elimination import EliminationGame + + + +# ba_meta require api 8 +# ba_meta export bascenev1.GameActivity +class GFGame(EliminationGame): + name = 'Gravity Falls' + + def spawn_player(self, player): + actor = self.spawn_player_spaz(player, (0,5,0)) + if not self._solo_mode: + bs.timer(0.3, babase.Call(self._print_lives, player)) + + # If we have any icons, update their state. + for icon in player.icons: + icon.handle_player_spawned() + bs.timer(1,babase.Call(self.raise_player, player)) + return actor + + def raise_player(self, player): + if player.is_alive(): + try: + player.actor.node.handlemessage("impulse",player.actor.node.position[0],player.actor.node.position[1]+.5,player.actor.node.position[2],0,5,0, 3,10,0,0, 0,5,0) + except: pass + bs.timer(0.05,babase.Call(self.raise_player,player)) \ No newline at end of file diff --git a/plugins/minigames/infinite_ninjas.py b/plugins/minigames/infinite_ninjas.py new file mode 100644 index 0000000..c43cb65 --- /dev/null +++ b/plugins/minigames/infinite_ninjas.py @@ -0,0 +1,134 @@ +# Ported to api 8 by brostos using baport.(https://github.com/bombsquad-community/baport) +# ba_meta require api 8 + +#Copy pasted from ExplodoRun by Blitz,just edited Bots and map 😝 + + +from __future__ import annotations + +import random +from typing import TYPE_CHECKING + +import babase +import bauiv1 as bui +import bascenev1 as bs +from bascenev1lib.actor.spazbot import SpazBotSet, ChargerBot, SpazBotDiedMessage +from bascenev1lib.actor.onscreentimer import OnScreenTimer + +if TYPE_CHECKING: + from typing import Any, Type, Dict, List, Optional + +## MoreMinigames.py support ## +def ba_get_api_version(): + return 6 + +def ba_get_levels(): + return [babase._level.Level( + 'Infinite Ninjas',gametype=InfiniteNinjasGame, + settings={}, + preview_texture_name = 'footballStadiumPreview'), + babase._level.Level( + 'Epic Infinite Ninjas',gametype=InfiniteNinjasGame, + settings={'Epic Mode':True}, + preview_texture_name = 'footballStadiumPreview')] +## MoreMinigames.py support ## + +class Player(bs.Player['Team']): + """Our player type for this game.""" + + +class Team(bs.Team[Player]): + """Our team type for this game.""" + +# ba_meta export bascenev1.GameActivity +class InfiniteNinjasGame(bs.TeamGameActivity[Player, Team]): + name = "Infinite Ninjas" + description = "How long can you survive from Ninjas??" + available_settings = [bs.BoolSetting('Epic Mode', default=False)] + scoreconfig = bs.ScoreConfig(label='Time', + scoretype=bs.ScoreType.MILLISECONDS, + lower_is_better=False) + default_music = bs.MusicType.TO_THE_DEATH + + def __init__(self, settings:dict): + settings['map'] = "Football Stadium" + self._epic_mode = settings.get('Epic Mode', False) + if self._epic_mode: + self.slow_motion = True + super().__init__(settings) + self._timer: Optional[OnScreenTimer] = None + self._winsound = bs.getsound('score') + self._won = False + self._bots = SpazBotSet() + self.wave = 1 + + def on_begin(self) -> None: + super().on_begin() + + self._timer = OnScreenTimer() + bs.timer(2.5, self._timer.start) + + #Bots Hehe + bs.timer(2.5,self.street) + + def street(self): + for a in range(self.wave): + p1 = random.choice([-5,-2.5,0,2.5,5]) + p3 = random.choice([-4.5,-4.14,-5,-3]) + time = random.choice([1,1.5,2.5,2]) + self._bots.spawn_bot(ChargerBot, pos=(p1,0.4,p3),spawn_time = time) + self.wave += 1 + + def botrespawn(self): + if not self._bots.have_living_bots(): + self.street() + def handlemessage(self, msg: Any) -> Any: + + # A player has died. + if isinstance(msg, bs.PlayerDiedMessage): + super().handlemessage(msg) # Augment standard behavior. + self._won = True + self.end_game() + + # A spaz-bot has died. + elif isinstance(msg, SpazBotDiedMessage): + # Unfortunately the bot-set will always tell us there are living + # bots if we ask here (the currently-dying bot isn't officially + # marked dead yet) ..so lets push a call into the event loop to + # check once this guy has finished dying. + babase.pushcall(self.botrespawn) + + # Let the base class handle anything we don't. + else: + return super().handlemessage(msg) + return None + + # When this is called, we should fill out results and end the game + # *regardless* of whether is has been won. (this may be called due + # to a tournament ending or other external reason). + def end_game(self) -> None: + + # Stop our on-screen timer so players can see what they got. + assert self._timer is not None + self._timer.stop() + + results = bs.GameResults() + + # If we won, set our score to the elapsed time in milliseconds. + # (there should just be 1 team here since this is co-op). + # ..if we didn't win, leave scores as default (None) which means + # we lost. + if self._won: + elapsed_time_ms = int((bs.time() - self._timer.starttime) * 1000.0) + bs.cameraflash() + self._winsound.play() + for team in self.teams: + for player in team.players: + if player.actor: + player.actor.handlemessage(bs.CelebrateMessage()) + results.set_team_score(team, elapsed_time_ms) + + # Ends the activity. + self.end(results) + + \ No newline at end of file diff --git a/plugins/minigames/lame_fight.py b/plugins/minigames/lame_fight.py new file mode 100644 index 0000000..e997a72 --- /dev/null +++ b/plugins/minigames/lame_fight.py @@ -0,0 +1,158 @@ +# Ported to api 8 by brostos using baport.(https://github.com/bombsquad-community/baport) + +# ba_meta require api 8 +# (see https://ballistica.net/wiki/meta-tag-system) + +from __future__ import annotations + +import random +from typing import TYPE_CHECKING + +import babase +import bauiv1 as bui +import bascenev1 as bs +from bascenev1lib.actor.spazbot import SpazBotSet, ChargerBot, BrawlerBotProShielded, TriggerBotProShielded, ExplodeyBot, BomberBotProShielded, SpazBotDiedMessage +from bascenev1lib.actor.onscreentimer import OnScreenTimer + +if TYPE_CHECKING: + from typing import Any, Type, Dict, List, Optional + +def ba_get_api_version(): + return 6 + +def ba_get_levels(): + return [babase._level.Level( + 'Lame Fight', + gametype=LameFightGame, + settings={}, + preview_texture_name='courtyardPreview')] + +class Player(bs.Player['Team']): + """Our player type for this game.""" + + +class Team(bs.Team[Player]): + """Our team type for this game.""" + +# ba_meta export bascenev1.GameActivity +class LameFightGame(bs.TeamGameActivity[Player, Team]): + name = "Lame Fight" + description = "Save World With Super Powers" + slow_motion = True + scoreconfig = bs.ScoreConfig(label='Time', + scoretype=bs.ScoreType.MILLISECONDS, + lower_is_better=True) + default_music = bs.MusicType.TO_THE_DEATH + + def __init__(self, settings:dict): + settings['map'] = "Courtyard" + super().__init__(settings) + self._timer: Optional[OnScreenTimer] = None + self._winsound = bs.getsound('score') + self._won = False + self._bots = SpazBotSet() + + def on_begin(self) -> None: + super().on_begin() + + self._timer = OnScreenTimer() + bs.timer(4.0, self._timer.start) + + #Bots Hehe + bs.timer(1.0, lambda: self._bots.spawn_bot(ChargerBot, pos=(3,3,-2),spawn_time = 3.0)) + bs.timer(1.0, lambda: self._bots.spawn_bot(ChargerBot, pos=(-3,3,-2),spawn_time = 3.0)) + bs.timer(1.0, lambda: self._bots.spawn_bot(ChargerBot, pos=(5,3,-2),spawn_time = 3.0)) + bs.timer(1.0, lambda: self._bots.spawn_bot(ChargerBot, pos=(-5,3,-2),spawn_time = 3.0)) + bs.timer(1.0, lambda: self._bots.spawn_bot(ChargerBot, pos=(0,3,1),spawn_time = 3.0)) + bs.timer(1.0, lambda: self._bots.spawn_bot(ChargerBot, pos=(0,3,-5),spawn_time = 3.0)) + bs.timer(9.0, lambda: self._bots.spawn_bot(BomberBotProShielded, pos=(-7,5,-7.5),spawn_time = 3.0)) + bs.timer(9.0, lambda: self._bots.spawn_bot(BomberBotProShielded, pos=(7,5,-7.5),spawn_time = 3.0)) + bs.timer(9.0, lambda: self._bots.spawn_bot(BomberBotProShielded, pos=(7,5,1.5),spawn_time = 3.0)) + bs.timer(9.0, lambda: self._bots.spawn_bot(BomberBotProShielded, pos=(-7,5,1.5),spawn_time = 3.0)) + bs.timer(12.0, lambda: self._bots.spawn_bot(TriggerBotProShielded, pos=(-1,7,-8),spawn_time = 3.0)) + bs.timer(12.0, lambda: self._bots.spawn_bot(TriggerBotProShielded, pos=(1,7,-8),spawn_time = 3.0)) + bs.timer(15.0, lambda: self._bots.spawn_bot(ExplodeyBot, pos=(0,3,-5),spawn_time = 3.0)) + bs.timer(20.0, lambda: self._bots.spawn_bot(ExplodeyBot, pos=(0,3,1),spawn_time = 3.0)) + bs.timer(20.0, lambda: self._bots.spawn_bot(ExplodeyBot, pos=(-5,3,-2),spawn_time = 3.0)) + bs.timer(20.0, lambda: self._bots.spawn_bot(ExplodeyBot, pos=(5,3,-2),spawn_time = 3.0)) + bs.timer(30,self.street) + + def street(self): + bs.broadcastmessage("Lame Guys Are Here!",color = (1,0,0)) + for a in range(-1,2): + for b in range(-3,0): + self._bots.spawn_bot(BrawlerBotProShielded, pos=(a,3,b),spawn_time = 3.0) + + def spawn_player(self, player: Player) -> bs.Actor: + spawn_center = (0, 3, -2) + pos = (spawn_center[0] + random.uniform(-1.5, 1.5), spawn_center[1], + spawn_center[2] + random.uniform(-1.5, 1.5)) + spaz = self.spawn_player_spaz(player,position = pos) + p = ["Bigger Blast","Stronger Punch","Shield","Speed"] + Power = random.choice(p) + spaz.bomb_type = random.choice(["normal","sticky","ice","impact","normal","ice","sticky"]) + bs.broadcastmessage(f"Now You Have {Power}") + if Power == p[0]: + spaz.bomb_count = 3 + spaz.blast_radius = 2.5 + if Power == p[1]: + spaz._punch_cooldown = 350 + spaz._punch_power_scale = 2.0 + if Power == p[2]: + spaz.equip_shields() + if Power == p[3]: + spaz.node.hockey = True + return spaz + def _check_if_won(self) -> None: + if not self._bots.have_living_bots(): + self._won = True + self.end_game() + def handlemessage(self, msg: Any) -> Any: + + # A player has died. + if isinstance(msg, bs.PlayerDiedMessage): + super().handlemessage(msg) # Augment standard behavior. + self.respawn_player(msg.getplayer(Player)) + + # A spaz-bot has died. + elif isinstance(msg, SpazBotDiedMessage): + # Unfortunately the bot-set will always tell us there are living + # bots if we ask here (the currently-dying bot isn't officially + # marked dead yet) ..so lets push a call into the event loop to + # check once this guy has finished dying. + babase.pushcall(self._check_if_won) + + # Let the base class handle anything we don't. + else: + return super().handlemessage(msg) + return None + + # When this is called, we should fill out results and end the game + # *regardless* of whether is has been won. (this may be called due + # to a tournament ending or other external reason). + def end_game(self) -> None: + + # Stop our on-screen timer so players can see what they got. + assert self._timer is not None + self._timer.stop() + + results = bs.GameResults() + + # If we won, set our score to the elapsed time in milliseconds. + # (there should just be 1 team here since this is co-op). + # ..if we didn't win, leave scores as default (None) which means + # we lost. + if self._won: + elapsed_time_ms = int((bs.time() - self._timer.starttime) * 1000.0) + bs.cameraflash() + self._winsound.play() + for team in self.teams: + for player in team.players: + if player.actor: + player.actor.handlemessage(bs.CelebrateMessage()) + results.set_team_score(team, elapsed_time_ms) + + # Ends the activity. + self.end(results) + + \ No newline at end of file diff --git a/plugins/minigames/onslaught_football.py b/plugins/minigames/onslaught_football.py new file mode 100644 index 0000000..06a5c5c --- /dev/null +++ b/plugins/minigames/onslaught_football.py @@ -0,0 +1,1023 @@ +# Ported to api 8 by brostos using baport.(https://github.com/bombsquad-community/baport) +# ba_meta require api 8 +# (see https://ballistica.net/wiki/meta-tag-system) + +from __future__ import annotations +from asyncio import base_subprocess + +import math +import random +from enum import Enum, unique +from dataclasses import dataclass +from typing import TYPE_CHECKING + +import babase +import bauiv1 as bui +import bascenev1 as bs +from bascenev1lib.actor.popuptext import PopupText +from bascenev1lib.actor.bomb import TNTSpawner +from bascenev1lib.actor.playerspaz import PlayerSpazHurtMessage +from bascenev1lib.actor.scoreboard import Scoreboard +from bascenev1lib.actor.controlsguide import ControlsGuide +from bascenev1lib.actor.powerupbox import PowerupBox, PowerupBoxFactory +from bascenev1lib.actor.spazbot import ( + SpazBotDiedMessage, + SpazBotSet, + ChargerBot, + StickyBot, + BomberBot, + BomberBotLite, + BrawlerBot, + BrawlerBotLite, + TriggerBot, + BomberBotStaticLite, + TriggerBotStatic, + BomberBotProStatic, + TriggerBotPro, + ExplodeyBot, + BrawlerBotProShielded, + ChargerBotProShielded, + BomberBotPro, + TriggerBotProShielded, + BrawlerBotPro, + BomberBotProShielded, +) + +if TYPE_CHECKING: + from typing import Any, Sequence + from bascenev1lib.actor.spazbot import SpazBot + + +@dataclass +class Wave: + """A wave of enemies.""" + + entries: list[Spawn | Spacing | Delay | None] + base_angle: float = 0.0 + + +@dataclass +class Spawn: + """A bot spawn event in a wave.""" + + bottype: type[SpazBot] | str + point: Point | None = None + spacing: float = 5.0 + + +@dataclass +class Spacing: + """Empty space in a wave.""" + + spacing: float = 5.0 + + +@dataclass +class Delay: + """A delay between events in a wave.""" + + duration: float + + +class Player(bs.Player['Team']): + """Our player type for this game.""" + + def __init__(self) -> None: + self.has_been_hurt = False + self.respawn_wave = 0 + + +class Team(bs.Team[Player]): + """Our team type for this game.""" + + +class OnslaughtFootballGame(bs.CoopGameActivity[Player, Team]): + """Co-op game where players try to survive attacking waves of enemies.""" + + name = 'Onslaught' + description = 'Defeat all enemies.' + + tips: list[str | babase.GameTip] = [ + 'Hold any button to run.' + ' (Trigger buttons work well if you have them)', + 'Try tricking enemies into killing eachother or running off cliffs.', + 'Try \'Cooking off\' bombs for a second or two before throwing them.', + 'It\'s easier to win with a friend or two helping.', + 'If you stay in one place, you\'re toast. Run and dodge to survive..', + 'Practice using your momentum to throw bombs more accurately.', + 'Your punches do much more damage if you are running or spinning.', + ] + + # Show messages when players die since it matters here. + announce_player_deaths = True + + def __init__(self, settings: dict): + super().__init__(settings) + self._new_wave_sound = bs.getsound('scoreHit01') + self._winsound = bs.getsound('score') + self._cashregistersound = bs.getsound('cashRegister') + self._a_player_has_been_hurt = False + self._player_has_dropped_bomb = False + self._spawn_center = (0, 0.2, 0) + self._tntspawnpos = (0, 0.95, -0.77) + self._powerup_center = (0, 1.5, 0) + self._powerup_spread = (6.0, 4.0) + self._scoreboard: Scoreboard | None = None + self._game_over = False + self._wavenum = 0 + self._can_end_wave = True + self._score = 0 + self._time_bonus = 0 + self._spawn_info_text: bs.NodeActor | None = None + self._dingsound = bs.getsound('dingSmall') + self._dingsoundhigh = bs.getsound('dingSmallHigh') + self._have_tnt = False + self._excluded_powerups: list[str] | None = None + self._waves: list[Wave] = [] + self._tntspawner: TNTSpawner | None = None + self._bots: SpazBotSet | None = None + self._powerup_drop_timer: bs.Timer | None = None + self._time_bonus_timer: bs.Timer | None = None + self._time_bonus_text: bs.NodeActor | None = None + self._flawless_bonus: int | None = None + self._wave_text: bs.NodeActor | None = None + self._wave_update_timer: bs.Timer | None = None + self._throw_off_kills = 0 + self._land_mine_kills = 0 + self._tnt_kills = 0 + + self._epic_mode = bool(settings['Epic Mode']) + # Base class overrides. + self.slow_motion = self._epic_mode + self.default_music = ( + bs.MusicType.EPIC if self._epic_mode else bs.MusicType.ONSLAUGHT + ) + + def on_transition_in(self) -> None: + super().on_transition_in() + self._spawn_info_text = bs.NodeActor( + bs.newnode( + 'text', + attrs={ + 'position': (15, -130), + 'h_attach': 'left', + 'v_attach': 'top', + 'scale': 0.55, + 'color': (0.3, 0.8, 0.3, 1.0), + 'text': '', + }, + ) + ) + self._scoreboard = Scoreboard( + label=babase.Lstr(resource='scoreText'), score_split=0.5 + ) + + def on_begin(self) -> None: + super().on_begin() + self._have_tnt = True + self._excluded_powerups = [] + self._waves = [] + bs.timer(4.0, self._start_powerup_drops) + + # Our TNT spawner (if applicable). + if self._have_tnt: + self._tntspawner = TNTSpawner(position=self._tntspawnpos) + + self.setup_low_life_warning_sound() + self._update_scores() + self._bots = SpazBotSet() + bs.timer(4.0, self._start_updating_waves) + self._next_ffa_start_index = random.randrange( + len(self.map.get_def_points('ffa_spawn')) + ) + + def _get_dist_grp_totals(self, grps: list[Any]) -> tuple[int, int]: + totalpts = 0 + totaldudes = 0 + for grp in grps: + for grpentry in grp: + dudes = grpentry[1] + totalpts += grpentry[0] * dudes + totaldudes += dudes + return totalpts, totaldudes + + def _get_distribution( + self, + target_points: int, + min_dudes: int, + max_dudes: int, + group_count: int, + max_level: int, + ) -> list[list[tuple[int, int]]]: + """Calculate a distribution of bad guys given some params.""" + max_iterations = 10 + max_dudes * 2 + + groups: list[list[tuple[int, int]]] = [] + for _g in range(group_count): + groups.append([]) + types = [1] + if max_level > 1: + types.append(2) + if max_level > 2: + types.append(3) + if max_level > 3: + types.append(4) + for iteration in range(max_iterations): + diff = self._add_dist_entry_if_possible( + groups, max_dudes, target_points, types + ) + + total_points, total_dudes = self._get_dist_grp_totals(groups) + full = total_points >= target_points + + if full: + # Every so often, delete a random entry just to + # shake up our distribution. + if random.random() < 0.2 and iteration != max_iterations - 1: + self._delete_random_dist_entry(groups) + + # If we don't have enough dudes, kill the group with + # the biggest point value. + elif ( + total_dudes < min_dudes and iteration != max_iterations - 1 + ): + self._delete_biggest_dist_entry(groups) + + # If we've got too many dudes, kill the group with the + # smallest point value. + elif ( + total_dudes > max_dudes and iteration != max_iterations - 1 + ): + self._delete_smallest_dist_entry(groups) + + # Close enough.. we're done. + else: + if diff == 0: + break + + return groups + + def _add_dist_entry_if_possible( + self, + groups: list[list[tuple[int, int]]], + max_dudes: int, + target_points: int, + types: list[int], + ) -> int: + # See how much we're off our target by. + total_points, total_dudes = self._get_dist_grp_totals(groups) + diff = target_points - total_points + dudes_diff = max_dudes - total_dudes + + # Add an entry if one will fit. + value = types[random.randrange(len(types))] + group = groups[random.randrange(len(groups))] + if not group: + max_count = random.randint(1, 6) + else: + max_count = 2 * random.randint(1, 3) + max_count = min(max_count, dudes_diff) + count = min(max_count, diff // value) + if count > 0: + group.append((value, count)) + total_points += value * count + total_dudes += count + diff = target_points - total_points + return diff + + def _delete_smallest_dist_entry( + self, groups: list[list[tuple[int, int]]] + ) -> None: + smallest_value = 9999 + smallest_entry = None + smallest_entry_group = None + for group in groups: + for entry in group: + if entry[0] < smallest_value or smallest_entry is None: + smallest_value = entry[0] + smallest_entry = entry + smallest_entry_group = group + assert smallest_entry is not None + assert smallest_entry_group is not None + smallest_entry_group.remove(smallest_entry) + + def _delete_biggest_dist_entry( + self, groups: list[list[tuple[int, int]]] + ) -> None: + biggest_value = 9999 + biggest_entry = None + biggest_entry_group = None + for group in groups: + for entry in group: + if entry[0] > biggest_value or biggest_entry is None: + biggest_value = entry[0] + biggest_entry = entry + biggest_entry_group = group + if biggest_entry is not None: + assert biggest_entry_group is not None + biggest_entry_group.remove(biggest_entry) + + def _delete_random_dist_entry( + self, groups: list[list[tuple[int, int]]] + ) -> None: + entry_count = 0 + for group in groups: + for _ in group: + entry_count += 1 + if entry_count > 1: + del_entry = random.randrange(entry_count) + entry_count = 0 + for group in groups: + for entry in group: + if entry_count == del_entry: + group.remove(entry) + break + entry_count += 1 + + def spawn_player(self, player: Player) -> bs.Actor: + + # We keep track of who got hurt each wave for score purposes. + player.has_been_hurt = False + pos = ( + self._spawn_center[0] + random.uniform(-1.5, 1.5), + self._spawn_center[1], + self._spawn_center[2] + random.uniform(-1.5, 1.5), + ) + spaz = self.spawn_player_spaz(player, position=pos) + spaz.add_dropped_bomb_callback(self._handle_player_dropped_bomb) + return spaz + + def _handle_player_dropped_bomb( + self, player: bs.Actor, bomb: bs.Actor + ) -> None: + del player, bomb # Unused. + self._player_has_dropped_bomb = True + + def _drop_powerup(self, index: int, poweruptype: str | None = None) -> None: + poweruptype = PowerupBoxFactory.get().get_random_powerup_type( + forcetype=poweruptype, excludetypes=self._excluded_powerups + ) + PowerupBox( + position=self.map.powerup_spawn_points[index], + poweruptype=poweruptype, + ).autoretain() + + def _start_powerup_drops(self) -> None: + self._powerup_drop_timer = bs.Timer( + 3.0, bs.WeakCall(self._drop_powerups), repeat=True + ) + + def _drop_powerups( + self, standard_points: bool = False, poweruptype: str | None = None + ) -> None: + """Generic powerup drop.""" + if standard_points: + points = self.map.powerup_spawn_points + for i in range(len(points)): + bs.timer( + 1.0 + i * 0.5, + bs.WeakCall( + self._drop_powerup, i, poweruptype if i == 0 else None + ), + ) + else: + point = ( + self._powerup_center[0] + + random.uniform( + -1.0 * self._powerup_spread[0], + 1.0 * self._powerup_spread[0], + ), + self._powerup_center[1], + self._powerup_center[2] + + random.uniform( + -self._powerup_spread[1], self._powerup_spread[1] + ), + ) + + # Drop one random one somewhere. + PowerupBox( + position=point, + poweruptype=PowerupBoxFactory.get().get_random_powerup_type( + excludetypes=self._excluded_powerups + ), + ).autoretain() + + def do_end(self, outcome: str, delay: float = 0.0) -> None: + """End the game with the specified outcome.""" + if outcome == 'defeat': + self.fade_to_red() + score: int | None + if self._wavenum >= 2: + score = self._score + fail_message = None + else: + score = None + fail_message = babase.Lstr(resource='reachWave2Text') + self.end( + { + 'outcome': outcome, + 'score': score, + 'fail_message': fail_message, + 'playerinfos': self.initialplayerinfos, + }, + delay=delay, + ) + + def _update_waves(self) -> None: + + # If we have no living bots, go to the next wave. + assert self._bots is not None + if ( + self._can_end_wave + and not self._bots.have_living_bots() + and not self._game_over + ): + self._can_end_wave = False + self._time_bonus_timer = None + self._time_bonus_text = None + base_delay = 0.0 + + # Reward time bonus. + if self._time_bonus > 0: + bs.timer(0, babase.Call(self._cashregistersound.play)) + bs.timer( + base_delay, + bs.WeakCall(self._award_time_bonus, self._time_bonus), + ) + base_delay += 1.0 + + # Reward flawless bonus. + if self._wavenum > 0: + have_flawless = False + for player in self.players: + if player.is_alive() and not player.has_been_hurt: + have_flawless = True + bs.timer( + base_delay, + bs.WeakCall(self._award_flawless_bonus, player), + ) + player.has_been_hurt = False # reset + if have_flawless: + base_delay += 1.0 + + self._wavenum += 1 + + # Short celebration after waves. + if self._wavenum > 1: + self.celebrate(0.5) + bs.timer(base_delay, bs.WeakCall(self._start_next_wave)) + + def _award_completion_bonus(self) -> None: + self._cashregistersound.play() + for player in self.players: + try: + if player.is_alive(): + assert self.initialplayerinfos is not None + self.stats.player_scored( + player, + int(100 / len(self.initialplayerinfos)), + scale=1.4, + color=(0.6, 0.6, 1.0, 1.0), + title=babase.Lstr(resource='completionBonusText'), + screenmessage=False, + ) + except Exception: + babase.print_exception() + + def _award_time_bonus(self, bonus: int) -> None: + self._cashregistersound.play() + PopupText( + babase.Lstr( + value='+${A} ${B}', + subs=[ + ('${A}', str(bonus)), + ('${B}', babase.Lstr(resource='timeBonusText')), + ], + ), + color=(1, 1, 0.5, 1), + scale=1.0, + position=(0, 3, -1), + ).autoretain() + self._score += self._time_bonus + self._update_scores() + + def _award_flawless_bonus(self, player: Player) -> None: + self._cashregistersound.play() + try: + if player.is_alive(): + assert self._flawless_bonus is not None + self.stats.player_scored( + player, + self._flawless_bonus, + scale=1.2, + color=(0.6, 1.0, 0.6, 1.0), + title=babase.Lstr(resource='flawlessWaveText'), + screenmessage=False, + ) + except Exception: + babase.print_exception() + + def _start_time_bonus_timer(self) -> None: + self._time_bonus_timer = bs.Timer( + 1.0, bs.WeakCall(self._update_time_bonus), repeat=True + ) + + def _update_player_spawn_info(self) -> None: + + # If we have no living players lets just blank this. + assert self._spawn_info_text is not None + assert self._spawn_info_text.node + if not any(player.is_alive() for player in self.teams[0].players): + self._spawn_info_text.node.text = '' + else: + text: str | babase.Lstr = '' + for player in self.players: + if not player.is_alive(): + rtxt = babase.Lstr( + resource='onslaughtRespawnText', + subs=[ + ('${PLAYER}', player.getname()), + ('${WAVE}', str(player.respawn_wave)), + ], + ) + text = babase.Lstr( + value='${A}${B}\n', + subs=[ + ('${A}', text), + ('${B}', rtxt), + ], + ) + self._spawn_info_text.node.text = text + + def _respawn_players_for_wave(self) -> None: + # Respawn applicable players. + if self._wavenum > 1 and not self.is_waiting_for_continue(): + for player in self.players: + if ( + not player.is_alive() + and player.respawn_wave == self._wavenum + ): + self.spawn_player(player) + self._update_player_spawn_info() + + def _setup_wave_spawns(self, wave: Wave) -> None: + tval = 0.0 + dtime = 0.2 + if self._wavenum == 1: + spawn_time = 3.973 + tval += 0.5 + else: + spawn_time = 2.648 + + bot_angle = wave.base_angle + self._time_bonus = 0 + self._flawless_bonus = 0 + for info in wave.entries: + if info is None: + continue + if isinstance(info, Delay): + spawn_time += info.duration + continue + if isinstance(info, Spacing): + bot_angle += info.spacing + continue + bot_type_2 = info.bottype + if bot_type_2 is not None: + assert not isinstance(bot_type_2, str) + self._time_bonus += bot_type_2.points_mult * 20 + self._flawless_bonus += bot_type_2.points_mult * 5 + + if self.map.name == 'Doom Shroom': + tval += dtime + spacing = info.spacing + bot_angle += spacing * 0.5 + if bot_type_2 is not None: + tcall = bs.WeakCall( + self.add_bot_at_angle, bot_angle, bot_type_2, spawn_time + ) + bs.timer(tval, tcall) + tval += dtime + bot_angle += spacing * 0.5 + else: + assert bot_type_2 is not None + spcall = bs.WeakCall( + self.add_bot_at_point, bot_type_2, spawn_time + ) + bs.timer(tval, spcall) + + # We can end the wave after all the spawning happens. + bs.timer( + tval + spawn_time - dtime + 0.01, + bs.WeakCall(self._set_can_end_wave), + ) + + def _start_next_wave(self) -> None: + + # This can happen if we beat a wave as we die. + # We don't wanna respawn players and whatnot if this happens. + if self._game_over: + return + + self._respawn_players_for_wave() + wave = self._generate_random_wave() + self._setup_wave_spawns(wave) + self._update_wave_ui_and_bonuses() + bs.timer(0.4, babase.Call(self._new_wave_sound.play)) + + def _update_wave_ui_and_bonuses(self) -> None: + self.show_zoom_message( + babase.Lstr( + value='${A} ${B}', + subs=[ + ('${A}', babase.Lstr(resource='waveText')), + ('${B}', str(self._wavenum)), + ], + ), + scale=1.0, + duration=1.0, + trail=True, + ) + + # Reset our time bonus. + tbtcolor = (1, 1, 0, 1) + tbttxt = babase.Lstr( + value='${A}: ${B}', + subs=[ + ('${A}', babase.Lstr(resource='timeBonusText')), + ('${B}', str(self._time_bonus)), + ], + ) + self._time_bonus_text = bs.NodeActor( + bs.newnode( + 'text', + attrs={ + 'v_attach': 'top', + 'h_attach': 'center', + 'h_align': 'center', + 'vr_depth': -30, + 'color': tbtcolor, + 'shadow': 1.0, + 'flatness': 1.0, + 'position': (0, -60), + 'scale': 0.8, + 'text': tbttxt, + }, + ) + ) + + bs.timer(5.0, bs.WeakCall(self._start_time_bonus_timer)) + wtcolor = (1, 1, 1, 1) + wttxt = babase.Lstr( + value='${A} ${B}', + subs=[ + ('${A}', babase.Lstr(resource='waveText')), + ('${B}', str(self._wavenum) + ('')), + ], + ) + self._wave_text = bs.NodeActor( + bs.newnode( + 'text', + attrs={ + 'v_attach': 'top', + 'h_attach': 'center', + 'h_align': 'center', + 'vr_depth': -10, + 'color': wtcolor, + 'shadow': 1.0, + 'flatness': 1.0, + 'position': (0, -40), + 'scale': 1.3, + 'text': wttxt, + }, + ) + ) + + def _bot_levels_for_wave(self) -> list[list[type[SpazBot]]]: + level = self._wavenum + bot_types = [ + BomberBot, + BrawlerBot, + TriggerBot, + ChargerBot, + BomberBotPro, + BrawlerBotPro, + TriggerBotPro, + BomberBotProShielded, + ExplodeyBot, + ChargerBotProShielded, + StickyBot, + BrawlerBotProShielded, + TriggerBotProShielded, + ] + if level > 5: + bot_types += [ + ExplodeyBot, + TriggerBotProShielded, + BrawlerBotProShielded, + ChargerBotProShielded, + ] + if level > 7: + bot_types += [ + ExplodeyBot, + TriggerBotProShielded, + BrawlerBotProShielded, + ChargerBotProShielded, + ] + if level > 10: + bot_types += [ + TriggerBotProShielded, + TriggerBotProShielded, + TriggerBotProShielded, + TriggerBotProShielded, + ] + if level > 13: + bot_types += [ + TriggerBotProShielded, + TriggerBotProShielded, + TriggerBotProShielded, + TriggerBotProShielded, + ] + bot_levels = [ + [b for b in bot_types if b.points_mult == 1], + [b for b in bot_types if b.points_mult == 2], + [b for b in bot_types if b.points_mult == 3], + [b for b in bot_types if b.points_mult == 4], + ] + + # Make sure all lists have something in them + if not all(bot_levels): + raise RuntimeError('Got empty bot level') + return bot_levels + + def _add_entries_for_distribution_group( + self, + group: list[tuple[int, int]], + bot_levels: list[list[type[SpazBot]]], + all_entries: list[Spawn | Spacing | Delay | None], + ) -> None: + entries: list[Spawn | Spacing | Delay | None] = [] + for entry in group: + bot_level = bot_levels[entry[0] - 1] + bot_type = bot_level[random.randrange(len(bot_level))] + rval = random.random() + if rval < 0.5: + spacing = 10.0 + elif rval < 0.9: + spacing = 20.0 + else: + spacing = 40.0 + split = random.random() > 0.3 + for i in range(entry[1]): + if split and i % 2 == 0: + entries.insert(0, Spawn(bot_type, spacing=spacing)) + else: + entries.append(Spawn(bot_type, spacing=spacing)) + if entries: + all_entries += entries + all_entries.append(Spacing(40.0 if random.random() < 0.5 else 80.0)) + + def _generate_random_wave(self) -> Wave: + level = self._wavenum + bot_levels = self._bot_levels_for_wave() + + target_points = level * 3 - 2 + min_dudes = min(1 + level // 3, 10) + max_dudes = min(10, level + 1) + max_level = ( + 4 if level > 6 else (3 if level > 3 else (2 if level > 2 else 1)) + ) + group_count = 3 + distribution = self._get_distribution( + target_points, min_dudes, max_dudes, group_count, max_level + ) + all_entries: list[Spawn | Spacing | Delay | None] = [] + for group in distribution: + self._add_entries_for_distribution_group( + group, bot_levels, all_entries + ) + angle_rand = random.random() + if angle_rand > 0.75: + base_angle = 130.0 + elif angle_rand > 0.5: + base_angle = 210.0 + elif angle_rand > 0.25: + base_angle = 20.0 + else: + base_angle = -30.0 + base_angle += (0.5 - random.random()) * 20.0 + wave = Wave(base_angle=base_angle, entries=all_entries) + return wave + + def add_bot_at_point( + self, spaz_type: type[SpazBot], spawn_time: float = 1.0 + ) -> None: + """Add a new bot at a specified named point.""" + if self._game_over: + return + def _getpt() -> Sequence[float]: + point = self.map.get_def_points( + 'ffa_spawn')[self._next_ffa_start_index] + self._next_ffa_start_index = ( + self._next_ffa_start_index + 1) % len( + self.map.get_def_points('ffa_spawn') + ) + x_range = (-0.5, 0.5) if point[3] == 0.0 else (-point[3], point[3]) + z_range = (-0.5, 0.5) if point[5] == 0.0 else (-point[5], point[5]) + point = ( + point[0] + random.uniform(*x_range), + point[1], + point[2] + random.uniform(*z_range), + ) + return point + pointpos = _getpt() + + assert self._bots is not None + self._bots.spawn_bot(spaz_type, pos=pointpos, spawn_time=spawn_time) + + def add_bot_at_angle( + self, angle: float, spaz_type: type[SpazBot], spawn_time: float = 1.0 + ) -> None: + """Add a new bot at a specified angle (for circular maps).""" + if self._game_over: + return + angle_radians = angle / 57.2957795 + xval = math.sin(angle_radians) * 1.06 + zval = math.cos(angle_radians) * 1.06 + point = (xval / 0.125, 2.3, (zval / 0.2) - 3.7) + assert self._bots is not None + self._bots.spawn_bot(spaz_type, pos=point, spawn_time=spawn_time) + + def _update_time_bonus(self) -> None: + self._time_bonus = int(self._time_bonus * 0.93) + if self._time_bonus > 0 and self._time_bonus_text is not None: + assert self._time_bonus_text.node + self._time_bonus_text.node.text = babase.Lstr( + value='${A}: ${B}', + subs=[ + ('${A}', babase.Lstr(resource='timeBonusText')), + ('${B}', str(self._time_bonus)), + ], + ) + else: + self._time_bonus_text = None + + def _start_updating_waves(self) -> None: + self._wave_update_timer = bs.Timer( + 2.0, bs.WeakCall(self._update_waves), repeat=True + ) + + def _update_scores(self) -> None: + score = self._score + assert self._scoreboard is not None + self._scoreboard.set_team_value(self.teams[0], score, max_score=None) + + def handlemessage(self, msg: Any) -> Any: + + if isinstance(msg, PlayerSpazHurtMessage): + msg.spaz.getplayer(Player, True).has_been_hurt = True + self._a_player_has_been_hurt = True + + elif isinstance(msg, bs.PlayerScoredMessage): + self._score += msg.score + self._update_scores() + + elif isinstance(msg, bs.PlayerDiedMessage): + super().handlemessage(msg) # Augment standard behavior. + player = msg.getplayer(Player) + self._a_player_has_been_hurt = True + + # Make note with the player when they can respawn: + if self._wavenum < 10: + player.respawn_wave = max(2, self._wavenum + 1) + elif self._wavenum < 15: + player.respawn_wave = max(2, self._wavenum + 2) + else: + player.respawn_wave = max(2, self._wavenum + 3) + bs.timer(0.1, self._update_player_spawn_info) + bs.timer(0.1, self._checkroundover) + + elif isinstance(msg, SpazBotDiedMessage): + pts, importance = msg.spazbot.get_death_points(msg.how) + if msg.killerplayer is not None: + target: Sequence[float] | None + if msg.spazbot.node: + target = msg.spazbot.node.position + else: + target = None + + killerplayer = msg.killerplayer + self.stats.player_scored( + killerplayer, + pts, + target=target, + kill=True, + screenmessage=False, + importance=importance, + ) + self._dingsound.play(volume=0.6) if importance == 1 else self._dingsoundhigh.play(volume=0.6) + + # Normally we pull scores from the score-set, but if there's + # no player lets be explicit. + else: + self._score += pts + self._update_scores() + else: + super().handlemessage(msg) + + def _handle_uber_kill_achievements(self, msg: SpazBotDiedMessage) -> None: + + # Uber mine achievement: + if msg.spazbot.last_attacked_type == ('explosion', 'land_mine'): + self._land_mine_kills += 1 + if self._land_mine_kills >= 6: + self._award_achievement('Gold Miner') + + # Uber tnt achievement: + if msg.spazbot.last_attacked_type == ('explosion', 'tnt'): + self._tnt_kills += 1 + if self._tnt_kills >= 6: + bs.timer( + 0.5, bs.WeakCall(self._award_achievement, 'TNT Terror') + ) + + def _handle_pro_kill_achievements(self, msg: SpazBotDiedMessage) -> None: + + # TNT achievement: + if msg.spazbot.last_attacked_type == ('explosion', 'tnt'): + self._tnt_kills += 1 + if self._tnt_kills >= 3: + bs.timer( + 0.5, + bs.WeakCall( + self._award_achievement, 'Boom Goes the Dynamite' + ), + ) + + def _handle_rookie_kill_achievements(self, msg: SpazBotDiedMessage) -> None: + # Land-mine achievement: + if msg.spazbot.last_attacked_type == ('explosion', 'land_mine'): + self._land_mine_kills += 1 + if self._land_mine_kills >= 3: + self._award_achievement('Mine Games') + + def _handle_training_kill_achievements( + self, msg: SpazBotDiedMessage + ) -> None: + # Toss-off-map achievement: + if msg.spazbot.last_attacked_type == ('picked_up', 'default'): + self._throw_off_kills += 1 + if self._throw_off_kills >= 3: + self._award_achievement('Off You Go Then') + + def _set_can_end_wave(self) -> None: + self._can_end_wave = True + + def end_game(self) -> None: + # Tell our bots to celebrate just to rub it in. + assert self._bots is not None + self._bots.final_celebrate() + self._game_over = True + self.do_end('defeat', delay=2.0) + bs.setmusic(None) + + def on_continue(self) -> None: + for player in self.players: + if not player.is_alive(): + self.spawn_player(player) + + def _checkroundover(self) -> None: + """Potentially end the round based on the state of the game.""" + if self.has_ended(): + return + if not any(player.is_alive() for player in self.teams[0].players): + # Allow continuing after wave 1. + if self._wavenum > 1: + self.continue_or_end_game() + else: + self.end_game() + +# ba_meta export plugin +class CustomOnslaughtLevel(babase.Plugin): + def on_app_running(self) -> None: + babase.app.classic.add_coop_practice_level( + bs._level.Level( + 'Onslaught Football', + gametype=OnslaughtFootballGame, + settings={ + 'map': 'Football Stadium', + 'Epic Mode': False, + }, + preview_texture_name='footballStadiumPreview', + ) + ) + babase.app.classic.add_coop_practice_level( + bs._level.Level( + 'Onslaught Football Epic', + gametype=OnslaughtFootballGame, + settings={ + 'map': 'Football Stadium', + 'Epic Mode': True, + }, + preview_texture_name='footballStadiumPreview', + ) + ) From 546a8d0a4a6ce2863b801c71ebeba6a1b5caedca Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Fri, 26 Jan 2024 02:02:31 +0000 Subject: [PATCH 14/36] [ci] auto-format --- plugins/minigames/ba_dark_fields.py | 165 +- plugins/minigames/gravity_falls.py | 17 +- plugins/minigames/infinite_ninjas.py | 47 +- plugins/minigames/lame_fight.py | 88 +- plugins/minigames/onslaught_football.py | 1932 ++++++++++++----------- 5 files changed, 1138 insertions(+), 1111 deletions(-) diff --git a/plugins/minigames/ba_dark_fields.py b/plugins/minigames/ba_dark_fields.py index 2a82005..03302ee 100644 --- a/plugins/minigames/ba_dark_fields.py +++ b/plugins/minigames/ba_dark_fields.py @@ -23,6 +23,7 @@ from bascenev1lib.actor.playerspaz import PlayerSpaz if TYPE_CHECKING: from typing import Any, Sequence, Optional, List, Dict, Type, Type + class Player(bs.Player['Team']): """Our player type for this game.""" @@ -34,36 +35,38 @@ class Team(bs.Team[Player]): self.score = 0 # ba_meta export bascenev1.GameActivity + + class DarkFieldsGame(bs.TeamGameActivity[Player, Team]): name = 'Dark Fields' description = 'Get to the other side.' available_settings = [ bs.IntSetting('Score to Win', - min_value=1, - default=3, - ), + min_value=1, + default=3, + ), bs.IntChoiceSetting('Time Limit', - choices=[ - ('None', 0), - ('1 Minute', 60), - ('2 Minutes', 120), - ('5 Minutes', 300), - ('10 Minutes', 600), - ('20 Minutes', 1200), - ], - default=0, - ), + 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, - ), + 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), bs.BoolSetting('Players as center of interest', default=True), ] @@ -90,26 +93,25 @@ class DarkFieldsGame(bs.TeamGameActivity[Player, Team]): self._scoreRegionMaterial = bs.Material() self._scoreRegionMaterial.add_actions( - conditions=("they_have_material",shared.player_material), - actions=(("modify_part_collision","collide",True), - ("modify_part_collision","physical",False), - ("call","at_connect", self._onPlayerScores))) + conditions=("they_have_material", shared.player_material), + actions=(("modify_part_collision", "collide", True), + ("modify_part_collision", "physical", False), + ("call", "at_connect", self._onPlayerScores))) self.slow_motion = self._epic_mode self.default_music = (bs.MusicType.EPIC if self._epic_mode else None) - def on_transition_in(self) -> None: super().on_transition_in() gnode = bs.getactivity().globalsnode - gnode.tint = (0.5,0.5,0.5) + gnode.tint = (0.5, 0.5, 0.5) + + a = bs.newnode('locator', attrs={'shape': 'box', 'position': (12.2, 0, .1087926362), + 'color': (5, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [2.5, 0.1, 12.8]}) + + b = bs.newnode('locator', attrs={'shape': 'box', 'position': (-12.1, 0, .1087926362), + 'color': (0, 0, 5), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [2.5, 0.1, 12.8]}) - a = bs.newnode('locator',attrs={'shape':'box','position':(12.2,0,.1087926362), - 'color':(5,0,0),'opacity':1,'draw_beauty':True,'additive':False,'size':[2.5,0.1,12.8]}) - - b = bs.newnode('locator',attrs={'shape':'box','position':(-12.1,0,.1087926362), - 'color':(0,0,5),'opacity':1,'draw_beauty':True,'additive':False,'size':[2.5,0.1,12.8]}) - def on_begin(self) -> None: # self._has_begun = False super().on_begin() @@ -132,21 +134,22 @@ class DarkFieldsGame(bs.TeamGameActivity[Player, Team]): self._scoreRegions = [] defs = bs.getactivity().map.defs self._scoreRegions.append(bs.NodeActor(bs.newnode('region', - attrs={'position':defs.boxes['goal1'][0:3], - 'scale':defs.boxes['goal1'][6:9], - 'type': 'box', - 'materials':(self._scoreRegionMaterial,)}))) + attrs={'position': defs.boxes['goal1'][0:3], + 'scale': defs.boxes['goal1'][6:9], + 'type': 'box', + 'materials': (self._scoreRegionMaterial,)}))) self.mines = [] self.spawnMines() - bs.timer(0.8 if self.slow_motion else 1.7,self.start) + bs.timer(0.8 if self.slow_motion else 1.7, self.start) def start(self): # self._has_begun = True self._show_info() - bs.timer(random.randrange(3,7),self.doRandomLighting) + bs.timer(random.randrange(3, 7), self.doRandomLighting) if not self._epic_mode: setmusic(bs.MusicType.SCARY) - animate_array(bs.getactivity().globalsnode,'tint',3,{0:(0.5,0.5,0.5),2:(0.2,0.2,0.2)}) + animate_array(bs.getactivity().globalsnode, 'tint', 3, + {0: (0.5, 0.5, 0.5), 2: (0.2, 0.2, 0.2)}) for p in self.players: self.doPlayer(p) @@ -157,10 +160,10 @@ class DarkFieldsGame(bs.TeamGameActivity[Player, Team]): else: self.doPlayer(player) - def doPlayer(self,player): - pos = (-12.4,1,random.randrange(-5,5)) - player = self.spawn_player_spaz(player,pos) - player.connect_controls_to_player(enable_punch=False,enable_bomb=False) + def doPlayer(self, player): + pos = (-12.4, 1, random.randrange(-5, 5)) + player = self.spawn_player_spaz(player, pos) + player.connect_controls_to_player(enable_punch=False, enable_bomb=False) player.node.is_area_of_interest = self._center_of_interest def _show_info(self) -> None: @@ -176,52 +179,53 @@ class DarkFieldsGame(bs.TeamGameActivity[Player, Team]): self._scoreboard.set_team_value(team, team.score, self._score_to_win) def doRandomLighting(self): - bs.timer(random.randrange(3,7),self.doRandomLighting) - if self.isUpdatingMines: return + bs.timer(random.randrange(3, 7), self.doRandomLighting) + if self.isUpdatingMines: + return delay = 0 for mine in self.mines: if mine.node.exists(): pos = mine.node.position - bs.timer(delay,babase.Call(self.do_light,pos)) + bs.timer(delay, babase.Call(self.do_light, pos)) delay += 0.005 if self._epic_mode else 0.01 - def do_light(self,pos): - light = bs.newnode('light',attrs={ - 'position': pos, - 'volume_intensity_scale': 1.0, - 'radius':0.1, - 'color': (1,0,0) - }) - bs.animate(light, 'intensity', { 0: 2.0, 3.0: 0.0}) + def do_light(self, pos): + light = bs.newnode('light', attrs={ + 'position': pos, + 'volume_intensity_scale': 1.0, + 'radius': 0.1, + 'color': (1, 0, 0) + }) + bs.animate(light, 'intensity', {0: 2.0, 3.0: 0.0}) bs.timer(3.0, light.delete) def spawnMines(self): delay = 0 - h_range = [10,8,6,4,2,0,-2,-4,-6,-8,-10] + h_range = [10, 8, 6, 4, 2, 0, -2, -4, -6, -8, -10] for h in h_range: - for i in range(random.randint(3,4)): + for i in range(random.randint(3, 4)): x = h+random.random() - y = random.randrange(-5,6)+(random.random()) - pos = (x,1,y) - bs.timer(delay,babase.Call(self.doMine,pos)) + y = random.randrange(-5, 6)+(random.random()) + pos = (x, 1, y) + bs.timer(delay, babase.Call(self.doMine, pos)) delay += 0.015 if self._epic_mode else 0.04 - bs.timer(5.0,self.stopUpdateMines) + bs.timer(5.0, self.stopUpdateMines) def stopUpdateMines(self): self.isUpdatingMines = False def updateMines(self): - if self.isUpdatingMines: return + if self.isUpdatingMines: + return self.isUpdatingMines = True for m in self.mines: m.node.delete() self.mines = [] self.spawnMines() - - - def doMine(self,pos): - b = bomb.Bomb(position=pos,bomb_type='land_mine').autoretain() + + def doMine(self, pos): + b = bomb.Bomb(position=pos, bomb_type='land_mine').autoretain() b.add_explode_callback(self._on_bomb_exploded) b.arm() self.mines.append(b) @@ -229,8 +233,8 @@ class DarkFieldsGame(bs.TeamGameActivity[Player, Team]): def _on_bomb_exploded(self, bomb: Bomb, blast: Blast) -> None: assert blast.node p = blast.node.position - pos = (p[0],p[1]+1,p[2]) - bs.timer(0.5,babase.Call(self.doMine,pos)) + pos = (p[0], p[1]+1, p[2]) + bs.timer(0.5, babase.Call(self.doMine, pos)) def _onPlayerScores(self): player: Optional[Player] @@ -238,7 +242,7 @@ class DarkFieldsGame(bs.TeamGameActivity[Player, Team]): spaz = bs.getcollision().opposingnode.getdelegate(PlayerSpaz, True) except bs.NotFoundError: return - + if not spaz.is_alive(): return @@ -246,25 +250,26 @@ class DarkFieldsGame(bs.TeamGameActivity[Player, Team]): player = spaz.getplayer(Player, True) except bs.NotFoundError: return - + if player.exists() and player.is_alive(): player.team.score += 1 - self._scoreSound.play() + self._scoreSound.play() pos = player.actor.node.position - animate_array(bs.getactivity().globalsnode,'tint',3,{0:(0.5,0.5,0.5),2.8:(0.2,0.2,0.2)}) + animate_array(bs.getactivity().globalsnode, 'tint', 3, { + 0: (0.5, 0.5, 0.5), 2.8: (0.2, 0.2, 0.2)}) self._update_scoreboard() light = bs.newnode('light', - attrs={ - 'position': pos, - 'radius': 0.5, - 'color': (1, 0, 0) - }) + attrs={ + 'position': pos, + 'radius': 0.5, + 'color': (1, 0, 0) + }) bs.animate(light, 'intensity', {0.0: 0, 0.1: 1, 0.5: 0}, loop=False) bs.timer(1.0, light.delete) - player.actor.handlemessage(bs.DieMessage( how=bs.DeathType.REACHED_GOAL)) + player.actor.handlemessage(bs.DieMessage(how=bs.DeathType.REACHED_GOAL)) self.updateMines() if any(team.score >= self._score_to_win for team in self.teams): @@ -288,4 +293,4 @@ class DarkFieldsGame(bs.TeamGameActivity[Player, Team]): results = bs.GameResults() for team in self.teams: results.set_team_score(team, team.score) - self.end(results=results) \ No newline at end of file + self.end(results=results) diff --git a/plugins/minigames/gravity_falls.py b/plugins/minigames/gravity_falls.py index f24b591..e4c7e44 100644 --- a/plugins/minigames/gravity_falls.py +++ b/plugins/minigames/gravity_falls.py @@ -1,6 +1,6 @@ # Ported to api 8 by brostos using baport.(https://github.com/bombsquad-community/baport) -## Made by MattZ45986 on GitHub -## Ported by: Freaku / @[Just] Freak#4999 +# Made by MattZ45986 on GitHub +# Ported by: Freaku / @[Just] Freak#4999 import babase @@ -9,26 +9,27 @@ import bascenev1 as bs from bascenev1lib.game.elimination import EliminationGame - # ba_meta require api 8 # ba_meta export bascenev1.GameActivity class GFGame(EliminationGame): name = 'Gravity Falls' def spawn_player(self, player): - actor = self.spawn_player_spaz(player, (0,5,0)) + actor = self.spawn_player_spaz(player, (0, 5, 0)) if not self._solo_mode: bs.timer(0.3, babase.Call(self._print_lives, player)) # If we have any icons, update their state. for icon in player.icons: icon.handle_player_spawned() - bs.timer(1,babase.Call(self.raise_player, player)) + bs.timer(1, babase.Call(self.raise_player, player)) return actor def raise_player(self, player): if player.is_alive(): try: - player.actor.node.handlemessage("impulse",player.actor.node.position[0],player.actor.node.position[1]+.5,player.actor.node.position[2],0,5,0, 3,10,0,0, 0,5,0) - except: pass - bs.timer(0.05,babase.Call(self.raise_player,player)) \ No newline at end of file + player.actor.node.handlemessage( + "impulse", player.actor.node.position[0], player.actor.node.position[1]+.5, player.actor.node.position[2], 0, 5, 0, 3, 10, 0, 0, 0, 5, 0) + except: + pass + bs.timer(0.05, babase.Call(self.raise_player, player)) diff --git a/plugins/minigames/infinite_ninjas.py b/plugins/minigames/infinite_ninjas.py index c43cb65..de2784f 100644 --- a/plugins/minigames/infinite_ninjas.py +++ b/plugins/minigames/infinite_ninjas.py @@ -1,7 +1,7 @@ # Ported to api 8 by brostos using baport.(https://github.com/bombsquad-community/baport) # ba_meta require api 8 -#Copy pasted from ExplodoRun by Blitz,just edited Bots and map 😝 +# Copy pasted from ExplodoRun by Blitz,just edited Bots and map 😝 from __future__ import annotations @@ -19,20 +19,24 @@ if TYPE_CHECKING: from typing import Any, Type, Dict, List, Optional ## MoreMinigames.py support ## + + def ba_get_api_version(): return 6 + def ba_get_levels(): return [babase._level.Level( - 'Infinite Ninjas',gametype=InfiniteNinjasGame, + 'Infinite Ninjas', gametype=InfiniteNinjasGame, settings={}, - preview_texture_name = 'footballStadiumPreview'), + preview_texture_name='footballStadiumPreview'), babase._level.Level( - 'Epic Infinite Ninjas',gametype=InfiniteNinjasGame, - settings={'Epic Mode':True}, - preview_texture_name = 'footballStadiumPreview')] + 'Epic Infinite Ninjas', gametype=InfiniteNinjasGame, + settings={'Epic Mode': True}, + preview_texture_name='footballStadiumPreview')] ## MoreMinigames.py support ## + class Player(bs.Player['Team']): """Our player type for this game.""" @@ -41,6 +45,8 @@ class Team(bs.Team[Player]): """Our team type for this game.""" # ba_meta export bascenev1.GameActivity + + class InfiniteNinjasGame(bs.TeamGameActivity[Player, Team]): name = "Infinite Ninjas" description = "How long can you survive from Ninjas??" @@ -49,8 +55,8 @@ class InfiniteNinjasGame(bs.TeamGameActivity[Player, Team]): scoretype=bs.ScoreType.MILLISECONDS, lower_is_better=False) default_music = bs.MusicType.TO_THE_DEATH - - def __init__(self, settings:dict): + + def __init__(self, settings: dict): settings['map'] = "Football Stadium" self._epic_mode = settings.get('Epic Mode', False) if self._epic_mode: @@ -61,27 +67,28 @@ class InfiniteNinjasGame(bs.TeamGameActivity[Player, Team]): self._won = False self._bots = SpazBotSet() self.wave = 1 - + def on_begin(self) -> None: super().on_begin() - + self._timer = OnScreenTimer() bs.timer(2.5, self._timer.start) - - #Bots Hehe - bs.timer(2.5,self.street) + + # Bots Hehe + bs.timer(2.5, self.street) def street(self): for a in range(self.wave): - p1 = random.choice([-5,-2.5,0,2.5,5]) - p3 = random.choice([-4.5,-4.14,-5,-3]) - time = random.choice([1,1.5,2.5,2]) - self._bots.spawn_bot(ChargerBot, pos=(p1,0.4,p3),spawn_time = time) + p1 = random.choice([-5, -2.5, 0, 2.5, 5]) + p3 = random.choice([-4.5, -4.14, -5, -3]) + time = random.choice([1, 1.5, 2.5, 2]) + self._bots.spawn_bot(ChargerBot, pos=(p1, 0.4, p3), spawn_time=time) self.wave += 1 - + def botrespawn(self): if not self._bots.have_living_bots(): self.street() + def handlemessage(self, msg: Any) -> Any: # A player has died. @@ -89,7 +96,7 @@ class InfiniteNinjasGame(bs.TeamGameActivity[Player, Team]): super().handlemessage(msg) # Augment standard behavior. self._won = True self.end_game() - + # A spaz-bot has died. elif isinstance(msg, SpazBotDiedMessage): # Unfortunately the bot-set will always tell us there are living @@ -130,5 +137,3 @@ class InfiniteNinjasGame(bs.TeamGameActivity[Player, Team]): # Ends the activity. self.end(results) - - \ No newline at end of file diff --git a/plugins/minigames/lame_fight.py b/plugins/minigames/lame_fight.py index e997a72..6b69d13 100644 --- a/plugins/minigames/lame_fight.py +++ b/plugins/minigames/lame_fight.py @@ -17,15 +17,18 @@ from bascenev1lib.actor.onscreentimer import OnScreenTimer if TYPE_CHECKING: from typing import Any, Type, Dict, List, Optional + def ba_get_api_version(): return 6 + def ba_get_levels(): - return [babase._level.Level( - 'Lame Fight', - gametype=LameFightGame, - settings={}, - preview_texture_name='courtyardPreview')] + return [babase._level.Level( + 'Lame Fight', + gametype=LameFightGame, + settings={}, + preview_texture_name='courtyardPreview')] + class Player(bs.Player['Team']): """Our player type for this game.""" @@ -35,6 +38,8 @@ class Team(bs.Team[Player]): """Our team type for this game.""" # ba_meta export bascenev1.GameActivity + + class LameFightGame(bs.TeamGameActivity[Player, Team]): name = "Lame Fight" description = "Save World With Super Powers" @@ -43,54 +48,61 @@ class LameFightGame(bs.TeamGameActivity[Player, Team]): scoretype=bs.ScoreType.MILLISECONDS, lower_is_better=True) default_music = bs.MusicType.TO_THE_DEATH - - def __init__(self, settings:dict): + + def __init__(self, settings: dict): settings['map'] = "Courtyard" super().__init__(settings) self._timer: Optional[OnScreenTimer] = None self._winsound = bs.getsound('score') self._won = False self._bots = SpazBotSet() - + def on_begin(self) -> None: super().on_begin() - + self._timer = OnScreenTimer() bs.timer(4.0, self._timer.start) - - #Bots Hehe - bs.timer(1.0, lambda: self._bots.spawn_bot(ChargerBot, pos=(3,3,-2),spawn_time = 3.0)) - bs.timer(1.0, lambda: self._bots.spawn_bot(ChargerBot, pos=(-3,3,-2),spawn_time = 3.0)) - bs.timer(1.0, lambda: self._bots.spawn_bot(ChargerBot, pos=(5,3,-2),spawn_time = 3.0)) - bs.timer(1.0, lambda: self._bots.spawn_bot(ChargerBot, pos=(-5,3,-2),spawn_time = 3.0)) - bs.timer(1.0, lambda: self._bots.spawn_bot(ChargerBot, pos=(0,3,1),spawn_time = 3.0)) - bs.timer(1.0, lambda: self._bots.spawn_bot(ChargerBot, pos=(0,3,-5),spawn_time = 3.0)) - bs.timer(9.0, lambda: self._bots.spawn_bot(BomberBotProShielded, pos=(-7,5,-7.5),spawn_time = 3.0)) - bs.timer(9.0, lambda: self._bots.spawn_bot(BomberBotProShielded, pos=(7,5,-7.5),spawn_time = 3.0)) - bs.timer(9.0, lambda: self._bots.spawn_bot(BomberBotProShielded, pos=(7,5,1.5),spawn_time = 3.0)) - bs.timer(9.0, lambda: self._bots.spawn_bot(BomberBotProShielded, pos=(-7,5,1.5),spawn_time = 3.0)) - bs.timer(12.0, lambda: self._bots.spawn_bot(TriggerBotProShielded, pos=(-1,7,-8),spawn_time = 3.0)) - bs.timer(12.0, lambda: self._bots.spawn_bot(TriggerBotProShielded, pos=(1,7,-8),spawn_time = 3.0)) - bs.timer(15.0, lambda: self._bots.spawn_bot(ExplodeyBot, pos=(0,3,-5),spawn_time = 3.0)) - bs.timer(20.0, lambda: self._bots.spawn_bot(ExplodeyBot, pos=(0,3,1),spawn_time = 3.0)) - bs.timer(20.0, lambda: self._bots.spawn_bot(ExplodeyBot, pos=(-5,3,-2),spawn_time = 3.0)) - bs.timer(20.0, lambda: self._bots.spawn_bot(ExplodeyBot, pos=(5,3,-2),spawn_time = 3.0)) - bs.timer(30,self.street) + + # Bots Hehe + bs.timer(1.0, lambda: self._bots.spawn_bot(ChargerBot, pos=(3, 3, -2), spawn_time=3.0)) + bs.timer(1.0, lambda: self._bots.spawn_bot(ChargerBot, pos=(-3, 3, -2), spawn_time=3.0)) + bs.timer(1.0, lambda: self._bots.spawn_bot(ChargerBot, pos=(5, 3, -2), spawn_time=3.0)) + bs.timer(1.0, lambda: self._bots.spawn_bot(ChargerBot, pos=(-5, 3, -2), spawn_time=3.0)) + bs.timer(1.0, lambda: self._bots.spawn_bot(ChargerBot, pos=(0, 3, 1), spawn_time=3.0)) + bs.timer(1.0, lambda: self._bots.spawn_bot(ChargerBot, pos=(0, 3, -5), spawn_time=3.0)) + bs.timer(9.0, lambda: self._bots.spawn_bot( + BomberBotProShielded, pos=(-7, 5, -7.5), spawn_time=3.0)) + bs.timer(9.0, lambda: self._bots.spawn_bot( + BomberBotProShielded, pos=(7, 5, -7.5), spawn_time=3.0)) + bs.timer(9.0, lambda: self._bots.spawn_bot( + BomberBotProShielded, pos=(7, 5, 1.5), spawn_time=3.0)) + bs.timer(9.0, lambda: self._bots.spawn_bot( + BomberBotProShielded, pos=(-7, 5, 1.5), spawn_time=3.0)) + bs.timer(12.0, lambda: self._bots.spawn_bot( + TriggerBotProShielded, pos=(-1, 7, -8), spawn_time=3.0)) + bs.timer(12.0, lambda: self._bots.spawn_bot( + TriggerBotProShielded, pos=(1, 7, -8), spawn_time=3.0)) + bs.timer(15.0, lambda: self._bots.spawn_bot(ExplodeyBot, pos=(0, 3, -5), spawn_time=3.0)) + bs.timer(20.0, lambda: self._bots.spawn_bot(ExplodeyBot, pos=(0, 3, 1), spawn_time=3.0)) + bs.timer(20.0, lambda: self._bots.spawn_bot(ExplodeyBot, pos=(-5, 3, -2), spawn_time=3.0)) + bs.timer(20.0, lambda: self._bots.spawn_bot(ExplodeyBot, pos=(5, 3, -2), spawn_time=3.0)) + bs.timer(30, self.street) def street(self): - bs.broadcastmessage("Lame Guys Are Here!",color = (1,0,0)) - for a in range(-1,2): - for b in range(-3,0): - self._bots.spawn_bot(BrawlerBotProShielded, pos=(a,3,b),spawn_time = 3.0) - + bs.broadcastmessage("Lame Guys Are Here!", color=(1, 0, 0)) + for a in range(-1, 2): + for b in range(-3, 0): + self._bots.spawn_bot(BrawlerBotProShielded, pos=(a, 3, b), spawn_time=3.0) + def spawn_player(self, player: Player) -> bs.Actor: spawn_center = (0, 3, -2) pos = (spawn_center[0] + random.uniform(-1.5, 1.5), spawn_center[1], spawn_center[2] + random.uniform(-1.5, 1.5)) - spaz = self.spawn_player_spaz(player,position = pos) - p = ["Bigger Blast","Stronger Punch","Shield","Speed"] + spaz = self.spawn_player_spaz(player, position=pos) + p = ["Bigger Blast", "Stronger Punch", "Shield", "Speed"] Power = random.choice(p) - spaz.bomb_type = random.choice(["normal","sticky","ice","impact","normal","ice","sticky"]) + spaz.bomb_type = random.choice( + ["normal", "sticky", "ice", "impact", "normal", "ice", "sticky"]) bs.broadcastmessage(f"Now You Have {Power}") if Power == p[0]: spaz.bomb_count = 3 @@ -103,10 +115,12 @@ class LameFightGame(bs.TeamGameActivity[Player, Team]): if Power == p[3]: spaz.node.hockey = True return spaz + def _check_if_won(self) -> None: if not self._bots.have_living_bots(): self._won = True self.end_game() + def handlemessage(self, msg: Any) -> Any: # A player has died. @@ -154,5 +168,3 @@ class LameFightGame(bs.TeamGameActivity[Player, Team]): # Ends the activity. self.end(results) - - \ No newline at end of file diff --git a/plugins/minigames/onslaught_football.py b/plugins/minigames/onslaught_football.py index 06a5c5c..b585581 100644 --- a/plugins/minigames/onslaught_football.py +++ b/plugins/minigames/onslaught_football.py @@ -21,1003 +21,1007 @@ from bascenev1lib.actor.scoreboard import Scoreboard from bascenev1lib.actor.controlsguide import ControlsGuide from bascenev1lib.actor.powerupbox import PowerupBox, PowerupBoxFactory from bascenev1lib.actor.spazbot import ( - SpazBotDiedMessage, - SpazBotSet, - ChargerBot, - StickyBot, - BomberBot, - BomberBotLite, - BrawlerBot, - BrawlerBotLite, - TriggerBot, - BomberBotStaticLite, - TriggerBotStatic, - BomberBotProStatic, - TriggerBotPro, - ExplodeyBot, - BrawlerBotProShielded, - ChargerBotProShielded, - BomberBotPro, - TriggerBotProShielded, - BrawlerBotPro, - BomberBotProShielded, + SpazBotDiedMessage, + SpazBotSet, + ChargerBot, + StickyBot, + BomberBot, + BomberBotLite, + BrawlerBot, + BrawlerBotLite, + TriggerBot, + BomberBotStaticLite, + TriggerBotStatic, + BomberBotProStatic, + TriggerBotPro, + ExplodeyBot, + BrawlerBotProShielded, + ChargerBotProShielded, + BomberBotPro, + TriggerBotProShielded, + BrawlerBotPro, + BomberBotProShielded, ) if TYPE_CHECKING: - from typing import Any, Sequence - from bascenev1lib.actor.spazbot import SpazBot + from typing import Any, Sequence + from bascenev1lib.actor.spazbot import SpazBot @dataclass class Wave: - """A wave of enemies.""" + """A wave of enemies.""" - entries: list[Spawn | Spacing | Delay | None] - base_angle: float = 0.0 + entries: list[Spawn | Spacing | Delay | None] + base_angle: float = 0.0 @dataclass class Spawn: - """A bot spawn event in a wave.""" + """A bot spawn event in a wave.""" - bottype: type[SpazBot] | str - point: Point | None = None - spacing: float = 5.0 + bottype: type[SpazBot] | str + point: Point | None = None + spacing: float = 5.0 @dataclass class Spacing: - """Empty space in a wave.""" + """Empty space in a wave.""" - spacing: float = 5.0 + spacing: float = 5.0 @dataclass class Delay: - """A delay between events in a wave.""" + """A delay between events in a wave.""" - duration: float + duration: float class Player(bs.Player['Team']): - """Our player type for this game.""" + """Our player type for this game.""" - def __init__(self) -> None: - self.has_been_hurt = False - self.respawn_wave = 0 + def __init__(self) -> None: + self.has_been_hurt = False + self.respawn_wave = 0 class Team(bs.Team[Player]): - """Our team type for this game.""" + """Our team type for this game.""" class OnslaughtFootballGame(bs.CoopGameActivity[Player, Team]): - """Co-op game where players try to survive attacking waves of enemies.""" - - name = 'Onslaught' - description = 'Defeat all enemies.' - - tips: list[str | babase.GameTip] = [ - 'Hold any button to run.' - ' (Trigger buttons work well if you have them)', - 'Try tricking enemies into killing eachother or running off cliffs.', - 'Try \'Cooking off\' bombs for a second or two before throwing them.', - 'It\'s easier to win with a friend or two helping.', - 'If you stay in one place, you\'re toast. Run and dodge to survive..', - 'Practice using your momentum to throw bombs more accurately.', - 'Your punches do much more damage if you are running or spinning.', - ] - - # Show messages when players die since it matters here. - announce_player_deaths = True - - def __init__(self, settings: dict): - super().__init__(settings) - self._new_wave_sound = bs.getsound('scoreHit01') - self._winsound = bs.getsound('score') - self._cashregistersound = bs.getsound('cashRegister') - self._a_player_has_been_hurt = False - self._player_has_dropped_bomb = False - self._spawn_center = (0, 0.2, 0) - self._tntspawnpos = (0, 0.95, -0.77) - self._powerup_center = (0, 1.5, 0) - self._powerup_spread = (6.0, 4.0) - self._scoreboard: Scoreboard | None = None - self._game_over = False - self._wavenum = 0 - self._can_end_wave = True - self._score = 0 - self._time_bonus = 0 - self._spawn_info_text: bs.NodeActor | None = None - self._dingsound = bs.getsound('dingSmall') - self._dingsoundhigh = bs.getsound('dingSmallHigh') - self._have_tnt = False - self._excluded_powerups: list[str] | None = None - self._waves: list[Wave] = [] - self._tntspawner: TNTSpawner | None = None - self._bots: SpazBotSet | None = None - self._powerup_drop_timer: bs.Timer | None = None - self._time_bonus_timer: bs.Timer | None = None - self._time_bonus_text: bs.NodeActor | None = None - self._flawless_bonus: int | None = None - self._wave_text: bs.NodeActor | None = None - self._wave_update_timer: bs.Timer | None = None - self._throw_off_kills = 0 - self._land_mine_kills = 0 - self._tnt_kills = 0 - - self._epic_mode = bool(settings['Epic Mode']) - # Base class overrides. - self.slow_motion = self._epic_mode - self.default_music = ( - bs.MusicType.EPIC if self._epic_mode else bs.MusicType.ONSLAUGHT - ) - - def on_transition_in(self) -> None: - super().on_transition_in() - self._spawn_info_text = bs.NodeActor( - bs.newnode( - 'text', - attrs={ - 'position': (15, -130), - 'h_attach': 'left', - 'v_attach': 'top', - 'scale': 0.55, - 'color': (0.3, 0.8, 0.3, 1.0), - 'text': '', - }, - ) - ) - self._scoreboard = Scoreboard( - label=babase.Lstr(resource='scoreText'), score_split=0.5 - ) - - def on_begin(self) -> None: - super().on_begin() - self._have_tnt = True - self._excluded_powerups = [] - self._waves = [] - bs.timer(4.0, self._start_powerup_drops) - - # Our TNT spawner (if applicable). - if self._have_tnt: - self._tntspawner = TNTSpawner(position=self._tntspawnpos) - - self.setup_low_life_warning_sound() - self._update_scores() - self._bots = SpazBotSet() - bs.timer(4.0, self._start_updating_waves) - self._next_ffa_start_index = random.randrange( - len(self.map.get_def_points('ffa_spawn')) - ) - - def _get_dist_grp_totals(self, grps: list[Any]) -> tuple[int, int]: - totalpts = 0 - totaldudes = 0 - for grp in grps: - for grpentry in grp: - dudes = grpentry[1] - totalpts += grpentry[0] * dudes - totaldudes += dudes - return totalpts, totaldudes - - def _get_distribution( - self, - target_points: int, - min_dudes: int, - max_dudes: int, - group_count: int, - max_level: int, - ) -> list[list[tuple[int, int]]]: - """Calculate a distribution of bad guys given some params.""" - max_iterations = 10 + max_dudes * 2 - - groups: list[list[tuple[int, int]]] = [] - for _g in range(group_count): - groups.append([]) - types = [1] - if max_level > 1: - types.append(2) - if max_level > 2: - types.append(3) - if max_level > 3: - types.append(4) - for iteration in range(max_iterations): - diff = self._add_dist_entry_if_possible( - groups, max_dudes, target_points, types - ) - - total_points, total_dudes = self._get_dist_grp_totals(groups) - full = total_points >= target_points - - if full: - # Every so often, delete a random entry just to - # shake up our distribution. - if random.random() < 0.2 and iteration != max_iterations - 1: - self._delete_random_dist_entry(groups) - - # If we don't have enough dudes, kill the group with - # the biggest point value. - elif ( - total_dudes < min_dudes and iteration != max_iterations - 1 - ): - self._delete_biggest_dist_entry(groups) - - # If we've got too many dudes, kill the group with the - # smallest point value. - elif ( - total_dudes > max_dudes and iteration != max_iterations - 1 - ): - self._delete_smallest_dist_entry(groups) - - # Close enough.. we're done. - else: - if diff == 0: - break - - return groups - - def _add_dist_entry_if_possible( - self, - groups: list[list[tuple[int, int]]], - max_dudes: int, - target_points: int, - types: list[int], - ) -> int: - # See how much we're off our target by. - total_points, total_dudes = self._get_dist_grp_totals(groups) - diff = target_points - total_points - dudes_diff = max_dudes - total_dudes - - # Add an entry if one will fit. - value = types[random.randrange(len(types))] - group = groups[random.randrange(len(groups))] - if not group: - max_count = random.randint(1, 6) - else: - max_count = 2 * random.randint(1, 3) - max_count = min(max_count, dudes_diff) - count = min(max_count, diff // value) - if count > 0: - group.append((value, count)) - total_points += value * count - total_dudes += count - diff = target_points - total_points - return diff - - def _delete_smallest_dist_entry( - self, groups: list[list[tuple[int, int]]] - ) -> None: - smallest_value = 9999 - smallest_entry = None - smallest_entry_group = None - for group in groups: - for entry in group: - if entry[0] < smallest_value or smallest_entry is None: - smallest_value = entry[0] - smallest_entry = entry - smallest_entry_group = group - assert smallest_entry is not None - assert smallest_entry_group is not None - smallest_entry_group.remove(smallest_entry) - - def _delete_biggest_dist_entry( - self, groups: list[list[tuple[int, int]]] - ) -> None: - biggest_value = 9999 - biggest_entry = None - biggest_entry_group = None - for group in groups: - for entry in group: - if entry[0] > biggest_value or biggest_entry is None: - biggest_value = entry[0] - biggest_entry = entry - biggest_entry_group = group - if biggest_entry is not None: - assert biggest_entry_group is not None - biggest_entry_group.remove(biggest_entry) - - def _delete_random_dist_entry( - self, groups: list[list[tuple[int, int]]] - ) -> None: - entry_count = 0 - for group in groups: - for _ in group: - entry_count += 1 - if entry_count > 1: - del_entry = random.randrange(entry_count) - entry_count = 0 - for group in groups: - for entry in group: - if entry_count == del_entry: - group.remove(entry) - break - entry_count += 1 - - def spawn_player(self, player: Player) -> bs.Actor: - - # We keep track of who got hurt each wave for score purposes. - player.has_been_hurt = False - pos = ( - self._spawn_center[0] + random.uniform(-1.5, 1.5), - self._spawn_center[1], - self._spawn_center[2] + random.uniform(-1.5, 1.5), - ) - spaz = self.spawn_player_spaz(player, position=pos) - spaz.add_dropped_bomb_callback(self._handle_player_dropped_bomb) - return spaz - - def _handle_player_dropped_bomb( - self, player: bs.Actor, bomb: bs.Actor - ) -> None: - del player, bomb # Unused. - self._player_has_dropped_bomb = True - - def _drop_powerup(self, index: int, poweruptype: str | None = None) -> None: - poweruptype = PowerupBoxFactory.get().get_random_powerup_type( - forcetype=poweruptype, excludetypes=self._excluded_powerups - ) - PowerupBox( - position=self.map.powerup_spawn_points[index], - poweruptype=poweruptype, - ).autoretain() - - def _start_powerup_drops(self) -> None: - self._powerup_drop_timer = bs.Timer( - 3.0, bs.WeakCall(self._drop_powerups), repeat=True - ) - - def _drop_powerups( - self, standard_points: bool = False, poweruptype: str | None = None - ) -> None: - """Generic powerup drop.""" - if standard_points: - points = self.map.powerup_spawn_points - for i in range(len(points)): - bs.timer( - 1.0 + i * 0.5, - bs.WeakCall( - self._drop_powerup, i, poweruptype if i == 0 else None - ), - ) - else: - point = ( - self._powerup_center[0] - + random.uniform( - -1.0 * self._powerup_spread[0], - 1.0 * self._powerup_spread[0], - ), - self._powerup_center[1], - self._powerup_center[2] - + random.uniform( - -self._powerup_spread[1], self._powerup_spread[1] - ), - ) - - # Drop one random one somewhere. - PowerupBox( - position=point, - poweruptype=PowerupBoxFactory.get().get_random_powerup_type( - excludetypes=self._excluded_powerups - ), - ).autoretain() - - def do_end(self, outcome: str, delay: float = 0.0) -> None: - """End the game with the specified outcome.""" - if outcome == 'defeat': - self.fade_to_red() - score: int | None - if self._wavenum >= 2: - score = self._score - fail_message = None - else: - score = None - fail_message = babase.Lstr(resource='reachWave2Text') - self.end( - { - 'outcome': outcome, - 'score': score, - 'fail_message': fail_message, - 'playerinfos': self.initialplayerinfos, - }, - delay=delay, - ) - - def _update_waves(self) -> None: - - # If we have no living bots, go to the next wave. - assert self._bots is not None - if ( - self._can_end_wave - and not self._bots.have_living_bots() - and not self._game_over - ): - self._can_end_wave = False - self._time_bonus_timer = None - self._time_bonus_text = None - base_delay = 0.0 - - # Reward time bonus. - if self._time_bonus > 0: - bs.timer(0, babase.Call(self._cashregistersound.play)) - bs.timer( - base_delay, - bs.WeakCall(self._award_time_bonus, self._time_bonus), - ) - base_delay += 1.0 - - # Reward flawless bonus. - if self._wavenum > 0: - have_flawless = False - for player in self.players: - if player.is_alive() and not player.has_been_hurt: - have_flawless = True - bs.timer( - base_delay, - bs.WeakCall(self._award_flawless_bonus, player), - ) - player.has_been_hurt = False # reset - if have_flawless: - base_delay += 1.0 - - self._wavenum += 1 - - # Short celebration after waves. - if self._wavenum > 1: - self.celebrate(0.5) - bs.timer(base_delay, bs.WeakCall(self._start_next_wave)) - - def _award_completion_bonus(self) -> None: - self._cashregistersound.play() - for player in self.players: - try: - if player.is_alive(): - assert self.initialplayerinfos is not None - self.stats.player_scored( - player, - int(100 / len(self.initialplayerinfos)), - scale=1.4, - color=(0.6, 0.6, 1.0, 1.0), - title=babase.Lstr(resource='completionBonusText'), - screenmessage=False, - ) - except Exception: - babase.print_exception() - - def _award_time_bonus(self, bonus: int) -> None: - self._cashregistersound.play() - PopupText( - babase.Lstr( - value='+${A} ${B}', - subs=[ - ('${A}', str(bonus)), - ('${B}', babase.Lstr(resource='timeBonusText')), - ], - ), - color=(1, 1, 0.5, 1), - scale=1.0, - position=(0, 3, -1), - ).autoretain() - self._score += self._time_bonus - self._update_scores() - - def _award_flawless_bonus(self, player: Player) -> None: - self._cashregistersound.play() - try: - if player.is_alive(): - assert self._flawless_bonus is not None - self.stats.player_scored( - player, - self._flawless_bonus, - scale=1.2, - color=(0.6, 1.0, 0.6, 1.0), - title=babase.Lstr(resource='flawlessWaveText'), - screenmessage=False, - ) - except Exception: - babase.print_exception() - - def _start_time_bonus_timer(self) -> None: - self._time_bonus_timer = bs.Timer( - 1.0, bs.WeakCall(self._update_time_bonus), repeat=True - ) - - def _update_player_spawn_info(self) -> None: - - # If we have no living players lets just blank this. - assert self._spawn_info_text is not None - assert self._spawn_info_text.node - if not any(player.is_alive() for player in self.teams[0].players): - self._spawn_info_text.node.text = '' - else: - text: str | babase.Lstr = '' - for player in self.players: - if not player.is_alive(): - rtxt = babase.Lstr( - resource='onslaughtRespawnText', - subs=[ - ('${PLAYER}', player.getname()), - ('${WAVE}', str(player.respawn_wave)), - ], - ) - text = babase.Lstr( - value='${A}${B}\n', - subs=[ - ('${A}', text), - ('${B}', rtxt), - ], - ) - self._spawn_info_text.node.text = text - - def _respawn_players_for_wave(self) -> None: - # Respawn applicable players. - if self._wavenum > 1 and not self.is_waiting_for_continue(): - for player in self.players: - if ( - not player.is_alive() - and player.respawn_wave == self._wavenum - ): - self.spawn_player(player) - self._update_player_spawn_info() - - def _setup_wave_spawns(self, wave: Wave) -> None: - tval = 0.0 - dtime = 0.2 - if self._wavenum == 1: - spawn_time = 3.973 - tval += 0.5 - else: - spawn_time = 2.648 - - bot_angle = wave.base_angle - self._time_bonus = 0 - self._flawless_bonus = 0 - for info in wave.entries: - if info is None: - continue - if isinstance(info, Delay): - spawn_time += info.duration - continue - if isinstance(info, Spacing): - bot_angle += info.spacing - continue - bot_type_2 = info.bottype - if bot_type_2 is not None: - assert not isinstance(bot_type_2, str) - self._time_bonus += bot_type_2.points_mult * 20 - self._flawless_bonus += bot_type_2.points_mult * 5 - - if self.map.name == 'Doom Shroom': - tval += dtime - spacing = info.spacing - bot_angle += spacing * 0.5 - if bot_type_2 is not None: - tcall = bs.WeakCall( - self.add_bot_at_angle, bot_angle, bot_type_2, spawn_time - ) - bs.timer(tval, tcall) - tval += dtime - bot_angle += spacing * 0.5 - else: - assert bot_type_2 is not None - spcall = bs.WeakCall( - self.add_bot_at_point, bot_type_2, spawn_time - ) - bs.timer(tval, spcall) - - # We can end the wave after all the spawning happens. - bs.timer( - tval + spawn_time - dtime + 0.01, - bs.WeakCall(self._set_can_end_wave), - ) - - def _start_next_wave(self) -> None: - - # This can happen if we beat a wave as we die. - # We don't wanna respawn players and whatnot if this happens. - if self._game_over: - return - - self._respawn_players_for_wave() - wave = self._generate_random_wave() - self._setup_wave_spawns(wave) - self._update_wave_ui_and_bonuses() - bs.timer(0.4, babase.Call(self._new_wave_sound.play)) - - def _update_wave_ui_and_bonuses(self) -> None: - self.show_zoom_message( - babase.Lstr( - value='${A} ${B}', - subs=[ - ('${A}', babase.Lstr(resource='waveText')), - ('${B}', str(self._wavenum)), - ], - ), - scale=1.0, - duration=1.0, - trail=True, - ) - - # Reset our time bonus. - tbtcolor = (1, 1, 0, 1) - tbttxt = babase.Lstr( - value='${A}: ${B}', - subs=[ - ('${A}', babase.Lstr(resource='timeBonusText')), - ('${B}', str(self._time_bonus)), - ], - ) - self._time_bonus_text = bs.NodeActor( - bs.newnode( - 'text', - attrs={ - 'v_attach': 'top', - 'h_attach': 'center', - 'h_align': 'center', - 'vr_depth': -30, - 'color': tbtcolor, - 'shadow': 1.0, - 'flatness': 1.0, - 'position': (0, -60), - 'scale': 0.8, - 'text': tbttxt, - }, - ) - ) - - bs.timer(5.0, bs.WeakCall(self._start_time_bonus_timer)) - wtcolor = (1, 1, 1, 1) - wttxt = babase.Lstr( - value='${A} ${B}', - subs=[ - ('${A}', babase.Lstr(resource='waveText')), - ('${B}', str(self._wavenum) + ('')), - ], - ) - self._wave_text = bs.NodeActor( - bs.newnode( - 'text', - attrs={ - 'v_attach': 'top', - 'h_attach': 'center', - 'h_align': 'center', - 'vr_depth': -10, - 'color': wtcolor, - 'shadow': 1.0, - 'flatness': 1.0, - 'position': (0, -40), - 'scale': 1.3, - 'text': wttxt, - }, - ) - ) - - def _bot_levels_for_wave(self) -> list[list[type[SpazBot]]]: - level = self._wavenum - bot_types = [ - BomberBot, - BrawlerBot, - TriggerBot, - ChargerBot, - BomberBotPro, - BrawlerBotPro, - TriggerBotPro, - BomberBotProShielded, - ExplodeyBot, - ChargerBotProShielded, - StickyBot, - BrawlerBotProShielded, - TriggerBotProShielded, - ] - if level > 5: - bot_types += [ - ExplodeyBot, - TriggerBotProShielded, - BrawlerBotProShielded, - ChargerBotProShielded, - ] - if level > 7: - bot_types += [ - ExplodeyBot, - TriggerBotProShielded, - BrawlerBotProShielded, - ChargerBotProShielded, - ] - if level > 10: - bot_types += [ - TriggerBotProShielded, - TriggerBotProShielded, - TriggerBotProShielded, - TriggerBotProShielded, - ] - if level > 13: - bot_types += [ - TriggerBotProShielded, - TriggerBotProShielded, - TriggerBotProShielded, - TriggerBotProShielded, - ] - bot_levels = [ - [b for b in bot_types if b.points_mult == 1], - [b for b in bot_types if b.points_mult == 2], - [b for b in bot_types if b.points_mult == 3], - [b for b in bot_types if b.points_mult == 4], - ] - - # Make sure all lists have something in them - if not all(bot_levels): - raise RuntimeError('Got empty bot level') - return bot_levels - - def _add_entries_for_distribution_group( - self, - group: list[tuple[int, int]], - bot_levels: list[list[type[SpazBot]]], - all_entries: list[Spawn | Spacing | Delay | None], - ) -> None: - entries: list[Spawn | Spacing | Delay | None] = [] - for entry in group: - bot_level = bot_levels[entry[0] - 1] - bot_type = bot_level[random.randrange(len(bot_level))] - rval = random.random() - if rval < 0.5: - spacing = 10.0 - elif rval < 0.9: - spacing = 20.0 - else: - spacing = 40.0 - split = random.random() > 0.3 - for i in range(entry[1]): - if split and i % 2 == 0: - entries.insert(0, Spawn(bot_type, spacing=spacing)) - else: - entries.append(Spawn(bot_type, spacing=spacing)) - if entries: - all_entries += entries - all_entries.append(Spacing(40.0 if random.random() < 0.5 else 80.0)) - - def _generate_random_wave(self) -> Wave: - level = self._wavenum - bot_levels = self._bot_levels_for_wave() - - target_points = level * 3 - 2 - min_dudes = min(1 + level // 3, 10) - max_dudes = min(10, level + 1) - max_level = ( - 4 if level > 6 else (3 if level > 3 else (2 if level > 2 else 1)) - ) - group_count = 3 - distribution = self._get_distribution( - target_points, min_dudes, max_dudes, group_count, max_level - ) - all_entries: list[Spawn | Spacing | Delay | None] = [] - for group in distribution: - self._add_entries_for_distribution_group( - group, bot_levels, all_entries - ) - angle_rand = random.random() - if angle_rand > 0.75: - base_angle = 130.0 - elif angle_rand > 0.5: - base_angle = 210.0 - elif angle_rand > 0.25: - base_angle = 20.0 - else: - base_angle = -30.0 - base_angle += (0.5 - random.random()) * 20.0 - wave = Wave(base_angle=base_angle, entries=all_entries) - return wave - - def add_bot_at_point( - self, spaz_type: type[SpazBot], spawn_time: float = 1.0 - ) -> None: - """Add a new bot at a specified named point.""" - if self._game_over: - return - def _getpt() -> Sequence[float]: - point = self.map.get_def_points( - 'ffa_spawn')[self._next_ffa_start_index] - self._next_ffa_start_index = ( - self._next_ffa_start_index + 1) % len( - self.map.get_def_points('ffa_spawn') - ) - x_range = (-0.5, 0.5) if point[3] == 0.0 else (-point[3], point[3]) - z_range = (-0.5, 0.5) if point[5] == 0.0 else (-point[5], point[5]) - point = ( - point[0] + random.uniform(*x_range), - point[1], - point[2] + random.uniform(*z_range), - ) - return point - pointpos = _getpt() - - assert self._bots is not None - self._bots.spawn_bot(spaz_type, pos=pointpos, spawn_time=spawn_time) - - def add_bot_at_angle( - self, angle: float, spaz_type: type[SpazBot], spawn_time: float = 1.0 - ) -> None: - """Add a new bot at a specified angle (for circular maps).""" - if self._game_over: - return - angle_radians = angle / 57.2957795 - xval = math.sin(angle_radians) * 1.06 - zval = math.cos(angle_radians) * 1.06 - point = (xval / 0.125, 2.3, (zval / 0.2) - 3.7) - assert self._bots is not None - self._bots.spawn_bot(spaz_type, pos=point, spawn_time=spawn_time) - - def _update_time_bonus(self) -> None: - self._time_bonus = int(self._time_bonus * 0.93) - if self._time_bonus > 0 and self._time_bonus_text is not None: - assert self._time_bonus_text.node - self._time_bonus_text.node.text = babase.Lstr( - value='${A}: ${B}', - subs=[ - ('${A}', babase.Lstr(resource='timeBonusText')), - ('${B}', str(self._time_bonus)), - ], - ) - else: - self._time_bonus_text = None - - def _start_updating_waves(self) -> None: - self._wave_update_timer = bs.Timer( - 2.0, bs.WeakCall(self._update_waves), repeat=True - ) - - def _update_scores(self) -> None: - score = self._score - assert self._scoreboard is not None - self._scoreboard.set_team_value(self.teams[0], score, max_score=None) - - def handlemessage(self, msg: Any) -> Any: - - if isinstance(msg, PlayerSpazHurtMessage): - msg.spaz.getplayer(Player, True).has_been_hurt = True - self._a_player_has_been_hurt = True - - elif isinstance(msg, bs.PlayerScoredMessage): - self._score += msg.score - self._update_scores() - - elif isinstance(msg, bs.PlayerDiedMessage): - super().handlemessage(msg) # Augment standard behavior. - player = msg.getplayer(Player) - self._a_player_has_been_hurt = True - - # Make note with the player when they can respawn: - if self._wavenum < 10: - player.respawn_wave = max(2, self._wavenum + 1) - elif self._wavenum < 15: - player.respawn_wave = max(2, self._wavenum + 2) - else: - player.respawn_wave = max(2, self._wavenum + 3) - bs.timer(0.1, self._update_player_spawn_info) - bs.timer(0.1, self._checkroundover) - - elif isinstance(msg, SpazBotDiedMessage): - pts, importance = msg.spazbot.get_death_points(msg.how) - if msg.killerplayer is not None: - target: Sequence[float] | None - if msg.spazbot.node: - target = msg.spazbot.node.position - else: - target = None - - killerplayer = msg.killerplayer - self.stats.player_scored( - killerplayer, - pts, - target=target, - kill=True, - screenmessage=False, - importance=importance, - ) - self._dingsound.play(volume=0.6) if importance == 1 else self._dingsoundhigh.play(volume=0.6) - - # Normally we pull scores from the score-set, but if there's - # no player lets be explicit. - else: - self._score += pts - self._update_scores() - else: - super().handlemessage(msg) - - def _handle_uber_kill_achievements(self, msg: SpazBotDiedMessage) -> None: - - # Uber mine achievement: - if msg.spazbot.last_attacked_type == ('explosion', 'land_mine'): - self._land_mine_kills += 1 - if self._land_mine_kills >= 6: - self._award_achievement('Gold Miner') - - # Uber tnt achievement: - if msg.spazbot.last_attacked_type == ('explosion', 'tnt'): - self._tnt_kills += 1 - if self._tnt_kills >= 6: - bs.timer( - 0.5, bs.WeakCall(self._award_achievement, 'TNT Terror') - ) - - def _handle_pro_kill_achievements(self, msg: SpazBotDiedMessage) -> None: - - # TNT achievement: - if msg.spazbot.last_attacked_type == ('explosion', 'tnt'): - self._tnt_kills += 1 - if self._tnt_kills >= 3: - bs.timer( - 0.5, - bs.WeakCall( - self._award_achievement, 'Boom Goes the Dynamite' - ), - ) - - def _handle_rookie_kill_achievements(self, msg: SpazBotDiedMessage) -> None: - # Land-mine achievement: - if msg.spazbot.last_attacked_type == ('explosion', 'land_mine'): - self._land_mine_kills += 1 - if self._land_mine_kills >= 3: - self._award_achievement('Mine Games') - - def _handle_training_kill_achievements( - self, msg: SpazBotDiedMessage - ) -> None: - # Toss-off-map achievement: - if msg.spazbot.last_attacked_type == ('picked_up', 'default'): - self._throw_off_kills += 1 - if self._throw_off_kills >= 3: - self._award_achievement('Off You Go Then') - - def _set_can_end_wave(self) -> None: - self._can_end_wave = True - - def end_game(self) -> None: - # Tell our bots to celebrate just to rub it in. - assert self._bots is not None - self._bots.final_celebrate() - self._game_over = True - self.do_end('defeat', delay=2.0) - bs.setmusic(None) - - def on_continue(self) -> None: - for player in self.players: - if not player.is_alive(): - self.spawn_player(player) - - def _checkroundover(self) -> None: - """Potentially end the round based on the state of the game.""" - if self.has_ended(): - return - if not any(player.is_alive() for player in self.teams[0].players): - # Allow continuing after wave 1. - if self._wavenum > 1: - self.continue_or_end_game() - else: - self.end_game() + """Co-op game where players try to survive attacking waves of enemies.""" + + name = 'Onslaught' + description = 'Defeat all enemies.' + + tips: list[str | babase.GameTip] = [ + 'Hold any button to run.' + ' (Trigger buttons work well if you have them)', + 'Try tricking enemies into killing eachother or running off cliffs.', + 'Try \'Cooking off\' bombs for a second or two before throwing them.', + 'It\'s easier to win with a friend or two helping.', + 'If you stay in one place, you\'re toast. Run and dodge to survive..', + 'Practice using your momentum to throw bombs more accurately.', + 'Your punches do much more damage if you are running or spinning.', + ] + + # Show messages when players die since it matters here. + announce_player_deaths = True + + def __init__(self, settings: dict): + super().__init__(settings) + self._new_wave_sound = bs.getsound('scoreHit01') + self._winsound = bs.getsound('score') + self._cashregistersound = bs.getsound('cashRegister') + self._a_player_has_been_hurt = False + self._player_has_dropped_bomb = False + self._spawn_center = (0, 0.2, 0) + self._tntspawnpos = (0, 0.95, -0.77) + self._powerup_center = (0, 1.5, 0) + self._powerup_spread = (6.0, 4.0) + self._scoreboard: Scoreboard | None = None + self._game_over = False + self._wavenum = 0 + self._can_end_wave = True + self._score = 0 + self._time_bonus = 0 + self._spawn_info_text: bs.NodeActor | None = None + self._dingsound = bs.getsound('dingSmall') + self._dingsoundhigh = bs.getsound('dingSmallHigh') + self._have_tnt = False + self._excluded_powerups: list[str] | None = None + self._waves: list[Wave] = [] + self._tntspawner: TNTSpawner | None = None + self._bots: SpazBotSet | None = None + self._powerup_drop_timer: bs.Timer | None = None + self._time_bonus_timer: bs.Timer | None = None + self._time_bonus_text: bs.NodeActor | None = None + self._flawless_bonus: int | None = None + self._wave_text: bs.NodeActor | None = None + self._wave_update_timer: bs.Timer | None = None + self._throw_off_kills = 0 + self._land_mine_kills = 0 + self._tnt_kills = 0 + + self._epic_mode = bool(settings['Epic Mode']) + # Base class overrides. + self.slow_motion = self._epic_mode + self.default_music = ( + bs.MusicType.EPIC if self._epic_mode else bs.MusicType.ONSLAUGHT + ) + + def on_transition_in(self) -> None: + super().on_transition_in() + self._spawn_info_text = bs.NodeActor( + bs.newnode( + 'text', + attrs={ + 'position': (15, -130), + 'h_attach': 'left', + 'v_attach': 'top', + 'scale': 0.55, + 'color': (0.3, 0.8, 0.3, 1.0), + 'text': '', + }, + ) + ) + self._scoreboard = Scoreboard( + label=babase.Lstr(resource='scoreText'), score_split=0.5 + ) + + def on_begin(self) -> None: + super().on_begin() + self._have_tnt = True + self._excluded_powerups = [] + self._waves = [] + bs.timer(4.0, self._start_powerup_drops) + + # Our TNT spawner (if applicable). + if self._have_tnt: + self._tntspawner = TNTSpawner(position=self._tntspawnpos) + + self.setup_low_life_warning_sound() + self._update_scores() + self._bots = SpazBotSet() + bs.timer(4.0, self._start_updating_waves) + self._next_ffa_start_index = random.randrange( + len(self.map.get_def_points('ffa_spawn')) + ) + + def _get_dist_grp_totals(self, grps: list[Any]) -> tuple[int, int]: + totalpts = 0 + totaldudes = 0 + for grp in grps: + for grpentry in grp: + dudes = grpentry[1] + totalpts += grpentry[0] * dudes + totaldudes += dudes + return totalpts, totaldudes + + def _get_distribution( + self, + target_points: int, + min_dudes: int, + max_dudes: int, + group_count: int, + max_level: int, + ) -> list[list[tuple[int, int]]]: + """Calculate a distribution of bad guys given some params.""" + max_iterations = 10 + max_dudes * 2 + + groups: list[list[tuple[int, int]]] = [] + for _g in range(group_count): + groups.append([]) + types = [1] + if max_level > 1: + types.append(2) + if max_level > 2: + types.append(3) + if max_level > 3: + types.append(4) + for iteration in range(max_iterations): + diff = self._add_dist_entry_if_possible( + groups, max_dudes, target_points, types + ) + + total_points, total_dudes = self._get_dist_grp_totals(groups) + full = total_points >= target_points + + if full: + # Every so often, delete a random entry just to + # shake up our distribution. + if random.random() < 0.2 and iteration != max_iterations - 1: + self._delete_random_dist_entry(groups) + + # If we don't have enough dudes, kill the group with + # the biggest point value. + elif ( + total_dudes < min_dudes and iteration != max_iterations - 1 + ): + self._delete_biggest_dist_entry(groups) + + # If we've got too many dudes, kill the group with the + # smallest point value. + elif ( + total_dudes > max_dudes and iteration != max_iterations - 1 + ): + self._delete_smallest_dist_entry(groups) + + # Close enough.. we're done. + else: + if diff == 0: + break + + return groups + + def _add_dist_entry_if_possible( + self, + groups: list[list[tuple[int, int]]], + max_dudes: int, + target_points: int, + types: list[int], + ) -> int: + # See how much we're off our target by. + total_points, total_dudes = self._get_dist_grp_totals(groups) + diff = target_points - total_points + dudes_diff = max_dudes - total_dudes + + # Add an entry if one will fit. + value = types[random.randrange(len(types))] + group = groups[random.randrange(len(groups))] + if not group: + max_count = random.randint(1, 6) + else: + max_count = 2 * random.randint(1, 3) + max_count = min(max_count, dudes_diff) + count = min(max_count, diff // value) + if count > 0: + group.append((value, count)) + total_points += value * count + total_dudes += count + diff = target_points - total_points + return diff + + def _delete_smallest_dist_entry( + self, groups: list[list[tuple[int, int]]] + ) -> None: + smallest_value = 9999 + smallest_entry = None + smallest_entry_group = None + for group in groups: + for entry in group: + if entry[0] < smallest_value or smallest_entry is None: + smallest_value = entry[0] + smallest_entry = entry + smallest_entry_group = group + assert smallest_entry is not None + assert smallest_entry_group is not None + smallest_entry_group.remove(smallest_entry) + + def _delete_biggest_dist_entry( + self, groups: list[list[tuple[int, int]]] + ) -> None: + biggest_value = 9999 + biggest_entry = None + biggest_entry_group = None + for group in groups: + for entry in group: + if entry[0] > biggest_value or biggest_entry is None: + biggest_value = entry[0] + biggest_entry = entry + biggest_entry_group = group + if biggest_entry is not None: + assert biggest_entry_group is not None + biggest_entry_group.remove(biggest_entry) + + def _delete_random_dist_entry( + self, groups: list[list[tuple[int, int]]] + ) -> None: + entry_count = 0 + for group in groups: + for _ in group: + entry_count += 1 + if entry_count > 1: + del_entry = random.randrange(entry_count) + entry_count = 0 + for group in groups: + for entry in group: + if entry_count == del_entry: + group.remove(entry) + break + entry_count += 1 + + def spawn_player(self, player: Player) -> bs.Actor: + + # We keep track of who got hurt each wave for score purposes. + player.has_been_hurt = False + pos = ( + self._spawn_center[0] + random.uniform(-1.5, 1.5), + self._spawn_center[1], + self._spawn_center[2] + random.uniform(-1.5, 1.5), + ) + spaz = self.spawn_player_spaz(player, position=pos) + spaz.add_dropped_bomb_callback(self._handle_player_dropped_bomb) + return spaz + + def _handle_player_dropped_bomb( + self, player: bs.Actor, bomb: bs.Actor + ) -> None: + del player, bomb # Unused. + self._player_has_dropped_bomb = True + + def _drop_powerup(self, index: int, poweruptype: str | None = None) -> None: + poweruptype = PowerupBoxFactory.get().get_random_powerup_type( + forcetype=poweruptype, excludetypes=self._excluded_powerups + ) + PowerupBox( + position=self.map.powerup_spawn_points[index], + poweruptype=poweruptype, + ).autoretain() + + def _start_powerup_drops(self) -> None: + self._powerup_drop_timer = bs.Timer( + 3.0, bs.WeakCall(self._drop_powerups), repeat=True + ) + + def _drop_powerups( + self, standard_points: bool = False, poweruptype: str | None = None + ) -> None: + """Generic powerup drop.""" + if standard_points: + points = self.map.powerup_spawn_points + for i in range(len(points)): + bs.timer( + 1.0 + i * 0.5, + bs.WeakCall( + self._drop_powerup, i, poweruptype if i == 0 else None + ), + ) + else: + point = ( + self._powerup_center[0] + + random.uniform( + -1.0 * self._powerup_spread[0], + 1.0 * self._powerup_spread[0], + ), + self._powerup_center[1], + self._powerup_center[2] + + random.uniform( + -self._powerup_spread[1], self._powerup_spread[1] + ), + ) + + # Drop one random one somewhere. + PowerupBox( + position=point, + poweruptype=PowerupBoxFactory.get().get_random_powerup_type( + excludetypes=self._excluded_powerups + ), + ).autoretain() + + def do_end(self, outcome: str, delay: float = 0.0) -> None: + """End the game with the specified outcome.""" + if outcome == 'defeat': + self.fade_to_red() + score: int | None + if self._wavenum >= 2: + score = self._score + fail_message = None + else: + score = None + fail_message = babase.Lstr(resource='reachWave2Text') + self.end( + { + 'outcome': outcome, + 'score': score, + 'fail_message': fail_message, + 'playerinfos': self.initialplayerinfos, + }, + delay=delay, + ) + + def _update_waves(self) -> None: + + # If we have no living bots, go to the next wave. + assert self._bots is not None + if ( + self._can_end_wave + and not self._bots.have_living_bots() + and not self._game_over + ): + self._can_end_wave = False + self._time_bonus_timer = None + self._time_bonus_text = None + base_delay = 0.0 + + # Reward time bonus. + if self._time_bonus > 0: + bs.timer(0, babase.Call(self._cashregistersound.play)) + bs.timer( + base_delay, + bs.WeakCall(self._award_time_bonus, self._time_bonus), + ) + base_delay += 1.0 + + # Reward flawless bonus. + if self._wavenum > 0: + have_flawless = False + for player in self.players: + if player.is_alive() and not player.has_been_hurt: + have_flawless = True + bs.timer( + base_delay, + bs.WeakCall(self._award_flawless_bonus, player), + ) + player.has_been_hurt = False # reset + if have_flawless: + base_delay += 1.0 + + self._wavenum += 1 + + # Short celebration after waves. + if self._wavenum > 1: + self.celebrate(0.5) + bs.timer(base_delay, bs.WeakCall(self._start_next_wave)) + + def _award_completion_bonus(self) -> None: + self._cashregistersound.play() + for player in self.players: + try: + if player.is_alive(): + assert self.initialplayerinfos is not None + self.stats.player_scored( + player, + int(100 / len(self.initialplayerinfos)), + scale=1.4, + color=(0.6, 0.6, 1.0, 1.0), + title=babase.Lstr(resource='completionBonusText'), + screenmessage=False, + ) + except Exception: + babase.print_exception() + + def _award_time_bonus(self, bonus: int) -> None: + self._cashregistersound.play() + PopupText( + babase.Lstr( + value='+${A} ${B}', + subs=[ + ('${A}', str(bonus)), + ('${B}', babase.Lstr(resource='timeBonusText')), + ], + ), + color=(1, 1, 0.5, 1), + scale=1.0, + position=(0, 3, -1), + ).autoretain() + self._score += self._time_bonus + self._update_scores() + + def _award_flawless_bonus(self, player: Player) -> None: + self._cashregistersound.play() + try: + if player.is_alive(): + assert self._flawless_bonus is not None + self.stats.player_scored( + player, + self._flawless_bonus, + scale=1.2, + color=(0.6, 1.0, 0.6, 1.0), + title=babase.Lstr(resource='flawlessWaveText'), + screenmessage=False, + ) + except Exception: + babase.print_exception() + + def _start_time_bonus_timer(self) -> None: + self._time_bonus_timer = bs.Timer( + 1.0, bs.WeakCall(self._update_time_bonus), repeat=True + ) + + def _update_player_spawn_info(self) -> None: + + # If we have no living players lets just blank this. + assert self._spawn_info_text is not None + assert self._spawn_info_text.node + if not any(player.is_alive() for player in self.teams[0].players): + self._spawn_info_text.node.text = '' + else: + text: str | babase.Lstr = '' + for player in self.players: + if not player.is_alive(): + rtxt = babase.Lstr( + resource='onslaughtRespawnText', + subs=[ + ('${PLAYER}', player.getname()), + ('${WAVE}', str(player.respawn_wave)), + ], + ) + text = babase.Lstr( + value='${A}${B}\n', + subs=[ + ('${A}', text), + ('${B}', rtxt), + ], + ) + self._spawn_info_text.node.text = text + + def _respawn_players_for_wave(self) -> None: + # Respawn applicable players. + if self._wavenum > 1 and not self.is_waiting_for_continue(): + for player in self.players: + if ( + not player.is_alive() + and player.respawn_wave == self._wavenum + ): + self.spawn_player(player) + self._update_player_spawn_info() + + def _setup_wave_spawns(self, wave: Wave) -> None: + tval = 0.0 + dtime = 0.2 + if self._wavenum == 1: + spawn_time = 3.973 + tval += 0.5 + else: + spawn_time = 2.648 + + bot_angle = wave.base_angle + self._time_bonus = 0 + self._flawless_bonus = 0 + for info in wave.entries: + if info is None: + continue + if isinstance(info, Delay): + spawn_time += info.duration + continue + if isinstance(info, Spacing): + bot_angle += info.spacing + continue + bot_type_2 = info.bottype + if bot_type_2 is not None: + assert not isinstance(bot_type_2, str) + self._time_bonus += bot_type_2.points_mult * 20 + self._flawless_bonus += bot_type_2.points_mult * 5 + + if self.map.name == 'Doom Shroom': + tval += dtime + spacing = info.spacing + bot_angle += spacing * 0.5 + if bot_type_2 is not None: + tcall = bs.WeakCall( + self.add_bot_at_angle, bot_angle, bot_type_2, spawn_time + ) + bs.timer(tval, tcall) + tval += dtime + bot_angle += spacing * 0.5 + else: + assert bot_type_2 is not None + spcall = bs.WeakCall( + self.add_bot_at_point, bot_type_2, spawn_time + ) + bs.timer(tval, spcall) + + # We can end the wave after all the spawning happens. + bs.timer( + tval + spawn_time - dtime + 0.01, + bs.WeakCall(self._set_can_end_wave), + ) + + def _start_next_wave(self) -> None: + + # This can happen if we beat a wave as we die. + # We don't wanna respawn players and whatnot if this happens. + if self._game_over: + return + + self._respawn_players_for_wave() + wave = self._generate_random_wave() + self._setup_wave_spawns(wave) + self._update_wave_ui_and_bonuses() + bs.timer(0.4, babase.Call(self._new_wave_sound.play)) + + def _update_wave_ui_and_bonuses(self) -> None: + self.show_zoom_message( + babase.Lstr( + value='${A} ${B}', + subs=[ + ('${A}', babase.Lstr(resource='waveText')), + ('${B}', str(self._wavenum)), + ], + ), + scale=1.0, + duration=1.0, + trail=True, + ) + + # Reset our time bonus. + tbtcolor = (1, 1, 0, 1) + tbttxt = babase.Lstr( + value='${A}: ${B}', + subs=[ + ('${A}', babase.Lstr(resource='timeBonusText')), + ('${B}', str(self._time_bonus)), + ], + ) + self._time_bonus_text = bs.NodeActor( + bs.newnode( + 'text', + attrs={ + 'v_attach': 'top', + 'h_attach': 'center', + 'h_align': 'center', + 'vr_depth': -30, + 'color': tbtcolor, + 'shadow': 1.0, + 'flatness': 1.0, + 'position': (0, -60), + 'scale': 0.8, + 'text': tbttxt, + }, + ) + ) + + bs.timer(5.0, bs.WeakCall(self._start_time_bonus_timer)) + wtcolor = (1, 1, 1, 1) + wttxt = babase.Lstr( + value='${A} ${B}', + subs=[ + ('${A}', babase.Lstr(resource='waveText')), + ('${B}', str(self._wavenum) + ('')), + ], + ) + self._wave_text = bs.NodeActor( + bs.newnode( + 'text', + attrs={ + 'v_attach': 'top', + 'h_attach': 'center', + 'h_align': 'center', + 'vr_depth': -10, + 'color': wtcolor, + 'shadow': 1.0, + 'flatness': 1.0, + 'position': (0, -40), + 'scale': 1.3, + 'text': wttxt, + }, + ) + ) + + def _bot_levels_for_wave(self) -> list[list[type[SpazBot]]]: + level = self._wavenum + bot_types = [ + BomberBot, + BrawlerBot, + TriggerBot, + ChargerBot, + BomberBotPro, + BrawlerBotPro, + TriggerBotPro, + BomberBotProShielded, + ExplodeyBot, + ChargerBotProShielded, + StickyBot, + BrawlerBotProShielded, + TriggerBotProShielded, + ] + if level > 5: + bot_types += [ + ExplodeyBot, + TriggerBotProShielded, + BrawlerBotProShielded, + ChargerBotProShielded, + ] + if level > 7: + bot_types += [ + ExplodeyBot, + TriggerBotProShielded, + BrawlerBotProShielded, + ChargerBotProShielded, + ] + if level > 10: + bot_types += [ + TriggerBotProShielded, + TriggerBotProShielded, + TriggerBotProShielded, + TriggerBotProShielded, + ] + if level > 13: + bot_types += [ + TriggerBotProShielded, + TriggerBotProShielded, + TriggerBotProShielded, + TriggerBotProShielded, + ] + bot_levels = [ + [b for b in bot_types if b.points_mult == 1], + [b for b in bot_types if b.points_mult == 2], + [b for b in bot_types if b.points_mult == 3], + [b for b in bot_types if b.points_mult == 4], + ] + + # Make sure all lists have something in them + if not all(bot_levels): + raise RuntimeError('Got empty bot level') + return bot_levels + + def _add_entries_for_distribution_group( + self, + group: list[tuple[int, int]], + bot_levels: list[list[type[SpazBot]]], + all_entries: list[Spawn | Spacing | Delay | None], + ) -> None: + entries: list[Spawn | Spacing | Delay | None] = [] + for entry in group: + bot_level = bot_levels[entry[0] - 1] + bot_type = bot_level[random.randrange(len(bot_level))] + rval = random.random() + if rval < 0.5: + spacing = 10.0 + elif rval < 0.9: + spacing = 20.0 + else: + spacing = 40.0 + split = random.random() > 0.3 + for i in range(entry[1]): + if split and i % 2 == 0: + entries.insert(0, Spawn(bot_type, spacing=spacing)) + else: + entries.append(Spawn(bot_type, spacing=spacing)) + if entries: + all_entries += entries + all_entries.append(Spacing(40.0 if random.random() < 0.5 else 80.0)) + + def _generate_random_wave(self) -> Wave: + level = self._wavenum + bot_levels = self._bot_levels_for_wave() + + target_points = level * 3 - 2 + min_dudes = min(1 + level // 3, 10) + max_dudes = min(10, level + 1) + max_level = ( + 4 if level > 6 else (3 if level > 3 else (2 if level > 2 else 1)) + ) + group_count = 3 + distribution = self._get_distribution( + target_points, min_dudes, max_dudes, group_count, max_level + ) + all_entries: list[Spawn | Spacing | Delay | None] = [] + for group in distribution: + self._add_entries_for_distribution_group( + group, bot_levels, all_entries + ) + angle_rand = random.random() + if angle_rand > 0.75: + base_angle = 130.0 + elif angle_rand > 0.5: + base_angle = 210.0 + elif angle_rand > 0.25: + base_angle = 20.0 + else: + base_angle = -30.0 + base_angle += (0.5 - random.random()) * 20.0 + wave = Wave(base_angle=base_angle, entries=all_entries) + return wave + + def add_bot_at_point( + self, spaz_type: type[SpazBot], spawn_time: float = 1.0 + ) -> None: + """Add a new bot at a specified named point.""" + if self._game_over: + return + + def _getpt() -> Sequence[float]: + point = self.map.get_def_points( + 'ffa_spawn')[self._next_ffa_start_index] + self._next_ffa_start_index = ( + self._next_ffa_start_index + 1) % len( + self.map.get_def_points('ffa_spawn') + ) + x_range = (-0.5, 0.5) if point[3] == 0.0 else (-point[3], point[3]) + z_range = (-0.5, 0.5) if point[5] == 0.0 else (-point[5], point[5]) + point = ( + point[0] + random.uniform(*x_range), + point[1], + point[2] + random.uniform(*z_range), + ) + return point + pointpos = _getpt() + + assert self._bots is not None + self._bots.spawn_bot(spaz_type, pos=pointpos, spawn_time=spawn_time) + + def add_bot_at_angle( + self, angle: float, spaz_type: type[SpazBot], spawn_time: float = 1.0 + ) -> None: + """Add a new bot at a specified angle (for circular maps).""" + if self._game_over: + return + angle_radians = angle / 57.2957795 + xval = math.sin(angle_radians) * 1.06 + zval = math.cos(angle_radians) * 1.06 + point = (xval / 0.125, 2.3, (zval / 0.2) - 3.7) + assert self._bots is not None + self._bots.spawn_bot(spaz_type, pos=point, spawn_time=spawn_time) + + def _update_time_bonus(self) -> None: + self._time_bonus = int(self._time_bonus * 0.93) + if self._time_bonus > 0 and self._time_bonus_text is not None: + assert self._time_bonus_text.node + self._time_bonus_text.node.text = babase.Lstr( + value='${A}: ${B}', + subs=[ + ('${A}', babase.Lstr(resource='timeBonusText')), + ('${B}', str(self._time_bonus)), + ], + ) + else: + self._time_bonus_text = None + + def _start_updating_waves(self) -> None: + self._wave_update_timer = bs.Timer( + 2.0, bs.WeakCall(self._update_waves), repeat=True + ) + + def _update_scores(self) -> None: + score = self._score + assert self._scoreboard is not None + self._scoreboard.set_team_value(self.teams[0], score, max_score=None) + + def handlemessage(self, msg: Any) -> Any: + + if isinstance(msg, PlayerSpazHurtMessage): + msg.spaz.getplayer(Player, True).has_been_hurt = True + self._a_player_has_been_hurt = True + + elif isinstance(msg, bs.PlayerScoredMessage): + self._score += msg.score + self._update_scores() + + elif isinstance(msg, bs.PlayerDiedMessage): + super().handlemessage(msg) # Augment standard behavior. + player = msg.getplayer(Player) + self._a_player_has_been_hurt = True + + # Make note with the player when they can respawn: + if self._wavenum < 10: + player.respawn_wave = max(2, self._wavenum + 1) + elif self._wavenum < 15: + player.respawn_wave = max(2, self._wavenum + 2) + else: + player.respawn_wave = max(2, self._wavenum + 3) + bs.timer(0.1, self._update_player_spawn_info) + bs.timer(0.1, self._checkroundover) + + elif isinstance(msg, SpazBotDiedMessage): + pts, importance = msg.spazbot.get_death_points(msg.how) + if msg.killerplayer is not None: + target: Sequence[float] | None + if msg.spazbot.node: + target = msg.spazbot.node.position + else: + target = None + + killerplayer = msg.killerplayer + self.stats.player_scored( + killerplayer, + pts, + target=target, + kill=True, + screenmessage=False, + importance=importance, + ) + self._dingsound.play( + volume=0.6) if importance == 1 else self._dingsoundhigh.play(volume=0.6) + + # Normally we pull scores from the score-set, but if there's + # no player lets be explicit. + else: + self._score += pts + self._update_scores() + else: + super().handlemessage(msg) + + def _handle_uber_kill_achievements(self, msg: SpazBotDiedMessage) -> None: + + # Uber mine achievement: + if msg.spazbot.last_attacked_type == ('explosion', 'land_mine'): + self._land_mine_kills += 1 + if self._land_mine_kills >= 6: + self._award_achievement('Gold Miner') + + # Uber tnt achievement: + if msg.spazbot.last_attacked_type == ('explosion', 'tnt'): + self._tnt_kills += 1 + if self._tnt_kills >= 6: + bs.timer( + 0.5, bs.WeakCall(self._award_achievement, 'TNT Terror') + ) + + def _handle_pro_kill_achievements(self, msg: SpazBotDiedMessage) -> None: + + # TNT achievement: + if msg.spazbot.last_attacked_type == ('explosion', 'tnt'): + self._tnt_kills += 1 + if self._tnt_kills >= 3: + bs.timer( + 0.5, + bs.WeakCall( + self._award_achievement, 'Boom Goes the Dynamite' + ), + ) + + def _handle_rookie_kill_achievements(self, msg: SpazBotDiedMessage) -> None: + # Land-mine achievement: + if msg.spazbot.last_attacked_type == ('explosion', 'land_mine'): + self._land_mine_kills += 1 + if self._land_mine_kills >= 3: + self._award_achievement('Mine Games') + + def _handle_training_kill_achievements( + self, msg: SpazBotDiedMessage + ) -> None: + # Toss-off-map achievement: + if msg.spazbot.last_attacked_type == ('picked_up', 'default'): + self._throw_off_kills += 1 + if self._throw_off_kills >= 3: + self._award_achievement('Off You Go Then') + + def _set_can_end_wave(self) -> None: + self._can_end_wave = True + + def end_game(self) -> None: + # Tell our bots to celebrate just to rub it in. + assert self._bots is not None + self._bots.final_celebrate() + self._game_over = True + self.do_end('defeat', delay=2.0) + bs.setmusic(None) + + def on_continue(self) -> None: + for player in self.players: + if not player.is_alive(): + self.spawn_player(player) + + def _checkroundover(self) -> None: + """Potentially end the round based on the state of the game.""" + if self.has_ended(): + return + if not any(player.is_alive() for player in self.teams[0].players): + # Allow continuing after wave 1. + if self._wavenum > 1: + self.continue_or_end_game() + else: + self.end_game() # ba_meta export plugin + + class CustomOnslaughtLevel(babase.Plugin): - def on_app_running(self) -> None: - babase.app.classic.add_coop_practice_level( - bs._level.Level( - 'Onslaught Football', - gametype=OnslaughtFootballGame, - settings={ - 'map': 'Football Stadium', - 'Epic Mode': False, - }, - preview_texture_name='footballStadiumPreview', - ) - ) - babase.app.classic.add_coop_practice_level( - bs._level.Level( - 'Onslaught Football Epic', - gametype=OnslaughtFootballGame, - settings={ - 'map': 'Football Stadium', - 'Epic Mode': True, - }, - preview_texture_name='footballStadiumPreview', - ) - ) + def on_app_running(self) -> None: + babase.app.classic.add_coop_practice_level( + bs._level.Level( + 'Onslaught Football', + gametype=OnslaughtFootballGame, + settings={ + 'map': 'Football Stadium', + 'Epic Mode': False, + }, + preview_texture_name='footballStadiumPreview', + ) + ) + babase.app.classic.add_coop_practice_level( + bs._level.Level( + 'Onslaught Football Epic', + gametype=OnslaughtFootballGame, + settings={ + 'map': 'Football Stadium', + 'Epic Mode': True, + }, + preview_texture_name='footballStadiumPreview', + ) + ) From 6c2125eaee4d511669aa143c3c56356aa173f9d2 Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Fri, 26 Jan 2024 16:07:34 +0300 Subject: [PATCH 15/36] more --- plugins/minigames.json | 14 + plugins/minigames/bot_chase.py | 218 +++++++ plugins/utilities.json | 14 + plugins/utilities/ba_colors.py | 1018 ++++++++++++++++++++++++++++++++ 4 files changed, 1264 insertions(+) create mode 100644 plugins/minigames/bot_chase.py create mode 100644 plugins/utilities/ba_colors.py diff --git a/plugins/minigames.json b/plugins/minigames.json index 83855ab..65479f7 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -1189,6 +1189,20 @@ "versions": { "1.0.0": null } + }, + "bot_chase": { + "description": "Try to survive from bots!", + "external_url": "", + "authors": [ + { + "name": "", + "email": "", + "discord": "" + } + ], + "versions": { + "1.0.0": null + } } } } \ No newline at end of file diff --git a/plugins/minigames/bot_chase.py b/plugins/minigames/bot_chase.py new file mode 100644 index 0000000..b9d2fe4 --- /dev/null +++ b/plugins/minigames/bot_chase.py @@ -0,0 +1,218 @@ +# Ported to api 8 by brostos using baport.(https://github.com/bombsquad-community/baport) +# 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.spazbot import BrawlerBot, SpazBotSet, SpazBot, SpazBotDiedMessage +from bascenev1lib.actor.bomb import Bomb +from bascenev1lib.actor.spaz import Spaz +from bascenev1lib.actor.onscreentimer import OnScreenTimer + +if TYPE_CHECKING: + from typing import Any, List, Type, Optional + + +# def ba_get_api_version(): +# return 6 + +def ba_get_levels(): + return [babase._level.Level( + 'Bot Chase',gametype=BotChaseGame, + settings={}, + preview_texture_name = 'footballStadiumPreview')] + + +class Player(bs.Player['Team']): + """Our player type for this game""" + + def __init__(self) -> None: + super().__init__() + self.death_time: Optional[float] = None + + +class MrSpazBot(SpazBot): + """Our bot type for this game""" + character = 'Spaz' + run = True + charge_dist_min = 10.0 + charge_dist_max = 9999.0 + charge_speed_min = 1.0 + charge_speed_max = 1.0 + throw_dist_min = 9999 + throw_dist_max = 9999 + + +class Team(bs.Team[Player]): + """Our team type for this minigame""" + + +# ba_meta export bascenev1.GameActivity +class BotChaseGame(bs.TeamGameActivity[Player, Team]): + """Our goal is to survive from spawning bots""" + name = 'Bot Chase' + description = 'Try to survive from bots!' + available_settings = [ + bs.BoolSetting( + 'Epic Mode', + default=False + ), + ] + + announce_player_deaths = True + + @classmethod + def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]: + return ['Football Stadium'] + + @classmethod + def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool: + return (issubclass(sessiontype, bs.FreeForAllSession) or issubclass(sessiontype, bs.DualTeamSession) or issubclass(sessiontype, bs.CoopSession)) # Coop session unused + + def __init__(self, settings: dict): + super().__init__(settings) + self._bots = SpazBotSet() + self._epic_mode = bool(settings['Epic Mode']) + self._timer: Optional[OnScreenTimer] = None + self._last_player_death_time: Optional[float] = None + + if self._epic_mode: + self.slow_motion = True + self.default_music = (bs.MusicType.EPIC if self._epic_mode else bs.MusicType.FORWARD_MARCH) + + def on_player_join(self, player: Player) -> None: + if self.has_begun(): + bs.broadcastmessage( + babase.Lstr(resource='playerDelayedJoinText', + subs=[('${PLAYER}', player.getname(full=True))]), + color=(0, 1, 0), + ) + assert self._timer is not None + player.death_time = self._timer.getstarttime() + return + self.spawn_player(player) + + def on_player_leave(self, player: Player) -> None: + super().on_player_leave(player) + self._check_end_game() + + def spawn_player(self, player: Player) -> bs.Actor: + spaz = self.spawn_player_spaz(player) + spaz.connect_controls_to_player(enable_punch=True, + enable_bomb=True, + enable_pickup=True) + + spaz.bomb_count = 3 + spaz.bomb_type = 'normal' + + #cerdo gordo + spaz.node.color_mask_texture = bs.gettexture('melColorMask') + spaz.node.color_texture = bs.gettexture('melColor') + spaz.node.head_mesh = bs.getmesh('melHead') + spaz.node.hand_mesh = bs.getmesh('melHand') + spaz.node.torso_mesh = bs.getmesh('melTorso') + spaz.node.pelvis_mesh = bs.getmesh('kronkPelvis') + spaz.node.upper_arm_mesh = bs.getmesh('melUpperArm') + spaz.node.forearm_mesh = bs.getmesh('melForeArm') + spaz.node.upper_leg_mesh = bs.getmesh('melUpperLeg') + spaz.node.lower_leg_mesh = bs.getmesh('melLowerLeg') + spaz.node.toes_mesh = bs.getmesh('melToes') + spaz.node.style = 'mel' + # Sounds cerdo gordo + mel_sounds = [bs.getsound('mel01'), bs.getsound('mel02'),bs.getsound('mel03'),bs.getsound('mel04'),bs.getsound('mel05'), + bs.getsound('mel06'),bs.getsound('mel07'),bs.getsound('mel08'),bs.getsound('mel09'),bs.getsound('mel10')] + spaz.node.jump_sounds = mel_sounds + spaz.node.attack_sounds = mel_sounds + spaz.node.impact_sounds = mel_sounds + spaz.node.pickup_sounds = mel_sounds + spaz.node.death_sounds = [bs.getsound('melDeath01')] + spaz.node.fall_sounds = [bs.getsound('melFall01')] + + spaz.play_big_death_sound = True + return spaz + + def on_begin(self) -> None: + super().on_begin() + self._bots.spawn_bot(MrSpazBot, pos=(random.choice([1, -1, 2, -2]), 1.34, random.choice([1, -1, 2, -2])), spawn_time=2.0) + self._bots.spawn_bot(MrSpazBot, pos=(random.choice([1, -1, 2, -2]), 1.34, random.choice([1, -1, 2, -2])), spawn_time=2.0) + + self._timer = OnScreenTimer() + self._timer.start() + + bs.timer(10.0, self._spawn_this_bot, repeat=True) + bs.timer(5.0, self._check_end_game) + + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, bs.PlayerDiedMessage): + + super().handlemessage(msg) + + curtime = bs.time() + + msg.getplayer(Player).death_time = curtime + + if isinstance(self.session, bs.CoopSession): + babase.pushcall(self._check_end_game) + + self._last_player_death_time = curtime + else: + bs.timer(1.0, self._check_end_game) + elif isinstance(msg, SpazBotDiedMessage): + self._spawn_this_bot() + else: + return super().handlemessage(msg) + return None + + def _spawn_this_bot(self) -> None: + self._bots.spawn_bot(MrSpazBot, pos=(random.choice([1, -1, 2, -2]), 1.34, random.choice([1, -1, 2, -2])), spawn_time=2.0) + + def _check_end_game(self) -> None: + living_team_count = 0 + for team in self.teams: + for player in team.players: + if player.is_alive(): + living_team_count += 1 + break + + if isinstance(self.session, bs.CoopSession): + if living_team_count <= 0: + self.end_game() + else: + if living_team_count <= 1: + self.end_game() + + def end_game(self) -> None: + cur_time = bs.time() + assert self._timer is not None + start_time = self._timer.getstarttime() + + for team in self.teams: + for player in team.players: + survived = False + + if player.death_time is None: + survived = True + player.death_time = cur_time + 1 + + score = int(player.death_time - self._timer.getstarttime()) + if survived: + score += 50 + self.stats.player_scored(player, score, screenmessage=False) + + self._timer.stop(endtime=self._last_player_death_time) + + results = bs.GameResults() + + for team in self.teams: + longest_life = 0.0 + for player in team.players: + assert player.death_time is not None + longest_life = max(longest_life, + player.death_time - start_time) + + results.set_team_score(team, int(1000.0 * longest_life)) + + self.end(results=results) \ No newline at end of file diff --git a/plugins/utilities.json b/plugins/utilities.json index fa71aa4..db809c6 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -1147,6 +1147,20 @@ "md5sum": "01cf9e10ab0e1bf51c07d80ff842c632" } } + }, + "ba_colours": { + "description": "Try to survive from bots!", + "external_url": "", + "authors": [ + { + "name": "Froshlee", + "email": "", + "discord": "froshlee24" + } + ], + "versions": { + "1.0.0": null + } } } } \ No newline at end of file diff --git a/plugins/utilities/ba_colors.py b/plugins/utilities/ba_colors.py new file mode 100644 index 0000000..8480f8b --- /dev/null +++ b/plugins/utilities/ba_colors.py @@ -0,0 +1,1018 @@ +# Ported to api 8 by brostos using baport.(https://github.com/bombsquad-community/baport) +"""Colors Mod.""" +#Mod by Froshlee14 +# ba_meta require api 8 + +from __future__ import annotations +from typing import TYPE_CHECKING + +import _babase +import babase +import bauiv1 as bui +import bascenev1 as bs + +if TYPE_CHECKING: + pass + +from bascenev1lib.actor.spazfactory import SpazFactory +from bascenev1lib.actor.scoreboard import Scoreboard +from bascenev1lib.game.elimination import EliminationGame, Icon, Player, Team +from bascenev1lib.gameutils import SharedObjects + +from bascenev1 import get_player_colors, get_player_profile_colors, get_player_profile_icon +from bauiv1lib.popup import PopupWindow +from bascenev1lib.actor import bomb, spaz +from bauiv1lib import tabs, confirm, mainmenu, popup +from bauiv1lib.colorpicker import ColorPicker +from bauiv1lib.mainmenu import MainMenuWindow +from bauiv1lib.profile.browser import * +from bascenev1lib.actor.playerspaz import * +from bascenev1lib.actor.flag import * +from bascenev1lib.actor.spazbot import * +from bascenev1lib.actor.spazfactory import SpazFactory +#from bascenev1lib.mainmenu import MainMenuActivity +import random + + +def getData(data): + return babase.app.config["colorsMod"][data] + +def getRandomColor(): + c = random.choice(getData("colors")) + return c + +def doColorMenu(self): + bui.containerwidget(edit=self._root_widget,transition='out_left') + openWindow() + +def updateButton(self): + color = (random.random(),random.random(),random.random()) + try: + bui.buttonwidget(edit=self._colorsModButton,color=color) + except Exception: + self._timer = None + +newConfig = {"colorPlayer":True, + "higlightPlayer":False, + "namePlayer":False, + "glowColor":False, + "glowHighlight":False, + "glowName":False, + "actab":1, + "shieldColor":False, + "xplotionColor":True, + "delScorch":True, + "colorBots":False, + "glowBots":False, + "flag":True, + #"test":True, + "glowScale":1, + "timeDelay":500, + "activeProfiles":['__account__'], + "colors":[color for color in get_player_colors()], + } + +def getDefaultSettings(): + return newConfig + +def getTranslation(text): + actLan = bs.app.lang.language + colorsModsLan = { + "title":{ + "Spanish":'Colors Mod', + "English":'Colors Mod' + }, + "player_tab":{ + "Spanish":'Ajustes de Jugador', + "English":'Player settings' + }, + "extras_tab":{ + "Spanish":'Ajustes Adicionales', + "English":'Adittional settings' + }, + "general_tab":{ + "Spanish":'Ajustes Generales', + "English":'General settings' + }, + "info_tab":{ + "Spanish":'Creditos', + "English":'Credits' + }, + "profiles":{ + "Spanish":'Perfiles', + "English":'Profiles' + }, + "palette":{ + "Spanish":'Paleta de Colores', + "English":'Pallete' + }, + "change":{ + "Spanish":'Cambiar', + "English":'Change' + }, + "glow":{ + "Spanish":'Brillar', + "English":'Glow' + }, + "glow_scale":{ + "Spanish":'Escala de Brillo', + "English":'Glow Scale' + }, + "time_delay":{ + "Spanish":'Intervalo de Tiempo', + "English":'Time Delay' + }, + "reset_values":{ + "Spanish":'Reiniciar Valores', + "English":'Reset Values' + }, + "players":{ + "Spanish":'Jugadores', + "English":'Players' + }, + "apply_to_color":{ + "Spanish":'Color Principal', + "English":'Main Color' + }, + "apply_to_highlight":{ + "Spanish":'Color de Resalte', + "English":'Highlight Color' + }, + "apply_to_name":{ + "Spanish":'Color del Nombre', + "English":'Name Color' + }, + "additional_features":{ + "Spanish":'Ajustes Adicionales', + "English":'Additional Features' + }, + "apply_to_bots":{ + "Spanish":'Color Principal de Bots', + "English":'Bots Main Color' + }, + "apply_to_shields":{ + "Spanish":'Escudos de Colores', + "English":'Apply to Shields' + }, + "apply_to_explotions":{ + "Spanish":'Explosiones de Colores', + "English":'Apply to Explotions' + }, + "apply_to_flags":{ + "Spanish":'Banderas de Colores', + "English":'Apply to Flags' + }, + "pick_color":{ + "Spanish":'Selecciona un Color', + "English":'Pick a Color' + }, + "add_color":{ + "Spanish":'Agregar Color', + "English":'Add Color' + }, + "remove_color":{ + "Spanish":'Quitar Color', + "English":'Remove Color' + }, + "clean_explotions":{ + "Spanish":'Limpiar Explosiones', + "English":'Remove Scorch' + }, + "restore_default_settings":{ + "Spanish":'Restaurar Ajustes Por Defecto', + "English":'Restore Default Settings' + }, + "settings_restored":{ + "Spanish":'Ajustes Restaurados', + "English":'Settings Restored' + }, + "restore_settings":{ + "Spanish":'¿Restaurar Ajustes Por Defecto?', + "English":'Restore Default Settings?' + }, + "nothing_selected":{ + "Spanish":'Nada Seleccionado', + "English":'Nothing Selected' + }, + "color_already":{ + "Spanish":'Este Color Ya Existe En La Paleta', + "English":'Color Already In The Palette' + }, + "tap_color":{ + "Spanish":'Toca un color para quitarlo.', + "English":'Tap to remove a color.' + }, + } + lans = ["Spanish","English"] + if actLan not in lans: + actLan = "English" + return colorsModsLan[text][actLan] + + +# ba_meta export plugin +class ColorsMod(babase.Plugin): + + #PLUGINS PLUS COMPATIBILITY + version = "1.7.2" + logo = 'gameCenterIcon' + logo_color = (1,1,1) + plugin_type = 'mod' + + def has_settings_ui (self): + return True + + def show_settings_ui(self, button): + ColorsMenu() + + if bs.app.lang.language == "Spanish": + information = ("Modifica y aplica efectos\n" + "a los colores de tu personaje,\n" + "explosiones, bots, escudos,\n" + "entre otras cosas...\n\n" + "Programado por Froshlee14\nTraducido por CerdoGordo\n\n" + "ADVERTENCIA\nEste mod puede ocacionar\n" + "efectos de epilepsia\na personas sensibles.") + else: + information = ("Modify and add effects\n" + "to your character colours.\n" + "And other stuff...\n\n" + "Coded by Froshlee14\nTranslated by CerdoGordo\n\n" + "WARNING\nThis mod can cause epileptic\n" + "seizures especially\nwith sensitive people") + + def on_app_running(self) -> None: + + if "colorsMod" in babase.app.config: + oldConfig = babase.app.config["colorsMod"] + for setting in newConfig: + if setting not in oldConfig: + babase.app.config["colorsMod"].update({setting:newConfig[setting]}) + bs.broadcastmessage(('Colors Mod: config updated'),color=(1,1,0)) + + removeList = [] + for setting in oldConfig: + if setting not in newConfig: + removeList.append(setting) + for element in removeList : + babase.app.config["colorsMod"].pop(element) + bs.broadcastmessage(('Colors Mod: old config deleted'),color=(1,1,0)) + else: + babase.app.config["colorsMod"] = newConfig + babase.app.config.apply_and_commit() + + + #MainMenuActivity.oldMakeWord = MainMenuActivity._make_word + #def newMakeWord(self, word: str, + # x: float, + # y: float, + # scale: float = 1.0, + # delay: float = 0.0, + # vr_depth_offset: float = 0.0, + # shadow: bool = False): + # self.oldMakeWord(word,x,y,scale,delay,vr_depth_offset,shadow) + # word = self._word_actors[-1] + # if word.node.getnodetype(): + # if word.node.color[3] == 1.0: + # word.node.color = getRandomColor() + #MainMenuActivity._make_word = newMakeWord + + #### GAME MODIFICATIONS #### + + #ESCUDO DE COLORES + def new_equip_shields(self, decay: bool = False) -> None: + if not self.node: + babase.print_error('Can\'t equip shields; no node.') + return + + factory = SpazFactory.get() + if self.shield is None: + self.shield = bs.newnode('shield',owner=self.node,attrs={ + 'color': (0.3, 0.2, 2.0),'radius': 1.3 }) + self.node.connectattr('position_center', self.shield, 'position') + self.shield_hitpoints = self.shield_hitpoints_max = 650 + self.shield_decay_rate = factory.shield_decay_rate if decay else 0 + self.shield.hurt = 0 + factory.shield_up_sound.play(1.0, position=self.node.position) + + if self.shield_decay_rate > 0: + self.shield_decay_timer = bs.Timer(0.5,bs.WeakCall(self.shield_decay),repeat=True) + self.shield.always_show_health_bar = True + def changeColor(): + if self.shield is None: return + if getData("shieldColor"): + self.shield.color = c = getRandomColor() + self._shieldTimer = bs.Timer(getData("timeDelay") / 1000,changeColor,repeat=True) + PlayerSpaz.equip_shields = new_equip_shields + + #BOTS DE COLORES + SpazBot.oldBotInit = SpazBot.__init__ + def newBotInit(self, *args, **kwargs): + self.oldBotInit(*args, **kwargs) + s = 1 + if getData("glowBots"): + s = getData("glowScale") + + self.node.highlight = (self.node.highlight[0]*s,self.node.highlight[1]*s,self.node.highlight[2]*s) + + def changeColor(): + if self.is_alive(): + if getData("colorBots"): + c = getRandomColor() + self.node.highlight = (c[0]*s,c[1]*s,c[2]*s) + self._timer = bs.Timer(getData("timeDelay") / 1000 ,changeColor,repeat=True) + SpazBot.__init__ = newBotInit + + #BANDERA DE COLORES + Flag.oldFlagInit = Flag.__init__ + def newFlaginit(self,position: Sequence[float] = (0.0, 1.0, 0.0), + color: Sequence[float] = (1.0, 1.0, 1.0), + materials: Sequence[bs.Material] = None, + touchable: bool = True, + dropped_timeout: int = None): + self.oldFlagInit(position, color,materials,touchable,dropped_timeout) + + def cC(): + if self.node.exists(): + if getData("flag"): + c = getRandomColor() + self.node.color = (c[0]*1.2,c[1]*1.2,c[2]*1.2) + else: return + if touchable : + self._timer = bs.Timer(getData("timeDelay") / 1000 ,cC,repeat=True) + + Flag.__init__ = newFlaginit + + #JUGADORES DE COLORES + PlayerSpaz.oldInit = PlayerSpaz.__init__ + def newInit(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', + powerups_expire: bool = True): + self.oldInit(player,color,highlight,character,powerups_expire) + + players = [] + for p in getData("activeProfiles"): + players.append(p) + + for x in range(len(players)): + if players[x] == "__account__" : + players[x] = bui.app.plus.get_v1_account_name()#_babase.get_v1_account_name() + + if player.getname() in players: + s = s2 = s3 = 1 + if getData("glowColor"): + s = getData("glowScale") + if getData("glowHighlight"): + s2 = getData("glowScale") + if getData("glowName"): + s3 = getData("glowScale") + + self.node.color = (self.node.color[0]*s,self.node.color[1]*s,self.node.color[2]*s) + self.node.highlight = (self.node.highlight[0]*s2,self.node.highlight[1]*s2,self.node.highlight[2]*s2) + self.node.name_color = (self.node.name_color[0]*s3,self.node.name_color[1]*s3,self.node.name_color[2]*s3) + + def changeColor(): + if self.is_alive(): + if getData("colorPlayer"): + c = getRandomColor() + self.node.color = (c[0]*s,c[1]*s,c[2]*s) + if getData("higlightPlayer"): + c = getRandomColor() + self.node.highlight = (c[0]*s2,c[1]*s2,c[2]*s2) + if getData("namePlayer"): + c = getRandomColor() + self.node.name_color = (c[0]*s3,c[1]*s3,c[2]*s3) + self._timer = bs.Timer(getData("timeDelay") / 1000 ,changeColor,repeat=True) + PlayerSpaz.__init__ = newInit + + #EXPLOSIONES DE COLORES + bomb.Blast.oldBlastInit = bomb.Blast.__init__ + def newBlastInit(self, position: Sequence[float] = (0.0, 1.0, 0.0), velocity: Sequence[float] = (0.0, 0.0, 0.0), + blast_radius: float = 2.0, blast_type: str = 'normal', source_player: bs.Player = None, + hit_type: str = 'explosion', hit_subtype: str = 'normal'): + + self.oldBlastInit(position, velocity, blast_radius, blast_type, source_player, hit_type, hit_subtype) + + if getData("xplotionColor"): + c = getRandomColor() + + scl = random.uniform(0.6, 0.9) + scorch_radius = light_radius = self.radius + if self.blast_type == 'tnt': + light_radius *= 1.4 + scorch_radius *= 1.15 + scl *= 3.0 + + for i in range(2): + scorch = bs.newnode('scorch',attrs={'position':self.node.position, 'size':scorch_radius*0.5,'big':(self.blast_type == 'tnt')}) + if self.blast_type == 'ice': scorch.color =(1,1,1.5) + else: scorch.color = c + if getData("xplotionColor"): + if getData("delScorch"): + bs.animate(scorch,"presence",{3:1, 13:0}) + bs.Timer(13,scorch.delete) + + if self.blast_type == 'ice': return + light = bs.newnode('light', attrs={ 'position': position,'volume_intensity_scale': 10.0,'color': c}) + + iscale = 1.6 + bs.animate(light, 'intensity', { + 0: 2.0 * iscale, + scl * 0.02: 0.1 * iscale, + scl * 0.025: 0.2 * iscale, + scl * 0.05: 17.0 * iscale, + scl * 0.06: 5.0 * iscale, + scl * 0.08: 4.0 * iscale, + scl * 0.2: 0.6 * iscale, + scl * 2.0: 0.00 * iscale, + scl * 3.0: 0.0}) + bs.animate(light, 'radius', { + 0: light_radius * 0.2, + scl * 0.05: light_radius * 0.55, + scl * 0.1: light_radius * 0.3, + scl * 0.3: light_radius * 0.15, + scl * 1.0: light_radius * 0.05}) + bs.timer(scl * 3.0, light.delete) + bomb.Blast.__init__ = newBlastInit + + +class ProfilesWindow(popup.PopupWindow): + """Popup window to view achievements.""" + + def __init__(self): + uiscale = bui.app.ui_v1.uiscale + scale = (1.8 if uiscale is babase.UIScale.SMALL else + 1.65 if uiscale is babase.UIScale.MEDIUM else 1.23) + self._transitioning_out = False + self._width = 300 + self._height = (300 if uiscale is babase.UIScale.SMALL else 350) + bg_color = (0.5, 0.4, 0.6) + + self._selected = None + self._activeProfiles = getData("activeProfiles") + + self._profiles = babase.app.config.get('Player Profiles', {}) + assert self._profiles is not None + items = list(self._profiles.items()) + items.sort(key=lambda x: x[0].lower()) + + accountName: Optional[str] + if bui.app.plus.get_v1_account_state() == 'signed_in': + accountName = bui.app.plus.get_v1_account_display_string() + else: accountName = None + #subHeight += (len(items)*45) + + # creates our _root_widget + popup.PopupWindow.__init__(self, + position=(0,0), + size=(self._width, self._height), + scale=scale, + bg_color=bg_color) + + self._cancel_button = bui.buttonwidget( parent=self.root_widget, + position=(50, self._height - 30), size=(50, 50), + scale=0.5, label='', + color=bg_color, + on_activate_call=self._on_cancel_press, + autoselect=True, + icon=bui.gettexture('crossOut'), + iconscale=1.2) + bui.containerwidget(edit=self.root_widget,cancel_button=self._cancel_button) + + + self._title_text = bui.textwidget(parent=self.root_widget, + position=(self._width * 0.5,self._height - 20), + size=(0, 0), + h_align='center', + v_align='center', + scale=01.0, + text=getTranslation('profiles'), + maxwidth=200, + color=(1, 1, 1, 0.4)) + + self._scrollwidget = bui.scrollwidget(parent=self.root_widget, + size=(self._width - 60, + self._height - 70), + position=(30, 30), + capture_arrows=True, + simple_culling_v=10) + bui.widget(edit=self._scrollwidget, autoselect=True) + + #incr = 36 + sub_width = self._width - 90 + sub_height = (len(items)*50) + + eq_rsrc = 'coopSelectWindow.powerRankingPointsEqualsText' + pts_rsrc = 'coopSelectWindow.powerRankingPointsText' + + self._subcontainer = box = bui.containerwidget(parent=self._scrollwidget, + size=(sub_width, sub_height), + background=False) + h = 20 + v = sub_height - 60 + for pName, p in items: + if pName == '__account__' and accountName is None: + continue + color, highlight = get_player_profile_colors(pName) + tval = (accountName if pName == '__account__' else + get_player_profile_icon(pName) + pName) + assert isinstance(tval, str) + #print(tval) + value = True if pName in self._activeProfiles else False + + w = bui.checkboxwidget(parent=box,position=(10,v), value=value, + on_value_change_call=bs.WeakCall(self.select, pName), + maxwidth=sub_width,size=(sub_width,50), + textcolor = color, + text=babase.Lstr(value=tval),autoselect=True) + v -= 45 + + def addProfile(self): + if self._selected is not None: + if self._selected not in self._activeProfiles: + self._activeProfiles.append(self._selected) + babase.app.config["colorsMod"]["activeProfiles"] = self._activeProfiles + babase.app.config.apply_and_commit() + else: bs.broadcastmessage(getTranslation('nothing_selected')) + + def removeProfile(self): + if self._selected is not None: + if self._selected in self._activeProfiles: + self._activeProfiles.remove(self._selected) + babase.app.config["colorsMod"]["activeProfiles"] = self._activeProfiles + babase.app.config.apply_and_commit() + else: print('not found') + else: bs.broadcastmessage(getTranslation('nothing_selected')) + + def select(self,name,m): + self._selected = name + if m == 0: self.removeProfile() + else: self.addProfile() + + def _on_cancel_press(self) -> None: + self._transition_out() + + def _transition_out(self) -> None: + if not self._transitioning_out: + self._transitioning_out = True + bui.containerwidget(edit=self.root_widget, transition='out_scale') + + def on_popup_cancel(self) -> None: + bui.getsound('swish').play() + self._transition_out() + + +class ColorsMenu(PopupWindow): + + def __init__(self,transition='in_right'): + #self._width = width = 650 + self._width = width = 800 + self._height = height = 450 + + self._scrollWidth = self._width*0.85 + self._scrollHeight = self._height - 120 + self._subWidth = self._scrollWidth*0.95; + self._subHeight = 200 + + self._current_tab = getData('actab') + self._timeDelay = getData("timeDelay") + self._glowScale = getData("glowScale") + + self.midwidth = self._scrollWidth*0.45 + self.qwidth = self.midwidth*0.4 + + app = bui.app.ui_v1 + uiscale = app.uiscale + + from bascenev1lib.mainmenu import MainMenuSession + self._in_game = not isinstance(bs.get_foreground_host_session(), + MainMenuSession) + + self._root_widget = bui.containerwidget(size=(width,height),transition=transition, + scale=1.5 if uiscale is babase.UIScale.SMALL else 1.0, + stack_offset=(0,-5) if uiscale is babase.UIScale.SMALL else (0,0)) + + self._title = bui.textwidget(parent=self._root_widget,position=(50,height-40),text='', + maxwidth=self._scrollWidth,size=(self._scrollWidth,20), + color=(0.8,0.8,0.8,1.0),h_align="center",scale=1.1) + + self._backButton = b = bui.buttonwidget(parent=self._root_widget,autoselect=True, + position=(50,height-60),size=(120,50), + scale=0.8,text_scale=1.2,label=babase.Lstr(resource='backText'), + button_type='back',on_activate_call=self._back) + bui.buttonwidget(edit=self._backButton, button_type='backSmall',size=(50, 50),label=babase.charstr(babase.SpecialChar.BACK)) + bui.containerwidget(edit=self._root_widget,cancel_button=b) + + self._nextButton = bui.buttonwidget(parent=self._root_widget,autoselect=True, + position=(width-60,height*0.5-20),size=(50,50), + scale=1.0,label=babase.charstr(babase.SpecialChar.RIGHT_ARROW), + color=(0.2,1,0.2),button_type='square', + on_activate_call=self.nextTabContainer) + + self._prevButton = bui.buttonwidget(parent=self._root_widget,autoselect=True, + position=(10,height*0.5-20),size=(50,50), + scale=1.0,label=babase.charstr(babase.SpecialChar.LEFT_ARROW), + color=(0.2,1,0.2),button_type='square', + on_activate_call=self.prevTabContainer) + + v = self._subHeight - 55 + v0 = height - 90 + + self.tabs = [ + [0,getTranslation('general_tab')], + [1,getTranslation('player_tab')], + [2,getTranslation('extras_tab')], + [3,getTranslation('info_tab')], + ] + + self._scrollwidget = sc = bui.scrollwidget(parent=self._root_widget,size=(self._subWidth,self._scrollHeight),border_opacity=0.3, highlight=False, position=((width*0.5)-(self._scrollWidth*0.47),50),capture_arrows=True,) + + bui.widget(edit=sc, left_widget=self._prevButton) + bui.widget(edit=sc, right_widget=self._nextButton) + bui.widget(edit=self._backButton, down_widget=sc) + + self.tabButtons = [] + h = 330 + for i in range(3): + tabButton = bui.buttonwidget(parent=self._root_widget,autoselect=True, + position=(h,20),size=(20,20), + scale=1.2,label='', + color=(0.3,0.9,0.3), + on_activate_call=babase.Call(self._setTab,self.tabs[i][0]), + texture=bui.gettexture('nub')) + self.tabButtons.append(tabButton) + h += 50 + self._tabContainer = None + self._setTab(self._current_tab) + + def nextTabContainer(self): + tab = babase.app.config['colorsMod']['actab'] + if tab == 2: self._setTab(0) + else: self._setTab(tab+1) + + def prevTabContainer(self): + tab = babase.app.config['colorsMod']['actab'] + if tab == 0: self._setTab(2) + else: self._setTab(tab-1) + + def _setTab(self,tab): + + self._colorTimer = None + self._current_tab = tab + + babase.app.config['colorsMod']['actab'] = tab + babase.app.config.apply_and_commit() + + if self._tabContainer is not None and self._tabContainer.exists(): + self._tabContainer.delete() + self._tabData = {} + + if tab == 0: #general + subHeight = 0 + + self._tabContainer = c = bui.containerwidget(parent=self._scrollwidget,size=(self._subWidth,subHeight), + background=False,selection_loops_to_parent=True) + + bui.textwidget(edit=self._title,text=getTranslation('general_tab')) + v0 = subHeight - 30 + v = v0 - 10 + + h = self._scrollWidth*0.12 + cSpacing = self._scrollWidth*0.15 + t = bui.textwidget(parent=c,position=(0,v), + text=getTranslation('glow_scale'), + maxwidth=self.midwidth ,size=(self.midwidth ,20),color=(0.8,0.8,0.8,1.0),h_align="center") + v -= 45 + b = bui.buttonwidget(parent=c,position=(h-20,v-12),size=(40,40),label="-", + autoselect=True,on_activate_call=babase.Call(self._glowScaleDecrement),repeat=True,enable_sound=True,button_type='square') + + self._glowScaleText = bui.textwidget(parent=c,position=(h+20,v),maxwidth=cSpacing, + size=(cSpacing,20),editable=False,color=(0.3,1.0,0.3),h_align="center",text=str(self._glowScale)) + + b2 = bui.buttonwidget(parent=c,position=(h+cSpacing+20,v-12),size=(40,40),label="+", + autoselect=True,on_activate_call=babase.Call(self._glowScaleIncrement),repeat=True,enable_sound=True,button_type='square') + + v -= 70 + t = bui.textwidget(parent=c,position=(0,v), + text=getTranslation('time_delay'), + maxwidth=self.midwidth ,size=(self.midwidth ,20),color=(0.8,0.8,0.8,1.0),h_align="center") + v -= 45 + a = bui.buttonwidget(parent=c,position=(h-20,v-12),size=(40,40),label="-", + autoselect=True,on_activate_call=babase.Call(self._timeDelayDecrement),repeat=True,enable_sound=True,button_type='square') + + self._timeDelayText = bui.textwidget(parent=c,position=(h+20,v),maxwidth=self._scrollWidth*0.9, + size=(cSpacing,20),editable=False,color=(0.3,1.0,0.3,1.0),h_align="center",text=str(self._timeDelay)) + + a2 = bui.buttonwidget(parent=c,position=(h+cSpacing+20,v-12),size=(40,40),label="+", + autoselect=True,on_activate_call=babase.Call(self._timeDelayIncrement),repeat=True,enable_sound=True,button_type='square') + + v -= 70 + reset = bui.buttonwidget(parent=c, autoselect=True, + position=((self._scrollWidth*0.22)-80, v-25), size=(160,50),scale=1.0, text_scale=1.2,textcolor=(1,1,1), + label=getTranslation('reset_values'),on_activate_call=self._resetValues) + self._updateColorTimer() + + v = v0 + h = self._scrollWidth*0.44 + + t = bui.textwidget(parent=c,position=(h,v), + text=getTranslation('palette'), + maxwidth=self.midwidth ,size=(self.midwidth ,20), + color=(0.8,0.8,0.8,1.0),h_align="center") + v -= 30 + t2 = bui.textwidget(parent=c,position=(h,v), + text=getTranslation('tap_color'), scale=0.9, + maxwidth=self.midwidth ,size=(self.midwidth ,20), + color=(0.6,0.6,0.6,1.0),h_align="center") + v -= 20 + sp = h+45 + self.updatePalette(v,sp) + + elif tab == 1: + subHeight = self._subHeight + + self._tabContainer = c = bui.containerwidget(parent=self._scrollwidget,size=(self._subWidth,subHeight), + background=False,selection_loops_to_parent=True) + v2 = v = v0 = subHeight + bui.textwidget(edit=self._title,text=getTranslation('player_tab')) + + t = babase.app.classic.spaz_appearances['Spaz'] + tex = bui.gettexture(t.icon_texture) + tintTex = bui.gettexture(t.icon_mask_texture) + gs = getData("glowScale") + tc = (1,1,1) + t2c = (1,1,1) + + v2 -= (50+180) + self._previewImage = bui.imagewidget(parent=c,position=(self._subWidth*0.72-100,v2),size=(200,200), + mask_texture=bui.gettexture('characterIconMask'),tint_texture=tintTex, + texture=tex, mesh_transparent=bui.getmesh('image1x1'), + tint_color=(tc[0]*gs,tc[1]*gs,tc[2]*gs),tint2_color=(t2c[0]*gs,t2c[1]*gs,t2c[2]*gs)) + + self._colorTimer = bui.AppTimer(getData("timeDelay") / 1000, + babase.Call(self._updatePreview),repeat=True) + v2 -= 70 + + def doProfileWindow(): + ProfilesWindow() + + reset = bui.buttonwidget(parent=c, autoselect=True,on_activate_call=doProfileWindow, + position=(self._subWidth*0.72-100,v2), size=(200,60),scale=1.0, text_scale=1.2,textcolor=(1,1,1), + label=getTranslation('profiles')) + miniBoxWidth = self.midwidth - 30 + miniBoxHeight = 80 + + v -= 18 + #Color + h = 50 + box1 = bui.containerwidget(parent=c,position=(h,v-miniBoxHeight), + size=(miniBoxWidth,miniBoxHeight),background=True) + vbox1 = miniBoxHeight -25 + t = bui.textwidget(parent=box1,position=(10,vbox1), + text=getTranslation('apply_to_color'), + maxwidth=miniBoxWidth-20,size=(miniBoxWidth,20),color=(0.8,0.8,0.8,1.0),h_align="left") + vbox1 -= 45 + self.bw = bui.checkboxwidget(parent=box1,position=(10,vbox1), value=getData("colorPlayer"), + on_value_change_call=babase.Call(self._setSetting,'colorPlayer'), maxwidth=self.qwidth, + text=getTranslation('change'),autoselect=True,size=(self.qwidth,25)) + #vbox1 -= 35 + self.bw = bui.checkboxwidget(parent=box1,position=(25+self.qwidth,vbox1), value=getData("glowColor"), + on_value_change_call=babase.Call(self._setSetting,'glowColor'), maxwidth=self.qwidth, + text=getTranslation('glow'),autoselect=True,size=(self.qwidth,25)) + v -= (miniBoxHeight+20) + + #Highlight + box1 = bui.containerwidget(parent=c,position=(h,v-miniBoxHeight), + size=(miniBoxWidth,miniBoxHeight),background=True) + vbox1 = miniBoxHeight -20 + t = bui.textwidget(parent=box1,position=(10,vbox1), + text=getTranslation('apply_to_highlight'), + maxwidth=miniBoxWidth-20,size=(miniBoxWidth,20),color=(0.8,0.8,0.8,1.0),h_align="left") + vbox1 -= 45 + self.bw = bui.checkboxwidget(parent=box1,position=(10,vbox1), value=getData("higlightPlayer"), + on_value_change_call=babase.Call(self._setSetting,'higlightPlayer'), maxwidth=self.qwidth, + text=getTranslation('change'),autoselect=True,size=(self.qwidth,25)) + #vbox1 -= 35 + self.bw = bui.checkboxwidget(parent=box1,position=(25+self.qwidth,vbox1), value=getData("glowHighlight"), + on_value_change_call=babase.Call(self._setSetting,'glowHighlight'), maxwidth=self.qwidth, + text=getTranslation('glow'),autoselect=True,size=(self.qwidth,25)) + v -= (miniBoxHeight+20) + #Name + box1 = bui.containerwidget(parent=c,position=(h,v-miniBoxHeight), + size=(miniBoxWidth,miniBoxHeight),background=True) + vbox1 = miniBoxHeight -20 + t = bui.textwidget(parent=box1,position=(10,vbox1), + text=getTranslation('apply_to_name'), + maxwidth=miniBoxWidth-20,size=(miniBoxWidth,20),color=(0.8,0.8,0.8,1.0),h_align="left") + vbox1 -= 40 + self.bw = bui.checkboxwidget(parent=box1,position=(10,vbox1), value=getData("namePlayer"), + on_value_change_call=babase.Call(self._setSetting,'namePlayer'), maxwidth=self.qwidth, + text=getTranslation('change'),autoselect=True,size=(self.qwidth,25)) + #vbox1 -= 35 + self.bw = bui.checkboxwidget(parent=box1,position=(25+self.qwidth,vbox1), value=getData("glowName"), + on_value_change_call=babase.Call(self._setSetting,'glowName'), maxwidth=self.qwidth, + text=getTranslation('glow'),autoselect=True,size=(self.qwidth,25)) + v -= (miniBoxHeight+50) + + elif tab == 2: + subHeight = 0 + self._tabContainer = c = bui.containerwidget(parent=self._scrollwidget,size=(self._subWidth,subHeight), + background=False,selection_loops_to_parent=True) + v0 = subHeight - 50 + + v = v0 + h = 30 + bui.textwidget(edit=self._title,text=getTranslation('extras_tab')) + self.bw = bui.checkboxwidget(parent=c,position=(h,v), value=getData("shieldColor"), + on_value_change_call=babase.Call(self._setSetting,'shieldColor'), maxwidth=self.midwidth, + text=getTranslation('apply_to_shields'),autoselect=True,size=(self.midwidth,30)) + v -= 50 + self.bw = bui.checkboxwidget(parent=c,position=(h,v), value=getData("flag"), + on_value_change_call=babase.Call(self._setSetting,'flag'), maxwidth=self.midwidth, + text=getTranslation('apply_to_flags'),autoselect=True,size=(self.midwidth,30)) + v = v0 + h = self.midwidth + self.bw = bui.checkboxwidget(parent=c,position=(h,v), value=getData("xplotionColor"), + on_value_change_call=babase.Call(self._setSetting,'xplotionColor'), maxwidth=self.midwidth, + text=getTranslation('apply_to_explotions'),autoselect=True,size=(self.midwidth,30)) + v -= 50 + self.bw = bui.checkboxwidget(parent=c,position=(h,v), value=getData("delScorch"), + on_value_change_call=babase.Call(self._setSetting,'delScorch'), maxwidth=self.midwidth, + text=getTranslation('clean_explotions'),autoselect=True,size=(self.midwidth,30)) + v -= 35 + miniBoxWidth = self.midwidth + miniBoxHeight = 80 + + #Bots Color + box1 = bui.containerwidget(parent=c,position=((self._scrollWidth*0.45) -(miniBoxWidth/2),v-miniBoxHeight), + size=(miniBoxWidth,miniBoxHeight),background=True) + vbox1 = miniBoxHeight -20 + t = bui.textwidget(parent=box1,position=(10,vbox1), + text=getTranslation('apply_to_bots'), + maxwidth=miniBoxWidth-20,size=(miniBoxWidth,20),color=(0.8,0.8,0.8,1.0),h_align="left") + vbox1 -= 45 + self.bw = bui.checkboxwidget(parent=box1,position=(10,vbox1),value=getData("colorBots"), + on_value_change_call=babase.Call(self._setSetting,'colorBots'), maxwidth=self.qwidth, + text=getTranslation('change'),autoselect=True,size=(self.qwidth,25)) + + self.bw = bui.checkboxwidget(parent=box1,position=(30+self.qwidth,vbox1), value=getData("glowBots"), + on_value_change_call=babase.Call(self._setSetting,'glowBots'), maxwidth=self.qwidth, + text=getTranslation('glow'),autoselect=True,size=(self.qwidth,25)) + + v -= 130 + reset = bui.buttonwidget(parent=c, autoselect=True,on_activate_call=self.restoreSettings, + position=((self._scrollWidth*0.45)-150, v-25), size=(300,50),scale=1.0, text_scale=1.2,textcolor=(1,1,1), + label=getTranslation('restore_default_settings')) + + for bttn in self.tabButtons: + bui.buttonwidget(edit=bttn,color = (0.1,0.5,0.1)) + bui.buttonwidget(edit=self.tabButtons[tab],color = (0.1,1,0.1)) + + def _setSetting(self,setting,m): + babase.app.config["colorsMod"][setting] = False if m==0 else True + babase.app.config.apply_and_commit() + + def _timeDelayDecrement(self): + self._timeDelay = max(50,self._timeDelay - 50) + bui.textwidget(edit=self._timeDelayText,text=str(self._timeDelay)) + babase.app.config["colorsMod"]["timeDelay"] = self._timeDelay + babase.app.config.apply_and_commit() + self._updateColorTimer() + + def _timeDelayIncrement(self): + self._timeDelay = self._timeDelay + 50 + bui.textwidget(edit=self._timeDelayText,text=str(self._timeDelay)) + babase.app.config["colorsMod"]["timeDelay"] = self._timeDelay + babase.app.config.apply_and_commit() + self._updateColorTimer() + + def _resetValues(self): + babase.app.config["colorsMod"]["glowScale"] = self._glowScale = 1 + babase.app.config["colorsMod"]["timeDelay"] = self._timeDelay = 500 + bui.textwidget(edit=self._glowScaleText,text=str(self._glowScale)) + bui.textwidget(edit=self._timeDelayText,text=str(self._timeDelay)) + babase.app.config.apply_and_commit() + self._updateColorTimer() + + def updatePalette(self,h,sp): + colours = getData("colors") + x = sp + y = h - 50 + cont = 1 + bttnSize = (45,45) + l = len(colours) + + for i in range(16): + if i < l: + w = bui.buttonwidget( + parent= self._tabContainer, position=(x,y), size=bttnSize, + autoselect=False, label="",button_type="square",color=colours[i], + on_activate_call=bs.WeakCall(self.removeColor,colours[i])) + else: + w = bui.buttonwidget( + parent= self._tabContainer, position=(x,y), size=bttnSize,color=(0.5, 0.4, 0.6), + autoselect=False, label="",texture=bui.gettexture('frameInset')) + if i == l: + bui.buttonwidget(edit=w,on_activate_call=bs.WeakCall(self._makePicker,w),label="+") + if cont % 4 == 0: + x = sp + y -= ((bttnSize[0]) + 10) + else: x += (bttnSize[0]) + 13 + cont += 1 + + def addColor(self,color): + if not self.colorIn(color): + babase.app.config["colorsMod"]["colors"].append(color) + babase.app.config.apply_and_commit() + self._setTab(0) + else: bs.broadcastmessage(getTranslation('color_already')) + + def removeColor(self,color): + if color is not None: + if len(getData("colors")) >= 3: + if color in getData("colors"): + babase.app.config["colorsMod"]["colors"].remove(color) + babase.app.config.apply_and_commit() + self._setTab(0) + else: print('not found') + else: bs.broadcastmessage("Min. 2 colors", color=(0, 1, 0)) + else: bs.broadcastmessage(getTranslation('nothing_selected')) + + def _makePicker(self, origin): + baseScale = 2.05 if babase.UIScale.SMALL else 1.6 if babase.UIScale.MEDIUM else 1.0 + initial_color = (0, 0.8, 0) + ColorPicker( parent=self._tabContainer, position=origin.get_screen_space_center(), + offset=(baseScale * (-100), 0),initial_color=initial_color, delegate=self, tag='color') + + def color_picker_closing(self, picker): + if not self._root_widget.exists(): return + tag = picker.get_tag() + + def color_picker_selected_color(self, picker, color): + self.addColor(color) + + def colorIn(self,c): + sColors = getData("colors") + for sC in sColors: + if c[0] == sC[0] and c[1] == sC[1] and c[2] == sC[2]: + return True + return False + + def setColor(self,c): + self._selected = c + bui.buttonwidget(edit=self._moveOut,color = (0.8, 0, 0)) + + def _updateColorTimer(self): + self._colorTimer = bui.AppTimer(getData("timeDelay") / 1000 , self._update, repeat=True) + + def _update(self): + color = (random.random(),random.random(),random.random()) + bui.textwidget(edit=self._timeDelayText,color=color) + + def _updatePreview(self): + gs = gs2 = getData("glowScale") + if not getData("glowColor"): gs =1 + if not getData("glowHighlight"): gs2 =1 + + c = (1,1,1) + if getData("colorPlayer"): + c = getRandomColor() + + c2 = (1,1,1) + if getData("higlightPlayer"): + c2 = getRandomColor() + + bui.imagewidget(edit=self._previewImage,tint_color=(c[0]*gs,c[1]*gs,c[2]*gs)) + bui.imagewidget(edit=self._previewImage,tint2_color=(c2[0]*gs2,c2[1]*gs2,c2[2]*gs2)) + + def _glowScaleDecrement(self): + self._glowScale = max(1,self._glowScale - 1) + bui.textwidget(edit=self._glowScaleText,text=str(self._glowScale)) + babase.app.config["colorsMod"]["glowScale"] = self._glowScale + babase.app.config.apply_and_commit() + + def _glowScaleIncrement(self): + self._glowScale = min(5,self._glowScale + 1) + bui.textwidget(edit=self._glowScaleText,text=str(self._glowScale)) + babase.app.config["colorsMod"]["glowScale"] = self._glowScale + babase.app.config.apply_and_commit() + + def restoreSettings(self): + def doIt(): + babase.app.config["colorsMod"] = getDefaultSettings() + babase.app.config.apply_and_commit() + self._setTab(2) + bs.broadcastmessage(getTranslation('settings_restored')) + confirm.ConfirmWindow(getTranslation('restore_settings'), + width=400, height=120, action=doIt, ok_text=babase.Lstr(resource='okText')) + + def _back(self): + bui.containerwidget(edit=self._root_widget,transition='out_right') + self._colorTimer = None + self._colorPreviewTimer = None + #if self._in_game: + # babase.app.main_menu_window = (mainmenu.MainMenuWindow(transition='in_left').get_root_widget()) + #else: + # babase.app.main_menu_window = ProfileBrowserWindow(transition='in_left').get_root_widget() + #babase.app.main_menu_window = (mainmenu.MainMenuWindow(transition='in_left').get_root_widget()) \ No newline at end of file From 472ac8022890be2354a97e9a60b41ce3f3707a61 Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Fri, 26 Jan 2024 16:10:05 +0300 Subject: [PATCH 16/36] Spelling error fix --- plugins/minigames.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index 65479f7..9513a6d 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -1120,7 +1120,7 @@ } } }, - "ba_dark_fileds": { + "ba_dark_fields": { "description": "Get to the other side and watch your step", "external_url": "", "authors": [ From 1664b4724953a05f470a6afa2d6f3cb653b0f59b Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Fri, 26 Jan 2024 13:12:06 +0000 Subject: [PATCH 17/36] [ci] auto-format --- plugins/minigames/bot_chase.py | 30 +- plugins/utilities/ba_colors.py | 1005 +++++++++++++++++--------------- 2 files changed, 542 insertions(+), 493 deletions(-) diff --git a/plugins/minigames/bot_chase.py b/plugins/minigames/bot_chase.py index b9d2fe4..6495ee4 100644 --- a/plugins/minigames/bot_chase.py +++ b/plugins/minigames/bot_chase.py @@ -21,9 +21,9 @@ if TYPE_CHECKING: def ba_get_levels(): return [babase._level.Level( - 'Bot Chase',gametype=BotChaseGame, + 'Bot Chase', gametype=BotChaseGame, settings={}, - preview_texture_name = 'footballStadiumPreview')] + preview_texture_name='footballStadiumPreview')] class Player(bs.Player['Team']): @@ -70,7 +70,8 @@ class BotChaseGame(bs.TeamGameActivity[Player, Team]): @classmethod def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool: - return (issubclass(sessiontype, bs.FreeForAllSession) or issubclass(sessiontype, bs.DualTeamSession) or issubclass(sessiontype, bs.CoopSession)) # Coop session unused + # Coop session unused + return (issubclass(sessiontype, bs.FreeForAllSession) or issubclass(sessiontype, bs.DualTeamSession) or issubclass(sessiontype, bs.CoopSession)) def __init__(self, settings: dict): super().__init__(settings) @@ -87,7 +88,7 @@ class BotChaseGame(bs.TeamGameActivity[Player, Team]): if self.has_begun(): bs.broadcastmessage( babase.Lstr(resource='playerDelayedJoinText', - subs=[('${PLAYER}', player.getname(full=True))]), + subs=[('${PLAYER}', player.getname(full=True))]), color=(0, 1, 0), ) assert self._timer is not None @@ -104,11 +105,11 @@ class BotChaseGame(bs.TeamGameActivity[Player, Team]): spaz.connect_controls_to_player(enable_punch=True, enable_bomb=True, enable_pickup=True) - + spaz.bomb_count = 3 spaz.bomb_type = 'normal' - #cerdo gordo + # cerdo gordo spaz.node.color_mask_texture = bs.gettexture('melColorMask') spaz.node.color_texture = bs.gettexture('melColor') spaz.node.head_mesh = bs.getmesh('melHead') @@ -122,8 +123,8 @@ class BotChaseGame(bs.TeamGameActivity[Player, Team]): spaz.node.toes_mesh = bs.getmesh('melToes') spaz.node.style = 'mel' # Sounds cerdo gordo - mel_sounds = [bs.getsound('mel01'), bs.getsound('mel02'),bs.getsound('mel03'),bs.getsound('mel04'),bs.getsound('mel05'), - bs.getsound('mel06'),bs.getsound('mel07'),bs.getsound('mel08'),bs.getsound('mel09'),bs.getsound('mel10')] + mel_sounds = [bs.getsound('mel01'), bs.getsound('mel02'), bs.getsound('mel03'), bs.getsound('mel04'), bs.getsound('mel05'), + bs.getsound('mel06'), bs.getsound('mel07'), bs.getsound('mel08'), bs.getsound('mel09'), bs.getsound('mel10')] spaz.node.jump_sounds = mel_sounds spaz.node.attack_sounds = mel_sounds spaz.node.impact_sounds = mel_sounds @@ -136,9 +137,11 @@ class BotChaseGame(bs.TeamGameActivity[Player, Team]): def on_begin(self) -> None: super().on_begin() - self._bots.spawn_bot(MrSpazBot, pos=(random.choice([1, -1, 2, -2]), 1.34, random.choice([1, -1, 2, -2])), spawn_time=2.0) - self._bots.spawn_bot(MrSpazBot, pos=(random.choice([1, -1, 2, -2]), 1.34, random.choice([1, -1, 2, -2])), spawn_time=2.0) - + self._bots.spawn_bot(MrSpazBot, pos=(random.choice( + [1, -1, 2, -2]), 1.34, random.choice([1, -1, 2, -2])), spawn_time=2.0) + self._bots.spawn_bot(MrSpazBot, pos=(random.choice( + [1, -1, 2, -2]), 1.34, random.choice([1, -1, 2, -2])), spawn_time=2.0) + self._timer = OnScreenTimer() self._timer.start() @@ -167,7 +170,8 @@ class BotChaseGame(bs.TeamGameActivity[Player, Team]): return None def _spawn_this_bot(self) -> None: - self._bots.spawn_bot(MrSpazBot, pos=(random.choice([1, -1, 2, -2]), 1.34, random.choice([1, -1, 2, -2])), spawn_time=2.0) + self._bots.spawn_bot(MrSpazBot, pos=(random.choice( + [1, -1, 2, -2]), 1.34, random.choice([1, -1, 2, -2])), spawn_time=2.0) def _check_end_game(self) -> None: living_team_count = 0 @@ -215,4 +219,4 @@ class BotChaseGame(bs.TeamGameActivity[Player, Team]): results.set_team_score(team, int(1000.0 * longest_life)) - self.end(results=results) \ No newline at end of file + self.end(results=results) diff --git a/plugins/utilities/ba_colors.py b/plugins/utilities/ba_colors.py index 8480f8b..e522529 100644 --- a/plugins/utilities/ba_colors.py +++ b/plugins/utilities/ba_colors.py @@ -1,6 +1,6 @@ # Ported to api 8 by brostos using baport.(https://github.com/bombsquad-community/baport) """Colors Mod.""" -#Mod by Froshlee14 +# Mod by Froshlee14 # ba_meta require api 8 from __future__ import annotations @@ -30,215 +30,221 @@ from bascenev1lib.actor.playerspaz import * from bascenev1lib.actor.flag import * from bascenev1lib.actor.spazbot import * from bascenev1lib.actor.spazfactory import SpazFactory -#from bascenev1lib.mainmenu import MainMenuActivity +# from bascenev1lib.mainmenu import MainMenuActivity import random def getData(data): return babase.app.config["colorsMod"][data] + def getRandomColor(): c = random.choice(getData("colors")) return c + def doColorMenu(self): - bui.containerwidget(edit=self._root_widget,transition='out_left') + bui.containerwidget(edit=self._root_widget, transition='out_left') openWindow() + def updateButton(self): - color = (random.random(),random.random(),random.random()) + color = (random.random(), random.random(), random.random()) try: - bui.buttonwidget(edit=self._colorsModButton,color=color) + bui.buttonwidget(edit=self._colorsModButton, color=color) except Exception: self._timer = None -newConfig = {"colorPlayer":True, - "higlightPlayer":False, - "namePlayer":False, - "glowColor":False, - "glowHighlight":False, - "glowName":False, - "actab":1, - "shieldColor":False, - "xplotionColor":True, - "delScorch":True, - "colorBots":False, - "glowBots":False, - "flag":True, - #"test":True, - "glowScale":1, - "timeDelay":500, - "activeProfiles":['__account__'], - "colors":[color for color in get_player_colors()], - } + +newConfig = {"colorPlayer": True, + "higlightPlayer": False, + "namePlayer": False, + "glowColor": False, + "glowHighlight": False, + "glowName": False, + "actab": 1, + "shieldColor": False, + "xplotionColor": True, + "delScorch": True, + "colorBots": False, + "glowBots": False, + "flag": True, + # "test":True, + "glowScale": 1, + "timeDelay": 500, + "activeProfiles": ['__account__'], + "colors": [color for color in get_player_colors()], + } + def getDefaultSettings(): return newConfig + def getTranslation(text): actLan = bs.app.lang.language colorsModsLan = { - "title":{ - "Spanish":'Colors Mod', - "English":'Colors Mod' + "title": { + "Spanish": 'Colors Mod', + "English": 'Colors Mod' }, - "player_tab":{ - "Spanish":'Ajustes de Jugador', - "English":'Player settings' + "player_tab": { + "Spanish": 'Ajustes de Jugador', + "English": 'Player settings' }, - "extras_tab":{ - "Spanish":'Ajustes Adicionales', - "English":'Adittional settings' + "extras_tab": { + "Spanish": 'Ajustes Adicionales', + "English": 'Adittional settings' }, - "general_tab":{ - "Spanish":'Ajustes Generales', - "English":'General settings' + "general_tab": { + "Spanish": 'Ajustes Generales', + "English": 'General settings' }, - "info_tab":{ - "Spanish":'Creditos', - "English":'Credits' + "info_tab": { + "Spanish": 'Creditos', + "English": 'Credits' }, - "profiles":{ - "Spanish":'Perfiles', - "English":'Profiles' + "profiles": { + "Spanish": 'Perfiles', + "English": 'Profiles' }, - "palette":{ - "Spanish":'Paleta de Colores', - "English":'Pallete' + "palette": { + "Spanish": 'Paleta de Colores', + "English": 'Pallete' }, - "change":{ - "Spanish":'Cambiar', - "English":'Change' + "change": { + "Spanish": 'Cambiar', + "English": 'Change' }, - "glow":{ - "Spanish":'Brillar', - "English":'Glow' + "glow": { + "Spanish": 'Brillar', + "English": 'Glow' }, - "glow_scale":{ - "Spanish":'Escala de Brillo', - "English":'Glow Scale' + "glow_scale": { + "Spanish": 'Escala de Brillo', + "English": 'Glow Scale' }, - "time_delay":{ - "Spanish":'Intervalo de Tiempo', - "English":'Time Delay' + "time_delay": { + "Spanish": 'Intervalo de Tiempo', + "English": 'Time Delay' }, - "reset_values":{ - "Spanish":'Reiniciar Valores', - "English":'Reset Values' + "reset_values": { + "Spanish": 'Reiniciar Valores', + "English": 'Reset Values' }, - "players":{ - "Spanish":'Jugadores', - "English":'Players' + "players": { + "Spanish": 'Jugadores', + "English": 'Players' }, - "apply_to_color":{ - "Spanish":'Color Principal', - "English":'Main Color' + "apply_to_color": { + "Spanish": 'Color Principal', + "English": 'Main Color' }, - "apply_to_highlight":{ - "Spanish":'Color de Resalte', - "English":'Highlight Color' + "apply_to_highlight": { + "Spanish": 'Color de Resalte', + "English": 'Highlight Color' }, - "apply_to_name":{ - "Spanish":'Color del Nombre', - "English":'Name Color' + "apply_to_name": { + "Spanish": 'Color del Nombre', + "English": 'Name Color' }, - "additional_features":{ - "Spanish":'Ajustes Adicionales', - "English":'Additional Features' + "additional_features": { + "Spanish": 'Ajustes Adicionales', + "English": 'Additional Features' }, - "apply_to_bots":{ - "Spanish":'Color Principal de Bots', - "English":'Bots Main Color' + "apply_to_bots": { + "Spanish": 'Color Principal de Bots', + "English": 'Bots Main Color' }, - "apply_to_shields":{ - "Spanish":'Escudos de Colores', - "English":'Apply to Shields' + "apply_to_shields": { + "Spanish": 'Escudos de Colores', + "English": 'Apply to Shields' }, - "apply_to_explotions":{ - "Spanish":'Explosiones de Colores', - "English":'Apply to Explotions' + "apply_to_explotions": { + "Spanish": 'Explosiones de Colores', + "English": 'Apply to Explotions' }, - "apply_to_flags":{ - "Spanish":'Banderas de Colores', - "English":'Apply to Flags' + "apply_to_flags": { + "Spanish": 'Banderas de Colores', + "English": 'Apply to Flags' }, - "pick_color":{ - "Spanish":'Selecciona un Color', - "English":'Pick a Color' + "pick_color": { + "Spanish": 'Selecciona un Color', + "English": 'Pick a Color' }, - "add_color":{ - "Spanish":'Agregar Color', - "English":'Add Color' + "add_color": { + "Spanish": 'Agregar Color', + "English": 'Add Color' }, - "remove_color":{ - "Spanish":'Quitar Color', - "English":'Remove Color' + "remove_color": { + "Spanish": 'Quitar Color', + "English": 'Remove Color' }, - "clean_explotions":{ - "Spanish":'Limpiar Explosiones', - "English":'Remove Scorch' + "clean_explotions": { + "Spanish": 'Limpiar Explosiones', + "English": 'Remove Scorch' }, - "restore_default_settings":{ - "Spanish":'Restaurar Ajustes Por Defecto', - "English":'Restore Default Settings' + "restore_default_settings": { + "Spanish": 'Restaurar Ajustes Por Defecto', + "English": 'Restore Default Settings' }, - "settings_restored":{ - "Spanish":'Ajustes Restaurados', - "English":'Settings Restored' + "settings_restored": { + "Spanish": 'Ajustes Restaurados', + "English": 'Settings Restored' }, - "restore_settings":{ - "Spanish":'¿Restaurar Ajustes Por Defecto?', - "English":'Restore Default Settings?' + "restore_settings": { + "Spanish": '¿Restaurar Ajustes Por Defecto?', + "English": 'Restore Default Settings?' }, - "nothing_selected":{ - "Spanish":'Nada Seleccionado', - "English":'Nothing Selected' + "nothing_selected": { + "Spanish": 'Nada Seleccionado', + "English": 'Nothing Selected' }, - "color_already":{ - "Spanish":'Este Color Ya Existe En La Paleta', - "English":'Color Already In The Palette' + "color_already": { + "Spanish": 'Este Color Ya Existe En La Paleta', + "English": 'Color Already In The Palette' }, - "tap_color":{ - "Spanish":'Toca un color para quitarlo.', - "English":'Tap to remove a color.' + "tap_color": { + "Spanish": 'Toca un color para quitarlo.', + "English": 'Tap to remove a color.' }, } - lans = ["Spanish","English"] + lans = ["Spanish", "English"] if actLan not in lans: actLan = "English" return colorsModsLan[text][actLan] - + # ba_meta export plugin class ColorsMod(babase.Plugin): - #PLUGINS PLUS COMPATIBILITY + # PLUGINS PLUS COMPATIBILITY version = "1.7.2" logo = 'gameCenterIcon' - logo_color = (1,1,1) + logo_color = (1, 1, 1) plugin_type = 'mod' - def has_settings_ui (self): + def has_settings_ui(self): return True def show_settings_ui(self, button): ColorsMenu() if bs.app.lang.language == "Spanish": - information = ("Modifica y aplica efectos\n" - "a los colores de tu personaje,\n" - "explosiones, bots, escudos,\n" - "entre otras cosas...\n\n" - "Programado por Froshlee14\nTraducido por CerdoGordo\n\n" - "ADVERTENCIA\nEste mod puede ocacionar\n" - "efectos de epilepsia\na personas sensibles.") + information = ("Modifica y aplica efectos\n" + "a los colores de tu personaje,\n" + "explosiones, bots, escudos,\n" + "entre otras cosas...\n\n" + "Programado por Froshlee14\nTraducido por CerdoGordo\n\n" + "ADVERTENCIA\nEste mod puede ocacionar\n" + "efectos de epilepsia\na personas sensibles.") else: - information = ("Modify and add effects\n" - "to your character colours.\n" - "And other stuff...\n\n" - "Coded by Froshlee14\nTranslated by CerdoGordo\n\n" - "WARNING\nThis mod can cause epileptic\n" - "seizures especially\nwith sensitive people") + information = ("Modify and add effects\n" + "to your character colours.\n" + "And other stuff...\n\n" + "Coded by Froshlee14\nTranslated by CerdoGordo\n\n" + "WARNING\nThis mod can cause epileptic\n" + "seizures especially\nwith sensitive people") def on_app_running(self) -> None: @@ -246,23 +252,22 @@ class ColorsMod(babase.Plugin): oldConfig = babase.app.config["colorsMod"] for setting in newConfig: if setting not in oldConfig: - babase.app.config["colorsMod"].update({setting:newConfig[setting]}) - bs.broadcastmessage(('Colors Mod: config updated'),color=(1,1,0)) + babase.app.config["colorsMod"].update({setting: newConfig[setting]}) + bs.broadcastmessage(('Colors Mod: config updated'), color=(1, 1, 0)) removeList = [] for setting in oldConfig: if setting not in newConfig: removeList.append(setting) - for element in removeList : + for element in removeList: babase.app.config["colorsMod"].pop(element) - bs.broadcastmessage(('Colors Mod: old config deleted'),color=(1,1,0)) + bs.broadcastmessage(('Colors Mod: old config deleted'), color=(1, 1, 0)) else: babase.app.config["colorsMod"] = newConfig babase.app.config.apply_and_commit() - - #MainMenuActivity.oldMakeWord = MainMenuActivity._make_word - #def newMakeWord(self, word: str, + # MainMenuActivity.oldMakeWord = MainMenuActivity._make_word + # def newMakeWord(self, word: str, # x: float, # y: float, # scale: float = 1.0, @@ -274,11 +279,12 @@ class ColorsMod(babase.Plugin): # if word.node.getnodetype(): # if word.node.color[3] == 1.0: # word.node.color = getRandomColor() - #MainMenuActivity._make_word = newMakeWord + # MainMenuActivity._make_word = newMakeWord #### GAME MODIFICATIONS #### - #ESCUDO DE COLORES + # ESCUDO DE COLORES + def new_equip_shields(self, decay: bool = False) -> None: if not self.node: babase.print_error('Can\'t equip shields; no node.') @@ -286,8 +292,8 @@ class ColorsMod(babase.Plugin): factory = SpazFactory.get() if self.shield is None: - self.shield = bs.newnode('shield',owner=self.node,attrs={ - 'color': (0.3, 0.2, 2.0),'radius': 1.3 }) + self.shield = bs.newnode('shield', owner=self.node, attrs={ + 'color': (0.3, 0.2, 2.0), 'radius': 1.3}) self.node.connectattr('position_center', self.shield, 'position') self.shield_hitpoints = self.shield_hitpoints_max = 650 self.shield_decay_rate = factory.shield_decay_rate if decay else 0 @@ -295,69 +301,76 @@ class ColorsMod(babase.Plugin): factory.shield_up_sound.play(1.0, position=self.node.position) if self.shield_decay_rate > 0: - self.shield_decay_timer = bs.Timer(0.5,bs.WeakCall(self.shield_decay),repeat=True) + self.shield_decay_timer = bs.Timer(0.5, bs.WeakCall(self.shield_decay), repeat=True) self.shield.always_show_health_bar = True + def changeColor(): - if self.shield is None: return + if self.shield is None: + return if getData("shieldColor"): self.shield.color = c = getRandomColor() - self._shieldTimer = bs.Timer(getData("timeDelay") / 1000,changeColor,repeat=True) + self._shieldTimer = bs.Timer(getData("timeDelay") / 1000, changeColor, repeat=True) PlayerSpaz.equip_shields = new_equip_shields - #BOTS DE COLORES + # BOTS DE COLORES SpazBot.oldBotInit = SpazBot.__init__ + def newBotInit(self, *args, **kwargs): self.oldBotInit(*args, **kwargs) s = 1 if getData("glowBots"): s = getData("glowScale") - - self.node.highlight = (self.node.highlight[0]*s,self.node.highlight[1]*s,self.node.highlight[2]*s) + + self.node.highlight = (self.node.highlight[0]*s, + self.node.highlight[1]*s, self.node.highlight[2]*s) def changeColor(): if self.is_alive(): if getData("colorBots"): c = getRandomColor() - self.node.highlight = (c[0]*s,c[1]*s,c[2]*s) - self._timer = bs.Timer(getData("timeDelay") / 1000 ,changeColor,repeat=True) + self.node.highlight = (c[0]*s, c[1]*s, c[2]*s) + self._timer = bs.Timer(getData("timeDelay") / 1000, changeColor, repeat=True) SpazBot.__init__ = newBotInit - #BANDERA DE COLORES + # BANDERA DE COLORES Flag.oldFlagInit = Flag.__init__ - def newFlaginit(self,position: Sequence[float] = (0.0, 1.0, 0.0), - color: Sequence[float] = (1.0, 1.0, 1.0), - materials: Sequence[bs.Material] = None, - touchable: bool = True, - dropped_timeout: int = None): - self.oldFlagInit(position, color,materials,touchable,dropped_timeout) - + + def newFlaginit(self, position: Sequence[float] = (0.0, 1.0, 0.0), + color: Sequence[float] = (1.0, 1.0, 1.0), + materials: Sequence[bs.Material] = None, + touchable: bool = True, + dropped_timeout: int = None): + self.oldFlagInit(position, color, materials, touchable, dropped_timeout) + def cC(): if self.node.exists(): if getData("flag"): c = getRandomColor() - self.node.color = (c[0]*1.2,c[1]*1.2,c[2]*1.2) - else: return - if touchable : - self._timer = bs.Timer(getData("timeDelay") / 1000 ,cC,repeat=True) - + self.node.color = (c[0]*1.2, c[1]*1.2, c[2]*1.2) + else: + return + if touchable: + self._timer = bs.Timer(getData("timeDelay") / 1000, cC, repeat=True) + Flag.__init__ = newFlaginit - #JUGADORES DE COLORES + # JUGADORES DE COLORES PlayerSpaz.oldInit = PlayerSpaz.__init__ - def newInit(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', - powerups_expire: bool = True): - self.oldInit(player,color,highlight,character,powerups_expire) + + def newInit(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', + powerups_expire: bool = True): + self.oldInit(player, color, highlight, character, powerups_expire) players = [] for p in getData("activeProfiles"): players.append(p) for x in range(len(players)): - if players[x] == "__account__" : - players[x] = bui.app.plus.get_v1_account_name()#_babase.get_v1_account_name() + if players[x] == "__account__": + players[x] = bui.app.plus.get_v1_account_name() # _babase.get_v1_account_name() if player.getname() in players: s = s2 = s3 = 1 @@ -368,31 +381,35 @@ class ColorsMod(babase.Plugin): if getData("glowName"): s3 = getData("glowScale") - self.node.color = (self.node.color[0]*s,self.node.color[1]*s,self.node.color[2]*s) - self.node.highlight = (self.node.highlight[0]*s2,self.node.highlight[1]*s2,self.node.highlight[2]*s2) - self.node.name_color = (self.node.name_color[0]*s3,self.node.name_color[1]*s3,self.node.name_color[2]*s3) + self.node.color = (self.node.color[0]*s, self.node.color[1]*s, self.node.color[2]*s) + self.node.highlight = ( + self.node.highlight[0]*s2, self.node.highlight[1]*s2, self.node.highlight[2]*s2) + self.node.name_color = ( + self.node.name_color[0]*s3, self.node.name_color[1]*s3, self.node.name_color[2]*s3) def changeColor(): if self.is_alive(): if getData("colorPlayer"): c = getRandomColor() - self.node.color = (c[0]*s,c[1]*s,c[2]*s) + self.node.color = (c[0]*s, c[1]*s, c[2]*s) if getData("higlightPlayer"): c = getRandomColor() - self.node.highlight = (c[0]*s2,c[1]*s2,c[2]*s2) + self.node.highlight = (c[0]*s2, c[1]*s2, c[2]*s2) if getData("namePlayer"): c = getRandomColor() - self.node.name_color = (c[0]*s3,c[1]*s3,c[2]*s3) - self._timer = bs.Timer(getData("timeDelay") / 1000 ,changeColor,repeat=True) + self.node.name_color = (c[0]*s3, c[1]*s3, c[2]*s3) + self._timer = bs.Timer(getData("timeDelay") / 1000, changeColor, repeat=True) PlayerSpaz.__init__ = newInit - #EXPLOSIONES DE COLORES + # EXPLOSIONES DE COLORES bomb.Blast.oldBlastInit = bomb.Blast.__init__ - def newBlastInit(self, position: Sequence[float] = (0.0, 1.0, 0.0), velocity: Sequence[float] = (0.0, 0.0, 0.0), - blast_radius: float = 2.0, blast_type: str = 'normal', source_player: bs.Player = None, - hit_type: str = 'explosion', hit_subtype: str = 'normal'): - self.oldBlastInit(position, velocity, blast_radius, blast_type, source_player, hit_type, hit_subtype) + def newBlastInit(self, position: Sequence[float] = (0.0, 1.0, 0.0), velocity: Sequence[float] = (0.0, 0.0, 0.0), + blast_radius: float = 2.0, blast_type: str = 'normal', source_player: bs.Player = None, + hit_type: str = 'explosion', hit_subtype: str = 'normal'): + + self.oldBlastInit(position, velocity, blast_radius, blast_type, + source_player, hit_type, hit_subtype) if getData("xplotionColor"): c = getRandomColor() @@ -405,16 +422,21 @@ class ColorsMod(babase.Plugin): scl *= 3.0 for i in range(2): - scorch = bs.newnode('scorch',attrs={'position':self.node.position, 'size':scorch_radius*0.5,'big':(self.blast_type == 'tnt')}) - if self.blast_type == 'ice': scorch.color =(1,1,1.5) - else: scorch.color = c + scorch = bs.newnode('scorch', attrs={ + 'position': self.node.position, 'size': scorch_radius*0.5, 'big': (self.blast_type == 'tnt')}) + if self.blast_type == 'ice': + scorch.color = (1, 1, 1.5) + else: + scorch.color = c if getData("xplotionColor"): if getData("delScorch"): - bs.animate(scorch,"presence",{3:1, 13:0}) - bs.Timer(13,scorch.delete) + bs.animate(scorch, "presence", {3: 1, 13: 0}) + bs.Timer(13, scorch.delete) - if self.blast_type == 'ice': return - light = bs.newnode('light', attrs={ 'position': position,'volume_intensity_scale': 10.0,'color': c}) + if self.blast_type == 'ice': + return + light = bs.newnode('light', attrs={'position': position, + 'volume_intensity_scale': 10.0, 'color': c}) iscale = 1.6 bs.animate(light, 'intensity', { @@ -458,48 +480,48 @@ class ProfilesWindow(popup.PopupWindow): items.sort(key=lambda x: x[0].lower()) accountName: Optional[str] - if bui.app.plus.get_v1_account_state() == 'signed_in': + if bui.app.plus.get_v1_account_state() == 'signed_in': accountName = bui.app.plus.get_v1_account_display_string() - else: accountName = None - #subHeight += (len(items)*45) + else: + accountName = None + # subHeight += (len(items)*45) # creates our _root_widget popup.PopupWindow.__init__(self, - position=(0,0), + position=(0, 0), size=(self._width, self._height), scale=scale, bg_color=bg_color) - self._cancel_button = bui.buttonwidget( parent=self.root_widget, - position=(50, self._height - 30), size=(50, 50), - scale=0.5, label='', - color=bg_color, - on_activate_call=self._on_cancel_press, - autoselect=True, - icon=bui.gettexture('crossOut'), - iconscale=1.2) - bui.containerwidget(edit=self.root_widget,cancel_button=self._cancel_button) - + self._cancel_button = bui.buttonwidget(parent=self.root_widget, + position=(50, self._height - 30), size=(50, 50), + scale=0.5, label='', + color=bg_color, + on_activate_call=self._on_cancel_press, + autoselect=True, + icon=bui.gettexture('crossOut'), + iconscale=1.2) + bui.containerwidget(edit=self.root_widget, cancel_button=self._cancel_button) self._title_text = bui.textwidget(parent=self.root_widget, - position=(self._width * 0.5,self._height - 20), - size=(0, 0), - h_align='center', - v_align='center', - scale=01.0, - text=getTranslation('profiles'), - maxwidth=200, - color=(1, 1, 1, 0.4)) + position=(self._width * 0.5, self._height - 20), + size=(0, 0), + h_align='center', + v_align='center', + scale=01.0, + text=getTranslation('profiles'), + maxwidth=200, + color=(1, 1, 1, 0.4)) self._scrollwidget = bui.scrollwidget(parent=self.root_widget, - size=(self._width - 60, - self._height - 70), - position=(30, 30), - capture_arrows=True, - simple_culling_v=10) + size=(self._width - 60, + self._height - 70), + position=(30, 30), + capture_arrows=True, + simple_culling_v=10) bui.widget(edit=self._scrollwidget, autoselect=True) - #incr = 36 + # incr = 36 sub_width = self._width - 90 sub_height = (len(items)*50) @@ -507,8 +529,8 @@ class ProfilesWindow(popup.PopupWindow): pts_rsrc = 'coopSelectWindow.powerRankingPointsText' self._subcontainer = box = bui.containerwidget(parent=self._scrollwidget, - size=(sub_width, sub_height), - background=False) + size=(sub_width, sub_height), + background=False) h = 20 v = sub_height - 60 for pName, p in items: @@ -518,14 +540,14 @@ class ProfilesWindow(popup.PopupWindow): tval = (accountName if pName == '__account__' else get_player_profile_icon(pName) + pName) assert isinstance(tval, str) - #print(tval) + # print(tval) value = True if pName in self._activeProfiles else False - w = bui.checkboxwidget(parent=box,position=(10,v), value=value, - on_value_change_call=bs.WeakCall(self.select, pName), - maxwidth=sub_width,size=(sub_width,50), - textcolor = color, - text=babase.Lstr(value=tval),autoselect=True) + w = bui.checkboxwidget(parent=box, position=(10, v), value=value, + on_value_change_call=bs.WeakCall(self.select, pName), + maxwidth=sub_width, size=(sub_width, 50), + textcolor=color, + text=babase.Lstr(value=tval), autoselect=True) v -= 45 def addProfile(self): @@ -534,7 +556,8 @@ class ProfilesWindow(popup.PopupWindow): self._activeProfiles.append(self._selected) babase.app.config["colorsMod"]["activeProfiles"] = self._activeProfiles babase.app.config.apply_and_commit() - else: bs.broadcastmessage(getTranslation('nothing_selected')) + else: + bs.broadcastmessage(getTranslation('nothing_selected')) def removeProfile(self): if self._selected is not None: @@ -542,13 +565,17 @@ class ProfilesWindow(popup.PopupWindow): self._activeProfiles.remove(self._selected) babase.app.config["colorsMod"]["activeProfiles"] = self._activeProfiles babase.app.config.apply_and_commit() - else: print('not found') - else: bs.broadcastmessage(getTranslation('nothing_selected')) + else: + print('not found') + else: + bs.broadcastmessage(getTranslation('nothing_selected')) - def select(self,name,m): + def select(self, name, m): self._selected = name - if m == 0: self.removeProfile() - else: self.addProfile() + if m == 0: + self.removeProfile() + else: + self.addProfile() def _on_cancel_press(self) -> None: self._transition_out() @@ -565,19 +592,19 @@ class ProfilesWindow(popup.PopupWindow): class ColorsMenu(PopupWindow): - def __init__(self,transition='in_right'): - #self._width = width = 650 + def __init__(self, transition='in_right'): + # self._width = width = 650 self._width = width = 800 self._height = height = 450 self._scrollWidth = self._width*0.85 self._scrollHeight = self._height - 120 - self._subWidth = self._scrollWidth*0.95; + self._subWidth = self._scrollWidth*0.95 self._subHeight = 200 - + self._current_tab = getData('actab') - self._timeDelay = getData("timeDelay") - self._glowScale = getData("glowScale") + self._timeDelay = getData("timeDelay") + self._glowScale = getData("glowScale") self.midwidth = self._scrollWidth*0.45 self.qwidth = self.midwidth*0.4 @@ -589,58 +616,61 @@ class ColorsMenu(PopupWindow): self._in_game = not isinstance(bs.get_foreground_host_session(), MainMenuSession) - self._root_widget = bui.containerwidget(size=(width,height),transition=transition, - scale=1.5 if uiscale is babase.UIScale.SMALL else 1.0, - stack_offset=(0,-5) if uiscale is babase.UIScale.SMALL else (0,0)) + self._root_widget = bui.containerwidget(size=(width, height), transition=transition, + scale=1.5 if uiscale is babase.UIScale.SMALL else 1.0, + stack_offset=(0, -5) if uiscale is babase.UIScale.SMALL else (0, 0)) - self._title = bui.textwidget(parent=self._root_widget,position=(50,height-40),text='', - maxwidth=self._scrollWidth,size=(self._scrollWidth,20), - color=(0.8,0.8,0.8,1.0),h_align="center",scale=1.1) - - self._backButton = b = bui.buttonwidget(parent=self._root_widget,autoselect=True, - position=(50,height-60),size=(120,50), - scale=0.8,text_scale=1.2,label=babase.Lstr(resource='backText'), - button_type='back',on_activate_call=self._back) - bui.buttonwidget(edit=self._backButton, button_type='backSmall',size=(50, 50),label=babase.charstr(babase.SpecialChar.BACK)) - bui.containerwidget(edit=self._root_widget,cancel_button=b) + self._title = bui.textwidget(parent=self._root_widget, position=(50, height-40), text='', + maxwidth=self._scrollWidth, size=(self._scrollWidth, 20), + color=(0.8, 0.8, 0.8, 1.0), h_align="center", scale=1.1) - self._nextButton = bui.buttonwidget(parent=self._root_widget,autoselect=True, - position=(width-60,height*0.5-20),size=(50,50), - scale=1.0,label=babase.charstr(babase.SpecialChar.RIGHT_ARROW), - color=(0.2,1,0.2),button_type='square', - on_activate_call=self.nextTabContainer) + self._backButton = b = bui.buttonwidget(parent=self._root_widget, autoselect=True, + position=(50, height-60), size=(120, 50), + scale=0.8, text_scale=1.2, label=babase.Lstr(resource='backText'), + button_type='back', on_activate_call=self._back) + bui.buttonwidget(edit=self._backButton, button_type='backSmall', size=( + 50, 50), label=babase.charstr(babase.SpecialChar.BACK)) + bui.containerwidget(edit=self._root_widget, cancel_button=b) + + self._nextButton = bui.buttonwidget(parent=self._root_widget, autoselect=True, + position=(width-60, height*0.5-20), size=(50, 50), + scale=1.0, label=babase.charstr(babase.SpecialChar.RIGHT_ARROW), + color=(0.2, 1, 0.2), button_type='square', + on_activate_call=self.nextTabContainer) + + self._prevButton = bui.buttonwidget(parent=self._root_widget, autoselect=True, + position=(10, height*0.5-20), size=(50, 50), + scale=1.0, label=babase.charstr(babase.SpecialChar.LEFT_ARROW), + color=(0.2, 1, 0.2), button_type='square', + on_activate_call=self.prevTabContainer) - self._prevButton = bui.buttonwidget(parent=self._root_widget,autoselect=True, - position=(10,height*0.5-20),size=(50,50), - scale=1.0,label=babase.charstr(babase.SpecialChar.LEFT_ARROW), - color=(0.2,1,0.2),button_type='square', - on_activate_call=self.prevTabContainer) - v = self._subHeight - 55 v0 = height - 90 self.tabs = [ - [0,getTranslation('general_tab')], - [1,getTranslation('player_tab')], - [2,getTranslation('extras_tab')], - [3,getTranslation('info_tab')], - ] - - self._scrollwidget = sc = bui.scrollwidget(parent=self._root_widget,size=(self._subWidth,self._scrollHeight),border_opacity=0.3, highlight=False, position=((width*0.5)-(self._scrollWidth*0.47),50),capture_arrows=True,) + [0, getTranslation('general_tab')], + [1, getTranslation('player_tab')], + [2, getTranslation('extras_tab')], + [3, getTranslation('info_tab')], + ] + + self._scrollwidget = sc = bui.scrollwidget(parent=self._root_widget, size=( + self._subWidth, self._scrollHeight), border_opacity=0.3, highlight=False, position=((width*0.5)-(self._scrollWidth*0.47), 50), capture_arrows=True,) bui.widget(edit=sc, left_widget=self._prevButton) bui.widget(edit=sc, right_widget=self._nextButton) bui.widget(edit=self._backButton, down_widget=sc) self.tabButtons = [] - h = 330 + h = 330 for i in range(3): - tabButton = bui.buttonwidget(parent=self._root_widget,autoselect=True, - position=(h,20),size=(20,20), - scale=1.2,label='', - color=(0.3,0.9,0.3), - on_activate_call=babase.Call(self._setTab,self.tabs[i][0]), - texture=bui.gettexture('nub')) + tabButton = bui.buttonwidget(parent=self._root_widget, autoselect=True, + position=(h, 20), size=(20, 20), + scale=1.2, label='', + color=(0.3, 0.9, 0.3), + on_activate_call=babase.Call( + self._setTab, self.tabs[i][0]), + texture=bui.gettexture('nub')) self.tabButtons.append(tabButton) h += 50 self._tabContainer = None @@ -648,15 +678,19 @@ class ColorsMenu(PopupWindow): def nextTabContainer(self): tab = babase.app.config['colorsMod']['actab'] - if tab == 2: self._setTab(0) - else: self._setTab(tab+1) + if tab == 2: + self._setTab(0) + else: + self._setTab(tab+1) def prevTabContainer(self): tab = babase.app.config['colorsMod']['actab'] - if tab == 0: self._setTab(2) - else: self._setTab(tab-1) - - def _setTab(self,tab): + if tab == 0: + self._setTab(2) + else: + self._setTab(tab-1) + + def _setTab(self, tab): self._colorTimer = None self._current_tab = tab @@ -668,334 +702,345 @@ class ColorsMenu(PopupWindow): self._tabContainer.delete() self._tabData = {} - if tab == 0: #general + if tab == 0: # general subHeight = 0 - self._tabContainer = c = bui.containerwidget(parent=self._scrollwidget,size=(self._subWidth,subHeight), - background=False,selection_loops_to_parent=True) - - bui.textwidget(edit=self._title,text=getTranslation('general_tab')) + self._tabContainer = c = bui.containerwidget(parent=self._scrollwidget, size=(self._subWidth, subHeight), + background=False, selection_loops_to_parent=True) + + bui.textwidget(edit=self._title, text=getTranslation('general_tab')) v0 = subHeight - 30 v = v0 - 10 - + h = self._scrollWidth*0.12 cSpacing = self._scrollWidth*0.15 - t = bui.textwidget(parent=c,position=(0,v), - text=getTranslation('glow_scale'), - maxwidth=self.midwidth ,size=(self.midwidth ,20),color=(0.8,0.8,0.8,1.0),h_align="center") - v -= 45 - b = bui.buttonwidget(parent=c,position=(h-20,v-12),size=(40,40),label="-", - autoselect=True,on_activate_call=babase.Call(self._glowScaleDecrement),repeat=True,enable_sound=True,button_type='square') + t = bui.textwidget(parent=c, position=(0, v), + text=getTranslation('glow_scale'), + maxwidth=self.midwidth, size=(self.midwidth, 20), color=(0.8, 0.8, 0.8, 1.0), h_align="center") + v -= 45 + b = bui.buttonwidget(parent=c, position=(h-20, v-12), size=(40, 40), label="-", + autoselect=True, on_activate_call=babase.Call(self._glowScaleDecrement), repeat=True, enable_sound=True, button_type='square') - self._glowScaleText = bui.textwidget(parent=c,position=(h+20,v),maxwidth=cSpacing, - size=(cSpacing,20),editable=False,color=(0.3,1.0,0.3),h_align="center",text=str(self._glowScale)) + self._glowScaleText = bui.textwidget(parent=c, position=(h+20, v), maxwidth=cSpacing, + size=(cSpacing, 20), editable=False, color=(0.3, 1.0, 0.3), h_align="center", text=str(self._glowScale)) - b2 = bui.buttonwidget(parent=c,position=(h+cSpacing+20,v-12),size=(40,40),label="+", - autoselect=True,on_activate_call=babase.Call(self._glowScaleIncrement),repeat=True,enable_sound=True,button_type='square') + b2 = bui.buttonwidget(parent=c, position=(h+cSpacing+20, v-12), size=(40, 40), label="+", + autoselect=True, on_activate_call=babase.Call(self._glowScaleIncrement), repeat=True, enable_sound=True, button_type='square') v -= 70 - t = bui.textwidget(parent=c,position=(0,v), - text=getTranslation('time_delay'), - maxwidth=self.midwidth ,size=(self.midwidth ,20),color=(0.8,0.8,0.8,1.0),h_align="center") - v -= 45 - a = bui.buttonwidget(parent=c,position=(h-20,v-12),size=(40,40),label="-", - autoselect=True,on_activate_call=babase.Call(self._timeDelayDecrement),repeat=True,enable_sound=True,button_type='square') + t = bui.textwidget(parent=c, position=(0, v), + text=getTranslation('time_delay'), + maxwidth=self.midwidth, size=(self.midwidth, 20), color=(0.8, 0.8, 0.8, 1.0), h_align="center") + v -= 45 + a = bui.buttonwidget(parent=c, position=(h-20, v-12), size=(40, 40), label="-", + autoselect=True, on_activate_call=babase.Call(self._timeDelayDecrement), repeat=True, enable_sound=True, button_type='square') - self._timeDelayText = bui.textwidget(parent=c,position=(h+20,v),maxwidth=self._scrollWidth*0.9, - size=(cSpacing,20),editable=False,color=(0.3,1.0,0.3,1.0),h_align="center",text=str(self._timeDelay)) + self._timeDelayText = bui.textwidget(parent=c, position=(h+20, v), maxwidth=self._scrollWidth*0.9, + size=(cSpacing, 20), editable=False, color=(0.3, 1.0, 0.3, 1.0), h_align="center", text=str(self._timeDelay)) + + a2 = bui.buttonwidget(parent=c, position=(h+cSpacing+20, v-12), size=(40, 40), label="+", + autoselect=True, on_activate_call=babase.Call(self._timeDelayIncrement), repeat=True, enable_sound=True, button_type='square') - a2 = bui.buttonwidget(parent=c,position=(h+cSpacing+20,v-12),size=(40,40),label="+", - autoselect=True,on_activate_call=babase.Call(self._timeDelayIncrement),repeat=True,enable_sound=True,button_type='square') - v -= 70 reset = bui.buttonwidget(parent=c, autoselect=True, - position=((self._scrollWidth*0.22)-80, v-25), size=(160,50),scale=1.0, text_scale=1.2,textcolor=(1,1,1), - label=getTranslation('reset_values'),on_activate_call=self._resetValues) + position=((self._scrollWidth*0.22)-80, v-25), size=(160, 50), scale=1.0, text_scale=1.2, textcolor=(1, 1, 1), + label=getTranslation('reset_values'), on_activate_call=self._resetValues) self._updateColorTimer() v = v0 h = self._scrollWidth*0.44 - t = bui.textwidget(parent=c,position=(h,v), - text=getTranslation('palette'), - maxwidth=self.midwidth ,size=(self.midwidth ,20), - color=(0.8,0.8,0.8,1.0),h_align="center") + t = bui.textwidget(parent=c, position=(h, v), + text=getTranslation('palette'), + maxwidth=self.midwidth, size=(self.midwidth, 20), + color=(0.8, 0.8, 0.8, 1.0), h_align="center") v -= 30 - t2 = bui.textwidget(parent=c,position=(h,v), - text=getTranslation('tap_color'), scale=0.9, - maxwidth=self.midwidth ,size=(self.midwidth ,20), - color=(0.6,0.6,0.6,1.0),h_align="center") + t2 = bui.textwidget(parent=c, position=(h, v), + text=getTranslation('tap_color'), scale=0.9, + maxwidth=self.midwidth, size=(self.midwidth, 20), + color=(0.6, 0.6, 0.6, 1.0), h_align="center") v -= 20 sp = h+45 - self.updatePalette(v,sp) + self.updatePalette(v, sp) elif tab == 1: subHeight = self._subHeight - self._tabContainer = c = bui.containerwidget(parent=self._scrollwidget,size=(self._subWidth,subHeight), - background=False,selection_loops_to_parent=True) + self._tabContainer = c = bui.containerwidget(parent=self._scrollwidget, size=(self._subWidth, subHeight), + background=False, selection_loops_to_parent=True) v2 = v = v0 = subHeight - bui.textwidget(edit=self._title,text=getTranslation('player_tab')) + bui.textwidget(edit=self._title, text=getTranslation('player_tab')) t = babase.app.classic.spaz_appearances['Spaz'] tex = bui.gettexture(t.icon_texture) tintTex = bui.gettexture(t.icon_mask_texture) gs = getData("glowScale") - tc = (1,1,1) - t2c = (1,1,1) + tc = (1, 1, 1) + t2c = (1, 1, 1) - v2 -= (50+180) - self._previewImage = bui.imagewidget(parent=c,position=(self._subWidth*0.72-100,v2),size=(200,200), - mask_texture=bui.gettexture('characterIconMask'),tint_texture=tintTex, - texture=tex, mesh_transparent=bui.getmesh('image1x1'), - tint_color=(tc[0]*gs,tc[1]*gs,tc[2]*gs),tint2_color=(t2c[0]*gs,t2c[1]*gs,t2c[2]*gs)) + v2 -= (50+180) + self._previewImage = bui.imagewidget(parent=c, position=(self._subWidth*0.72-100, v2), size=(200, 200), + mask_texture=bui.gettexture('characterIconMask'), tint_texture=tintTex, + texture=tex, mesh_transparent=bui.getmesh( + 'image1x1'), + tint_color=(tc[0]*gs, tc[1]*gs, tc[2]*gs), tint2_color=(t2c[0]*gs, t2c[1]*gs, t2c[2]*gs)) self._colorTimer = bui.AppTimer(getData("timeDelay") / 1000, - babase.Call(self._updatePreview),repeat=True) + babase.Call(self._updatePreview), repeat=True) v2 -= 70 def doProfileWindow(): ProfilesWindow() - reset = bui.buttonwidget(parent=c, autoselect=True,on_activate_call=doProfileWindow, - position=(self._subWidth*0.72-100,v2), size=(200,60),scale=1.0, text_scale=1.2,textcolor=(1,1,1), - label=getTranslation('profiles')) + reset = bui.buttonwidget(parent=c, autoselect=True, on_activate_call=doProfileWindow, + position=(self._subWidth*0.72-100, v2), size=(200, 60), scale=1.0, text_scale=1.2, textcolor=(1, 1, 1), + label=getTranslation('profiles')) miniBoxWidth = self.midwidth - 30 miniBoxHeight = 80 v -= 18 - #Color + # Color h = 50 - box1 = bui.containerwidget(parent=c,position=(h,v-miniBoxHeight), - size=(miniBoxWidth,miniBoxHeight),background=True) - vbox1 = miniBoxHeight -25 - t = bui.textwidget(parent=box1,position=(10,vbox1), - text=getTranslation('apply_to_color'), - maxwidth=miniBoxWidth-20,size=(miniBoxWidth,20),color=(0.8,0.8,0.8,1.0),h_align="left") + box1 = bui.containerwidget(parent=c, position=(h, v-miniBoxHeight), + size=(miniBoxWidth, miniBoxHeight), background=True) + vbox1 = miniBoxHeight - 25 + t = bui.textwidget(parent=box1, position=(10, vbox1), + text=getTranslation('apply_to_color'), + maxwidth=miniBoxWidth-20, size=(miniBoxWidth, 20), color=(0.8, 0.8, 0.8, 1.0), h_align="left") vbox1 -= 45 - self.bw = bui.checkboxwidget(parent=box1,position=(10,vbox1), value=getData("colorPlayer"), - on_value_change_call=babase.Call(self._setSetting,'colorPlayer'), maxwidth=self.qwidth, - text=getTranslation('change'),autoselect=True,size=(self.qwidth,25)) - #vbox1 -= 35 - self.bw = bui.checkboxwidget(parent=box1,position=(25+self.qwidth,vbox1), value=getData("glowColor"), - on_value_change_call=babase.Call(self._setSetting,'glowColor'), maxwidth=self.qwidth, - text=getTranslation('glow'),autoselect=True,size=(self.qwidth,25)) + self.bw = bui.checkboxwidget(parent=box1, position=(10, vbox1), value=getData("colorPlayer"), + on_value_change_call=babase.Call(self._setSetting, 'colorPlayer'), maxwidth=self.qwidth, + text=getTranslation('change'), autoselect=True, size=(self.qwidth, 25)) + # vbox1 -= 35 + self.bw = bui.checkboxwidget(parent=box1, position=(25+self.qwidth, vbox1), value=getData("glowColor"), + on_value_change_call=babase.Call(self._setSetting, 'glowColor'), maxwidth=self.qwidth, + text=getTranslation('glow'), autoselect=True, size=(self.qwidth, 25)) v -= (miniBoxHeight+20) - #Highlight - box1 = bui.containerwidget(parent=c,position=(h,v-miniBoxHeight), - size=(miniBoxWidth,miniBoxHeight),background=True) - vbox1 = miniBoxHeight -20 - t = bui.textwidget(parent=box1,position=(10,vbox1), - text=getTranslation('apply_to_highlight'), - maxwidth=miniBoxWidth-20,size=(miniBoxWidth,20),color=(0.8,0.8,0.8,1.0),h_align="left") + # Highlight + box1 = bui.containerwidget(parent=c, position=(h, v-miniBoxHeight), + size=(miniBoxWidth, miniBoxHeight), background=True) + vbox1 = miniBoxHeight - 20 + t = bui.textwidget(parent=box1, position=(10, vbox1), + text=getTranslation('apply_to_highlight'), + maxwidth=miniBoxWidth-20, size=(miniBoxWidth, 20), color=(0.8, 0.8, 0.8, 1.0), h_align="left") vbox1 -= 45 - self.bw = bui.checkboxwidget(parent=box1,position=(10,vbox1), value=getData("higlightPlayer"), - on_value_change_call=babase.Call(self._setSetting,'higlightPlayer'), maxwidth=self.qwidth, - text=getTranslation('change'),autoselect=True,size=(self.qwidth,25)) - #vbox1 -= 35 - self.bw = bui.checkboxwidget(parent=box1,position=(25+self.qwidth,vbox1), value=getData("glowHighlight"), - on_value_change_call=babase.Call(self._setSetting,'glowHighlight'), maxwidth=self.qwidth, - text=getTranslation('glow'),autoselect=True,size=(self.qwidth,25)) + self.bw = bui.checkboxwidget(parent=box1, position=(10, vbox1), value=getData("higlightPlayer"), + on_value_change_call=babase.Call(self._setSetting, 'higlightPlayer'), maxwidth=self.qwidth, + text=getTranslation('change'), autoselect=True, size=(self.qwidth, 25)) + # vbox1 -= 35 + self.bw = bui.checkboxwidget(parent=box1, position=(25+self.qwidth, vbox1), value=getData("glowHighlight"), + on_value_change_call=babase.Call(self._setSetting, 'glowHighlight'), maxwidth=self.qwidth, + text=getTranslation('glow'), autoselect=True, size=(self.qwidth, 25)) v -= (miniBoxHeight+20) - #Name - box1 = bui.containerwidget(parent=c,position=(h,v-miniBoxHeight), - size=(miniBoxWidth,miniBoxHeight),background=True) - vbox1 = miniBoxHeight -20 - t = bui.textwidget(parent=box1,position=(10,vbox1), - text=getTranslation('apply_to_name'), - maxwidth=miniBoxWidth-20,size=(miniBoxWidth,20),color=(0.8,0.8,0.8,1.0),h_align="left") + # Name + box1 = bui.containerwidget(parent=c, position=(h, v-miniBoxHeight), + size=(miniBoxWidth, miniBoxHeight), background=True) + vbox1 = miniBoxHeight - 20 + t = bui.textwidget(parent=box1, position=(10, vbox1), + text=getTranslation('apply_to_name'), + maxwidth=miniBoxWidth-20, size=(miniBoxWidth, 20), color=(0.8, 0.8, 0.8, 1.0), h_align="left") vbox1 -= 40 - self.bw = bui.checkboxwidget(parent=box1,position=(10,vbox1), value=getData("namePlayer"), - on_value_change_call=babase.Call(self._setSetting,'namePlayer'), maxwidth=self.qwidth, - text=getTranslation('change'),autoselect=True,size=(self.qwidth,25)) - #vbox1 -= 35 - self.bw = bui.checkboxwidget(parent=box1,position=(25+self.qwidth,vbox1), value=getData("glowName"), - on_value_change_call=babase.Call(self._setSetting,'glowName'), maxwidth=self.qwidth, - text=getTranslation('glow'),autoselect=True,size=(self.qwidth,25)) + self.bw = bui.checkboxwidget(parent=box1, position=(10, vbox1), value=getData("namePlayer"), + on_value_change_call=babase.Call(self._setSetting, 'namePlayer'), maxwidth=self.qwidth, + text=getTranslation('change'), autoselect=True, size=(self.qwidth, 25)) + # vbox1 -= 35 + self.bw = bui.checkboxwidget(parent=box1, position=(25+self.qwidth, vbox1), value=getData("glowName"), + on_value_change_call=babase.Call(self._setSetting, 'glowName'), maxwidth=self.qwidth, + text=getTranslation('glow'), autoselect=True, size=(self.qwidth, 25)) v -= (miniBoxHeight+50) elif tab == 2: subHeight = 0 - self._tabContainer = c = bui.containerwidget(parent=self._scrollwidget,size=(self._subWidth,subHeight), - background=False,selection_loops_to_parent=True) + self._tabContainer = c = bui.containerwidget(parent=self._scrollwidget, size=(self._subWidth, subHeight), + background=False, selection_loops_to_parent=True) v0 = subHeight - 50 v = v0 h = 30 - bui.textwidget(edit=self._title,text=getTranslation('extras_tab')) - self.bw = bui.checkboxwidget(parent=c,position=(h,v), value=getData("shieldColor"), - on_value_change_call=babase.Call(self._setSetting,'shieldColor'), maxwidth=self.midwidth, - text=getTranslation('apply_to_shields'),autoselect=True,size=(self.midwidth,30)) + bui.textwidget(edit=self._title, text=getTranslation('extras_tab')) + self.bw = bui.checkboxwidget(parent=c, position=(h, v), value=getData("shieldColor"), + on_value_change_call=babase.Call(self._setSetting, 'shieldColor'), maxwidth=self.midwidth, + text=getTranslation('apply_to_shields'), autoselect=True, size=(self.midwidth, 30)) v -= 50 - self.bw = bui.checkboxwidget(parent=c,position=(h,v), value=getData("flag"), - on_value_change_call=babase.Call(self._setSetting,'flag'), maxwidth=self.midwidth, - text=getTranslation('apply_to_flags'),autoselect=True,size=(self.midwidth,30)) + self.bw = bui.checkboxwidget(parent=c, position=(h, v), value=getData("flag"), + on_value_change_call=babase.Call(self._setSetting, 'flag'), maxwidth=self.midwidth, + text=getTranslation('apply_to_flags'), autoselect=True, size=(self.midwidth, 30)) v = v0 h = self.midwidth - self.bw = bui.checkboxwidget(parent=c,position=(h,v), value=getData("xplotionColor"), - on_value_change_call=babase.Call(self._setSetting,'xplotionColor'), maxwidth=self.midwidth, - text=getTranslation('apply_to_explotions'),autoselect=True,size=(self.midwidth,30)) + self.bw = bui.checkboxwidget(parent=c, position=(h, v), value=getData("xplotionColor"), + on_value_change_call=babase.Call(self._setSetting, 'xplotionColor'), maxwidth=self.midwidth, + text=getTranslation('apply_to_explotions'), autoselect=True, size=(self.midwidth, 30)) v -= 50 - self.bw = bui.checkboxwidget(parent=c,position=(h,v), value=getData("delScorch"), - on_value_change_call=babase.Call(self._setSetting,'delScorch'), maxwidth=self.midwidth, - text=getTranslation('clean_explotions'),autoselect=True,size=(self.midwidth,30)) + self.bw = bui.checkboxwidget(parent=c, position=(h, v), value=getData("delScorch"), + on_value_change_call=babase.Call(self._setSetting, 'delScorch'), maxwidth=self.midwidth, + text=getTranslation('clean_explotions'), autoselect=True, size=(self.midwidth, 30)) v -= 35 miniBoxWidth = self.midwidth miniBoxHeight = 80 - #Bots Color - box1 = bui.containerwidget(parent=c,position=((self._scrollWidth*0.45) -(miniBoxWidth/2),v-miniBoxHeight), - size=(miniBoxWidth,miniBoxHeight),background=True) - vbox1 = miniBoxHeight -20 - t = bui.textwidget(parent=box1,position=(10,vbox1), - text=getTranslation('apply_to_bots'), - maxwidth=miniBoxWidth-20,size=(miniBoxWidth,20),color=(0.8,0.8,0.8,1.0),h_align="left") + # Bots Color + box1 = bui.containerwidget(parent=c, position=((self._scrollWidth*0.45) - (miniBoxWidth/2), v-miniBoxHeight), + size=(miniBoxWidth, miniBoxHeight), background=True) + vbox1 = miniBoxHeight - 20 + t = bui.textwidget(parent=box1, position=(10, vbox1), + text=getTranslation('apply_to_bots'), + maxwidth=miniBoxWidth-20, size=(miniBoxWidth, 20), color=(0.8, 0.8, 0.8, 1.0), h_align="left") vbox1 -= 45 - self.bw = bui.checkboxwidget(parent=box1,position=(10,vbox1),value=getData("colorBots"), - on_value_change_call=babase.Call(self._setSetting,'colorBots'), maxwidth=self.qwidth, - text=getTranslation('change'),autoselect=True,size=(self.qwidth,25)) + self.bw = bui.checkboxwidget(parent=box1, position=(10, vbox1), value=getData("colorBots"), + on_value_change_call=babase.Call(self._setSetting, 'colorBots'), maxwidth=self.qwidth, + text=getTranslation('change'), autoselect=True, size=(self.qwidth, 25)) - self.bw = bui.checkboxwidget(parent=box1,position=(30+self.qwidth,vbox1), value=getData("glowBots"), - on_value_change_call=babase.Call(self._setSetting,'glowBots'), maxwidth=self.qwidth, - text=getTranslation('glow'),autoselect=True,size=(self.qwidth,25)) + self.bw = bui.checkboxwidget(parent=box1, position=(30+self.qwidth, vbox1), value=getData("glowBots"), + on_value_change_call=babase.Call(self._setSetting, 'glowBots'), maxwidth=self.qwidth, + text=getTranslation('glow'), autoselect=True, size=(self.qwidth, 25)) v -= 130 - reset = bui.buttonwidget(parent=c, autoselect=True,on_activate_call=self.restoreSettings, - position=((self._scrollWidth*0.45)-150, v-25), size=(300,50),scale=1.0, text_scale=1.2,textcolor=(1,1,1), - label=getTranslation('restore_default_settings')) - - for bttn in self.tabButtons: - bui.buttonwidget(edit=bttn,color = (0.1,0.5,0.1)) - bui.buttonwidget(edit=self.tabButtons[tab],color = (0.1,1,0.1)) + reset = bui.buttonwidget(parent=c, autoselect=True, on_activate_call=self.restoreSettings, + position=((self._scrollWidth*0.45)-150, v-25), size=(300, 50), scale=1.0, text_scale=1.2, textcolor=(1, 1, 1), + label=getTranslation('restore_default_settings')) - def _setSetting(self,setting,m): - babase.app.config["colorsMod"][setting] = False if m==0 else True + for bttn in self.tabButtons: + bui.buttonwidget(edit=bttn, color=(0.1, 0.5, 0.1)) + bui.buttonwidget(edit=self.tabButtons[tab], color=(0.1, 1, 0.1)) + + def _setSetting(self, setting, m): + babase.app.config["colorsMod"][setting] = False if m == 0 else True babase.app.config.apply_and_commit() - + def _timeDelayDecrement(self): - self._timeDelay = max(50,self._timeDelay - 50) - bui.textwidget(edit=self._timeDelayText,text=str(self._timeDelay)) - babase.app.config["colorsMod"]["timeDelay"] = self._timeDelay + self._timeDelay = max(50, self._timeDelay - 50) + bui.textwidget(edit=self._timeDelayText, text=str(self._timeDelay)) + babase.app.config["colorsMod"]["timeDelay"] = self._timeDelay babase.app.config.apply_and_commit() self._updateColorTimer() - + def _timeDelayIncrement(self): self._timeDelay = self._timeDelay + 50 - bui.textwidget(edit=self._timeDelayText,text=str(self._timeDelay)) - babase.app.config["colorsMod"]["timeDelay"] = self._timeDelay - babase.app.config.apply_and_commit() - self._updateColorTimer() - - def _resetValues(self): - babase.app.config["colorsMod"]["glowScale"] = self._glowScale = 1 - babase.app.config["colorsMod"]["timeDelay"] = self._timeDelay = 500 - bui.textwidget(edit=self._glowScaleText,text=str(self._glowScale)) - bui.textwidget(edit=self._timeDelayText,text=str(self._timeDelay)) + bui.textwidget(edit=self._timeDelayText, text=str(self._timeDelay)) + babase.app.config["colorsMod"]["timeDelay"] = self._timeDelay babase.app.config.apply_and_commit() self._updateColorTimer() - def updatePalette(self,h,sp): + def _resetValues(self): + babase.app.config["colorsMod"]["glowScale"] = self._glowScale = 1 + babase.app.config["colorsMod"]["timeDelay"] = self._timeDelay = 500 + bui.textwidget(edit=self._glowScaleText, text=str(self._glowScale)) + bui.textwidget(edit=self._timeDelayText, text=str(self._timeDelay)) + babase.app.config.apply_and_commit() + self._updateColorTimer() + + def updatePalette(self, h, sp): colours = getData("colors") x = sp y = h - 50 cont = 1 - bttnSize = (45,45) + bttnSize = (45, 45) l = len(colours) for i in range(16): if i < l: w = bui.buttonwidget( - parent= self._tabContainer, position=(x,y), size=bttnSize, - autoselect=False, label="",button_type="square",color=colours[i], - on_activate_call=bs.WeakCall(self.removeColor,colours[i])) + parent=self._tabContainer, position=(x, y), size=bttnSize, + autoselect=False, label="", button_type="square", color=colours[i], + on_activate_call=bs.WeakCall(self.removeColor, colours[i])) else: w = bui.buttonwidget( - parent= self._tabContainer, position=(x,y), size=bttnSize,color=(0.5, 0.4, 0.6), - autoselect=False, label="",texture=bui.gettexture('frameInset')) + parent=self._tabContainer, position=( + x, y), size=bttnSize, color=(0.5, 0.4, 0.6), + autoselect=False, label="", texture=bui.gettexture('frameInset')) if i == l: - bui.buttonwidget(edit=w,on_activate_call=bs.WeakCall(self._makePicker,w),label="+") + bui.buttonwidget(edit=w, on_activate_call=bs.WeakCall( + self._makePicker, w), label="+") if cont % 4 == 0: x = sp y -= ((bttnSize[0]) + 10) - else: x += (bttnSize[0]) + 13 + else: + x += (bttnSize[0]) + 13 cont += 1 - def addColor(self,color): - if not self.colorIn(color): + def addColor(self, color): + if not self.colorIn(color): babase.app.config["colorsMod"]["colors"].append(color) babase.app.config.apply_and_commit() self._setTab(0) - else: bs.broadcastmessage(getTranslation('color_already')) + else: + bs.broadcastmessage(getTranslation('color_already')) - def removeColor(self,color): + def removeColor(self, color): if color is not None: if len(getData("colors")) >= 3: if color in getData("colors"): babase.app.config["colorsMod"]["colors"].remove(color) babase.app.config.apply_and_commit() self._setTab(0) - else: print('not found') - else: bs.broadcastmessage("Min. 2 colors", color=(0, 1, 0)) - else: bs.broadcastmessage(getTranslation('nothing_selected')) + else: + print('not found') + else: + bs.broadcastmessage("Min. 2 colors", color=(0, 1, 0)) + else: + bs.broadcastmessage(getTranslation('nothing_selected')) def _makePicker(self, origin): baseScale = 2.05 if babase.UIScale.SMALL else 1.6 if babase.UIScale.MEDIUM else 1.0 initial_color = (0, 0.8, 0) - ColorPicker( parent=self._tabContainer, position=origin.get_screen_space_center(), - offset=(baseScale * (-100), 0),initial_color=initial_color, delegate=self, tag='color') + ColorPicker(parent=self._tabContainer, position=origin.get_screen_space_center(), + offset=(baseScale * (-100), 0), initial_color=initial_color, delegate=self, tag='color') def color_picker_closing(self, picker): - if not self._root_widget.exists(): return + if not self._root_widget.exists(): + return tag = picker.get_tag() def color_picker_selected_color(self, picker, color): self.addColor(color) - def colorIn(self,c): + def colorIn(self, c): sColors = getData("colors") for sC in sColors: - if c[0] == sC[0] and c[1] == sC[1] and c[2] == sC[2]: - return True + if c[0] == sC[0] and c[1] == sC[1] and c[2] == sC[2]: + return True return False - def setColor(self,c): + def setColor(self, c): self._selected = c - bui.buttonwidget(edit=self._moveOut,color = (0.8, 0, 0)) + bui.buttonwidget(edit=self._moveOut, color=(0.8, 0, 0)) def _updateColorTimer(self): - self._colorTimer = bui.AppTimer(getData("timeDelay") / 1000 , self._update, repeat=True) - + self._colorTimer = bui.AppTimer(getData("timeDelay") / 1000, self._update, repeat=True) + def _update(self): - color = (random.random(),random.random(),random.random()) - bui.textwidget(edit=self._timeDelayText,color=color) + color = (random.random(), random.random(), random.random()) + bui.textwidget(edit=self._timeDelayText, color=color) def _updatePreview(self): gs = gs2 = getData("glowScale") - if not getData("glowColor"): gs =1 - if not getData("glowHighlight"): gs2 =1 + if not getData("glowColor"): + gs = 1 + if not getData("glowHighlight"): + gs2 = 1 - c = (1,1,1) + c = (1, 1, 1) if getData("colorPlayer"): c = getRandomColor() - c2 = (1,1,1) + c2 = (1, 1, 1) if getData("higlightPlayer"): c2 = getRandomColor() - bui.imagewidget(edit=self._previewImage,tint_color=(c[0]*gs,c[1]*gs,c[2]*gs)) - bui.imagewidget(edit=self._previewImage,tint2_color=(c2[0]*gs2,c2[1]*gs2,c2[2]*gs2)) - + bui.imagewidget(edit=self._previewImage, tint_color=(c[0]*gs, c[1]*gs, c[2]*gs)) + bui.imagewidget(edit=self._previewImage, tint2_color=(c2[0]*gs2, c2[1]*gs2, c2[2]*gs2)) + def _glowScaleDecrement(self): - self._glowScale = max(1,self._glowScale - 1) - bui.textwidget(edit=self._glowScaleText,text=str(self._glowScale)) - babase.app.config["colorsMod"]["glowScale"] = self._glowScale + self._glowScale = max(1, self._glowScale - 1) + bui.textwidget(edit=self._glowScaleText, text=str(self._glowScale)) + babase.app.config["colorsMod"]["glowScale"] = self._glowScale babase.app.config.apply_and_commit() - + def _glowScaleIncrement(self): - self._glowScale = min(5,self._glowScale + 1) - bui.textwidget(edit=self._glowScaleText,text=str(self._glowScale)) - babase.app.config["colorsMod"]["glowScale"] = self._glowScale + self._glowScale = min(5, self._glowScale + 1) + bui.textwidget(edit=self._glowScaleText, text=str(self._glowScale)) + babase.app.config["colorsMod"]["glowScale"] = self._glowScale babase.app.config.apply_and_commit() def restoreSettings(self): @@ -1005,14 +1050,14 @@ class ColorsMenu(PopupWindow): self._setTab(2) bs.broadcastmessage(getTranslation('settings_restored')) confirm.ConfirmWindow(getTranslation('restore_settings'), - width=400, height=120, action=doIt, ok_text=babase.Lstr(resource='okText')) + width=400, height=120, action=doIt, ok_text=babase.Lstr(resource='okText')) def _back(self): - bui.containerwidget(edit=self._root_widget,transition='out_right') + bui.containerwidget(edit=self._root_widget, transition='out_right') self._colorTimer = None self._colorPreviewTimer = None - #if self._in_game: + # if self._in_game: # babase.app.main_menu_window = (mainmenu.MainMenuWindow(transition='in_left').get_root_widget()) - #else: + # else: # babase.app.main_menu_window = ProfileBrowserWindow(transition='in_left').get_root_widget() - #babase.app.main_menu_window = (mainmenu.MainMenuWindow(transition='in_left').get_root_widget()) \ No newline at end of file + # babase.app.main_menu_window = (mainmenu.MainMenuWindow(transition='in_left').get_root_widget()) From 0d5f03d62b557c1c56d81454ef87c329375e095c Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Fri, 26 Jan 2024 16:14:42 +0300 Subject: [PATCH 18/36] ... --- plugins/utilities/{ba_colors.py => ba_colours.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename plugins/utilities/{ba_colors.py => ba_colours.py} (100%) diff --git a/plugins/utilities/ba_colors.py b/plugins/utilities/ba_colours.py similarity index 100% rename from plugins/utilities/ba_colors.py rename to plugins/utilities/ba_colours.py From d99d0cad72740d86924f0c62ad48b15089d5001e Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Thu, 1 Feb 2024 11:57:50 +0300 Subject: [PATCH 19/36] more --- plugins/minigames.json | 98 +++ plugins/minigames/better_deathmatch.py | 271 ++++++++ plugins/minigames/better_elimination.py | 660 +++++++++++++++++++ plugins/minigames/bot_shower.py | 195 ++++++ plugins/minigames/down_into_the_abyss.py | 789 +++++++++++++++++++++++ plugins/minigames/explodo_run.py | 132 ++++ plugins/minigames/extinction.py | 254 ++++++++ plugins/minigames/fat_pigs.py | 340 ++++++++++ plugins/utilities.json | 16 +- plugins/utilities/xyz_tool.py | 85 +++ 10 files changed, 2839 insertions(+), 1 deletion(-) create mode 100644 plugins/minigames/better_deathmatch.py create mode 100644 plugins/minigames/better_elimination.py create mode 100644 plugins/minigames/bot_shower.py create mode 100644 plugins/minigames/down_into_the_abyss.py create mode 100644 plugins/minigames/explodo_run.py create mode 100644 plugins/minigames/extinction.py create mode 100644 plugins/minigames/fat_pigs.py create mode 100644 plugins/utilities/xyz_tool.py diff --git a/plugins/minigames.json b/plugins/minigames.json index 9513a6d..4cdc9ce 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -1203,6 +1203,104 @@ "versions": { "1.0.0": null } + }, + "down_into_the_abyss": { + "description": "Survive as long as you can but dont miss a step", + "external_url": "", + "authors": [ + { + "name": "", + "email": "", + "discord": "" + } + ], + "versions": { + "1.0.0": null + } + }, + "better_deathmatch": { + "description": "A very-customisable DeathMatch mini-game", + "external_url": "", + "authors": [ + { + "name": "Freaku", + "email": "", + "discord": "freakyyyy" + } + ], + "versions": { + "1.0.0": null + } + }, + "better_elimination": { + "description": "A very-customisable Elimination mini-game", + "external_url": "", + "authors": [ + { + "name": "Freaku", + "email": "", + "discord": "freakyyyy" + } + ], + "versions": { + "1.0.0": null + } + }, + "bot_shower": { + "description": "Survive from the bots.", + "external_url": "", + "authors": [ + { + "name": "", + "email": "", + "discord": "" + } + ], + "versions": { + "1.0.0": null + } + }, + "explodo_run": { + "description": "Run For Your Life :))", + "external_url": "", + "authors": [ + { + "name": "", + "email": "", + "discord": "" + } + ], + "versions": { + "1.0.0": null + } + }, + "extinction_run": { + "description": "Survive the Extinction.", + "external_url": "", + "authors": [ + { + "name": "", + "email": "", + "discord": "" + } + ], + "versions": { + "1.0.0": null + } + }, + "fat_pigs": { + "description": "Survive the Extinction.", + "external_url": "Survive the pigs...", + "authors": [ + { + "name": "Zacker Tz", + "email": "", + "discord": "zacker_tz" + } + ], + "versions": { + "1.0.0": null + } } } } \ No newline at end of file diff --git a/plugins/minigames/better_deathmatch.py b/plugins/minigames/better_deathmatch.py new file mode 100644 index 0000000..34116a5 --- /dev/null +++ b/plugins/minigames/better_deathmatch.py @@ -0,0 +1,271 @@ +# Ported to api 8 by brostos using baport.(https://github.com/bombsquad-community/baport) +#BetterDeathMatch +#Made by your friend: @[Just] Freak#4999 + +"""Defines a very-customisable DeathMatch mini-game""" + +# ba_meta require api 8 + +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 + +if TYPE_CHECKING: + from typing import Any, Type, List, Dict, Tuple, Union, Sequence, Optional + + +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 BetterDeathMatchGame(bs.TeamGameActivity[Player, Team]): + """A game type based on acquiring kills.""" + + name = 'Btrr Death Match' + description = 'Kill a set number of enemies to win.\nbyFREAK' + + # 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('Epic Mode', default=False), + + +## Add settings ## + bs.BoolSetting('Enable Gloves', False), + bs.BoolSetting('Enable Powerups', True), + bs.BoolSetting('Night Mode', False), + bs.BoolSetting('Icy Floor', False), + bs.BoolSetting('One Punch Kill', False), + bs.BoolSetting('Spawn with Shield', False), + bs.BoolSetting('Punching Only', False), +## Add settings ## + ] + + + # In teams mode, a suicide gives a point to the other team, but in + # free-for-all it subtracts from your own score. By default we clamp + # 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, 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]: + 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 = bui.getsound('dingSmall') + + +## Take applied settings ## + self._boxing_gloves = bool(settings['Enable Gloves']) + self._enable_powerups = bool(settings['Enable Powerups']) + self._night_mode = bool(settings['Night Mode']) + self._icy_floor = bool(settings['Icy Floor']) + self._one_punch_kill = bool(settings['One Punch Kill']) + self._shield_ = bool(settings['Spawn with Shield']) + self._only_punch = bool(settings['Punching Only']) +## Take applied settings ## + + + 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) + + def get_instance_description(self) -> Union[str, Sequence]: + return 'Crush ${ARG1} of your enemies. byFREAK', self._score_to_win + + def get_instance_description_short(self) -> Union[str, Sequence]: + return 'kill ${ARG1} enemies. byFREAK', self._score_to_win + + def on_team_join(self, team: Team) -> None: + if self.has_begun(): + self._update_scoreboard() + + +## Run settings related: IcyFloor ## + def on_transition_in(self) -> None: + super().on_transition_in() + activity = bs.getactivity() + if self._icy_floor: + activity.map.is_hockey = True + else: + return +## Run settings related: IcyFloor ## + + + + def on_begin(self) -> None: + super().on_begin() + self.setup_standard_time_limit(self._time_limit) + + +## Run settings related: NightMode,Powerups ## + if self._night_mode: + bs.getactivity().globalsnode.tint = (0.5, 0.7, 1) + else: + pass +#-# Tried return here, pfft. Took me 30mins to figure out why pwps spawning only on NightMode +#-# Now its fixed :) + if self._enable_powerups: + self.setup_standard_powerup_drops() + else: + pass +## Run settings related: NightMode,Powerups ## + + + # 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 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, 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 + + +## Run settings related: Spaz ## + def spawn_player(self, player: Player) -> bs.Actor: + spaz = self.spawn_player_spaz(player) + if self._boxing_gloves: + spaz.equip_boxing_gloves() + if self._one_punch_kill: + spaz._punch_power_scale = 15 + if self._shield_: + spaz.equip_shields() + if self._only_punch: + spaz.connect_controls_to_player(enable_bomb=False, enable_pickup=False) + + return spaz +## Run settings related: Spaz ## + + + 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/better_elimination.py b/plugins/minigames/better_elimination.py new file mode 100644 index 0000000..6ff2910 --- /dev/null +++ b/plugins/minigames/better_elimination.py @@ -0,0 +1,660 @@ +# Ported to api 8 by brostos using baport.(https://github.com/bombsquad-community/baport) +#BetterElimination +#Made by your friend: @[Just] Freak#4999 + +#Huge Thx to Nippy for "Live Team Balance" + + +"""Defines a very-customisable Elimination mini-game""" + +# ba_meta require api 8 + +from __future__ import annotations + +from typing import TYPE_CHECKING + +import babase +import bauiv1 as bui +import bascenev1 as bs +from bascenev1lib.actor.spazfactory import SpazFactory +from bascenev1lib.actor.scoreboard import Scoreboard + +if TYPE_CHECKING: + from typing import (Any, Tuple, Dict, Type, List, Sequence, Optional, + Union) + + +class Icon(bs.Actor): + """Creates in in-game icon on screen.""" + + def __init__(self, + player: Player, + position: Tuple[float, float], + scale: float, + show_lives: bool = True, + show_death: bool = True, + name_scale: float = 1.0, + name_maxwidth: float = 115.0, + flatness: float = 1.0, + shadow: float = 1.0): + super().__init__() + + self._player = player + self._show_lives = show_lives + self._show_death = show_death + self._name_scale = name_scale + self._outline_tex = bs.gettexture('characterIconMask') + + icon = player.get_icon() + self.node = bs.newnode('image', + delegate=self, + attrs={ + 'texture': icon['texture'], + 'tint_texture': icon['tint_texture'], + 'tint_color': icon['tint_color'], + 'vr_depth': 400, + 'tint2_color': icon['tint2_color'], + 'mask_texture': self._outline_tex, + 'opacity': 1.0, + 'absolute_scale': True, + 'attach': 'bottomCenter' + }) + self._name_text = bs.newnode( + 'text', + owner=self.node, + attrs={ + 'text': babase.Lstr(value=player.getname()), + 'color': babase.safecolor(player.team.color), + 'h_align': 'center', + 'v_align': 'center', + 'vr_depth': 410, + 'maxwidth': name_maxwidth, + 'shadow': shadow, + 'flatness': flatness, + 'h_attach': 'center', + 'v_attach': 'bottom' + }) + if self._show_lives: + self._lives_text = bs.newnode('text', + owner=self.node, + attrs={ + 'text': 'x0', + 'color': (1, 1, 0.5), + 'h_align': 'left', + 'vr_depth': 430, + 'shadow': 1.0, + 'flatness': 1.0, + 'h_attach': 'center', + 'v_attach': 'bottom' + }) + self.set_position_and_scale(position, scale) + + def set_position_and_scale(self, position: Tuple[float, float], + scale: float) -> None: + """(Re)position the icon.""" + assert self.node + self.node.position = position + self.node.scale = [70.0 * scale] + self._name_text.position = (position[0], position[1] + scale * 52.0) + self._name_text.scale = 1.0 * scale * self._name_scale + if self._show_lives: + self._lives_text.position = (position[0] + scale * 10.0, + position[1] - scale * 43.0) + self._lives_text.scale = 1.0 * scale + + def update_for_lives(self) -> None: + """Update for the target player's current lives.""" + if self._player: + lives = self._player.lives + else: + lives = 0 + if self._show_lives: + if lives > 0: + self._lives_text.text = 'x' + str(lives - 1) + else: + self._lives_text.text = '' + if lives == 0: + self._name_text.opacity = 0.2 + assert self.node + self.node.color = (0.7, 0.3, 0.3) + self.node.opacity = 0.2 + + def handle_player_spawned(self) -> None: + """Our player spawned; hooray!""" + if not self.node: + return + self.node.opacity = 1.0 + self.update_for_lives() + + def handle_player_died(self) -> None: + """Well poo; our player died.""" + if not self.node: + return + if self._show_death: + bs.animate( + self.node, 'opacity', { + 0.00: 1.0, + 0.05: 0.0, + 0.10: 1.0, + 0.15: 0.0, + 0.20: 1.0, + 0.25: 0.0, + 0.30: 1.0, + 0.35: 0.0, + 0.40: 1.0, + 0.45: 0.0, + 0.50: 1.0, + 0.55: 0.2 + }) + lives = self._player.lives + if lives == 0: + bs.timer(0.6, self.update_for_lives) + + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, bs.DieMessage): + self.node.delete() + return None + return super().handlemessage(msg) + + +class Player(bs.Player['Team']): + """Our player type for this game.""" + + def __init__(self) -> None: + self.lives = 0 + self.icons: List[Icon] = [] + + +class Team(bs.Team[Player]): + """Our team type for this game.""" + + def __init__(self) -> None: + self.survival_seconds: Optional[int] = None + self.spawn_order: List[Player] = [] + + +# ba_meta export bascenev1.GameActivity +class BetterEliminationGame(bs.TeamGameActivity[Player, Team]): + """Game type where last player(s) left alive win.""" + + name = 'Bttr Elimination' + description = 'Last remaining alive wins.\nbyFREAK' + 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 + + @classmethod + def get_available_settings( + cls, sessiontype: Type[bs.Session]) -> List[babase.Setting]: + settings = [ + bs.IntSetting( + 'Life\'s Per Player', + default=1, + min_value=1, + max_value=10, + increment=1, + ), + bs.IntChoiceSetting( + 'Time Limit', + choices=[ + ('None', 0), + ('1 Minute', 60), + ('2 Minutes', 120), + ('5 Minutes', 300), + ('10 Minutes', 600), + ('20 Minutes', 1200), + ], + default=0, + ), + bs.FloatChoiceSetting( + 'Respawn Times', + choices=[ + ('Shorter', 0.25), + ('Short', 0.5), + ('Normal', 1.0), + ('Long', 2.0), + ('Longer', 4.0), + ], + default=1.0, + ), + bs.BoolSetting('Epic Mode', default=False), + + +## Add settings ## + bs.BoolSetting('Live Team Balance (by Nippy#2677)', True), + bs.BoolSetting('Enable Gloves', False), + bs.BoolSetting('Enable Powerups', True), + bs.BoolSetting('Night Mode', False), + bs.BoolSetting('Icy Floor', False), + bs.BoolSetting('One Punch Kill', False), + bs.BoolSetting('Spawn with Shield', False), + bs.BoolSetting('Punching Only', False), +## Add settings ## + ] + if issubclass(sessiontype, bs.DualTeamSession): + settings.append(bs.BoolSetting('Solo Mode', default=False)) + settings.append( + bs.BoolSetting('Balance Total Life\'s (on spawn only)', 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]: + return bs.app.classic.getmaps('melee') + + def __init__(self, settings: dict): + super().__init__(settings) + self._scoreboard = Scoreboard() + self._start_time: Optional[float] = None + self._vs_text: Optional[bs.Actor] = None + self._round_end_timer: Optional[bs.Timer] = None + +## Take applied settings ## + self._live_team_balance = bool(settings['Live Team Balance (by Nippy#2677)']) + self._boxing_gloves = bool(settings['Enable Gloves']) + self._enable_powerups = bool(settings['Enable Powerups']) + self._night_mode = bool(settings['Night Mode']) + self._icy_floor = bool(settings['Icy Floor']) + self._one_punch_kill = bool(settings['One Punch Kill']) + self._shield_ = bool(settings['Spawn with Shield']) + self._only_punch = bool(settings['Punching Only']) +## Take applied settings ## + + self._epic_mode = bool(settings['Epic Mode']) + self._lives_per_player = int(settings['Life\'s Per Player']) + self._time_limit = float(settings['Time Limit']) + self._balance_total_lives = bool( + settings.get('Balance Total Life\'s (on spawn only)', False)) + 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) -> Union[str, Sequence]: + return 'Last team standing wins. byFREAK' if isinstance( + self.session, bs.DualTeamSession) else 'Last one standing wins.' + + def get_instance_description_short(self) -> Union[str, Sequence]: + return 'last team standing wins. byFREAK' if isinstance( + self.session, bs.DualTeamSession) else 'last one standing wins' + + def on_player_join(self, player: Player) -> None: + + # No longer allowing mid-game joiners here; too easy to exploit. + if self.has_begun(): + + # Make sure their team has survival seconds set if they're all dead + # (otherwise blocked new ffa players are considered 'still alive' + # in score tallying). + if (self._get_total_team_lives(player.team) == 0 + and player.team.survival_seconds is None): + player.team.survival_seconds = 0 + bui.screenmessage( + babase.Lstr(resource='playerDelayedJoinText', + subs=[('${PLAYER}', player.getname(full=True))]), + color=(0, 1, 0), + ) + return + + player.lives = self._lives_per_player + + if self._solo_mode: + player.team.spawn_order.append(player) + self._update_solo_mode() + else: + # Create our icon and spawn. + player.icons = [Icon(player, position=(0, 50), scale=0.8)] + if player.lives > 0: + self.spawn_player(player) + + # Don't waste time doing this until begin. + if self.has_begun(): + self._update_icons() + + +## Run settings related: IcyFloor ## + def on_transition_in(self) -> None: + super().on_transition_in() + activity = bs.getactivity() + if self._icy_floor: + activity.map.is_hockey = True + else: + return +## Run settings related: IcyFloor ## + + + + def on_begin(self) -> None: + super().on_begin() + self._start_time = bs.time() + self.setup_standard_time_limit(self._time_limit) + + +## Run settings related: NightMode,Powerups ## + if self._night_mode: + bs.getactivity().globalsnode.tint = (0.5, 0.7, 1) + else: + pass +#-# Tried return here, pfft. Took me 30mins to figure out why pwps spawning only on NightMode +#-# Now its fixed :) + if self._enable_powerups: + self.setup_standard_powerup_drops() + else: + pass +## Run settings related: NightMode,Powerups ## + + + if self._solo_mode: + 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') + })) + + # If balance-team-lives is on, add lives to the smaller team until + # total lives match. + if (isinstance(self.session, bs.DualTeamSession) + and self._balance_total_lives and self.teams[0].players + and self.teams[1].players): + if self._get_total_team_lives( + self.teams[0]) < self._get_total_team_lives(self.teams[1]): + lesser_team = self.teams[0] + greater_team = self.teams[1] + else: + lesser_team = self.teams[1] + greater_team = self.teams[0] + add_index = 0 + while (self._get_total_team_lives(lesser_team) < + self._get_total_team_lives(greater_team)): + lesser_team.players[add_index].lives += 1 + add_index = (add_index + 1) % len(lesser_team.players) + + self._update_icons() + + # We could check game-over conditions at explicit trigger points, + # but lets just do the simple thing and poll it. + bs.timer(1.0, self._update, repeat=True) + + def _update_solo_mode(self) -> None: + # For both teams, find the first player on the spawn order list with + # lives remaining and spawn them if they're not alive. + for team in self.teams: + # Prune dead players from the spawn order. + team.spawn_order = [p for p in team.spawn_order if p] + for player in team.spawn_order: + assert isinstance(player, Player) + if player.lives > 0: + if not player.is_alive(): + self.spawn_player(player) + break + + 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: + player = team.players[0] + 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: + for icon in player.icons: + icon.set_position_and_scale((xval, 30), 0.7) + icon.update_for_lives() + xval += x_offs + + def _get_spawn_point(self, player: Player) -> Optional[babase.Vec3]: + del player # Unused. + + # In solo-mode, if there's an existing live player on the map, spawn at + # whichever spot is farthest from them (keeps the action spread out). + if self._solo_mode: + living_player = None + living_player_pos = None + for team in self.teams: + for tplayer in team.players: + if tplayer.is_alive(): + assert tplayer.node + ppos = tplayer.node.position + living_player = tplayer + living_player_pos = ppos + break + if living_player: + assert living_player_pos is not None + player_pos = babase.Vec3(living_player_pos) + points: List[Tuple[float, babase.Vec3]] = [] + for team in self.teams: + start_pos = babase.Vec3(self.map.get_start_position(team.id)) + points.append( + ((start_pos - player_pos).length(), start_pos)) + # Hmm.. we need to sorting vectors too? + points.sort(key=lambda x: x[0]) + return points[-1][1] + return None + + def spawn_player(self, player: Player) -> bs.Actor: + actor = self.spawn_player_spaz(player, self._get_spawn_point(player)) + if not self._solo_mode: + bs.timer(0.3, babase.Call(self._print_lives, player)) + + # If we have any icons, update their state. + for icon in player.icons: + icon.handle_player_spawned() + +## Run settings related: Spaz ## + if self._boxing_gloves: + actor.equip_boxing_gloves() + if self._one_punch_kill: + actor._punch_power_scale = 15 + if self._shield_: + actor.equip_shields() + if self._only_punch: + actor.connect_controls_to_player(enable_bomb=False, enable_pickup=False) + + return actor +## Run settings related: Spaz ## + + + def _print_lives(self, player: Player) -> None: + from bascenev1lib.actor import popuptext + + # We get called in a timer so it's possible our player has left/etc. + if not player or not player.is_alive() or not player.node: + return + + popuptext.PopupText('x' + str(player.lives - 1), + color=(1, 1, 0, 1), + offset=(0, -0.8, 0), + random_offset=0.0, + scale=1.8, + position=player.node.position).autoretain() + + def on_player_leave(self, player: Player) -> None: + ########################################################Nippy#2677 + team_count=1 #Just initiating + if player.lives>0 and self._live_team_balance: + team_mem=[] + for teamer in player.team.players: + if player!=teamer: + team_mem.append(teamer) #Got Dead players Team + live=player.lives + team_count=len(team_mem) + for i in range(int((live if live%2==0 else live+1)/2)): #Extending Player List for Sorted Players + team_mem.extend(team_mem) + if team_count>0: + for i in range(live): + team_mem[i].lives+=1 + + if team_count<=0 : #Draw if Player Leaves + self.end_game() + ########################################################Nippy#2677 + super().on_player_leave(player) + player.icons = [] + + # Remove us from spawn-order. + if self._solo_mode: + if player in player.team.spawn_order: + player.team.spawn_order.remove(player) + + # Update icons in a moment since our team will be gone from the + # list then. + bs.timer(0, self._update_icons) + + # If the player to leave was the last in spawn order and had + # their final turn currently in-progress, mark the survival time + # for their team. + if self._get_total_team_lives(player.team) == 0: + assert self._start_time is not None + player.team.survival_seconds = int(bs.time() - self._start_time) + + def _get_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: + babase.print_error( + "Got lives < 0 in Elim; this shouldn't happen. solo:" + + str(self._solo_mode)) + 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 self._solo_mode or player.lives == 0: + SpazFactory.get().single_player_death_sound.play() + + # If we hit zero lives, we're dead (and our team might be too). + if player.lives == 0: + # If the whole team is now dead, mark their survival time. + if self._get_total_team_lives(player.team) == 0: + assert self._start_time is not None + player.team.survival_seconds = int(bs.time() - + self._start_time) + else: + # Otherwise, in regular mode, respawn. + if not self._solo_mode: + self.respawn_player(player) + + # In solo, put ourself at the back of the spawn order. + if self._solo_mode: + player.team.spawn_order.remove(player) + player.team.spawn_order.append(player) + + def _update(self) -> None: + if self._solo_mode: + # For both teams, find the first player on the spawn order + # list with lives remaining and spawn them if they're not alive. + for team in self.teams: + # Prune dead players from the spawn order. + team.spawn_order = [p for p in team.spawn_order if p] + for player in team.spawn_order: + assert isinstance(player, Player) + if player.lives > 0: + if not player.is_alive(): + self.spawn_player(player) + self._update_icons() + break + + # If we're down to 1 or fewer living teams, start a timer to end + # the game (allows the dust to settle and draws to occur if deaths + # are close enough). + if len(self._get_living_teams()) < 2: + self._round_end_timer = bs.Timer(0.5, self.end_game) + + def _get_living_teams(self) -> List[Team]: + return [ + team for team in self.teams + if len(team.players) > 0 and any(player.lives > 0 + for player in team.players) + ] + + 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/bot_shower.py b/plugins/minigames/bot_shower.py new file mode 100644 index 0000000..ebbd14b --- /dev/null +++ b/plugins/minigames/bot_shower.py @@ -0,0 +1,195 @@ +# Ported to api 8 by brostos using baport.(https://github.com/bombsquad-community/baport) + +# 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.onscreentimer import OnScreenTimer +from bascenev1lib.actor.spazbot import ( + SpazBot, SpazBotSet, + BomberBot, BrawlerBot, BouncyBot, + ChargerBot, StickyBot, TriggerBot, + ExplodeyBot) + +if TYPE_CHECKING: + from typing import Any, List, Type, Optional + + +class Player(bs.Player['Team']): + """Our player type for this game.""" + + def __init__(self) -> None: + super().__init__() + self.death_time: Optional[float] = None + + +class Team(bs.Team[Player]): + """Our team type for this game.""" + + +# ba_meta export bascenev1.GameActivity +class BotShowerGame(bs.TeamGameActivity[Player, Team]): + """A babase.MeteorShowerGame but replaced with bots.""" + + name = 'Bot Shower' + description = 'Survive from the bots.' + available_settings = [ + bs.BoolSetting('Spaz', default=True), + bs.BoolSetting('Zoe', default=True), + bs.BoolSetting('Kronk', default=True), + bs.BoolSetting('Snake Shadow', default=True), + bs.BoolSetting('Mel', default=True), + bs.BoolSetting('Jack Morgan', default=True), + bs.BoolSetting('Easter Bunny', default=True), + bs.BoolSetting('Epic Mode', default=False), + ] + + announce_player_deaths = True + + @classmethod + def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]: + return ['Football Stadium', 'Hockey Stadium'] + + def __init__(self, settings: dict) -> None: + super().__init__(settings) + self._epic_mode = settings['Epic Mode'] + self._last_player_death_time: Optional[float] = None + self._timer: Optional[OnScreenTimer] = None + self._bots: Optional[SpazBotSet] = None + self._bot_type: List[SpazBot] = [] + + if bool(settings['Spaz']) == True: + self._bot_type.append(BomberBot) + else: + if BomberBot in self._bot_type: + self._bot_type.remove(BomberBot) + if bool(settings['Zoe']) == True: + self._bot_type.append(TriggerBot) + else: + if TriggerBot in self._bot_type: + self._bot_type.remove(TriggerBot) + if bool(settings['Kronk']) == True: + self._bot_type.append(BrawlerBot) + else: + if BrawlerBot in self._bot_type: + self._bot_type.remove(BrawlerBot) + if bool(settings['Snake Shadow']) == True: + self._bot_type.append(ChargerBot) + else: + if ChargerBot in self._bot_type: + self._bot_type.remove(ChargerBot) + if bool(settings['Jack Morgan']) == True: + self._bot_type.append(ExplodeyBot) + else: + if ExplodeyBot in self._bot_type: + self._bot_type.remove(ExplodeyBot) + if bool(settings['Easter Bunny']) == True: + self._bot_type.append(BouncyBot) + else: + if BouncyBot in self._bot_type: + self._bot_type.remove(BouncyBot) + + self.slow_motion = self._epic_mode + self.default_music = (bs.MusicType.EPIC + if self._epic_mode else bs.MusicType.SURVIVAL) + + def on_begin(self) -> None: + super().on_begin() + self._bots = SpazBotSet() + self._timer = OnScreenTimer() + self._timer.start() + + if self._epic_mode: + bs.timer(1.0, self._start_spawning_bots) + else: + bs.timer(5.0, self._start_spawning_bots) + + bs.timer(5.0, self._check_end_game) + + def spawn_player(self, player: Player) -> None: + spaz = self.spawn_player_spaz(player) + spaz.connect_controls_to_player( + enable_punch=False, + enable_bomb=False, + enable_pickup=False) + return spaz + + def on_player_join(self, player: Player) -> None: + if self.has_begun(): + bui.screenmessage( + babase.Lstr(resource='playerDelayedJoinText', + subs=[('${PLAYER}', player.getname(full=True))]), + color=(1, 1, 0), + ) + + assert self._timer is not None + player.death_time = self._timer.getstarttime() + return + self.spawn_player(player) + + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, bs.PlayerDiedMessage): + curtime = bs.time() + msg.getplayer(Player).death_time = curtime + + bs.timer(1.0, self._check_end_game) + else: + super().handlemessage(msg) + + def _start_spawning_bots(self) -> None: + bs.timer(1.2, self._spawn_bot, repeat=True) + bs.timer(2.2, self._spawn_bot, repeat=True) + + def _spawn_bot(self) -> None: + assert self._bots is not None + self._bots.spawn_bot(random.choice(self._bot_type), pos=(random.uniform(-11, 11), (9.8 if self.map.getname() == 'Football Stadium' else 5.0), random.uniform(-5, 5))) + + def _check_end_game(self) -> None: + living_team_count = 0 + for team in self.teams: + for player in team.players: + if player.is_alive(): + living_team_count += 1 + break + + if living_team_count <= 1: + self.end_game() + + def end_game(self) -> None: + cur_time = bs.time() + assert self._timer is not None + start_time = self._timer.getstarttime() + + for team in self.teams: + for player in team.players: + survived = False + + if player.death_time is None: + survived = True + player.death_time = cur_time + 1 + + score = int(player.death_time - self._timer.getstarttime()) + if survived: + score += 50 + self.stats.player_scored(player, score, screenmessage=False) + + self._timer.stop(endtime=self._last_player_death_time) + + results = bs.GameResults() + + for team in self.teams: + + longest_life = 0.0 + for player in team.players: + assert player.death_time is not None + longest_life = max(longest_life, + player.death_time - start_time) + + results.set_team_score(team, int(1000.0 * longest_life)) + + self.end(results=results) \ No newline at end of file diff --git a/plugins/minigames/down_into_the_abyss.py b/plugins/minigames/down_into_the_abyss.py new file mode 100644 index 0000000..2ecac4e --- /dev/null +++ b/plugins/minigames/down_into_the_abyss.py @@ -0,0 +1,789 @@ +# Ported to api 8 by brostos using baport.(https://github.com/bombsquad-community/baport) +# 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 _babase +import random +from bascenev1._map import register_map +from bascenev1lib.actor.spaz import PickupMessage +from bascenev1lib.actor.playerspaz import PlayerSpaz +from bascenev1lib.actor.spazfactory import SpazFactory +from bascenev1lib.gameutils import SharedObjects +from bascenev1lib.actor.spazbot import SpazBotSet, ChargerBotPro, TriggerBotPro +from bascenev1lib.actor.bomb import Blast +from bascenev1lib.actor.powerupbox import PowerupBoxFactory +from bascenev1lib.actor.onscreentimer import OnScreenTimer + +if TYPE_CHECKING: + from typing import Any, Sequence + + +lang = bs.app.lang.language + +if lang == 'Spanish': + name = 'Abajo en el Abismo' + description = 'Sobrevive tanto como puedas' + help = 'El mapa es 3D, ¡ten cuidado!' + author = 'Autor: Deva' + github = 'GitHub: spdv123' + blog = 'Blog: superdeva.info' + peaceTime = 'Tiempo de Paz' + npcDensity = 'Densidad de Enemigos' + hint_use_punch = '¡Ahora puedes golpear a los enemigos!' +elif lang == 'Chinese': + name = '无尽深渊' + description = '在无穷尽的坠落中存活更长时间' + help = '' + author = '作者: Deva' + github = 'GitHub: spdv123' + blog = '博客: superdeva.info' + peaceTime = '和平时间' + npcDensity = 'NPC密度' + hint_use_punch = u'现在可以使用拳头痛扁你的敌人了' +else: + name = 'Down Into The Abyss' + description = 'Survive as long as you can' + help = 'The map is 3D, be careful!' + author = 'Author: Deva' + github = 'GitHub: spdv123' + blog = 'Blog: superdeva.info' + peaceTime = 'Peace Time' + npcDensity = 'NPC Density' + hint_use_punch = 'You can punch your enemies now!' + + +class AbyssMap(bs.Map): + from bascenev1lib.mapdata import happy_thoughts as defs + # Add the y-dimension space for players + defs.boxes['map_bounds'] = (-0.8748348681, 9.212941713, -9.729538885) \ + + (0.0, 0.0, 0.0) \ + + (36.09666006, 26.19950145, 20.89541168) + name = 'Abyss Unhappy' + + @classmethod + def get_play_types(cls) -> list[str]: + """Return valid play types for this map.""" + return ['abyss'] + + @classmethod + def get_preview_texture_name(cls) -> str: + return 'alwaysLandPreview' + + @classmethod + def on_preload(cls) -> Any: + data: dict[str, Any] = { + 'mesh': bs.getmesh('alwaysLandLevel'), + 'bottom_mesh': bs.getmesh('alwaysLandLevelBottom'), + 'bgmesh': bs.getmesh('alwaysLandBG'), + 'collision_mesh': bs.getcollisionmesh('alwaysLandLevelCollide'), + 'tex': bs.gettexture('alwaysLandLevelColor'), + 'bgtex': bs.gettexture('alwaysLandBGColor'), + 'vr_fill_mound_mesh': bs.getmesh('alwaysLandVRFillMound'), + 'vr_fill_mound_tex': bs.gettexture('vrFillMound') + } + return data + + @classmethod + def get_music_type(cls) -> bs.MusicType: + return bs.MusicType.FLYING + + def __init__(self) -> None: + super().__init__(vr_overlay_offset=(0, -3.7, 2.5)) + self.background = bs.newnode( + 'terrain', + attrs={ + 'mesh': self.preloaddata['bgmesh'], + 'lighting': False, + 'background': True, + 'color_texture': self.preloaddata['bgtex'] + }) + bs.newnode('terrain', + attrs={ + 'mesh': self.preloaddata['vr_fill_mound_mesh'], + 'lighting': False, + 'vr_only': True, + 'color': (0.2, 0.25, 0.2), + 'background': True, + 'color_texture': self.preloaddata['vr_fill_mound_tex'] + }) + gnode = bs.getactivity().globalsnode + gnode.happy_thoughts_mode = True + gnode.shadow_offset = (0.0, 8.0, 5.0) + gnode.tint = (1.3, 1.23, 1.0) + gnode.ambient_color = (1.3, 1.23, 1.0) + gnode.vignette_outer = (0.64, 0.59, 0.69) + gnode.vignette_inner = (0.95, 0.95, 0.93) + gnode.vr_near_clip = 1.0 + self.is_flying = True + +register_map(AbyssMap) + + +class SpazTouchFoothold: + pass + +class BombToDieMessage: + pass + + +class Foothold(bs.Actor): + + def __init__(self, + position: Sequence[float] = (0.0, 1.0, 0.0), + power: str = 'random', + size: float = 6.0, + breakable: bool = True, + moving: bool = False): + super().__init__() + shared = SharedObjects.get() + powerup = PowerupBoxFactory.get() + + fmesh = bs.getmesh('landMine') + fmeshs = bs.getmesh('powerupSimple') + self.died = False + self.breakable = breakable + self.moving = moving # move right and left + self.lrSig = 1 # left or right signal + self.lrSpeedPlus = random.uniform(1 / 2.0, 1 / 0.7) + self._npcBots = SpazBotSet() + + self.foothold_material = bs.Material() + self.impact_sound = bui.getsound('impactMedium') + + self.foothold_material.add_actions( + conditions=(('they_dont_have_material', shared.player_material), + 'and', + ('they_have_material', shared.object_material), + 'or', + ('they_have_material', shared.footing_material)), + actions=(('modify_node_collision', 'collide', True), + )) + + self.foothold_material.add_actions( + conditions=('they_have_material', shared.player_material), + actions=(('modify_part_collision', 'physical', True), + ('modify_part_collision', 'stiffness', 0.05), + ('message', 'our_node', 'at_connect', SpazTouchFoothold()), + )) + + self.foothold_material.add_actions( + conditions=('they_have_material', self.foothold_material), + actions=('modify_node_collision', 'collide', False), + ) + + tex = { + 'punch': powerup.tex_punch, + 'sticky_bombs': powerup.tex_sticky_bombs, + 'ice_bombs': powerup.tex_ice_bombs, + 'impact_bombs': powerup.tex_impact_bombs, + 'health': powerup.tex_health, + 'curse': powerup.tex_curse, + 'shield': powerup.tex_shield, + 'land_mines': powerup.tex_land_mines, + 'tnt': bs.gettexture('tnt'), + }.get(power, bs.gettexture('tnt')) + + powerupdist = { + powerup.tex_bomb: 3, + powerup.tex_ice_bombs: 2, + powerup.tex_punch: 3, + powerup.tex_impact_bombs: 3, + powerup.tex_land_mines: 3, + powerup.tex_sticky_bombs: 4, + powerup.tex_shield: 4, + powerup.tex_health: 3, + powerup.tex_curse: 1, + bs.gettexture('tnt'): 2 + } + + self.randtex = [] + + for keyTex in powerupdist: + for i in range(powerupdist[keyTex]): + self.randtex.append(keyTex) + + if power == 'random': + random.seed() + tex = random.choice(self.randtex) + + self.tex = tex + self.powerup_type = { + powerup.tex_punch: 'punch', + powerup.tex_bomb: 'triple_bombs', + powerup.tex_ice_bombs: 'ice_bombs', + powerup.tex_impact_bombs: 'impact_bombs', + powerup.tex_land_mines: 'land_mines', + powerup.tex_sticky_bombs: 'sticky_bombs', + powerup.tex_shield: 'shield', + powerup.tex_health: 'health', + powerup.tex_curse: 'curse', + bs.gettexture('tnt'): 'tnt' + }.get(self.tex, '') + + self._spawn_pos = (position[0], position[1], position[2]) + + self.node = bs.newnode( + 'prop', + delegate=self, + attrs={ + 'body': 'landMine', + 'position': self._spawn_pos, + 'mesh': fmesh, + 'light_mesh': fmeshs, + 'shadow_size': 0.5, + 'velocity': (0, 0, 0), + 'density': 90000000000, + 'sticky': False, + 'body_scale': size, + 'mesh_scale': size, + 'color_texture': tex, + 'reflection': 'powerup', + 'is_area_of_interest': True, + 'gravity_scale': 0.0, + 'reflection_scale': [0], + 'materials': [self.foothold_material, + shared.object_material, + shared.footing_material] + }) + self.touchedSpazs = set() + self.keep_vel() + + def keep_vel(self) -> None: + if self.node and not self.died: + speed = bs.getactivity().cur_speed + if self.moving: + if abs(self.node.position[0]) > 10: + self.lrSig *= -1 + self.node.velocity = ( + self.lrSig * speed * self.lrSpeedPlus,speed, 0) + bs.timer(0.1, bs.WeakCall(self.keep_vel)) + else: + self.node.velocity = (0, speed, 0) + # self.node.extraacceleration = (0, self.speed, 0) + bs.timer(0.1, bs.WeakCall(self.keep_vel)) + + def tnt_explode(self) -> None: + pos = self.node.position + Blast(position=pos, + blast_radius=6.0, + blast_type='tnt', + source_player=None).autoretain() + + def spawn_npc(self) -> None: + if not self.breakable: + return + if self._npcBots.have_living_bots(): + return + if random.randint(0, 3) >= bs.getactivity().npc_density: + return + pos = self.node.position + pos = (pos[0], pos[1] + 1, pos[2]) + self._npcBots.spawn_bot( + bot_type=random.choice([ChargerBotPro, TriggerBotPro]), + pos=pos, + spawn_time=10) + + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, bs.DieMessage): + if self.node: + self.node.delete() + self.died = True + elif isinstance(msg, bs.OutOfBoundsMessage): + self.handlemessage(bs.DieMessage()) + elif isinstance(msg, BombToDieMessage): + if self.powerup_type == 'tnt': + self.tnt_explode() + self.handlemessage(bs.DieMessage()) + elif isinstance(msg, bs.HitMessage): + ispunched = (msg.srcnode and msg.srcnode.getnodetype() == 'spaz') + if not ispunched: + if self.breakable: + self.handlemessage(BombToDieMessage()) + elif isinstance(msg, SpazTouchFoothold): + node = bs.getcollision().opposingnode + if node is not None and node: + try: + spaz = node.getdelegate(object) + if not isinstance(spaz, AbyssPlayerSpaz): + return + if spaz in self.touchedSpazs: + return + self.touchedSpazs.add(spaz) + self.spawn_npc() + spaz.fix_2D_position() + if self.powerup_type not in ['', 'tnt']: + node.handlemessage( + bs.PowerupMessage(self.powerup_type)) + except Exception as e: + print(e) + pass + + +class AbyssPlayerSpaz(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', + powerups_expire: bool = True): + super().__init__(player=player, + color=color, + highlight=highlight, + character=character, + powerups_expire=powerups_expire) + self.node.fly = False + self.node.hockey = True + self.hitpoints_max = self.hitpoints = 1500 # more HP to handle drop + bs.timer(bs.getactivity().peace_time, + bs.WeakCall(self.safe_connect_controls_to_player)) + + def safe_connect_controls_to_player(self) -> None: + try: + self.connect_controls_to_player() + except: + pass + + def on_move_up_down(self, value: float) -> None: + """ + Called to set the up/down joystick amount on this spaz; + used for player or AI connections. + value will be between -32768 to 32767 + WARNING: deprecated; use on_move instead. + """ + if not self.node: + return + if self.node.run > 0.1: + self.node.move_up_down = value + else: + self.node.move_up_down = value / 3. + + def on_move_left_right(self, value: float) -> None: + """ + Called to set the left/right joystick amount on this spaz; + used for player or AI connections. + value will be between -32768 to 32767 + WARNING: deprecated; use on_move instead. + """ + if not self.node: + return + if self.node.run > 0.1: + self.node.move_left_right = value + else: + self.node.move_left_right = value / 1.5 + + def fix_2D_position(self) -> None: + self.node.fly = True + bs.timer(0.02, bs.WeakCall(self.disable_fly)) + + def disable_fly(self) -> None: + if self.node: + self.node.fly = False + + def curse(self) -> None: + """ + Give this poor spaz a curse; + he will explode in 5 seconds. + """ + if not self._cursed: + factory = SpazFactory.get() + self._cursed = True + + # Add the curse material. + for attr in ['materials', 'roller_materials']: + materials = getattr(self.node, attr) + if factory.curse_material not in materials: + setattr(self.node, attr, + materials + (factory.curse_material, )) + + # None specifies no time limit + assert self.node + if self.curse_time == -1: + self.node.curse_death_time = -1 + else: + # Note: curse-death-time takes milliseconds. + tval = bs.time() + assert isinstance(tval, (float, int)) + self.node.curse_death_time = bs.time() + 15 + bs.timer(15, bs.WeakCall(self.curse_explode)) + + def handlemessage(self, msg: Any) -> Any: + dontUp = False + + if isinstance(msg, PickupMessage): + dontUp = True + collision = bs.getcollision() + opposingnode = collision.opposingnode + opposingbody = collision.opposingbody + + if opposingnode is None or not opposingnode: + return True + opposingdelegate = opposingnode.getdelegate(object) + # Don't pick up the foothold + if isinstance(opposingdelegate, Foothold): + return True + + # dont allow picking up of invincible dudes + try: + if opposingnode.invincible: + return True + except Exception: + pass + + # if we're grabbing the pelvis of a non-shattered spaz, + # we wanna grab the torso instead + if (opposingnode.getnodetype() == 'spaz' + and not opposingnode.shattered and opposingbody == 4): + opposingbody = 1 + + + # Special case - if we're holding a flag, don't replace it + # (hmm - should make this customizable or more low level). + held = self.node.hold_node + if held and held.getnodetype() == 'flag': + return True + + # Note: hold_body needs to be set before hold_node. + self.node.hold_body = opposingbody + self.node.hold_node = opposingnode + + if not dontUp: + PlayerSpaz.handlemessage(self, msg) + + +class Player(bs.Player['Team']): + """Our player type for this game.""" + + def __init__(self) -> None: + super().__init__() + self.death_time: float | None = None + self.notIn: bool = None + + +class Team(bs.Team[Player]): + """Our team type for this game.""" + + +# ba_meta export bascenev1.GameActivity +class AbyssGame(bs.TeamGameActivity[Player, Team]): + + name = name + description = description + 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[bs.Session]) -> list[str]: + return ['Abyss Unhappy'] + + @classmethod + def get_available_settings( + cls, sessiontype: type[bs.Session]) -> list[babase.Setting]: + settings = [ + bs.FloatChoiceSetting( + peaceTime, + choices=[ + ('None', 0.0), + ('Shorter', 2.5), + ('Short', 5.0), + ('Normal', 10.0), + ('Long', 15.0), + ('Longer', 20.0), + ], + default=10.0, + ), + bs.FloatChoiceSetting( + npcDensity, + choices=[ + ('0%', 0), + ('25%', 1), + ('50%', 2), + ('75%', 3), + ('100%', 4), + ], + default=2, + ), + bs.BoolSetting('Epic Mode', default=False), + ] + return settings + + # We support teams, free-for-all, and co-op sessions. + @classmethod + def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool: + return (issubclass(sessiontype, bs.DualTeamSession) + or issubclass(sessiontype, bs.FreeForAllSession) + or issubclass(sessiontype, bs.CoopSession)) + + def __init__(self, settings: dict): + super().__init__(settings) + self._epic_mode = settings.get('Epic Mode', False) + self._last_player_death_time: float | None = None + self._timer: OnScreenTimer | None = None + self.fix_y = -5.614479365 + self.start_z = 0 + self.init_position = (0, self.start_z, self.fix_y) + self.team_init_positions = [(-5, self.start_z, self.fix_y), + (5, self.start_z, self.fix_y)] + self.cur_speed = 2.5 + # TODO: The variable below should be set in settings + self.peace_time = float(settings[peaceTime]) + self.npc_density = float(settings[npcDensity]) + + # Some base class overrides: + self.default_music = (bs.MusicType.EPIC + if self._epic_mode else bs.MusicType.SURVIVAL) + if self._epic_mode: + self.slow_motion = True + + self._game_credit = bs.NodeActor( + bs.newnode( + 'text', + attrs={ + 'v_attach': 'bottom', + 'h_align': 'center', + 'vr_depth': 0, + 'color': (0.0, 0.7, 1.0), + 'shadow': 1.0 if True else 0.5, + 'flatness': 1.0 if True else 0.5, + 'position': (0, 0), + 'scale': 0.8, + 'text': ' | '.join([author, github, blog]) + })) + + def get_instance_description(self) -> str | Sequence: + return description + + def get_instance_description_short(self) -> str | Sequence: + return self.get_instance_description() + '\n' + help + + def on_player_join(self, player: Player) -> None: + if self.has_begun(): + player.notIn = True + bs.broadcastmessage(babase.Lstr( + resource='playerDelayedJoinText', + subs=[('${PLAYER}', player.getname(full=True))]), + color=(0, 1, 0)) + self.spawn_player(player) + + def on_begin(self) -> None: + super().on_begin() + self._timer = OnScreenTimer() + self._timer.start() + + self.level_cnt = 1 + + if self.teams_or_ffa() == 'teams': + ip0 = self.team_init_positions[0] + ip1 = self.team_init_positions[1] + Foothold( + (ip0[0], ip0[1] - 2, ip0[2]), + power='shield', breakable=False).autoretain() + Foothold( + (ip1[0], ip1[1] - 2, ip1[2]), + power='shield', breakable=False).autoretain() + else: + ip = self.init_position + Foothold( + (ip[0], ip[1] - 2, ip[2]), + power='shield', breakable=False).autoretain() + + bs.timer(int(5.0 / self.cur_speed), + bs.WeakCall(self.add_foothold), repeat=True) + + # Repeat check game end + bs.timer(1.0, self._check_end_game, repeat=True) + bs.timer(self.peace_time + 0.1, + bs.WeakCall(self.tip_hint, hint_use_punch)) + bs.timer(6.0, bs.WeakCall(self.faster_speed), repeat=True) + + def tip_hint(self, text: str) -> None: + bs.broadcastmessage(text, color=(0.2, 0.2, 1)) + + def faster_speed(self) -> None: + self.cur_speed *= 1.15 + + def add_foothold(self) -> None: + ip = self.init_position + ip_1 = (ip[0] - 7, ip[1], ip[2]) + ip_2 = (ip[0] + 7, ip[1], ip[2]) + ru = random.uniform + self.level_cnt += 1 + if self.level_cnt % 3: + Foothold(( + ip_1[0] + ru(-5, 5), + ip[1] - 2, + ip[2] + ru(-0.0, 0.0))).autoretain() + Foothold(( + ip_2[0] + ru(-5, 5), + ip[1] - 2, + ip[2] + ru(-0.0, 0.0))).autoretain() + else: + Foothold(( + ip[0] + ru(-8, 8), + ip[1] - 2, + ip[2]), moving=True).autoretain() + + def teams_or_ffa(self) -> None: + if isinstance(self.session, bs.DualTeamSession): + return 'teams' + return 'ffa' + + def spawn_player_spaz(self, + player: Player, + position: Sequence[float] = (0, 0, 0), + angle: float | None = None) -> PlayerSpaz: + # pylint: disable=too-many-locals + # pylint: disable=cyclic-import + from babase import _math + from bascenev1._gameutils import animate + + position = self.init_position + if self.teams_or_ffa() == 'teams': + position = self.team_init_positions[player.team.id % 2] + angle = None + + 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 = AbyssPlayerSpaz(color=color, + highlight=highlight, + character=player.character, + player=player) + + player.actor = spaz + assert spaz.node + + spaz.node.name = name + spaz.node.name_color = display_color + spaz.connect_controls_to_player(enable_punch=False, + enable_bomb=True, + enable_pickup=False) + + # 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') + animate(light, 'intensity', {0: 0, 0.25: 1, 0.5: 0}) + bs.timer(0.5, light.delete) + return spaz + + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, bs.PlayerDiedMessage): + + # Augment standard behavior. + super().handlemessage(msg) + + curtime = bs.time() + + # Record the player's moment of death. + # assert isinstance(msg.spaz.player + msg.getplayer(Player).death_time = curtime + + # In co-op mode, end the game the instant everyone dies + # (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, bs.CoopSession): + # Teams will still show up if we check now.. check in + # the next cycle. + babase.pushcall(self._check_end_game) + + # Also record this for a final setting of the clock. + self._last_player_death_time = curtime + else: + bs.timer(1.0, self._check_end_game) + + else: + # Default handler: + return super().handlemessage(msg) + return None + + def _check_end_game(self) -> None: + living_team_count = 0 + for team in self.teams: + for player in team.players: + if player.is_alive(): + living_team_count += 1 + break + + # In co-op, we go till everyone is dead.. otherwise we go + # until one team remains. + if isinstance(self.session, bs.CoopSession): + if living_team_count <= 0: + self.end_game() + else: + if living_team_count <= 0: + self.end_game() + + def end_game(self) -> None: + cur_time = bs.time() + assert self._timer is not None + start_time = self._timer.getstarttime() + + # Mark death-time as now for any still-living players + # and award players points for how long they lasted. + # (these per-player scores are only meaningful in team-games) + for team in self.teams: + for player in team.players: + survived = False + if player.notIn: + player.death_time = 0 + + # Throw an extra fudge factor in so teams that + # didn't die come out ahead of teams that did. + if player.death_time is None: + survived = True + player.death_time = cur_time + 1 + + # Award a per-player score depending on how many seconds + # they lasted (per-player scores only affect teams mode; + # everywhere else just looks at the per-team score). + score = int(player.death_time - self._timer.getstarttime()) + if survived: + score += 50 # A bit extra for survivors. + self.stats.player_scored(player, score, screenmessage=False) + + # Stop updating our time text, and set the final time to match + # exactly when our last guy died. + self._timer.stop(endtime=self._last_player_death_time) + + # Ok now calc game results: set a score for each team and then tell + # the game to end. + 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 + # just always deal in teams and have all cases covered. + for team in self.teams: + + # Set the team score to the max time survived by any player on + # that team. + longest_life = 0.0 + for player in team.players: + assert player.death_time is not None + longest_life = max(longest_life, + player.death_time - start_time) + + # Submit the score value in milliseconds. + results.set_team_score(team, int(1000.0 * longest_life)) + + self.end(results=results) diff --git a/plugins/minigames/explodo_run.py b/plugins/minigames/explodo_run.py new file mode 100644 index 0000000..be013c7 --- /dev/null +++ b/plugins/minigames/explodo_run.py @@ -0,0 +1,132 @@ +# Ported to api 8 by brostos using baport.(https://github.com/bombsquad-community/baport) + +# ba_meta require api 8 +# (see https://ballistica.net/wiki/meta-tag-system) + +from __future__ import annotations + +import random +from typing import TYPE_CHECKING + +import babase +import bauiv1 as bui +import bascenev1 as bs +from bascenev1lib.actor.spazbot import SpazBotSet, ExplodeyBot, SpazBotDiedMessage +from bascenev1lib.actor.onscreentimer import OnScreenTimer + +if TYPE_CHECKING: + from typing import Any, Type, Dict, List, Optional + +def ba_get_api_version(): + return 8 + +def ba_get_levels(): + return [bs._level.Level( + 'Explodo Run', + gametype=ExplodoRunGame, + settings={}, + preview_texture_name='rampagePreview'),bs._level.Level( + 'Epic Explodo Run', + gametype=ExplodoRunGame, + settings={'Epic Mode':True}, + preview_texture_name='rampagePreview')] + +class Player(bs.Player['Team']): + """Our player type for this game.""" + + +class Team(bs.Team[Player]): + """Our team type for this game.""" + +# ba_meta export bascenev1.GameActivity +class ExplodoRunGame(bs.TeamGameActivity[Player, Team]): + name = "Explodo Run" + description = "Run For Your Life :))" + available_settings = [bs.BoolSetting('Epic Mode', default=False)] + scoreconfig = bs.ScoreConfig(label='Time', + scoretype=bs.ScoreType.MILLISECONDS, + lower_is_better=False) + default_music = bs.MusicType.TO_THE_DEATH + + def __init__(self, settings:dict): + settings['map'] = "Rampage" + self._epic_mode = settings.get('Epic Mode', False) + if self._epic_mode: + self.slow_motion = True + super().__init__(settings) + self._timer: Optional[OnScreenTimer] = None + self._winsound = bs.getsound('score') + self._won = False + self._bots = SpazBotSet() + self.wave = 1 + + def on_begin(self) -> None: + super().on_begin() + + self._timer = OnScreenTimer() + bs.timer(2.5, self._timer.start) + + #Bots Hehe + bs.timer(2.5,self.street) + + def street(self): + for a in range(self.wave): + p1 = random.choice([-5,-2.5,0,2.5,5]) + p3 = random.choice([-4.5,-4.14,-5,-3]) + time = random.choice([1,1.5,2.5,2]) + self._bots.spawn_bot(ExplodeyBot, pos=(p1,5.5,p3),spawn_time = time) + self.wave += 1 + + def botrespawn(self): + if not self._bots.have_living_bots(): + self.street() + def handlemessage(self, msg: Any) -> Any: + + # A player has died. + if isinstance(msg, bs.PlayerDiedMessage): + super().handlemessage(msg) # Augment standard behavior. + self._won = True + self.end_game() + + # A spaz-bot has died. + elif isinstance(msg, SpazBotDiedMessage): + # Unfortunately the bot-set will always tell us there are living + # bots if we ask here (the currently-dying bot isn't officially + # marked dead yet) ..so lets push a call into the event loop to + # check once this guy has finished dying. + babase.pushcall(self.botrespawn) + + # Let the base class handle anything we don't. + else: + return super().handlemessage(msg) + return None + + # When this is called, we should fill out results and end the game + # *regardless* of whether is has been won. (this may be called due + # to a tournament ending or other external reason). + def end_game(self) -> None: + + # Stop our on-screen timer so players can see what they got. + assert self._timer is not None + self._timer.stop() + + results = bs.GameResults() + + # If we won, set our score to the elapsed time in milliseconds. + # (there should just be 1 team here since this is co-op). + # ..if we didn't win, leave scores as default (None) which means + # we lost. + if self._won: + elapsed_time_ms = int((bs.time() - self._timer.starttime) * 1000.0) + bs.cameraflash() + self._winsound.play() + for team in self.teams: + for player in team.players: + if player.actor: + player.actor.handlemessage(bs.CelebrateMessage()) + results.set_team_score(team, elapsed_time_ms) + + # Ends the activity. + self.end(results) + + \ No newline at end of file diff --git a/plugins/minigames/extinction.py b/plugins/minigames/extinction.py new file mode 100644 index 0000000..39266e5 --- /dev/null +++ b/plugins/minigames/extinction.py @@ -0,0 +1,254 @@ +# Ported to api 8 by brostos using baport.(https://github.com/bombsquad-community/baport) +"""For 1.7.33""" + +# 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.bomb import BombFactory, Blast, ImpactMessage +from bascenev1lib.actor.onscreentimer import OnScreenTimer +from bascenev1lib.gameutils import SharedObjects + +if TYPE_CHECKING: + from typing import Any, Sequence, Optional, Type + + +def ba_get_api_version(): + return 8 + +def ba_get_levels(): + return [babase._level.Level( + 'Extinction', + gametype=NewMeteorShowerGame, + settings={'Epic Mode': False}, + preview_texture_name='footballStadiumPreview'), + babase._level.Level( + 'Epic Extinction', + gametype=NewMeteorShowerGame, + settings={'Epic Mode': True}, + preview_texture_name='footballStadiumPreview')] + +class Meteor(bs.Actor): + """A giant meteor instead of bombs.""" + + def __init__(self, + pos: Sequence[float] = (0.0, 1.0, 0.0), + velocity: Sequence[float] = (0.0, 0.0, 0.0)): + super().__init__() + + shared = SharedObjects.get() + factory = BombFactory.get() + + materials = (shared.object_material, + factory.impact_blast_material) + + self.pos = (pos[0], pos[1], pos[2]) + self.velocity = (velocity[0], velocity[1], velocity[2]) + + self.node = bs.newnode( + 'prop', + delegate=self, + attrs={ + 'position': self.pos, + 'velocity': self.velocity, + 'mesh': factory.sticky_bomb_mesh, + 'color_texture': factory.tnt_tex, + 'mesh_scale': 3.0, + 'body_scale': 2.99, + 'body': 'sphere', + 'shadow_size': 0.5, + 'reflection': 'soft', + 'reflection_scale': [0.45], + 'materials': materials + }) + + def explode(self) -> None: + Blast(position=self.node.position, + velocity=self.node.velocity, + blast_type='tnt', + blast_radius=2.0) + + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, bs.DieMessage): + if self.node: + self.node.delete() + elif isinstance(msg, ImpactMessage): + self.explode() + self.handlemessage(bs.DieMessage()) + else: + super().handlemessage(msg) + + +class Player(bs.Player['Team']): + """Our player type for this game.""" + + def __init__(self): + super().__init__() + self.death_time: Optional[float] = None + +class Team(bs.Team[Player]): + """Our team type for this game.""" + + +# ba_meta export bascenev1.GameActivity +class NewMeteorShowerGame(bs.TeamGameActivity[Player, Team]): + """Minigame by Jetz.""" + + name = 'Extinction' + description = 'Survive the Extinction.' + available_settings = [ + bs.BoolSetting('Epic Mode', default=False)] + + announce_player_deaths = True + + @classmethod + def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]: + return ['Football Stadium'] + + @classmethod + def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool: + return (issubclass(sessiontype, bs.FreeForAllSession) + or issubclass(sessiontype, bs.DualTeamSession)) + + def __init__(self, settings: dict): + super().__init__(settings) + + self._epic_mode = bool(settings['Epic Mode']) + self._last_player_death_time: Optiobal[float] = None + self._meteor_time = 2.0 + self._timer: Optional[OnScreenTimer] = None + + self.default_music = (bs.MusicType.EPIC + if self._epic_mode else bs.MusicType.SURVIVAL) + + if self._epic_mode: + self.slow_motion = True + + def on_begin(self) -> None: + super().on_begin() + + delay = 5.0 if len(self.players) > 2 else 2.5 + if self._epic_mode: + delay *= 0.25 + bs.timer(delay, self._decrement_meteor_time, repeat=True) + + delay = 3.0 + if self._epic_mode: + delay *= 0.25 + bs.timer(delay, self._set_meteor_timer) + + self._timer = OnScreenTimer() + self._timer.start() + self._check_end_game() + + def on_player_join(self, player: Player) -> None: + if self.has_begun(): + bs.broadcastmessage( + babase.Lstr(resource='playerDelayedJoinText', + subs=[('${PLAYER}', player.getname(full=True))]), + color=(0, 1, 0), + ) + assert self._timer is not None + player.death_time = self._timer.getstarttime() + return + self.spawn_player(player) + + def spawn_player(self, player: Player) -> None: + spaz = self.spawn_player_spaz(player) + + spaz.connect_controls_to_player(enable_punch=False, + enable_pickup=False, + enable_bomb=False, + enable_jump=False) + spaz.play_big_death_sound = True + + return spaz + + def on_player_leave(self, player: Player) -> None: + super().on_player_leave(player) + + self._check_end_game() + + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, bs.PlayerDiedMessage): + curtime = bs.time() + + msg.getplayer(Player).death_time = curtime + bs.timer(1.0, self._check_end_game) + else: + return super().handlemessage(msg) + + def _spawn_meteors(self) -> None: + pos = (random.randint(-6, 7), 12, + random.uniform(-2, 1)) + velocity = (random.randint(-11, 11), 0, + random.uniform(-5, 5)) + Meteor(pos=pos, velocity=velocity).autoretain() + + def _spawn_meteors_cluster(self) -> None: + delay = 0.0 + for _i in range(random.randrange(1, 3)): + bs.timer(delay, self._spawn_meteors) + delay += 1 + self._set_meteor_timer() + + def _decrement_meteor_time(self) -> None: + self._meteor_time = max(0.01, self._meteor_time * 0.9) + + def _set_meteor_timer(self) -> None: + bs.timer((1.0 + 0.2 * random.random()) * self._meteor_time, + self._spawn_meteors_cluster) + + def _check_end_game(self) -> None: + living_team_count = 0 + for team in self.teams: + for player in team.players: + if player.is_alive(): + living_team_count += 1 + break + + if isinstance(self.session, bs.CoopSession): + if living_team_count <= 0: + self.end_game() + else: + if living_team_count <= 1: + self.end_game() + + def end_game(self) -> None: + cur_time = bs.time() + assert self._timer is not None + start_time = self._timer.getstarttime() + + for team in self.teams: + for player in team.players: + survived = False + + if player.death_time is None: + survived = True + player.death_time = cur_time + 1 + + score = int(player.death_time - self._timer.getstarttime()) + if survived: + score += 50 + self.stats.player_scored(player, score, screenmessage=False) + + self._timer.stop(endtime=self._last_player_death_time) + + results = bs.GameResults() + + for team in self.teams: + + longest_life = 0.0 + for player in team.players: + assert player.death_time is not None + longest_life = max(longest_life, + player.death_time - start_time) + + results.set_team_score(team, int(1000.0 * longest_life)) + + self.end(results=results) \ No newline at end of file diff --git a/plugins/minigames/fat_pigs.py b/plugins/minigames/fat_pigs.py new file mode 100644 index 0000000..aed1a69 --- /dev/null +++ b/plugins/minigames/fat_pigs.py @@ -0,0 +1,340 @@ +# Ported to api 8 by brostos using baport.(https://github.com/bombsquad-community/baport) +# ba_meta require api 8 + +# - - - - - - - - - - - - - - - - - - - - - +# - Fat-Pigs! by Zacker Tz || Zacker#5505 - +# - Version 0.01 :v - +# - - - - - - - - - - - - - - - - - - - - - + +from __future__ import annotations + +from typing import TYPE_CHECKING + +import random +import babase +import bauiv1 as bui +import bascenev1 as bs +from bascenev1lib.actor.bomb import Bomb +from bascenev1lib.actor.onscreentimer import OnScreenTimer +from bascenev1lib.actor.playerspaz import PlayerSpaz +from bascenev1lib.actor.scoreboard import Scoreboard + +if TYPE_CHECKING: + from typing import Any, Union, Sequence, Optional + +# - - - - - - - Mini - Settings - - - - - - - - - - - - - - - - # + +zkBombs_limit = 3 # Number of bombs you can use | Default = 3 +zkPunch = False # Enable/Disable punchs | Default = False +zkPickup = False # Enable/Disable pickup | Default = False + +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # + +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 FatPigs(bs.TeamGameActivity[Player, Team]): + """A game type based on acquiring kills.""" + + name = 'Fat-Pigs!' + description = 'Survive...' + + # 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=0.25, + ), + bs.BoolSetting('Epic Mode', default=False), + ] + + # In teams mode, a suicide gives a point to the other team, but in + # free-for-all it subtracts from your own score. By default we clamp + # 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, 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]: + return ['Courtyard', 'Rampage', 'Monkey Face', 'Lake Frigid', 'Step Right Up'] + + def __init__(self, settings: dict): + super().__init__(settings) + self._scoreboard = Scoreboard() + self._meteor_time = 2.0 + self._score_to_win: Optional[int] = None + self._dingsound = bs.getsound('dingSmall') + self._epic_mode = bool(settings['Epic Mode']) + # self._text_credit = bool(settings['Credits']) + 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) + + 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_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) + # self.setup_standard_powerup_drops() + #Ambiente + gnode = bs.getactivity().globalsnode + gnode.tint = (0.8, 1.2, 0.8) + gnode.ambient_color = (0.7, 1.0, 0.6) + gnode.vignette_outer = (0.4, 0.6, 0.4) #C + # gnode.vignette_inner = (0.9, 0.9, 0.9) + + + + # 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() + + delay = 5.0 if len(self.players) > 2 else 2.5 + if self._epic_mode: + delay *= 0.25 + bs.timer(delay, self._decrement_meteor_time, repeat=False) + + # Kick off the first wave in a few seconds. + delay = 3.0 + if self._epic_mode: + delay *= 0.25 + bs.timer(delay, self._set_meteor_timer) + + # self._timer = OnScreenTimer() + # self._timer.start() + + # Check for immediate end (if we've only got 1 player, etc). + bs.timer(5.0, self._check_end_game) + + t = bs.newnode('text', + attrs={ 'text':"Minigame by Zacker Tz", + 'scale':0.7, + 'position':(0.001,625), + 'shadow':0.5, + 'opacity':0.7, + 'flatness':1.2, + 'color':(0.6, 1, 0.6), + 'h_align':'center', + 'v_attach':'bottom'}) + + + def spawn_player(self, player: Player) -> bs.Actor: + spaz = self.spawn_player_spaz(player) + + # Let's reconnect this player's controls to this + # spaz but *without* the ability to attack or pick stuff up. + spaz.connect_controls_to_player(enable_punch=zkPunch, + enable_bomb=True, + enable_pickup=zkPickup) + + spaz.bomb_count = zkBombs_limit + spaz._max_bomb_count = zkBombs_limit + spaz.bomb_type_default = 'sticky' + spaz.bomb_type = 'sticky' + + #cerdo gordo + spaz.node.color_mask_texture = bs.gettexture('melColorMask') + spaz.node.color_texture = bs.gettexture('melColor') + spaz.node.head_mesh = bs.getmesh('melHead') + spaz.node.hand_mesh = bs.getmesh('melHand') + spaz.node.torso_mesh = bs.getmesh('melTorso') + spaz.node.pelvis_mesh = bs.getmesh('kronkPelvis') + spaz.node.upper_arm_mesh = bs.getmesh('melUpperArm') + spaz.node.forearm_mesh = bs.getmesh('melForeArm') + spaz.node.upper_leg_mesh = bs.getmesh('melUpperLeg') + spaz.node.lower_leg_mesh = bs.getmesh('melLowerLeg') + spaz.node.toes_mesh = bs.getmesh('melToes') + spaz.node.style = 'mel' + # Sounds cerdo gordo + mel_sounds = [bs.getsound('mel01'), bs.getsound('mel02'),bs.getsound('mel03'),bs.getsound('mel04'),bs.getsound('mel05'), + bs.getsound('mel06'),bs.getsound('mel07'),bs.getsound('mel08'),bs.getsound('mel09'),bs.getsound('mel10')] + spaz.node.jump_sounds = mel_sounds + spaz.node.attack_sounds = mel_sounds + spaz.node.impact_sounds = mel_sounds + spaz.node.pickup_sounds = mel_sounds + spaz.node.death_sounds = [bs.getsound('melDeath01')] + spaz.node.fall_sounds = [bs.getsound('melFall01')] + + def _set_meteor_timer(self) -> None: + bs.timer((1.0 + 0.2 * random.random()) * self._meteor_time, + self._drop_bomb_cluster) + + def _drop_bomb_cluster(self) -> None: + + # Random note: code like this is a handy way to plot out extents + # and debug things. + loc_test = False + if loc_test: + bs.newnode('locator', attrs={'position': (8, 6, -5.5)}) + bs.newnode('locator', attrs={'position': (8, 6, -2.3)}) + bs.newnode('locator', attrs={'position': (-7.3, 6, -5.5)}) + bs.newnode('locator', attrs={'position': (-7.3, 6, -2.3)}) + + # Drop several bombs in series. + 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(), 11, + -5.5 + 2.1 * random.random()) + dropdir = (-1.0 if pos[0] > 0 else 1.0) + vel = ((-5.0 + random.random() * 30.0) * dropdir, -4.0, 0) + bs.timer(delay, babase.Call(self._drop_bomb, pos, vel)) + delay += 0.1 + self._set_meteor_timer() + + def _drop_bomb(self, position: Sequence[float], + velocity: Sequence[float]) -> None: + Bomb(position=position, velocity=velocity,bomb_type='sticky').autoretain() + + def _decrement_meteor_time(self) -> None: + self._meteor_time = max(0.01, self._meteor_time * 0.9) + + + 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, 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 _check_end_game(self) -> None: + living_team_count = 0 + for team in self.teams: + for player in team.players: + if player.is_alive(): + living_team_count += 1 + break + + # In co-op, we go till everyone is dead.. otherwise we go + # until one team remains. + if isinstance(self.session, bs.CoopSession): + if living_team_count <= 0: + self.end_game() + else: + if living_team_count <= 1: + self.end_game() + + 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/utilities.json b/plugins/utilities.json index db809c6..0a5c094 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -1149,7 +1149,7 @@ } }, "ba_colours": { - "description": "Try to survive from bots!", + "description": "Colourful bots and more", "external_url": "", "authors": [ { @@ -1161,6 +1161,20 @@ "versions": { "1.0.0": null } + }, + "xyz_tool": { + "description": "Punch to save the co-ordinates", + "external_url": "", + "authors": [ + { + "name": "", + "email": "", + "discord": "" + } + ], + "versions": { + "1.0.0": null + } } } } \ No newline at end of file diff --git a/plugins/utilities/xyz_tool.py b/plugins/utilities/xyz_tool.py new file mode 100644 index 0000000..2ad1efd --- /dev/null +++ b/plugins/utilities/xyz_tool.py @@ -0,0 +1,85 @@ +# Ported to api 8 by brostos using baport.(https://github.com/bombsquad-community/baport) +# Released under the MIT License. See LICENSE for details. +# ba_meta require api 8 + +from __future__ import annotations +from typing import TYPE_CHECKING +from bascenev1lib.actor.playerspaz import PlayerSpaz +from bascenev1lib.actor.spazfactory import SpazFactory +import babase +import bauiv1 as bui +import bascenev1 as bs +import math +import os +import _babase +import shutil +if TYPE_CHECKING: + pass + +DECIMAL_LIMIT = 7 + + +PlayerSpaz.supershit = PlayerSpaz.__init__ +def ShitInit(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', + powerups_expire: bool = True) -> None: + self.supershit(player, color, highlight, character, powerups_expire) + self.offt = bs.newnode('math', owner=self.node, attrs={'input1': (1.2, 1.8, -0.7),'operation': 'add'}) + self.node.connectattr('torso_position', self.offt, 'input2') + self.txt = bs.newnode('text', owner=self.node, attrs={'text': '3.0','in_world': True,'text':'0','shadow': 1.0,'color': (1,0,0),'flatness': 0.5,'scale': 0.01,'h_align': 'right'}) + p = self.node.position + self.xyz = 0 + self.txt.text = "X: " + str(p[0]) + "\nY: " + str(p[1]) + "\nZ: " + str(p[2]) + self.offt.connectattr('output', self.txt, 'position') + def update(): + p = self.node.position + is_moving = abs(self.node.move_up_down) >= 0.01 or abs(self.node.move_left_right) >= 0.01 + if is_moving: + self.xyz = (p[0],p[1],p[2]) + self.txt.text = "X: " + str(round(self.xyz[0],DECIMAL_LIMIT)) + "\nY: " + str(round(self.xyz[1],DECIMAL_LIMIT)) + "\nZ: " + str(round(self.xyz[2],DECIMAL_LIMIT)) + bs.timer(0.1,update,repeat=True) + +def replaceable_punch(self) -> None: + """ + Called to 'press punch' on this spaz; + used for player or AI connections. + """ + if not self.node or self.frozen or self.node.knockout > 0.0: + return + index = 0 + path_aid = _babase.env()['python_directory_user'] + '/Saved XYZ' + path, dirs, files = next(os.walk(path_aid)) + index += len(files) + c27 = str(index + 1) + with open(path_aid + '/coords' + c27 + '.txt', 'w') as gg: + gg.write("X: " + str(round(self.xyz[0],DECIMAL_LIMIT)) + "\nY: " + str(round(self.xyz[1],DECIMAL_LIMIT)) + "\nZ: " + str(round(self.xyz[2],DECIMAL_LIMIT)) + '\n\n' + '(' + str(round(self.xyz[0],DECIMAL_LIMIT)) + ', ' + str(round(self.xyz[1],DECIMAL_LIMIT)) + ', ' + str(round(self.xyz[2],DECIMAL_LIMIT)) + ')') + bui.screenmessage("Coordinates saved in: " + "BombSquad/Saved XYZ/" + "coords" + c27) + if _babase.app.classic.platform == 'android': + _babase.android_media_scan_file(path_aid) + t_ms = bs.time() * 1000 + assert isinstance(t_ms, int) + if t_ms - self.last_punch_time_ms >= self._punch_cooldown: + if self.punch_callback is not None: + self.punch_callback(self) + self._punched_nodes = set() # Reset this. + self.last_punch_time_ms = t_ms + self.node.punch_pressed = True + if not self.node.hold_node: + bs.timer( + 0.1, + bs.WeakCall(self._safe_play_sound, + SpazFactory.get().swish_sound, 0.8)) + self._turbo_filter_add_press('punch') + +# ba_meta export plugin +class ragingspeedhorn(babase.Plugin): + try: + oath = _babase.env()['python_directory_user'] + '/Saved XYZ' + os.makedirs(oath,exist_ok=False) + except: pass + PlayerSpaz.on_punch_press = replaceable_punch + PlayerSpaz.__init__ = ShitInit + PlayerSpaz.xyz = 0 \ No newline at end of file From e7158a0878c9a184eb8b39b8fbe6c9dbdf6a564d Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Thu, 1 Feb 2024 08:58:54 +0000 Subject: [PATCH 20/36] [ci] auto-format --- plugins/minigames/better_deathmatch.py | 22 +- plugins/minigames/better_elimination.py | 49 +- plugins/minigames/bot_shower.py | 7 +- plugins/minigames/down_into_the_abyss.py | 1291 +++++++++++----------- plugins/minigames/explodo_run.py | 52 +- plugins/minigames/extinction.py | 95 +- plugins/minigames/fat_pigs.py | 65 +- plugins/utilities/xyz_tool.py | 51 +- 8 files changed, 824 insertions(+), 808 deletions(-) diff --git a/plugins/minigames/better_deathmatch.py b/plugins/minigames/better_deathmatch.py index 34116a5..6882c8a 100644 --- a/plugins/minigames/better_deathmatch.py +++ b/plugins/minigames/better_deathmatch.py @@ -1,6 +1,6 @@ # Ported to api 8 by brostos using baport.(https://github.com/bombsquad-community/baport) -#BetterDeathMatch -#Made by your friend: @[Just] Freak#4999 +# BetterDeathMatch +# Made by your friend: @[Just] Freak#4999 """Defines a very-customisable DeathMatch mini-game""" @@ -77,7 +77,7 @@ class BetterDeathMatchGame(bs.TeamGameActivity[Player, Team]): bs.BoolSetting('Epic Mode', default=False), -## Add settings ## + ## Add settings ## bs.BoolSetting('Enable Gloves', False), bs.BoolSetting('Enable Powerups', True), bs.BoolSetting('Night Mode', False), @@ -85,10 +85,9 @@ class BetterDeathMatchGame(bs.TeamGameActivity[Player, Team]): bs.BoolSetting('One Punch Kill', False), bs.BoolSetting('Spawn with Shield', False), bs.BoolSetting('Punching Only', False), -## Add settings ## + ## Add settings ## ] - # In teams mode, a suicide gives a point to the other team, but in # free-for-all it subtracts from your own score. By default we clamp # this at zero to benefit new players, but pro players might like to @@ -126,7 +125,6 @@ class BetterDeathMatchGame(bs.TeamGameActivity[Player, Team]): self._only_punch = bool(settings['Punching Only']) ## Take applied settings ## - self._epic_mode = bool(settings['Epic Mode']) self._kills_to_win_per_player = int( settings['Kills to Win Per Player']) @@ -151,6 +149,8 @@ class BetterDeathMatchGame(bs.TeamGameActivity[Player, Team]): ## Run settings related: IcyFloor ## + + def on_transition_in(self) -> None: super().on_transition_in() activity = bs.getactivity() @@ -160,8 +160,6 @@ class BetterDeathMatchGame(bs.TeamGameActivity[Player, Team]): return ## Run settings related: IcyFloor ## - - def on_begin(self) -> None: super().on_begin() self.setup_standard_time_limit(self._time_limit) @@ -172,15 +170,14 @@ class BetterDeathMatchGame(bs.TeamGameActivity[Player, Team]): bs.getactivity().globalsnode.tint = (0.5, 0.7, 1) else: pass -#-# Tried return here, pfft. Took me 30mins to figure out why pwps spawning only on NightMode -#-# Now its fixed :) +# -# Tried return here, pfft. Took me 30mins to figure out why pwps spawning only on NightMode +# -# Now its fixed :) if self._enable_powerups: self.setup_standard_powerup_drops() else: pass ## Run settings related: NightMode,Powerups ## - # 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))) @@ -244,6 +241,8 @@ class BetterDeathMatchGame(bs.TeamGameActivity[Player, Team]): ## Run settings related: Spaz ## + + def spawn_player(self, player: Player) -> bs.Actor: spaz = self.spawn_player_spaz(player) if self._boxing_gloves: @@ -258,7 +257,6 @@ class BetterDeathMatchGame(bs.TeamGameActivity[Player, Team]): return spaz ## Run settings related: Spaz ## - def _update_scoreboard(self) -> None: for team in self.teams: self._scoreboard.set_team_value(team, team.score, diff --git a/plugins/minigames/better_elimination.py b/plugins/minigames/better_elimination.py index 6ff2910..8edd4c1 100644 --- a/plugins/minigames/better_elimination.py +++ b/plugins/minigames/better_elimination.py @@ -1,8 +1,8 @@ # Ported to api 8 by brostos using baport.(https://github.com/bombsquad-community/baport) -#BetterElimination -#Made by your friend: @[Just] Freak#4999 +# BetterElimination +# Made by your friend: @[Just] Freak#4999 -#Huge Thx to Nippy for "Live Team Balance" +# Huge Thx to Nippy for "Live Team Balance" """Defines a very-customisable Elimination mini-game""" @@ -222,7 +222,7 @@ class BetterEliminationGame(bs.TeamGameActivity[Player, Team]): bs.BoolSetting('Epic Mode', default=False), -## Add settings ## + ## Add settings ## bs.BoolSetting('Live Team Balance (by Nippy#2677)', True), bs.BoolSetting('Enable Gloves', False), bs.BoolSetting('Enable Powerups', True), @@ -231,7 +231,7 @@ class BetterEliminationGame(bs.TeamGameActivity[Player, Team]): bs.BoolSetting('One Punch Kill', False), bs.BoolSetting('Spawn with Shield', False), bs.BoolSetting('Punching Only', False), -## Add settings ## + ## Add settings ## ] if issubclass(sessiontype, bs.DualTeamSession): settings.append(bs.BoolSetting('Solo Mode', default=False)) @@ -299,7 +299,7 @@ class BetterEliminationGame(bs.TeamGameActivity[Player, Team]): player.team.survival_seconds = 0 bui.screenmessage( babase.Lstr(resource='playerDelayedJoinText', - subs=[('${PLAYER}', player.getname(full=True))]), + subs=[('${PLAYER}', player.getname(full=True))]), color=(0, 1, 0), ) return @@ -321,6 +321,8 @@ class BetterEliminationGame(bs.TeamGameActivity[Player, Team]): ## Run settings related: IcyFloor ## + + def on_transition_in(self) -> None: super().on_transition_in() activity = bs.getactivity() @@ -330,8 +332,6 @@ class BetterEliminationGame(bs.TeamGameActivity[Player, Team]): return ## Run settings related: IcyFloor ## - - def on_begin(self) -> None: super().on_begin() self._start_time = bs.time() @@ -343,15 +343,14 @@ class BetterEliminationGame(bs.TeamGameActivity[Player, Team]): bs.getactivity().globalsnode.tint = (0.5, 0.7, 1) else: pass -#-# Tried return here, pfft. Took me 30mins to figure out why pwps spawning only on NightMode -#-# Now its fixed :) +# -# Tried return here, pfft. Took me 30mins to figure out why pwps spawning only on NightMode +# -# Now its fixed :) if self._enable_powerups: self.setup_standard_powerup_drops() else: pass ## Run settings related: NightMode,Powerups ## - if self._solo_mode: self._vs_text = bs.NodeActor( bs.newnode('text', @@ -526,7 +525,6 @@ class BetterEliminationGame(bs.TeamGameActivity[Player, Team]): return actor ## Run settings related: Spaz ## - def _print_lives(self, player: Player) -> None: from bascenev1lib.actor import popuptext @@ -542,24 +540,25 @@ class BetterEliminationGame(bs.TeamGameActivity[Player, Team]): position=player.node.position).autoretain() def on_player_leave(self, player: Player) -> None: - ########################################################Nippy#2677 - team_count=1 #Just initiating - if player.lives>0 and self._live_team_balance: - team_mem=[] + # Nippy#2677 + team_count = 1 # Just initiating + if player.lives > 0 and self._live_team_balance: + team_mem = [] for teamer in player.team.players: - if player!=teamer: - team_mem.append(teamer) #Got Dead players Team - live=player.lives - team_count=len(team_mem) - for i in range(int((live if live%2==0 else live+1)/2)): #Extending Player List for Sorted Players + if player != teamer: + team_mem.append(teamer) # Got Dead players Team + live = player.lives + team_count = len(team_mem) + # Extending Player List for Sorted Players + for i in range(int((live if live % 2 == 0 else live+1)/2)): team_mem.extend(team_mem) - if team_count>0: + if team_count > 0: for i in range(live): - team_mem[i].lives+=1 + team_mem[i].lives += 1 - if team_count<=0 : #Draw if Player Leaves + if team_count <= 0: # Draw if Player Leaves self.end_game() - ########################################################Nippy#2677 + # Nippy#2677 super().on_player_leave(player) player.icons = [] diff --git a/plugins/minigames/bot_shower.py b/plugins/minigames/bot_shower.py index ebbd14b..bbc6da9 100644 --- a/plugins/minigames/bot_shower.py +++ b/plugins/minigames/bot_shower.py @@ -123,7 +123,7 @@ class BotShowerGame(bs.TeamGameActivity[Player, Team]): if self.has_begun(): bui.screenmessage( babase.Lstr(resource='playerDelayedJoinText', - subs=[('${PLAYER}', player.getname(full=True))]), + subs=[('${PLAYER}', player.getname(full=True))]), color=(1, 1, 0), ) @@ -147,7 +147,8 @@ class BotShowerGame(bs.TeamGameActivity[Player, Team]): def _spawn_bot(self) -> None: assert self._bots is not None - self._bots.spawn_bot(random.choice(self._bot_type), pos=(random.uniform(-11, 11), (9.8 if self.map.getname() == 'Football Stadium' else 5.0), random.uniform(-5, 5))) + self._bots.spawn_bot(random.choice(self._bot_type), pos=( + random.uniform(-11, 11), (9.8 if self.map.getname() == 'Football Stadium' else 5.0), random.uniform(-5, 5))) def _check_end_game(self) -> None: living_team_count = 0 @@ -192,4 +193,4 @@ class BotShowerGame(bs.TeamGameActivity[Player, Team]): results.set_team_score(team, int(1000.0 * longest_life)) - self.end(results=results) \ No newline at end of file + self.end(results=results) diff --git a/plugins/minigames/down_into_the_abyss.py b/plugins/minigames/down_into_the_abyss.py index 2ecac4e..ab26ef5 100644 --- a/plugins/minigames/down_into_the_abyss.py +++ b/plugins/minigames/down_into_the_abyss.py @@ -22,768 +22,769 @@ from bascenev1lib.actor.powerupbox import PowerupBoxFactory from bascenev1lib.actor.onscreentimer import OnScreenTimer if TYPE_CHECKING: - from typing import Any, Sequence + from typing import Any, Sequence lang = bs.app.lang.language if lang == 'Spanish': - name = 'Abajo en el Abismo' - description = 'Sobrevive tanto como puedas' - help = 'El mapa es 3D, ¡ten cuidado!' - author = 'Autor: Deva' - github = 'GitHub: spdv123' - blog = 'Blog: superdeva.info' - peaceTime = 'Tiempo de Paz' - npcDensity = 'Densidad de Enemigos' - hint_use_punch = '¡Ahora puedes golpear a los enemigos!' + name = 'Abajo en el Abismo' + description = 'Sobrevive tanto como puedas' + help = 'El mapa es 3D, ¡ten cuidado!' + author = 'Autor: Deva' + github = 'GitHub: spdv123' + blog = 'Blog: superdeva.info' + peaceTime = 'Tiempo de Paz' + npcDensity = 'Densidad de Enemigos' + hint_use_punch = '¡Ahora puedes golpear a los enemigos!' elif lang == 'Chinese': - name = '无尽深渊' - description = '在无穷尽的坠落中存活更长时间' - help = '' - author = '作者: Deva' - github = 'GitHub: spdv123' - blog = '博客: superdeva.info' - peaceTime = '和平时间' - npcDensity = 'NPC密度' - hint_use_punch = u'现在可以使用拳头痛扁你的敌人了' + name = '无尽深渊' + description = '在无穷尽的坠落中存活更长时间' + help = '' + author = '作者: Deva' + github = 'GitHub: spdv123' + blog = '博客: superdeva.info' + peaceTime = '和平时间' + npcDensity = 'NPC密度' + hint_use_punch = u'现在可以使用拳头痛扁你的敌人了' else: - name = 'Down Into The Abyss' - description = 'Survive as long as you can' - help = 'The map is 3D, be careful!' - author = 'Author: Deva' - github = 'GitHub: spdv123' - blog = 'Blog: superdeva.info' - peaceTime = 'Peace Time' - npcDensity = 'NPC Density' - hint_use_punch = 'You can punch your enemies now!' + name = 'Down Into The Abyss' + description = 'Survive as long as you can' + help = 'The map is 3D, be careful!' + author = 'Author: Deva' + github = 'GitHub: spdv123' + blog = 'Blog: superdeva.info' + peaceTime = 'Peace Time' + npcDensity = 'NPC Density' + hint_use_punch = 'You can punch your enemies now!' class AbyssMap(bs.Map): - from bascenev1lib.mapdata import happy_thoughts as defs - # Add the y-dimension space for players - defs.boxes['map_bounds'] = (-0.8748348681, 9.212941713, -9.729538885) \ - + (0.0, 0.0, 0.0) \ - + (36.09666006, 26.19950145, 20.89541168) - name = 'Abyss Unhappy' + from bascenev1lib.mapdata import happy_thoughts as defs + # Add the y-dimension space for players + defs.boxes['map_bounds'] = (-0.8748348681, 9.212941713, -9.729538885) \ + + (0.0, 0.0, 0.0) \ + + (36.09666006, 26.19950145, 20.89541168) + name = 'Abyss Unhappy' - @classmethod - def get_play_types(cls) -> list[str]: - """Return valid play types for this map.""" - return ['abyss'] + @classmethod + def get_play_types(cls) -> list[str]: + """Return valid play types for this map.""" + return ['abyss'] - @classmethod - def get_preview_texture_name(cls) -> str: - return 'alwaysLandPreview' + @classmethod + def get_preview_texture_name(cls) -> str: + return 'alwaysLandPreview' - @classmethod - def on_preload(cls) -> Any: - data: dict[str, Any] = { - 'mesh': bs.getmesh('alwaysLandLevel'), - 'bottom_mesh': bs.getmesh('alwaysLandLevelBottom'), - 'bgmesh': bs.getmesh('alwaysLandBG'), - 'collision_mesh': bs.getcollisionmesh('alwaysLandLevelCollide'), - 'tex': bs.gettexture('alwaysLandLevelColor'), - 'bgtex': bs.gettexture('alwaysLandBGColor'), - 'vr_fill_mound_mesh': bs.getmesh('alwaysLandVRFillMound'), - 'vr_fill_mound_tex': bs.gettexture('vrFillMound') - } - return data + @classmethod + def on_preload(cls) -> Any: + data: dict[str, Any] = { + 'mesh': bs.getmesh('alwaysLandLevel'), + 'bottom_mesh': bs.getmesh('alwaysLandLevelBottom'), + 'bgmesh': bs.getmesh('alwaysLandBG'), + 'collision_mesh': bs.getcollisionmesh('alwaysLandLevelCollide'), + 'tex': bs.gettexture('alwaysLandLevelColor'), + 'bgtex': bs.gettexture('alwaysLandBGColor'), + 'vr_fill_mound_mesh': bs.getmesh('alwaysLandVRFillMound'), + 'vr_fill_mound_tex': bs.gettexture('vrFillMound') + } + return data - @classmethod - def get_music_type(cls) -> bs.MusicType: - return bs.MusicType.FLYING + @classmethod + def get_music_type(cls) -> bs.MusicType: + return bs.MusicType.FLYING + + def __init__(self) -> None: + super().__init__(vr_overlay_offset=(0, -3.7, 2.5)) + self.background = bs.newnode( + 'terrain', + attrs={ + 'mesh': self.preloaddata['bgmesh'], + 'lighting': False, + 'background': True, + 'color_texture': self.preloaddata['bgtex'] + }) + bs.newnode('terrain', + attrs={ + 'mesh': self.preloaddata['vr_fill_mound_mesh'], + 'lighting': False, + 'vr_only': True, + 'color': (0.2, 0.25, 0.2), + 'background': True, + 'color_texture': self.preloaddata['vr_fill_mound_tex'] + }) + gnode = bs.getactivity().globalsnode + gnode.happy_thoughts_mode = True + gnode.shadow_offset = (0.0, 8.0, 5.0) + gnode.tint = (1.3, 1.23, 1.0) + gnode.ambient_color = (1.3, 1.23, 1.0) + gnode.vignette_outer = (0.64, 0.59, 0.69) + gnode.vignette_inner = (0.95, 0.95, 0.93) + gnode.vr_near_clip = 1.0 + self.is_flying = True - def __init__(self) -> None: - super().__init__(vr_overlay_offset=(0, -3.7, 2.5)) - self.background = bs.newnode( - 'terrain', - attrs={ - 'mesh': self.preloaddata['bgmesh'], - 'lighting': False, - 'background': True, - 'color_texture': self.preloaddata['bgtex'] - }) - bs.newnode('terrain', - attrs={ - 'mesh': self.preloaddata['vr_fill_mound_mesh'], - 'lighting': False, - 'vr_only': True, - 'color': (0.2, 0.25, 0.2), - 'background': True, - 'color_texture': self.preloaddata['vr_fill_mound_tex'] - }) - gnode = bs.getactivity().globalsnode - gnode.happy_thoughts_mode = True - gnode.shadow_offset = (0.0, 8.0, 5.0) - gnode.tint = (1.3, 1.23, 1.0) - gnode.ambient_color = (1.3, 1.23, 1.0) - gnode.vignette_outer = (0.64, 0.59, 0.69) - gnode.vignette_inner = (0.95, 0.95, 0.93) - gnode.vr_near_clip = 1.0 - self.is_flying = True register_map(AbyssMap) class SpazTouchFoothold: - pass + pass + class BombToDieMessage: - pass + pass class Foothold(bs.Actor): - def __init__(self, - position: Sequence[float] = (0.0, 1.0, 0.0), - power: str = 'random', - size: float = 6.0, - breakable: bool = True, - moving: bool = False): - super().__init__() - shared = SharedObjects.get() - powerup = PowerupBoxFactory.get() + def __init__(self, + position: Sequence[float] = (0.0, 1.0, 0.0), + power: str = 'random', + size: float = 6.0, + breakable: bool = True, + moving: bool = False): + super().__init__() + shared = SharedObjects.get() + powerup = PowerupBoxFactory.get() - fmesh = bs.getmesh('landMine') - fmeshs = bs.getmesh('powerupSimple') - self.died = False - self.breakable = breakable - self.moving = moving # move right and left - self.lrSig = 1 # left or right signal - self.lrSpeedPlus = random.uniform(1 / 2.0, 1 / 0.7) - self._npcBots = SpazBotSet() + fmesh = bs.getmesh('landMine') + fmeshs = bs.getmesh('powerupSimple') + self.died = False + self.breakable = breakable + self.moving = moving # move right and left + self.lrSig = 1 # left or right signal + self.lrSpeedPlus = random.uniform(1 / 2.0, 1 / 0.7) + self._npcBots = SpazBotSet() - self.foothold_material = bs.Material() - self.impact_sound = bui.getsound('impactMedium') + self.foothold_material = bs.Material() + self.impact_sound = bui.getsound('impactMedium') - self.foothold_material.add_actions( - conditions=(('they_dont_have_material', shared.player_material), - 'and', - ('they_have_material', shared.object_material), - 'or', - ('they_have_material', shared.footing_material)), - actions=(('modify_node_collision', 'collide', True), - )) + self.foothold_material.add_actions( + conditions=(('they_dont_have_material', shared.player_material), + 'and', + ('they_have_material', shared.object_material), + 'or', + ('they_have_material', shared.footing_material)), + actions=(('modify_node_collision', 'collide', True), + )) - self.foothold_material.add_actions( - conditions=('they_have_material', shared.player_material), - actions=(('modify_part_collision', 'physical', True), - ('modify_part_collision', 'stiffness', 0.05), - ('message', 'our_node', 'at_connect', SpazTouchFoothold()), - )) + self.foothold_material.add_actions( + conditions=('they_have_material', shared.player_material), + actions=(('modify_part_collision', 'physical', True), + ('modify_part_collision', 'stiffness', 0.05), + ('message', 'our_node', 'at_connect', SpazTouchFoothold()), + )) - self.foothold_material.add_actions( - conditions=('they_have_material', self.foothold_material), - actions=('modify_node_collision', 'collide', False), - ) + self.foothold_material.add_actions( + conditions=('they_have_material', self.foothold_material), + actions=('modify_node_collision', 'collide', False), + ) - tex = { - 'punch': powerup.tex_punch, - 'sticky_bombs': powerup.tex_sticky_bombs, - 'ice_bombs': powerup.tex_ice_bombs, - 'impact_bombs': powerup.tex_impact_bombs, - 'health': powerup.tex_health, - 'curse': powerup.tex_curse, - 'shield': powerup.tex_shield, - 'land_mines': powerup.tex_land_mines, - 'tnt': bs.gettexture('tnt'), - }.get(power, bs.gettexture('tnt')) + tex = { + 'punch': powerup.tex_punch, + 'sticky_bombs': powerup.tex_sticky_bombs, + 'ice_bombs': powerup.tex_ice_bombs, + 'impact_bombs': powerup.tex_impact_bombs, + 'health': powerup.tex_health, + 'curse': powerup.tex_curse, + 'shield': powerup.tex_shield, + 'land_mines': powerup.tex_land_mines, + 'tnt': bs.gettexture('tnt'), + }.get(power, bs.gettexture('tnt')) - powerupdist = { - powerup.tex_bomb: 3, - powerup.tex_ice_bombs: 2, - powerup.tex_punch: 3, - powerup.tex_impact_bombs: 3, - powerup.tex_land_mines: 3, - powerup.tex_sticky_bombs: 4, - powerup.tex_shield: 4, - powerup.tex_health: 3, - powerup.tex_curse: 1, - bs.gettexture('tnt'): 2 - } + powerupdist = { + powerup.tex_bomb: 3, + powerup.tex_ice_bombs: 2, + powerup.tex_punch: 3, + powerup.tex_impact_bombs: 3, + powerup.tex_land_mines: 3, + powerup.tex_sticky_bombs: 4, + powerup.tex_shield: 4, + powerup.tex_health: 3, + powerup.tex_curse: 1, + bs.gettexture('tnt'): 2 + } - self.randtex = [] + self.randtex = [] - for keyTex in powerupdist: - for i in range(powerupdist[keyTex]): - self.randtex.append(keyTex) + for keyTex in powerupdist: + for i in range(powerupdist[keyTex]): + self.randtex.append(keyTex) - if power == 'random': - random.seed() - tex = random.choice(self.randtex) + if power == 'random': + random.seed() + tex = random.choice(self.randtex) - self.tex = tex - self.powerup_type = { - powerup.tex_punch: 'punch', - powerup.tex_bomb: 'triple_bombs', - powerup.tex_ice_bombs: 'ice_bombs', - powerup.tex_impact_bombs: 'impact_bombs', - powerup.tex_land_mines: 'land_mines', - powerup.tex_sticky_bombs: 'sticky_bombs', - powerup.tex_shield: 'shield', - powerup.tex_health: 'health', - powerup.tex_curse: 'curse', - bs.gettexture('tnt'): 'tnt' - }.get(self.tex, '') + self.tex = tex + self.powerup_type = { + powerup.tex_punch: 'punch', + powerup.tex_bomb: 'triple_bombs', + powerup.tex_ice_bombs: 'ice_bombs', + powerup.tex_impact_bombs: 'impact_bombs', + powerup.tex_land_mines: 'land_mines', + powerup.tex_sticky_bombs: 'sticky_bombs', + powerup.tex_shield: 'shield', + powerup.tex_health: 'health', + powerup.tex_curse: 'curse', + bs.gettexture('tnt'): 'tnt' + }.get(self.tex, '') - self._spawn_pos = (position[0], position[1], position[2]) + self._spawn_pos = (position[0], position[1], position[2]) - self.node = bs.newnode( - 'prop', - delegate=self, - attrs={ - 'body': 'landMine', - 'position': self._spawn_pos, - 'mesh': fmesh, - 'light_mesh': fmeshs, - 'shadow_size': 0.5, - 'velocity': (0, 0, 0), - 'density': 90000000000, - 'sticky': False, - 'body_scale': size, - 'mesh_scale': size, - 'color_texture': tex, - 'reflection': 'powerup', - 'is_area_of_interest': True, - 'gravity_scale': 0.0, - 'reflection_scale': [0], - 'materials': [self.foothold_material, - shared.object_material, - shared.footing_material] - }) - self.touchedSpazs = set() - self.keep_vel() + self.node = bs.newnode( + 'prop', + delegate=self, + attrs={ + 'body': 'landMine', + 'position': self._spawn_pos, + 'mesh': fmesh, + 'light_mesh': fmeshs, + 'shadow_size': 0.5, + 'velocity': (0, 0, 0), + 'density': 90000000000, + 'sticky': False, + 'body_scale': size, + 'mesh_scale': size, + 'color_texture': tex, + 'reflection': 'powerup', + 'is_area_of_interest': True, + 'gravity_scale': 0.0, + 'reflection_scale': [0], + 'materials': [self.foothold_material, + shared.object_material, + shared.footing_material] + }) + self.touchedSpazs = set() + self.keep_vel() - def keep_vel(self) -> None: - if self.node and not self.died: - speed = bs.getactivity().cur_speed - if self.moving: - if abs(self.node.position[0]) > 10: - self.lrSig *= -1 - self.node.velocity = ( - self.lrSig * speed * self.lrSpeedPlus,speed, 0) - bs.timer(0.1, bs.WeakCall(self.keep_vel)) - else: - self.node.velocity = (0, speed, 0) - # self.node.extraacceleration = (0, self.speed, 0) - bs.timer(0.1, bs.WeakCall(self.keep_vel)) + def keep_vel(self) -> None: + if self.node and not self.died: + speed = bs.getactivity().cur_speed + if self.moving: + if abs(self.node.position[0]) > 10: + self.lrSig *= -1 + self.node.velocity = ( + self.lrSig * speed * self.lrSpeedPlus, speed, 0) + bs.timer(0.1, bs.WeakCall(self.keep_vel)) + else: + self.node.velocity = (0, speed, 0) + # self.node.extraacceleration = (0, self.speed, 0) + bs.timer(0.1, bs.WeakCall(self.keep_vel)) - def tnt_explode(self) -> None: - pos = self.node.position - Blast(position=pos, - blast_radius=6.0, - blast_type='tnt', - source_player=None).autoretain() + def tnt_explode(self) -> None: + pos = self.node.position + Blast(position=pos, + blast_radius=6.0, + blast_type='tnt', + source_player=None).autoretain() - def spawn_npc(self) -> None: - if not self.breakable: - return - if self._npcBots.have_living_bots(): - return - if random.randint(0, 3) >= bs.getactivity().npc_density: - return - pos = self.node.position - pos = (pos[0], pos[1] + 1, pos[2]) - self._npcBots.spawn_bot( - bot_type=random.choice([ChargerBotPro, TriggerBotPro]), - pos=pos, - spawn_time=10) + def spawn_npc(self) -> None: + if not self.breakable: + return + if self._npcBots.have_living_bots(): + return + if random.randint(0, 3) >= bs.getactivity().npc_density: + return + pos = self.node.position + pos = (pos[0], pos[1] + 1, pos[2]) + self._npcBots.spawn_bot( + bot_type=random.choice([ChargerBotPro, TriggerBotPro]), + pos=pos, + spawn_time=10) - def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, bs.DieMessage): - if self.node: - self.node.delete() - self.died = True - elif isinstance(msg, bs.OutOfBoundsMessage): - self.handlemessage(bs.DieMessage()) - elif isinstance(msg, BombToDieMessage): - if self.powerup_type == 'tnt': - self.tnt_explode() - self.handlemessage(bs.DieMessage()) - elif isinstance(msg, bs.HitMessage): - ispunched = (msg.srcnode and msg.srcnode.getnodetype() == 'spaz') - if not ispunched: - if self.breakable: - self.handlemessage(BombToDieMessage()) - elif isinstance(msg, SpazTouchFoothold): - node = bs.getcollision().opposingnode - if node is not None and node: - try: - spaz = node.getdelegate(object) - if not isinstance(spaz, AbyssPlayerSpaz): - return - if spaz in self.touchedSpazs: - return - self.touchedSpazs.add(spaz) - self.spawn_npc() - spaz.fix_2D_position() - if self.powerup_type not in ['', 'tnt']: - node.handlemessage( - bs.PowerupMessage(self.powerup_type)) - except Exception as e: - print(e) - pass + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, bs.DieMessage): + if self.node: + self.node.delete() + self.died = True + elif isinstance(msg, bs.OutOfBoundsMessage): + self.handlemessage(bs.DieMessage()) + elif isinstance(msg, BombToDieMessage): + if self.powerup_type == 'tnt': + self.tnt_explode() + self.handlemessage(bs.DieMessage()) + elif isinstance(msg, bs.HitMessage): + ispunched = (msg.srcnode and msg.srcnode.getnodetype() == 'spaz') + if not ispunched: + if self.breakable: + self.handlemessage(BombToDieMessage()) + elif isinstance(msg, SpazTouchFoothold): + node = bs.getcollision().opposingnode + if node is not None and node: + try: + spaz = node.getdelegate(object) + if not isinstance(spaz, AbyssPlayerSpaz): + return + if spaz in self.touchedSpazs: + return + self.touchedSpazs.add(spaz) + self.spawn_npc() + spaz.fix_2D_position() + if self.powerup_type not in ['', 'tnt']: + node.handlemessage( + bs.PowerupMessage(self.powerup_type)) + except Exception as e: + print(e) + pass class AbyssPlayerSpaz(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', - powerups_expire: bool = True): - super().__init__(player=player, - color=color, - highlight=highlight, - character=character, - powerups_expire=powerups_expire) - self.node.fly = False - self.node.hockey = True - self.hitpoints_max = self.hitpoints = 1500 # more HP to handle drop - bs.timer(bs.getactivity().peace_time, - bs.WeakCall(self.safe_connect_controls_to_player)) + 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', + powerups_expire: bool = True): + super().__init__(player=player, + color=color, + highlight=highlight, + character=character, + powerups_expire=powerups_expire) + self.node.fly = False + self.node.hockey = True + self.hitpoints_max = self.hitpoints = 1500 # more HP to handle drop + bs.timer(bs.getactivity().peace_time, + bs.WeakCall(self.safe_connect_controls_to_player)) - def safe_connect_controls_to_player(self) -> None: - try: - self.connect_controls_to_player() - except: - pass + def safe_connect_controls_to_player(self) -> None: + try: + self.connect_controls_to_player() + except: + pass - def on_move_up_down(self, value: float) -> None: - """ - Called to set the up/down joystick amount on this spaz; - used for player or AI connections. - value will be between -32768 to 32767 - WARNING: deprecated; use on_move instead. - """ - if not self.node: - return - if self.node.run > 0.1: - self.node.move_up_down = value - else: - self.node.move_up_down = value / 3. + def on_move_up_down(self, value: float) -> None: + """ + Called to set the up/down joystick amount on this spaz; + used for player or AI connections. + value will be between -32768 to 32767 + WARNING: deprecated; use on_move instead. + """ + if not self.node: + return + if self.node.run > 0.1: + self.node.move_up_down = value + else: + self.node.move_up_down = value / 3. - def on_move_left_right(self, value: float) -> None: - """ - Called to set the left/right joystick amount on this spaz; - used for player or AI connections. - value will be between -32768 to 32767 - WARNING: deprecated; use on_move instead. - """ - if not self.node: - return - if self.node.run > 0.1: - self.node.move_left_right = value - else: - self.node.move_left_right = value / 1.5 + def on_move_left_right(self, value: float) -> None: + """ + Called to set the left/right joystick amount on this spaz; + used for player or AI connections. + value will be between -32768 to 32767 + WARNING: deprecated; use on_move instead. + """ + if not self.node: + return + if self.node.run > 0.1: + self.node.move_left_right = value + else: + self.node.move_left_right = value / 1.5 - def fix_2D_position(self) -> None: - self.node.fly = True - bs.timer(0.02, bs.WeakCall(self.disable_fly)) + def fix_2D_position(self) -> None: + self.node.fly = True + bs.timer(0.02, bs.WeakCall(self.disable_fly)) - def disable_fly(self) -> None: - if self.node: - self.node.fly = False + def disable_fly(self) -> None: + if self.node: + self.node.fly = False - def curse(self) -> None: - """ - Give this poor spaz a curse; - he will explode in 5 seconds. - """ - if not self._cursed: - factory = SpazFactory.get() - self._cursed = True + def curse(self) -> None: + """ + Give this poor spaz a curse; + he will explode in 5 seconds. + """ + if not self._cursed: + factory = SpazFactory.get() + self._cursed = True - # Add the curse material. - for attr in ['materials', 'roller_materials']: - materials = getattr(self.node, attr) - if factory.curse_material not in materials: - setattr(self.node, attr, - materials + (factory.curse_material, )) + # Add the curse material. + for attr in ['materials', 'roller_materials']: + materials = getattr(self.node, attr) + if factory.curse_material not in materials: + setattr(self.node, attr, + materials + (factory.curse_material, )) - # None specifies no time limit - assert self.node - if self.curse_time == -1: - self.node.curse_death_time = -1 - else: - # Note: curse-death-time takes milliseconds. - tval = bs.time() - assert isinstance(tval, (float, int)) - self.node.curse_death_time = bs.time() + 15 - bs.timer(15, bs.WeakCall(self.curse_explode)) + # None specifies no time limit + assert self.node + if self.curse_time == -1: + self.node.curse_death_time = -1 + else: + # Note: curse-death-time takes milliseconds. + tval = bs.time() + assert isinstance(tval, (float, int)) + self.node.curse_death_time = bs.time() + 15 + bs.timer(15, bs.WeakCall(self.curse_explode)) - def handlemessage(self, msg: Any) -> Any: - dontUp = False + def handlemessage(self, msg: Any) -> Any: + dontUp = False - if isinstance(msg, PickupMessage): - dontUp = True - collision = bs.getcollision() - opposingnode = collision.opposingnode - opposingbody = collision.opposingbody + if isinstance(msg, PickupMessage): + dontUp = True + collision = bs.getcollision() + opposingnode = collision.opposingnode + opposingbody = collision.opposingbody - if opposingnode is None or not opposingnode: - return True - opposingdelegate = opposingnode.getdelegate(object) - # Don't pick up the foothold - if isinstance(opposingdelegate, Foothold): - return True + if opposingnode is None or not opposingnode: + return True + opposingdelegate = opposingnode.getdelegate(object) + # Don't pick up the foothold + if isinstance(opposingdelegate, Foothold): + return True - # dont allow picking up of invincible dudes - try: - if opposingnode.invincible: - return True - except Exception: - pass + # dont allow picking up of invincible dudes + try: + if opposingnode.invincible: + return True + except Exception: + pass - # if we're grabbing the pelvis of a non-shattered spaz, - # we wanna grab the torso instead - if (opposingnode.getnodetype() == 'spaz' - and not opposingnode.shattered and opposingbody == 4): - opposingbody = 1 + # if we're grabbing the pelvis of a non-shattered spaz, + # we wanna grab the torso instead + if (opposingnode.getnodetype() == 'spaz' + and not opposingnode.shattered and opposingbody == 4): + opposingbody = 1 + # Special case - if we're holding a flag, don't replace it + # (hmm - should make this customizable or more low level). + held = self.node.hold_node + if held and held.getnodetype() == 'flag': + return True - # Special case - if we're holding a flag, don't replace it - # (hmm - should make this customizable or more low level). - held = self.node.hold_node - if held and held.getnodetype() == 'flag': - return True + # Note: hold_body needs to be set before hold_node. + self.node.hold_body = opposingbody + self.node.hold_node = opposingnode - # Note: hold_body needs to be set before hold_node. - self.node.hold_body = opposingbody - self.node.hold_node = opposingnode - - if not dontUp: - PlayerSpaz.handlemessage(self, msg) + if not dontUp: + PlayerSpaz.handlemessage(self, msg) class Player(bs.Player['Team']): - """Our player type for this game.""" + """Our player type for this game.""" - def __init__(self) -> None: - super().__init__() - self.death_time: float | None = None - self.notIn: bool = None + def __init__(self) -> None: + super().__init__() + self.death_time: float | None = None + self.notIn: bool = None class Team(bs.Team[Player]): - """Our team type for this game.""" + """Our team type for this game.""" # ba_meta export bascenev1.GameActivity class AbyssGame(bs.TeamGameActivity[Player, Team]): - name = name - description = description - scoreconfig = bs.ScoreConfig(label='Survived', - scoretype=bs.ScoreType.MILLISECONDS, - version='B') + name = name + description = description + 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 + # 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[bs.Session]) -> list[str]: - return ['Abyss Unhappy'] + # We're currently hard-coded for one map. + @classmethod + def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]: + return ['Abyss Unhappy'] - @classmethod - def get_available_settings( - cls, sessiontype: type[bs.Session]) -> list[babase.Setting]: - settings = [ - bs.FloatChoiceSetting( - peaceTime, - choices=[ - ('None', 0.0), - ('Shorter', 2.5), - ('Short', 5.0), - ('Normal', 10.0), - ('Long', 15.0), - ('Longer', 20.0), - ], - default=10.0, - ), - bs.FloatChoiceSetting( - npcDensity, - choices=[ - ('0%', 0), - ('25%', 1), - ('50%', 2), - ('75%', 3), - ('100%', 4), - ], - default=2, - ), - bs.BoolSetting('Epic Mode', default=False), - ] - return settings + @classmethod + def get_available_settings( + cls, sessiontype: type[bs.Session]) -> list[babase.Setting]: + settings = [ + bs.FloatChoiceSetting( + peaceTime, + choices=[ + ('None', 0.0), + ('Shorter', 2.5), + ('Short', 5.0), + ('Normal', 10.0), + ('Long', 15.0), + ('Longer', 20.0), + ], + default=10.0, + ), + bs.FloatChoiceSetting( + npcDensity, + choices=[ + ('0%', 0), + ('25%', 1), + ('50%', 2), + ('75%', 3), + ('100%', 4), + ], + default=2, + ), + bs.BoolSetting('Epic Mode', default=False), + ] + return settings - # We support teams, free-for-all, and co-op sessions. - @classmethod - def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool: - return (issubclass(sessiontype, bs.DualTeamSession) - or issubclass(sessiontype, bs.FreeForAllSession) - or issubclass(sessiontype, bs.CoopSession)) + # We support teams, free-for-all, and co-op sessions. + @classmethod + def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool: + return (issubclass(sessiontype, bs.DualTeamSession) + or issubclass(sessiontype, bs.FreeForAllSession) + or issubclass(sessiontype, bs.CoopSession)) - def __init__(self, settings: dict): - super().__init__(settings) - self._epic_mode = settings.get('Epic Mode', False) - self._last_player_death_time: float | None = None - self._timer: OnScreenTimer | None = None - self.fix_y = -5.614479365 - self.start_z = 0 - self.init_position = (0, self.start_z, self.fix_y) - self.team_init_positions = [(-5, self.start_z, self.fix_y), - (5, self.start_z, self.fix_y)] - self.cur_speed = 2.5 - # TODO: The variable below should be set in settings - self.peace_time = float(settings[peaceTime]) - self.npc_density = float(settings[npcDensity]) + def __init__(self, settings: dict): + super().__init__(settings) + self._epic_mode = settings.get('Epic Mode', False) + self._last_player_death_time: float | None = None + self._timer: OnScreenTimer | None = None + self.fix_y = -5.614479365 + self.start_z = 0 + self.init_position = (0, self.start_z, self.fix_y) + self.team_init_positions = [(-5, self.start_z, self.fix_y), + (5, self.start_z, self.fix_y)] + self.cur_speed = 2.5 + # TODO: The variable below should be set in settings + self.peace_time = float(settings[peaceTime]) + self.npc_density = float(settings[npcDensity]) - # Some base class overrides: - self.default_music = (bs.MusicType.EPIC - if self._epic_mode else bs.MusicType.SURVIVAL) - if self._epic_mode: - self.slow_motion = True + # Some base class overrides: + self.default_music = (bs.MusicType.EPIC + if self._epic_mode else bs.MusicType.SURVIVAL) + if self._epic_mode: + self.slow_motion = True - self._game_credit = bs.NodeActor( - bs.newnode( - 'text', - attrs={ - 'v_attach': 'bottom', - 'h_align': 'center', - 'vr_depth': 0, - 'color': (0.0, 0.7, 1.0), - 'shadow': 1.0 if True else 0.5, - 'flatness': 1.0 if True else 0.5, - 'position': (0, 0), - 'scale': 0.8, - 'text': ' | '.join([author, github, blog]) - })) + self._game_credit = bs.NodeActor( + bs.newnode( + 'text', + attrs={ + 'v_attach': 'bottom', + 'h_align': 'center', + 'vr_depth': 0, + 'color': (0.0, 0.7, 1.0), + 'shadow': 1.0 if True else 0.5, + 'flatness': 1.0 if True else 0.5, + 'position': (0, 0), + 'scale': 0.8, + 'text': ' | '.join([author, github, blog]) + })) - def get_instance_description(self) -> str | Sequence: - return description + def get_instance_description(self) -> str | Sequence: + return description - def get_instance_description_short(self) -> str | Sequence: - return self.get_instance_description() + '\n' + help + def get_instance_description_short(self) -> str | Sequence: + return self.get_instance_description() + '\n' + help - def on_player_join(self, player: Player) -> None: - if self.has_begun(): - player.notIn = True - bs.broadcastmessage(babase.Lstr( - resource='playerDelayedJoinText', - subs=[('${PLAYER}', player.getname(full=True))]), - color=(0, 1, 0)) - self.spawn_player(player) + def on_player_join(self, player: Player) -> None: + if self.has_begun(): + player.notIn = True + bs.broadcastmessage(babase.Lstr( + resource='playerDelayedJoinText', + subs=[('${PLAYER}', player.getname(full=True))]), + color=(0, 1, 0)) + self.spawn_player(player) - def on_begin(self) -> None: - super().on_begin() - self._timer = OnScreenTimer() - self._timer.start() + def on_begin(self) -> None: + super().on_begin() + self._timer = OnScreenTimer() + self._timer.start() - self.level_cnt = 1 + self.level_cnt = 1 - if self.teams_or_ffa() == 'teams': - ip0 = self.team_init_positions[0] - ip1 = self.team_init_positions[1] - Foothold( - (ip0[0], ip0[1] - 2, ip0[2]), - power='shield', breakable=False).autoretain() - Foothold( - (ip1[0], ip1[1] - 2, ip1[2]), - power='shield', breakable=False).autoretain() - else: - ip = self.init_position - Foothold( - (ip[0], ip[1] - 2, ip[2]), - power='shield', breakable=False).autoretain() + if self.teams_or_ffa() == 'teams': + ip0 = self.team_init_positions[0] + ip1 = self.team_init_positions[1] + Foothold( + (ip0[0], ip0[1] - 2, ip0[2]), + power='shield', breakable=False).autoretain() + Foothold( + (ip1[0], ip1[1] - 2, ip1[2]), + power='shield', breakable=False).autoretain() + else: + ip = self.init_position + Foothold( + (ip[0], ip[1] - 2, ip[2]), + power='shield', breakable=False).autoretain() - bs.timer(int(5.0 / self.cur_speed), - bs.WeakCall(self.add_foothold), repeat=True) + bs.timer(int(5.0 / self.cur_speed), + bs.WeakCall(self.add_foothold), repeat=True) - # Repeat check game end - bs.timer(1.0, self._check_end_game, repeat=True) - bs.timer(self.peace_time + 0.1, - bs.WeakCall(self.tip_hint, hint_use_punch)) - bs.timer(6.0, bs.WeakCall(self.faster_speed), repeat=True) + # Repeat check game end + bs.timer(1.0, self._check_end_game, repeat=True) + bs.timer(self.peace_time + 0.1, + bs.WeakCall(self.tip_hint, hint_use_punch)) + bs.timer(6.0, bs.WeakCall(self.faster_speed), repeat=True) - def tip_hint(self, text: str) -> None: - bs.broadcastmessage(text, color=(0.2, 0.2, 1)) + def tip_hint(self, text: str) -> None: + bs.broadcastmessage(text, color=(0.2, 0.2, 1)) - def faster_speed(self) -> None: - self.cur_speed *= 1.15 + def faster_speed(self) -> None: + self.cur_speed *= 1.15 - def add_foothold(self) -> None: - ip = self.init_position - ip_1 = (ip[0] - 7, ip[1], ip[2]) - ip_2 = (ip[0] + 7, ip[1], ip[2]) - ru = random.uniform - self.level_cnt += 1 - if self.level_cnt % 3: - Foothold(( - ip_1[0] + ru(-5, 5), - ip[1] - 2, - ip[2] + ru(-0.0, 0.0))).autoretain() - Foothold(( - ip_2[0] + ru(-5, 5), - ip[1] - 2, - ip[2] + ru(-0.0, 0.0))).autoretain() - else: - Foothold(( - ip[0] + ru(-8, 8), - ip[1] - 2, - ip[2]), moving=True).autoretain() + def add_foothold(self) -> None: + ip = self.init_position + ip_1 = (ip[0] - 7, ip[1], ip[2]) + ip_2 = (ip[0] + 7, ip[1], ip[2]) + ru = random.uniform + self.level_cnt += 1 + if self.level_cnt % 3: + Foothold(( + ip_1[0] + ru(-5, 5), + ip[1] - 2, + ip[2] + ru(-0.0, 0.0))).autoretain() + Foothold(( + ip_2[0] + ru(-5, 5), + ip[1] - 2, + ip[2] + ru(-0.0, 0.0))).autoretain() + else: + Foothold(( + ip[0] + ru(-8, 8), + ip[1] - 2, + ip[2]), moving=True).autoretain() - def teams_or_ffa(self) -> None: - if isinstance(self.session, bs.DualTeamSession): - return 'teams' - return 'ffa' + def teams_or_ffa(self) -> None: + if isinstance(self.session, bs.DualTeamSession): + return 'teams' + return 'ffa' - def spawn_player_spaz(self, - player: Player, - position: Sequence[float] = (0, 0, 0), - angle: float | None = None) -> PlayerSpaz: - # pylint: disable=too-many-locals - # pylint: disable=cyclic-import - from babase import _math - from bascenev1._gameutils import animate + def spawn_player_spaz(self, + player: Player, + position: Sequence[float] = (0, 0, 0), + angle: float | None = None) -> PlayerSpaz: + # pylint: disable=too-many-locals + # pylint: disable=cyclic-import + from babase import _math + from bascenev1._gameutils import animate - position = self.init_position - if self.teams_or_ffa() == 'teams': - position = self.team_init_positions[player.team.id % 2] - angle = None + position = self.init_position + if self.teams_or_ffa() == 'teams': + position = self.team_init_positions[player.team.id % 2] + angle = None - name = player.getname() - color = player.color - highlight = player.highlight + 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 = AbyssPlayerSpaz(color=color, - highlight=highlight, - character=player.character, - player=player) + light_color = _math.normalized_color(color) + display_color = _babase.safecolor(color, target_intensity=0.75) + spaz = AbyssPlayerSpaz(color=color, + highlight=highlight, + character=player.character, + player=player) - player.actor = spaz - assert spaz.node + player.actor = spaz + assert spaz.node - spaz.node.name = name - spaz.node.name_color = display_color - spaz.connect_controls_to_player(enable_punch=False, - enable_bomb=True, - enable_pickup=False) + spaz.node.name = name + spaz.node.name_color = display_color + spaz.connect_controls_to_player(enable_punch=False, + enable_bomb=True, + enable_pickup=False) - # 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') - animate(light, 'intensity', {0: 0, 0.25: 1, 0.5: 0}) - bs.timer(0.5, light.delete) - return spaz + # 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') + animate(light, 'intensity', {0: 0, 0.25: 1, 0.5: 0}) + bs.timer(0.5, light.delete) + return spaz - def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, bs.PlayerDiedMessage): + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, bs.PlayerDiedMessage): - # Augment standard behavior. - super().handlemessage(msg) + # Augment standard behavior. + super().handlemessage(msg) - curtime = bs.time() + curtime = bs.time() - # Record the player's moment of death. - # assert isinstance(msg.spaz.player - msg.getplayer(Player).death_time = curtime + # Record the player's moment of death. + # assert isinstance(msg.spaz.player + msg.getplayer(Player).death_time = curtime - # In co-op mode, end the game the instant everyone dies - # (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, bs.CoopSession): - # Teams will still show up if we check now.. check in - # the next cycle. - babase.pushcall(self._check_end_game) + # In co-op mode, end the game the instant everyone dies + # (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, bs.CoopSession): + # Teams will still show up if we check now.. check in + # the next cycle. + babase.pushcall(self._check_end_game) - # Also record this for a final setting of the clock. - self._last_player_death_time = curtime - else: - bs.timer(1.0, self._check_end_game) + # Also record this for a final setting of the clock. + self._last_player_death_time = curtime + else: + bs.timer(1.0, self._check_end_game) - else: - # Default handler: - return super().handlemessage(msg) - return None + else: + # Default handler: + return super().handlemessage(msg) + return None - def _check_end_game(self) -> None: - living_team_count = 0 - for team in self.teams: - for player in team.players: - if player.is_alive(): - living_team_count += 1 - break + def _check_end_game(self) -> None: + living_team_count = 0 + for team in self.teams: + for player in team.players: + if player.is_alive(): + living_team_count += 1 + break - # In co-op, we go till everyone is dead.. otherwise we go - # until one team remains. - if isinstance(self.session, bs.CoopSession): - if living_team_count <= 0: - self.end_game() - else: - if living_team_count <= 0: - self.end_game() + # In co-op, we go till everyone is dead.. otherwise we go + # until one team remains. + if isinstance(self.session, bs.CoopSession): + if living_team_count <= 0: + self.end_game() + else: + if living_team_count <= 0: + self.end_game() - def end_game(self) -> None: - cur_time = bs.time() - assert self._timer is not None - start_time = self._timer.getstarttime() + def end_game(self) -> None: + cur_time = bs.time() + assert self._timer is not None + start_time = self._timer.getstarttime() - # Mark death-time as now for any still-living players - # and award players points for how long they lasted. - # (these per-player scores are only meaningful in team-games) - for team in self.teams: - for player in team.players: - survived = False - if player.notIn: - player.death_time = 0 + # Mark death-time as now for any still-living players + # and award players points for how long they lasted. + # (these per-player scores are only meaningful in team-games) + for team in self.teams: + for player in team.players: + survived = False + if player.notIn: + player.death_time = 0 - # Throw an extra fudge factor in so teams that - # didn't die come out ahead of teams that did. - if player.death_time is None: - survived = True - player.death_time = cur_time + 1 + # Throw an extra fudge factor in so teams that + # didn't die come out ahead of teams that did. + if player.death_time is None: + survived = True + player.death_time = cur_time + 1 - # Award a per-player score depending on how many seconds - # they lasted (per-player scores only affect teams mode; - # everywhere else just looks at the per-team score). - score = int(player.death_time - self._timer.getstarttime()) - if survived: - score += 50 # A bit extra for survivors. - self.stats.player_scored(player, score, screenmessage=False) + # Award a per-player score depending on how many seconds + # they lasted (per-player scores only affect teams mode; + # everywhere else just looks at the per-team score). + score = int(player.death_time - self._timer.getstarttime()) + if survived: + score += 50 # A bit extra for survivors. + self.stats.player_scored(player, score, screenmessage=False) - # Stop updating our time text, and set the final time to match - # exactly when our last guy died. - self._timer.stop(endtime=self._last_player_death_time) + # Stop updating our time text, and set the final time to match + # exactly when our last guy died. + self._timer.stop(endtime=self._last_player_death_time) - # Ok now calc game results: set a score for each team and then tell - # the game to end. - results = bs.GameResults() + # Ok now calc game results: set a score for each team and then tell + # the game to end. + 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 - # just always deal in teams and have all cases covered. - for team in self.teams: + # Remember that 'free-for-all' mode is simply a special form + # of 'teams' mode where each player gets their own team, so we can + # just always deal in teams and have all cases covered. + for team in self.teams: - # Set the team score to the max time survived by any player on - # that team. - longest_life = 0.0 - for player in team.players: - assert player.death_time is not None - longest_life = max(longest_life, - player.death_time - start_time) + # Set the team score to the max time survived by any player on + # that team. + longest_life = 0.0 + for player in team.players: + assert player.death_time is not None + longest_life = max(longest_life, + player.death_time - start_time) - # Submit the score value in milliseconds. - results.set_team_score(team, int(1000.0 * longest_life)) + # Submit the score value in milliseconds. + results.set_team_score(team, int(1000.0 * longest_life)) - self.end(results=results) + self.end(results=results) diff --git a/plugins/minigames/explodo_run.py b/plugins/minigames/explodo_run.py index be013c7..cac6a65 100644 --- a/plugins/minigames/explodo_run.py +++ b/plugins/minigames/explodo_run.py @@ -17,19 +17,22 @@ from bascenev1lib.actor.onscreentimer import OnScreenTimer if TYPE_CHECKING: from typing import Any, Type, Dict, List, Optional + def ba_get_api_version(): return 8 + def ba_get_levels(): - return [bs._level.Level( - 'Explodo Run', - gametype=ExplodoRunGame, - settings={}, - preview_texture_name='rampagePreview'),bs._level.Level( - 'Epic Explodo Run', - gametype=ExplodoRunGame, - settings={'Epic Mode':True}, - preview_texture_name='rampagePreview')] + return [bs._level.Level( + 'Explodo Run', + gametype=ExplodoRunGame, + settings={}, + preview_texture_name='rampagePreview'), bs._level.Level( + 'Epic Explodo Run', + gametype=ExplodoRunGame, + settings={'Epic Mode': True}, + preview_texture_name='rampagePreview')] + class Player(bs.Player['Team']): """Our player type for this game.""" @@ -39,6 +42,8 @@ class Team(bs.Team[Player]): """Our team type for this game.""" # ba_meta export bascenev1.GameActivity + + class ExplodoRunGame(bs.TeamGameActivity[Player, Team]): name = "Explodo Run" description = "Run For Your Life :))" @@ -47,8 +52,8 @@ class ExplodoRunGame(bs.TeamGameActivity[Player, Team]): scoretype=bs.ScoreType.MILLISECONDS, lower_is_better=False) default_music = bs.MusicType.TO_THE_DEATH - - def __init__(self, settings:dict): + + def __init__(self, settings: dict): settings['map'] = "Rampage" self._epic_mode = settings.get('Epic Mode', False) if self._epic_mode: @@ -59,27 +64,28 @@ class ExplodoRunGame(bs.TeamGameActivity[Player, Team]): self._won = False self._bots = SpazBotSet() self.wave = 1 - + def on_begin(self) -> None: super().on_begin() - + self._timer = OnScreenTimer() bs.timer(2.5, self._timer.start) - - #Bots Hehe - bs.timer(2.5,self.street) + + # Bots Hehe + bs.timer(2.5, self.street) def street(self): for a in range(self.wave): - p1 = random.choice([-5,-2.5,0,2.5,5]) - p3 = random.choice([-4.5,-4.14,-5,-3]) - time = random.choice([1,1.5,2.5,2]) - self._bots.spawn_bot(ExplodeyBot, pos=(p1,5.5,p3),spawn_time = time) + p1 = random.choice([-5, -2.5, 0, 2.5, 5]) + p3 = random.choice([-4.5, -4.14, -5, -3]) + time = random.choice([1, 1.5, 2.5, 2]) + self._bots.spawn_bot(ExplodeyBot, pos=(p1, 5.5, p3), spawn_time=time) self.wave += 1 - + def botrespawn(self): if not self._bots.have_living_bots(): self.street() + def handlemessage(self, msg: Any) -> Any: # A player has died. @@ -87,7 +93,7 @@ class ExplodoRunGame(bs.TeamGameActivity[Player, Team]): super().handlemessage(msg) # Augment standard behavior. self._won = True self.end_game() - + # A spaz-bot has died. elif isinstance(msg, SpazBotDiedMessage): # Unfortunately the bot-set will always tell us there are living @@ -128,5 +134,3 @@ class ExplodoRunGame(bs.TeamGameActivity[Player, Team]): # Ends the activity. self.end(results) - - \ No newline at end of file diff --git a/plugins/minigames/extinction.py b/plugins/minigames/extinction.py index 39266e5..22ca2fc 100644 --- a/plugins/minigames/extinction.py +++ b/plugins/minigames/extinction.py @@ -21,6 +21,7 @@ if TYPE_CHECKING: def ba_get_api_version(): return 8 + def ba_get_levels(): return [babase._level.Level( 'Extinction', @@ -33,23 +34,24 @@ def ba_get_levels(): settings={'Epic Mode': True}, preview_texture_name='footballStadiumPreview')] + class Meteor(bs.Actor): """A giant meteor instead of bombs.""" - + def __init__(self, pos: Sequence[float] = (0.0, 1.0, 0.0), velocity: Sequence[float] = (0.0, 0.0, 0.0)): super().__init__() - + shared = SharedObjects.get() factory = BombFactory.get() - + materials = (shared.object_material, factory.impact_blast_material) - + self.pos = (pos[0], pos[1], pos[2]) self.velocity = (velocity[0], velocity[1], velocity[2]) - + self.node = bs.newnode( 'prop', delegate=self, @@ -66,13 +68,13 @@ class Meteor(bs.Actor): 'reflection_scale': [0.45], 'materials': materials }) - + def explode(self) -> None: Blast(position=self.node.position, velocity=self.node.velocity, blast_type='tnt', blast_radius=2.0) - + def handlemessage(self, msg: Any) -> Any: if isinstance(msg, bs.DieMessage): if self.node: @@ -86,11 +88,12 @@ class Meteor(bs.Actor): class Player(bs.Player['Team']): """Our player type for this game.""" - + def __init__(self): super().__init__() self.death_time: Optional[float] = None + class Team(bs.Team[Player]): """Our team type for this game.""" @@ -98,112 +101,112 @@ class Team(bs.Team[Player]): # ba_meta export bascenev1.GameActivity class NewMeteorShowerGame(bs.TeamGameActivity[Player, Team]): """Minigame by Jetz.""" - + name = 'Extinction' description = 'Survive the Extinction.' available_settings = [ bs.BoolSetting('Epic Mode', default=False)] - + announce_player_deaths = True - + @classmethod def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]: return ['Football Stadium'] - + @classmethod def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool: return (issubclass(sessiontype, bs.FreeForAllSession) or issubclass(sessiontype, bs.DualTeamSession)) - + def __init__(self, settings: dict): super().__init__(settings) - + self._epic_mode = bool(settings['Epic Mode']) self._last_player_death_time: Optiobal[float] = None self._meteor_time = 2.0 self._timer: Optional[OnScreenTimer] = None - + self.default_music = (bs.MusicType.EPIC if self._epic_mode else bs.MusicType.SURVIVAL) - + if self._epic_mode: self.slow_motion = True - + def on_begin(self) -> None: super().on_begin() - + delay = 5.0 if len(self.players) > 2 else 2.5 if self._epic_mode: delay *= 0.25 bs.timer(delay, self._decrement_meteor_time, repeat=True) - + delay = 3.0 if self._epic_mode: delay *= 0.25 bs.timer(delay, self._set_meteor_timer) - + self._timer = OnScreenTimer() self._timer.start() self._check_end_game() - + def on_player_join(self, player: Player) -> None: if self.has_begun(): bs.broadcastmessage( babase.Lstr(resource='playerDelayedJoinText', - subs=[('${PLAYER}', player.getname(full=True))]), + subs=[('${PLAYER}', player.getname(full=True))]), color=(0, 1, 0), ) assert self._timer is not None player.death_time = self._timer.getstarttime() return self.spawn_player(player) - + def spawn_player(self, player: Player) -> None: spaz = self.spawn_player_spaz(player) - + spaz.connect_controls_to_player(enable_punch=False, enable_pickup=False, enable_bomb=False, enable_jump=False) spaz.play_big_death_sound = True - + return spaz - + def on_player_leave(self, player: Player) -> None: super().on_player_leave(player) - + self._check_end_game() - + def handlemessage(self, msg: Any) -> Any: if isinstance(msg, bs.PlayerDiedMessage): curtime = bs.time() - + msg.getplayer(Player).death_time = curtime bs.timer(1.0, self._check_end_game) else: return super().handlemessage(msg) - + def _spawn_meteors(self) -> None: pos = (random.randint(-6, 7), 12, random.uniform(-2, 1)) velocity = (random.randint(-11, 11), 0, random.uniform(-5, 5)) Meteor(pos=pos, velocity=velocity).autoretain() - + def _spawn_meteors_cluster(self) -> None: delay = 0.0 for _i in range(random.randrange(1, 3)): bs.timer(delay, self._spawn_meteors) delay += 1 self._set_meteor_timer() - + def _decrement_meteor_time(self) -> None: self._meteor_time = max(0.01, self._meteor_time * 0.9) - + def _set_meteor_timer(self) -> None: bs.timer((1.0 + 0.2 * random.random()) * self._meteor_time, self._spawn_meteors_cluster) - + def _check_end_game(self) -> None: living_team_count = 0 for team in self.teams: @@ -211,44 +214,44 @@ class NewMeteorShowerGame(bs.TeamGameActivity[Player, Team]): if player.is_alive(): living_team_count += 1 break - + if isinstance(self.session, bs.CoopSession): if living_team_count <= 0: self.end_game() else: if living_team_count <= 1: self.end_game() - + def end_game(self) -> None: cur_time = bs.time() assert self._timer is not None start_time = self._timer.getstarttime() - + for team in self.teams: for player in team.players: survived = False - + if player.death_time is None: survived = True player.death_time = cur_time + 1 - + score = int(player.death_time - self._timer.getstarttime()) if survived: score += 50 self.stats.player_scored(player, score, screenmessage=False) - + self._timer.stop(endtime=self._last_player_death_time) - + results = bs.GameResults() - + for team in self.teams: - + longest_life = 0.0 for player in team.players: assert player.death_time is not None longest_life = max(longest_life, player.death_time - start_time) - + results.set_team_score(team, int(1000.0 * longest_life)) - - self.end(results=results) \ No newline at end of file + + self.end(results=results) diff --git a/plugins/minigames/fat_pigs.py b/plugins/minigames/fat_pigs.py index aed1a69..78c56c3 100644 --- a/plugins/minigames/fat_pigs.py +++ b/plugins/minigames/fat_pigs.py @@ -3,7 +3,7 @@ # - - - - - - - - - - - - - - - - - - - - - # - Fat-Pigs! by Zacker Tz || Zacker#5505 - -# - Version 0.01 :v - +# - Version 0.01 :v - # - - - - - - - - - - - - - - - - - - - - - from __future__ import annotations @@ -24,12 +24,13 @@ if TYPE_CHECKING: # - - - - - - - Mini - Settings - - - - - - - - - - - - - - - - # -zkBombs_limit = 3 # Number of bombs you can use | Default = 3 -zkPunch = False # Enable/Disable punchs | Default = False -zkPickup = False # Enable/Disable pickup | Default = False +zkBombs_limit = 3 # Number of bombs you can use | Default = 3 +zkPunch = False # Enable/Disable punchs | Default = False +zkPickup = False # Enable/Disable pickup | Default = False # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # + class Player(bs.Player['Team']): """Our player type for this game.""" @@ -40,7 +41,9 @@ class Team(bs.Team[Player]): def __init__(self) -> None: self.score = 0 -# ba_meta export bascenev1.GameActivity +# ba_meta export bascenev1.GameActivity + + class FatPigs(bs.TeamGameActivity[Player, Team]): """A game type based on acquiring kills.""" @@ -139,20 +142,18 @@ class FatPigs(bs.TeamGameActivity[Player, Team]): super().on_begin() self.setup_standard_time_limit(self._time_limit) # self.setup_standard_powerup_drops() - #Ambiente + # Ambiente gnode = bs.getactivity().globalsnode gnode.tint = (0.8, 1.2, 0.8) gnode.ambient_color = (0.7, 1.0, 0.6) - gnode.vignette_outer = (0.4, 0.6, 0.4) #C + gnode.vignette_outer = (0.4, 0.6, 0.4) # C # gnode.vignette_inner = (0.9, 0.9, 0.9) - - # 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() - + delay = 5.0 if len(self.players) > 2 else 2.5 if self._epic_mode: delay *= 0.25 @@ -169,18 +170,17 @@ class FatPigs(bs.TeamGameActivity[Player, Team]): # Check for immediate end (if we've only got 1 player, etc). bs.timer(5.0, self._check_end_game) - + t = bs.newnode('text', - attrs={ 'text':"Minigame by Zacker Tz", - 'scale':0.7, - 'position':(0.001,625), - 'shadow':0.5, - 'opacity':0.7, - 'flatness':1.2, - 'color':(0.6, 1, 0.6), - 'h_align':'center', - 'v_attach':'bottom'}) - + attrs={'text': "Minigame by Zacker Tz", + 'scale': 0.7, + 'position': (0.001, 625), + 'shadow': 0.5, + 'opacity': 0.7, + 'flatness': 1.2, + 'color': (0.6, 1, 0.6), + 'h_align': 'center', + 'v_attach': 'bottom'}) def spawn_player(self, player: Player) -> bs.Actor: spaz = self.spawn_player_spaz(player) @@ -190,13 +190,13 @@ class FatPigs(bs.TeamGameActivity[Player, Team]): spaz.connect_controls_to_player(enable_punch=zkPunch, enable_bomb=True, enable_pickup=zkPickup) - + spaz.bomb_count = zkBombs_limit spaz._max_bomb_count = zkBombs_limit spaz.bomb_type_default = 'sticky' spaz.bomb_type = 'sticky' - #cerdo gordo + # cerdo gordo spaz.node.color_mask_texture = bs.gettexture('melColorMask') spaz.node.color_texture = bs.gettexture('melColor') spaz.node.head_mesh = bs.getmesh('melHead') @@ -210,19 +210,19 @@ class FatPigs(bs.TeamGameActivity[Player, Team]): spaz.node.toes_mesh = bs.getmesh('melToes') spaz.node.style = 'mel' # Sounds cerdo gordo - mel_sounds = [bs.getsound('mel01'), bs.getsound('mel02'),bs.getsound('mel03'),bs.getsound('mel04'),bs.getsound('mel05'), - bs.getsound('mel06'),bs.getsound('mel07'),bs.getsound('mel08'),bs.getsound('mel09'),bs.getsound('mel10')] + mel_sounds = [bs.getsound('mel01'), bs.getsound('mel02'), bs.getsound('mel03'), bs.getsound('mel04'), bs.getsound('mel05'), + bs.getsound('mel06'), bs.getsound('mel07'), bs.getsound('mel08'), bs.getsound('mel09'), bs.getsound('mel10')] spaz.node.jump_sounds = mel_sounds spaz.node.attack_sounds = mel_sounds spaz.node.impact_sounds = mel_sounds spaz.node.pickup_sounds = mel_sounds spaz.node.death_sounds = [bs.getsound('melDeath01')] spaz.node.fall_sounds = [bs.getsound('melFall01')] - + def _set_meteor_timer(self) -> None: bs.timer((1.0 + 0.2 * random.random()) * self._meteor_time, - self._drop_bomb_cluster) - + self._drop_bomb_cluster) + def _drop_bomb_cluster(self) -> None: # Random note: code like this is a handy way to plot out extents @@ -245,15 +245,14 @@ class FatPigs(bs.TeamGameActivity[Player, Team]): vel = ((-5.0 + random.random() * 30.0) * dropdir, -4.0, 0) bs.timer(delay, babase.Call(self._drop_bomb, pos, vel)) delay += 0.1 - self._set_meteor_timer() - + self._set_meteor_timer() + def _drop_bomb(self, position: Sequence[float], velocity: Sequence[float]) -> None: - Bomb(position=position, velocity=velocity,bomb_type='sticky').autoretain() + Bomb(position=position, velocity=velocity, bomb_type='sticky').autoretain() def _decrement_meteor_time(self) -> None: self._meteor_time = max(0.01, self._meteor_time * 0.9) - def handlemessage(self, msg: Any) -> Any: @@ -326,7 +325,7 @@ class FatPigs(bs.TeamGameActivity[Player, Team]): self.end_game() else: if living_team_count <= 1: - self.end_game() + self.end_game() def _update_scoreboard(self) -> None: for team in self.teams: diff --git a/plugins/utilities/xyz_tool.py b/plugins/utilities/xyz_tool.py index 2ad1efd..c3cf567 100644 --- a/plugins/utilities/xyz_tool.py +++ b/plugins/utilities/xyz_tool.py @@ -20,28 +20,35 @@ DECIMAL_LIMIT = 7 PlayerSpaz.supershit = PlayerSpaz.__init__ + + def ShitInit(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', - powerups_expire: bool = True) -> None: + player: bs.Player, + color: Sequence[float] = (1.0, 1.0, 1.0), + highlight: Sequence[float] = (0.5, 0.5, 0.5), + character: str = 'Spaz', + powerups_expire: bool = True) -> None: self.supershit(player, color, highlight, character, powerups_expire) - self.offt = bs.newnode('math', owner=self.node, attrs={'input1': (1.2, 1.8, -0.7),'operation': 'add'}) + self.offt = bs.newnode('math', owner=self.node, attrs={ + 'input1': (1.2, 1.8, -0.7), 'operation': 'add'}) self.node.connectattr('torso_position', self.offt, 'input2') - self.txt = bs.newnode('text', owner=self.node, attrs={'text': '3.0','in_world': True,'text':'0','shadow': 1.0,'color': (1,0,0),'flatness': 0.5,'scale': 0.01,'h_align': 'right'}) + self.txt = bs.newnode('text', owner=self.node, attrs={'text': '3.0', 'in_world': True, 'text': '0', 'shadow': 1.0, 'color': ( + 1, 0, 0), 'flatness': 0.5, 'scale': 0.01, 'h_align': 'right'}) p = self.node.position self.xyz = 0 self.txt.text = "X: " + str(p[0]) + "\nY: " + str(p[1]) + "\nZ: " + str(p[2]) self.offt.connectattr('output', self.txt, 'position') + def update(): p = self.node.position is_moving = abs(self.node.move_up_down) >= 0.01 or abs(self.node.move_left_right) >= 0.01 if is_moving: - self.xyz = (p[0],p[1],p[2]) - self.txt.text = "X: " + str(round(self.xyz[0],DECIMAL_LIMIT)) + "\nY: " + str(round(self.xyz[1],DECIMAL_LIMIT)) + "\nZ: " + str(round(self.xyz[2],DECIMAL_LIMIT)) - bs.timer(0.1,update,repeat=True) - + self.xyz = (p[0], p[1], p[2]) + self.txt.text = "X: " + str(round(self.xyz[0], DECIMAL_LIMIT)) + "\nY: " + str( + round(self.xyz[1], DECIMAL_LIMIT)) + "\nZ: " + str(round(self.xyz[2], DECIMAL_LIMIT)) + bs.timer(0.1, update, repeat=True) + + def replaceable_punch(self) -> None: """ Called to 'press punch' on this spaz; @@ -55,10 +62,11 @@ def replaceable_punch(self) -> None: index += len(files) c27 = str(index + 1) with open(path_aid + '/coords' + c27 + '.txt', 'w') as gg: - gg.write("X: " + str(round(self.xyz[0],DECIMAL_LIMIT)) + "\nY: " + str(round(self.xyz[1],DECIMAL_LIMIT)) + "\nZ: " + str(round(self.xyz[2],DECIMAL_LIMIT)) + '\n\n' + '(' + str(round(self.xyz[0],DECIMAL_LIMIT)) + ', ' + str(round(self.xyz[1],DECIMAL_LIMIT)) + ', ' + str(round(self.xyz[2],DECIMAL_LIMIT)) + ')') + gg.write("X: " + str(round(self.xyz[0], DECIMAL_LIMIT)) + "\nY: " + str(round(self.xyz[1], DECIMAL_LIMIT)) + "\nZ: " + str(round(self.xyz[2], DECIMAL_LIMIT)) + + '\n\n' + '(' + str(round(self.xyz[0], DECIMAL_LIMIT)) + ', ' + str(round(self.xyz[1], DECIMAL_LIMIT)) + ', ' + str(round(self.xyz[2], DECIMAL_LIMIT)) + ')') bui.screenmessage("Coordinates saved in: " + "BombSquad/Saved XYZ/" + "coords" + c27) if _babase.app.classic.platform == 'android': - _babase.android_media_scan_file(path_aid) + _babase.android_media_scan_file(path_aid) t_ms = bs.time() * 1000 assert isinstance(t_ms, int) if t_ms - self.last_punch_time_ms >= self._punch_cooldown: @@ -69,17 +77,20 @@ def replaceable_punch(self) -> None: self.node.punch_pressed = True if not self.node.hold_node: bs.timer( - 0.1, - bs.WeakCall(self._safe_play_sound, - SpazFactory.get().swish_sound, 0.8)) + 0.1, + bs.WeakCall(self._safe_play_sound, + SpazFactory.get().swish_sound, 0.8)) self._turbo_filter_add_press('punch') # ba_meta export plugin + + class ragingspeedhorn(babase.Plugin): try: - oath = _babase.env()['python_directory_user'] + '/Saved XYZ' - os.makedirs(oath,exist_ok=False) - except: pass + oath = _babase.env()['python_directory_user'] + '/Saved XYZ' + os.makedirs(oath, exist_ok=False) + except: + pass PlayerSpaz.on_punch_press = replaceable_punch PlayerSpaz.__init__ = ShitInit - PlayerSpaz.xyz = 0 \ No newline at end of file + PlayerSpaz.xyz = 0 From 0fd7c5bed18919410c1aad103a69680fc2c08dee Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Thu, 1 Feb 2024 13:07:51 +0300 Subject: [PATCH 21/36] More --- plugins/minigames.json | 20 +- plugins/minigames/flag_day.py | 614 ++++++++++++++++++ plugins/utilities.json | 28 + plugins/utilities/bots_can_accept_powerups.py | 41 ++ plugins/utilities/cheat_menu.py | 355 ++++++++++ 5 files changed, 1055 insertions(+), 3 deletions(-) create mode 100644 plugins/minigames/flag_day.py create mode 100644 plugins/utilities/bots_can_accept_powerups.py create mode 100644 plugins/utilities/cheat_menu.py diff --git a/plugins/minigames.json b/plugins/minigames.json index 4cdc9ce..db4143e 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -1274,7 +1274,7 @@ "1.0.0": null } }, - "extinction_run": { + "extinction": { "description": "Survive the Extinction.", "external_url": "", "authors": [ @@ -1289,8 +1289,8 @@ } }, "fat_pigs": { - "description": "Survive the Extinction.", - "external_url": "Survive the pigs...", + "description": "Survive...", + "external_url": "", "authors": [ { "name": "Zacker Tz", @@ -1301,6 +1301,20 @@ "versions": { "1.0.0": null } + }, + "flag_day": { + "description": "Pick up flags to receive a prize.\nBut beware...", + "external_url": "https://youtu.be/ANDzdBicjA4?si=h8S_TPUAxSaG7nls", + "authors": [ + { + "name": "MattZ45986", + "email": "", + "discord": "" + } + ], + "versions": { + "1.0.0": null + } } } } \ No newline at end of file diff --git a/plugins/minigames/flag_day.py b/plugins/minigames/flag_day.py new file mode 100644 index 0000000..d5d473c --- /dev/null +++ b/plugins/minigames/flag_day.py @@ -0,0 +1,614 @@ + +#Ported by brostos to api 8 +# 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 _babase +import json +import math +import random +from bascenev1lib.game.elimination import Icon +from bascenev1lib.actor.bomb import Bomb, Blast +from bascenev1lib.actor.playerspaz import PlayerSpaz +from bascenev1lib.actor.scoreboard import Scoreboard +from bascenev1lib.actor.powerupbox import PowerupBox +from bascenev1lib.actor.flag import Flag, FlagPickedUpMessage +from bascenev1lib.actor.spazbot import SpazBotSet, BrawlerBotLite, SpazBotDiedMessage + +if TYPE_CHECKING: + from typing import Any, Sequence + + +lang = bs.app.lang.language +if lang == 'Spanish': + name = 'Día de la Bandera' + description = ('Recoge las banderas para recibir un premio.\n' + 'Pero ten cuidado...') + slow_motion_deaths = 'Muertes en Cámara Lenta' + credits = 'Creado por MattZ45986 en Github | Actualizado por byANG3L and brostos' + you_were = 'Estas' + cursed_text = 'MALDITO' + run = 'CORRE' + climb_top = 'Escala a la cima' + bomb_rain = '¡LLUVIA DE BOMBAS!' + lame_guys = 'Chicos Ligeros' + jackpot = '¡PREMIO MAYOR!' + diedtxt = '¡' + diedtxt2 = ' ha sido eliminado!' +else: + name = 'Flag Day' + description = 'Pick up flags to receive a prize.\nBut beware...' + slow_motion_deaths = 'Slow Motion Deaths' + credits = 'Created by MattZ45986 on Github | Updated by byANG3L and brostos' + you_were = 'You were' + cursed_text = 'CURSED' + run = 'RUN' + climb_top = 'Climb to the top' + bomb_rain = 'BOMB RAIN!' + lame_guys = 'Lame Guys' + jackpot = '!JACKPOT!' + diedtxt = '' + diedtxt2 = ' died!' + + +class Icon(Icon): + + def __init__( + self, + player: Player, + position: tuple[float, float], + scale: float, + show_lives: bool = True, + show_death: bool = True, + name_scale: float = 1.0, + name_maxwidth: float = 115.0, + flatness: float = 1.0, + shadow: float = 1.0, + dead: bool = False, + ): + super().__init__(player,position,scale,show_lives,show_death, + name_scale,name_maxwidth,flatness,shadow) + if dead: + self._name_text.opacity = 0.2 + self.node.color = (0.7, 0.3, 0.3) + self.node.opacity = 0.2 + + +class FlagBearer(PlayerSpaz): + def handlemessage(self, msg: Any) -> Any: + super().handlemessage(msg) + if isinstance(msg, bs.PowerupMessage): + activity = self.activity + player = self.getplayer(Player) + if not player.is_alive(): + return + if activity.last_prize == 'curse': + player.team.score += 25 + activity._update_scoreboard() + elif activity.last_prize == 'land_mines': + player.team.score += 15 + activity._update_scoreboard() + self.connect_controls_to_player() + elif activity.last_prize == 'climb': + player.team.score += 50 + activity._update_scoreboard() + if msg.poweruptype == 'health': + activity.round_timer = None + bs.timer(0.2, activity.setup_next_round) + + +class Player(bs.Player['Team']): + """Our player type for this game.""" + + def __init__(self) -> None: + self.dead = False + self.icons: list[Icon] = [] + +class Team(bs.Team[Player]): + """Our team type for this game.""" + + def __init__(self) -> None: + self.score = 0 + + +# ba_meta export bascenev1.GameActivity +class FlagDayGame(bs.TeamGameActivity[Player, Team]): + """A game type based on acquiring kills.""" + + name = name + description = description + + # Print messages when players die since it matters here. + announce_player_deaths = True + + allow_mid_activity_joins = False + + @classmethod + def get_available_settings( + cls, sessiontype: type[bs.Session] + ) -> list[babase.Setting]: + settings = [ + bs.BoolSetting(slow_motion_deaths, default=True), + bs.BoolSetting('Epic Mode', default=False), + ] + return settings + + @classmethod + def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool: + return ( + issubclass(sessiontype, bs.CoopSession) + or issubclass(sessiontype, bs.DualTeamSession) + or issubclass(sessiontype, bs.FreeForAllSession) + ) + + @classmethod + def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]: + return ['Courtyard'] + + def __init__(self, settings: dict): + super().__init__(settings) + self.credits() + self._scoreboard = Scoreboard() + self._dingsound = bui.getsound('dingSmall') + self._epic_mode = bool(settings['Epic Mode']) + self._slow_motion_deaths = bool(settings[slow_motion_deaths]) + self.current_player: Player | None = None + self.prize_recipient: Player | None = None + self.bomb_survivor: Player | None = None + self.bad_guy_cost: int = 0 + self.player_index: int = 0 + self.bombs: list = [] + self.queue_line: list = [] + self._bots: SpazBotSet | None = None + self.light: bs.Node | None = None + self.last_prize = 'none' + self._flag: Flag | None = None + self._flag2: Flag | None = None + self._flag3: Flag | None = None + self._flag4: Flag | None = None + self._flag5: Flag | None = None + self._flag6: Flag | None = None + self._flag7: Flag | None = None + self._flag8: Flag | None = None + self.set = False + self.round_timer: bs.Timer | None = None + self.give_points_timer: bs.Timer | None = None + + self._jackpot_sound = bui.getsound('achievement') + self._round_sound = bui.getsound('powerup01') + self._dingsound = bui.getsound('dingSmall') + + # 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 on_team_join(self, team: Team) -> None: + if self.has_begun(): + self._update_scoreboard() + + def on_player_leave(self, player: Player) -> None: + if player is self.current_player: + self.setup_next_round() + self._check_end_game() + super().on_player_leave(player) + self.queue_line.remove(player) + self._update_icons() + + def on_begin(self) -> None: + super().on_begin() + for player in self.players: + if player.actor: + player.actor.handlemessage(bs.DieMessage()) + player.actor.node.delete() + self.queue_line.append(player) + self.spawn_player_spaz( + self.queue_line[self.player_index % len(self.queue_line)], + (0.0, 3.0, -2.0)) + self.current_player = self.queue_line[0] + # Declare a set of bots (enemies) that we will use later + self._bots = SpazBotSet() + self.reset_flags() + self._update_icons() + self._update_scoreboard() + + def credits(self) -> None: + bs.newnode( + 'text', + attrs={ + 'v_attach': 'bottom', + 'h_align': 'center', + 'vr_depth': 0, + 'color': (0, 0.2, 0), + 'shadow': 1.0, + 'flatness': 1.0, + 'position': (0,0), + 'scale': 0.8, + 'text': credits + }) + + def _update_icons(self) -> None: + # pylint: disable=too-many-branches + for player in self.queue_line: + player.icons = [] + if player == self.current_player: + xval = 0 + x_offs = -78 + player.icons.append( + Icon(player, + position=(xval, 65), + scale=1.0, + name_maxwidth=130, + name_scale=0.8, + flatness=0.0, + shadow=0.5, + show_death=True, + show_lives=False)) + elif player.dead: + xval = 65 + x_offs = 78 + player.icons.append( + Icon(player, + position=(xval, 50), + scale=0.5, + name_maxwidth=75, + name_scale=1.0, + flatness=1.0, + shadow=1.0, + show_death=False, + show_lives=False, + dead=True)) + xval += x_offs * 0.56 + else: + xval = -65 + x_offs = 78 + player.icons.append( + Icon(player, + position=(xval, 50), + 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 + + def give_prize(self, prize: int) -> None: + if prize == 1: + # Curse him aka make him blow up in 5 seconds + # give them a nice message + bs.broadcastmessage(you_were, color=(0.1, 0.1, 0.1)) + bs.broadcastmessage(cursed_text, color=(1.0, 0.0, 0.0)) + self.make_health_box((0.0, 0.0, 0.0)) + self.last_prize = 'curse' + self.prize_recipient.actor.curse() + # bs.timer(5.5, self.setup_next_round) + if prize == 2: + self.setup_rof() + bs.broadcastmessage(run, color=(1.0, 0.2, 0.1)) + self.last_prize = 'ring_of_fire' + if prize == 3: + self.last_prize = 'climb' + self.light = bs.newnode( + 'locator', + attrs={ + 'shape': 'circle', + 'position': (0.0, 3.0, -9.0), + 'color': (1.0, 1.0, 1.0), + 'opacity': 1.0, + 'draw_beauty': True, + 'additive': True + }) + bs.broadcastmessage(climb_top, color=(0.5, 0.5, 0.5)) + bs.timer(3.0, babase.Call(self.make_health_box, (0.0, 6.0, -9.0))) + self.round_timer = bs.Timer(10.0, self.setup_next_round) + if prize == 4: + self.last_prize = 'land_mines' + self.make_health_box((6.0, 5.0, -2.0)) + self.make_land_mines() + self.prize_recipient.actor.connect_controls_to_player( + enable_bomb=False) + self.prize_recipient.actor.node.handlemessage( + bs.StandMessage(position=(-6.0, 3.0, -2.0))) + self.round_timer = bs.Timer(7.0, self.setup_next_round) + if prize == 5: + # Make it rain bombs + self.bomb_survivor = self.prize_recipient + bs.broadcastmessage(bomb_rain, color=(1.0, 0.5, 0.16)) + # Set positions for the bombs to drop + for bzz in range(-5,6): + for azz in range(-5,2): + # for each position make a bomb drop there + self.make_bomb(bzz, azz) + self.give_points_timer = bs.Timer(3.3, self.give_points) + self.last_prize = 'bombrain' + if prize == 6: + self.setup_br() + self.bomb_survivor = self.prize_recipient + self.give_points_timer = bs.Timer(7.0, self.give_points) + self.last_prize = 'bombroad' + if prize == 7: + # makes killing a bad guy worth ten points + self.bad_guy_cost = 2 + bs.broadcastmessage(lame_guys, color=(1.0, 0.5, 0.16)) + # makes a set of nine positions + for a in range(-1, 2): + for b in range(-3, 0): + # and spawns one in each position + self._bots.spawn_bot(BrawlerBotLite, pos=(a, 2.5, b)) + # and we give our player boxing gloves and a shield + self._player.equip_boxing_gloves() + self._player.equip_shields() + self.last_prize = 'lameguys' + if prize == 8: + self._jackpot_sound.play() + bs.broadcastmessage(jackpot, color=(1.0, 0.0, 0.0)) + bs.broadcastmessage(jackpot, color=(0.0, 1.0, 0.0)) + bs.broadcastmessage(jackpot, color=(0.0, 0.0, 1.0)) + team = self.prize_recipient.team + # GIVE THEM A WHOPPING 50 POINTS!!! + team.score += 50 + # and update the scores + self._update_scoreboard() + self.last_prize = 'jackpot' + bs.timer(2.0, self.setup_next_round) + + def setup_next_round(self) -> None: + if self._slow_motion_deaths: + bs.getactivity().globalsnode.slow_motion = False + if self.set: + return + if self.light: + self.light.delete() + for bomb in self.bombs: + bomb.handlemessage(bs.DieMessage()) + self.kill_flags() + self._bots.clear() + self.reset_flags() + self.current_player.actor.handlemessage( + bs.DieMessage(how='game')) + self.current_player.actor.node.delete() + c = 0 + self.player_index += 1 + self.player_index %= len(self.queue_line) + if len(self.queue_line) > 0: + while self.queue_line[self.player_index].dead: + if c > len(self.queue_line): + return + self.player_index += 1 + self.player_index %= len(self.queue_line) + c += 1 + self.spawn_player_spaz( + self.queue_line[self.player_index], (0.0, 3.0, -2.0)) + self.current_player = self.queue_line[self.player_index] + self.last_prize = 'none' + self._update_icons() + + def check_bots(self) -> None: + if not self._bots.have_living_bots(): + self.setup_next_round() + + def make_land_mines(self) -> None: + self.bombs = [] + for i in range(-11, 7): + self.bombs.append(Bomb( + position=(0.0, 6.0, i/2.0), + bomb_type='land_mine', + blast_radius=2.0)) + self.bombs[i+10].arm() + + def give_points(self) -> None: + if self.bomb_survivor is not None and self.bomb_survivor.is_alive(): + self.bomb_survivor.team.score += 20 + self._update_scoreboard() + self.round_timer = bs.Timer(1.0, self.setup_next_round) + + def make_health_box(self, position: Sequence[float]) -> None: + if position == (0.0, 3.0, 0.0): + position = (random.randint(-6, 6), 6, random.randint(-6, 4)) + elif position == (0,0,0): + position = random.choice( + ((-7, 6, -5), (7, 6, -5), (-7, 6, 1), (7, 6, 1))) + self.health_box = PowerupBox( + position=position, poweruptype='health').autoretain() + + # called in prize #5 + def make_bomb(self, xpos: float, zpos: float) -> None: + # makes a bomb at the given position then auto-retains it aka: + # makes sure it doesn't disappear because there is no reference to it + self.bombs.append(Bomb(position=(xpos, 12, zpos))) + + def setup_br(self) -> None: + self.make_bomb_row(6) + self.prize_recipient.actor.handlemessage( + bs.StandMessage(position=(6.0, 3.0, -2.0))) + + def make_bomb_row(self, num: int) -> None: + if not self.prize_recipient.is_alive(): + return + if num == 0: + self.round_timer = bs.Timer(1.0, self.setup_next_round) + return + for i in range(-11, 7): + self.bombs.append( + Bomb(position=(-3, 3, i/2.0), + velocity=(12, 0.0, 0.0), + bomb_type='normal', + blast_radius=1.2)) + bs.timer(1.0, babase.Call(self.make_bomb_row, num-1)) + + def setup_rof(self) -> None: + self.make_blast_ring(10) + self.prize_recipient.actor.handlemessage( + bs.StandMessage(position=(0.0, 3.0, -2.0))) + + def make_blast_ring(self, length: float) -> None: + if not self.prize_recipient.is_alive(): + return + if length == 0: + self.setup_next_round() + self.prize_recipient.team.score += 50 + self._update_scoreboard() + return + for angle in range(0, 360, 45): + angle += random.randint(0, 45) + angle %= 360 + x = length * math.cos(math.radians(angle)) + z = length * math.sin(math.radians(angle)) + blast = Blast(position=(x, 2.2, z-2), blast_radius=3.5) + bs.timer(0.75, babase.Call(self.make_blast_ring, length-1)) + + # a method to remake the flags + def reset_flags(self) -> None: + # remake the flags + self._flag = Flag( + position=(0.0, 3.0, 1.0), touchable=True, color=(0.0, 0.0, 1.0)) + self._flag2 = Flag( + position=(0.0, 3.0, -5.0), touchable=True, color=(1.0, 0.0, 0.0)) + self._flag3 = Flag( + position=(3.0, 3.0, -2.0), touchable=True, color=(0.0, 1.0, 0.0)) + self._flag4 = Flag( + position=(-3.0, 3.0, -2.0), touchable=True, color=(1.0, 1.0, 1.0)) + self._flag5 = Flag( + position=(1.8, 3.0, 0.2), touchable=True, color=(0.0, 1.0, 1.0)) + self._flag6 = Flag( + position=(-1.8, 3.0, 0.2), touchable=True, color=(1.0, 0.0, 1.0)) + self._flag7 = Flag( + position=(1.8, 3.0, -3.8), touchable=True, color=(1.0, 1.0, 0.0)) + self._flag8 = Flag( + position=(-1.8, 3.0, -3.8), touchable=True, color=(0.0, 0.0, 0.0)) + + # a method to kill the flags + def kill_flags(self) -> None: + # destroy all the flags by erasing all references to them, + # indicated by None similar to null + self._flag.node.delete() + self._flag2.node.delete() + self._flag3.node.delete() + self._flag4.node.delete() + self._flag5.node.delete() # 132, 210 ,12 + self._flag6.node.delete() + self._flag7.node.delete() + self._flag8.node.delete() + + def _check_end_game(self) -> None: + for player in self.queue_line: + if not player.dead: + return + self.end_game() + + def spawn_player_spaz( + self, + player: PlayerT, + position: Sequence[float] = (0, 0, 0), + angle: float | None = None, + ) -> PlayerSpaz: + from babase import _math + from bascenev1._gameutils import animate + from bascenev1._coopsession import CoopSession + + angle = None + 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 = FlagBearer(color=color, + highlight=highlight, + character=player.character, + player=player) + + player.actor = spaz + assert spaz.node + + 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') + animate(light, 'intensity', {0: 0, 0.25: 1, 0.5: 0}) + bs.timer(0.5, light.delete) + return spaz + + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, bs.PlayerDiedMessage): + # give them a nice farewell + if bs.time() < 0.5: + return + if msg.how == 'game': + return + player = msg.getplayer(Player) + bs.broadcastmessage( + diedtxt + str(player.getname()) + diedtxt2, color=player.color) + player.dead = True + if player is self.current_player: + self.round_timer = None + self.give_points_timer = None + if not msg.how is bs.DeathType.FALL: + if self._slow_motion_deaths: + bs.getactivity().globalsnode.slow_motion = True + time = 0.5 + else: + time = 0.01 + # check to see if we can end the game + self._check_end_game() + bs.timer(time, self.setup_next_round) + elif isinstance(msg, FlagPickedUpMessage): + msg.flag.last_player_to_hold = msg.node.getdelegate( + FlagBearer, True + ).getplayer(Player, True) + self._player = msg.node.getdelegate( + FlagBearer, True + ) + self.prize_recipient = msg.node.getdelegate( + FlagBearer, True + ).getplayer(Player, True) + self.kill_flags() + self.give_prize(random.randint(1, 8)) + self._round_sound.play() + self.current_player = self.prize_recipient + elif isinstance(msg, SpazBotDiedMessage): + # find out which team the last person to hold a flag was on + team = self.prize_recipient.team + # give them their points + team.score += self.bad_guy_cost + self._dingsound.play(0.5) + # update the scores + for team in self.teams: + self._scoreboard.set_team_value(team, team.score) + bs.timer(0.3, self.check_bots) + return None + + def _update_scoreboard(self) -> None: + for player in self.queue_line: + if not player.dead: + if player.team.score > 0: + self._dingsound.play() + self._scoreboard.set_team_value(player.team, player.team.score) + + def end_game(self) -> None: + if self.set: + return + self.set = True + results = bs.GameResults() + for team in self.teams: + results.set_team_score(team, team.score) + self.end(results=results) diff --git a/plugins/utilities.json b/plugins/utilities.json index 0a5c094..b5f63eb 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -1175,6 +1175,34 @@ "versions": { "1.0.0": null } + }, + "bots_can_accept_powerups": { + "description": "Bots can steal your powerups", + "external_url": "", + "authors": [ + { + "name": "", + "email": "", + "discord": "" + } + ], + "versions": { + "1.0.0": null + } + }, + "cheat_menu": { + "description": "Cheat menu on the settings window", + "external_url": "", + "authors": [ + { + "name": "pranav", + "email": "", + "discord": "" + } + ], + "versions": { + "1.0.0": null + } } } } \ No newline at end of file diff --git a/plugins/utilities/bots_can_accept_powerups.py b/plugins/utilities/bots_can_accept_powerups.py new file mode 100644 index 0000000..7c00f67 --- /dev/null +++ b/plugins/utilities/bots_can_accept_powerups.py @@ -0,0 +1,41 @@ +# Ported to api 8 by brostos using baport.(https://github.com/bombsquad-community/baport) +# 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.spazbot import SpazBot +from bascenev1lib.actor.powerupbox import PowerupBoxFactory + +if TYPE_CHECKING: + pass + + +# ba_meta export plugin +class BotsCanAcceptPowerupsPlugin(babase.Plugin): + def on_app_running(self) -> None: + SpazBot.oldinit = SpazBot.__init__ + def __init__(self) -> None: + self.oldinit() + pam = PowerupBoxFactory.get().powerup_accept_material + materials = self.node.materials + materials = list(materials) + materials.append(pam) + materials = tuple(materials) + self.node.materials = materials + roller_materials = self.node.roller_materials + roller_materials = list(roller_materials) + roller_materials.append(pam) + roller_materials = tuple(roller_materials) + self.node.roller_materials = roller_materials + extras_material = self.node.extras_material + extras_material = list(extras_material) + extras_material.append(pam) + extras_material = tuple(extras_material) + self.node.extras_material = extras_material + SpazBot.__init__ = __init__ diff --git a/plugins/utilities/cheat_menu.py b/plugins/utilities/cheat_menu.py new file mode 100644 index 0000000..8648dea --- /dev/null +++ b/plugins/utilities/cheat_menu.py @@ -0,0 +1,355 @@ +# Ported by brostos to api 8 +# Tool used to make porting easier.(https://github.com/bombsquad-community/baport) +"""CheatMenu | now cheat much as you can haha!! please eric sir dont kill me + + +Credits To: +Pranav"Modder"= Creator of the mod. +Emily"Skin and Modder"= Code and Mod Ideas.(pls dont be angry) :"( +And Me(Edited): Well Litterally Nothing lol. + +Important Note From the Creator: "I apreciate any kind of modification. So feel free to use or edit code or change credit string.... no problem. +this mod uses activity loop cheacks if change in config and update it on our player node" + +Really Awesome servers: + Bombsquad Consultancy Service - https://discord.gg/2RKd9QQdQY. + bombspot - https://discord.gg/ucyaesh. + cyclones - https://discord.gg/pJXxkbQ7kH. +""" +from __future__ import annotations + +__author__ = 'egg' +__version__ = 1.0 + +import babase +import bauiv1 as bui +import bascenev1 as bs +import _babase + +from baenv import TARGET_BALLISTICA_BUILD as build_number +from bauiv1lib.settings.allsettings import AllSettingsWindow +from bascenev1lib.actor.spaz import Spaz + +from typing import ( + Text, + Tuple, + Optional, + Union, + get_args +) +type + +# Default Confings/Settings +CONFIG = "CheatMenu" +APPCONFIG = babase.app.config +Configs = { + "Unlimited Heath": False, + "SpeedBoots": False, + "Fly": False, + "SuperPunch": False, + "ImpactOnly": False, + "StickyOnly": False, + "IceOnly" : False, + "Infinite Bombs": False, + "More Are Coming": False, + "Credits": False, +} + + +def setconfigs() -> None: + """Set required defualt configs for mod""" + if CONFIG not in APPCONFIG: + APPCONFIG[str(CONFIG)] = Configs + + for c in Configs: + if c not in APPCONFIG[str(CONFIG)]: + APPCONFIG[str(CONFIG)][str(c)] = Configs[str(c)] + else: + pass + APPCONFIG.apply_and_commit() + + +def update_config(config: str, change: any): + """update's given value in json config file of pluguin""" + APPCONFIG[str(CONFIG)][str(config)] = change + APPCONFIG.apply_and_commit() + + +# ba_meta require api 8 +# ba_meta export plugin +class Plugin(babase.Plugin): + def on_app_running(self) -> None: + if babase.app.build_number if build_number < 21282 else babase.app.env.build_number: + setconfigs() + self.overwrite() + + else: + babase.screenmessage(f'{__name__} only works on api 8') + + def overwrite(self) -> None: + AllSettingsWindow.init = AllSettingsWindow.__init__ + AllSettingsWindow.__init__ = AllSettingsWindowInit + + +# creating Cheat button, start button +def AllSettingsWindowInit(self, transition: str = 'in_right', origin_widget: bui.Widget = None): + self.init(transition) + + uiscale = bui.app.ui_v1.uiscale + btn_width = 720 if uiscale is babase.UIScale.SMALL else 400 + btn_height = 380 + + self.cheat_menu_btn = bui.buttonwidget( + parent=self._root_widget, + autoselect=True, + position=(btn_width, btn_height), + size=(105, 50), + icon=bui.gettexture('settingsIcon'), + label='Cheats', + button_type='square', + text_scale=1.2, + on_activate_call=babase.Call( + on_cheat_menu_btn_press, self)) + + +# on cheat button press call Window +def on_cheat_menu_btn_press(self): + bui.containerwidget(edit=self._root_widget, + transition='out_scale') + bui.app.ui_v1.set_main_menu_window( + CheatMenuWindow( + transition='in_right').get_root_widget(), from_window=self._root_widget) + + +class CheatMenuWindow(bui.Window): + def __init__(self, + transition: Optional[str] = 'in_right') -> None: + + # background window, main widget parameters + uiscale = bui.app.ui_v1.uiscale + self._width = 870.0 if uiscale is babase.UIScale.SMALL else 670.0 + self._height = (390.0 if uiscale is babase.UIScale.SMALL else + 450.0 if uiscale is babase.UIScale.MEDIUM else 520.0) + extra_x = 100 if uiscale is babase.UIScale.SMALL else 0 + self.extra_x = extra_x + top_extra = 20 if uiscale is babase.UIScale.SMALL else 0 + + # scroll widget parameters + self._scroll_width = self._width - (100 + 2 * extra_x) + self._scroll_height = self._height - 115.0 + self._sub_width = self._scroll_width * 0.95 + self._sub_height = 640.0 + self._spacing = 32 + self._extra_button_spacing = self._spacing * 2.5 + + super().__init__( + root_widget=bui.containerwidget( + size=(self._width, self._height), + transition=transition, + scale=(2.06 if uiscale is babase.UIScale.SMALL else + 1.4 if uiscale is babase.UIScale.MEDIUM else 1.0))) + + # back button widget + self._back_button = bui.buttonwidget( + parent=self._root_widget, + autoselect=True, + position=(52 + self.extra_x, + self._height - 60 - top_extra), + size=(60, 60), + scale=0.8, + label=babase.charstr(babase.SpecialChar.BACK), + button_type='backSmall', + on_activate_call=self._back) + bui.containerwidget(edit=self._root_widget, + cancel_button=self._back_button) + + # window title, apears in top center of window + self._title_text = bui.textwidget( + parent=self._root_widget, + position=(0, self._height - 40 - top_extra), + size=(self._width, 25), + text='Cheat Menu', + color=bui.app.ui_v1.title_color, + scale=1.2, + h_align='center', + v_align='top') + + self._scrollwidget = bui.scrollwidget( + parent=self._root_widget, + position=(50 + extra_x, 50 - top_extra), + simple_culling_v=20.0, + highlight=False, + size=(self._scroll_width, + self._scroll_height), + selection_loops_to_parent=True) + bui.widget(edit=self._scrollwidget, + right_widget=self._scrollwidget) + + # subcontainer represents scroll widget and used as parent + self._subcontainer = bui.containerwidget( + parent=self._scrollwidget, + size=(self._sub_width, + self._sub_height), + background=False, + selection_loops_to_parent=True) + + v = self._sub_height - 35 + v -= self._spacing * 1.2 + conf = APPCONFIG[str(CONFIG)] + + for checkbox in Configs: + bui.checkboxwidget( + parent=self._subcontainer, + autoselect=True, + position=(25.0, v), + size=(40, 40), + text=checkbox, + textcolor=(0.8, 0.8, 0.8), + value=APPCONFIG[CONFIG][checkbox], + on_value_change_call=babase.Call( + self.update, checkbox), + scale=1.4, + maxwidth=430) + v -= 70 + + def update(self, config: str, change) -> None: + """Change config and get our sounds + + Args: + config: str + change: any + """ + try: + if change == True and config == "Fly": + bui.screenmessage("Some maps may not work good for flying", + color=(1, 0, 0)) + update_config(config, change) + bui.getsound('gunCocking').play() + except Exception: + bui.screenmessage("error", color=(1, 0, 0)) + bui.getsound('error').play() + + try: + if change == True and config == "SuperPunch": + bui.screenmessage("SuperPunch Activated", + color=(1, 0, 0)) + elif change == False and config == "SuperPunch": + bui.screenmessage("Super Punch Deactivated", + color=(0.5,0,0)) + update_config(config, change) + bui.getsound('gunCocking').play() + except Exception: + bui.screenmessage("error", color=(1, 0, 0)) + bui.getsound('spazOw').play() + + try: + if change == True and config == "IceOnly": + bui.screenmessage("Ice Bombs Activated", + color=(0.1, 1, 1)) + elif change == False and config == "IceOnly": + bui.screenmessage("Ice Bombs Deactivated", + color=(1, 0, 0)) + update_config(config, change) + bui.getsound('gunCocking').play() + except Exception: + bui.screenmessage("error", color=(1, 0, 0)) + bui.getsound('spazOw').play() + try: + if change == True and config == "StickyOnly": + bui.screenmessage("Sticky Bombs Activated", + color=(0, 1, 0)) + elif change == False and config == "StickyOnly": + bui.screenmessage("Sticky Bombs Deactivated", + color=(1, 0, 0)) + update_config(config, change) + bui.getsound('gunCocking').play() + except Exception: + bui.screenmessage("error", color=(1, 0, 0)) + bui.getsound('spazOw').play() + + try: + if change == True and config == "ImpactOnly": + bui.screenmessage("Impact Bombs Activated", + color=(0.5, 0.5, 0.5)) + elif change == False and config == "ImpactOnly": + bui.screenmessage("Impact Bombs Deactivated", + color=(1, 0, 0)) + update_config(config, change) + bui.getsound('gunCocking').play() + except Exception: + bui.screenmessage("error", color=(1, 0, 0)) + bui.getsound('spazOw').play() + + try: + if change == True and config == "More Are Coming": + bui.screenmessage("Check out https://discord.gg/2RKd9QQdQY For More Mods", + color=(4, 9, 2)) + update_config(config, change) + bui.getsound('gunCocking').play() + except Exception: + bui.screenmessage("error", color=(1, 0, 0)) + bui.getsound('cheer').play() + + try: + if change == True and config == "Credits": + bui.screenmessage("To Pranav Made The Mod and Emily For Ideas, Thx", + color=(4, 9, 2)) + update_config(config, change) + bui.getsound('gunCocking').play() + except Exception: + bui.screenmessage("error", color=(1, 0, 0)) + bui.getsound('cheer').play() + + def _back(self) -> None: + """Kill the window and get back to previous one + """ + bui.containerwidget(edit=self._root_widget, + transition='out_scale') + bui.app.ui_v1.set_main_menu_window( + AllSettingsWindow( + transition='in_left').get_root_widget(), from_window=self._root_widget) + + +def ishost(): + session = bs.get_foreground_host_session() + with session.context: + for player in session.sessionplayers: + if player.inputdevice.client_id == -1: + return True + +def activity_loop(): + if bs.get_foreground_host_activity() is not None: + activity = bs.get_foreground_host_activity() + with activity.context: + for player in activity.players: + if not ishost() or not player.actor: + return + config = APPCONFIG[CONFIG] + + player.actor.node.invincible = config["Unlimited Heath"] + player.actor.node.fly = config["Fly"] + player.actor.node.hockey = config["SpeedBoots"] + + if config["SuperPunch"]: + player.actor._punch_power_scale = 2 + + elif not config["SuperPunch"]: + player.actor._punch_power_scale = 1.2 + + if config["IceOnly"]: + player.actor.bomb_type = 'ice' + elif not config["IceOnly"]: + player.actor.bomb_type = 'normal' + player.actor.bomb_count= 1 + + if config["ImpactOnly"]: + player.actor.bomb_type = 'impact' + player.actor.bomb_count = 1 + + if config["StickyOnly"]: + player.actor.bomb_type = 'sticky' + player.actor.bomb_count = 1 + + if config["Infinite Bombs"]: + player.actor.bomb_count = 100 +timer = babase.AppTimer(2, activity_loop,repeat=True) \ No newline at end of file From 4941d0cb0e208fbf794f7ef47c2ba5caad41d058 Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Thu, 1 Feb 2024 10:09:19 +0000 Subject: [PATCH 22/36] [ci] auto-format --- plugins/minigames/flag_day.py | 1059 +++++++++-------- plugins/utilities/bots_can_accept_powerups.py | 1 + plugins/utilities/cheat_menu.py | 67 +- 3 files changed, 566 insertions(+), 561 deletions(-) diff --git a/plugins/minigames/flag_day.py b/plugins/minigames/flag_day.py index d5d473c..534ec6f 100644 --- a/plugins/minigames/flag_day.py +++ b/plugins/minigames/flag_day.py @@ -1,5 +1,5 @@ -#Ported by brostos to api 8 +# Ported by brostos to api 8 # ba_meta require api 8 # (see https://ballistica.net/wiki/meta-tag-system) @@ -23,592 +23,593 @@ from bascenev1lib.actor.flag import Flag, FlagPickedUpMessage from bascenev1lib.actor.spazbot import SpazBotSet, BrawlerBotLite, SpazBotDiedMessage if TYPE_CHECKING: - from typing import Any, Sequence + from typing import Any, Sequence lang = bs.app.lang.language if lang == 'Spanish': - name = 'Día de la Bandera' - description = ('Recoge las banderas para recibir un premio.\n' - 'Pero ten cuidado...') - slow_motion_deaths = 'Muertes en Cámara Lenta' - credits = 'Creado por MattZ45986 en Github | Actualizado por byANG3L and brostos' - you_were = 'Estas' - cursed_text = 'MALDITO' - run = 'CORRE' - climb_top = 'Escala a la cima' - bomb_rain = '¡LLUVIA DE BOMBAS!' - lame_guys = 'Chicos Ligeros' - jackpot = '¡PREMIO MAYOR!' - diedtxt = '¡' - diedtxt2 = ' ha sido eliminado!' + name = 'Día de la Bandera' + description = ('Recoge las banderas para recibir un premio.\n' + 'Pero ten cuidado...') + slow_motion_deaths = 'Muertes en Cámara Lenta' + credits = 'Creado por MattZ45986 en Github | Actualizado por byANG3L and brostos' + you_were = 'Estas' + cursed_text = 'MALDITO' + run = 'CORRE' + climb_top = 'Escala a la cima' + bomb_rain = '¡LLUVIA DE BOMBAS!' + lame_guys = 'Chicos Ligeros' + jackpot = '¡PREMIO MAYOR!' + diedtxt = '¡' + diedtxt2 = ' ha sido eliminado!' else: - name = 'Flag Day' - description = 'Pick up flags to receive a prize.\nBut beware...' - slow_motion_deaths = 'Slow Motion Deaths' - credits = 'Created by MattZ45986 on Github | Updated by byANG3L and brostos' - you_were = 'You were' - cursed_text = 'CURSED' - run = 'RUN' - climb_top = 'Climb to the top' - bomb_rain = 'BOMB RAIN!' - lame_guys = 'Lame Guys' - jackpot = '!JACKPOT!' - diedtxt = '' - diedtxt2 = ' died!' + name = 'Flag Day' + description = 'Pick up flags to receive a prize.\nBut beware...' + slow_motion_deaths = 'Slow Motion Deaths' + credits = 'Created by MattZ45986 on Github | Updated by byANG3L and brostos' + you_were = 'You were' + cursed_text = 'CURSED' + run = 'RUN' + climb_top = 'Climb to the top' + bomb_rain = 'BOMB RAIN!' + lame_guys = 'Lame Guys' + jackpot = '!JACKPOT!' + diedtxt = '' + diedtxt2 = ' died!' class Icon(Icon): - def __init__( - self, - player: Player, - position: tuple[float, float], - scale: float, - show_lives: bool = True, - show_death: bool = True, - name_scale: float = 1.0, - name_maxwidth: float = 115.0, - flatness: float = 1.0, - shadow: float = 1.0, - dead: bool = False, - ): - super().__init__(player,position,scale,show_lives,show_death, - name_scale,name_maxwidth,flatness,shadow) - if dead: - self._name_text.opacity = 0.2 - self.node.color = (0.7, 0.3, 0.3) - self.node.opacity = 0.2 + def __init__( + self, + player: Player, + position: tuple[float, float], + scale: float, + show_lives: bool = True, + show_death: bool = True, + name_scale: float = 1.0, + name_maxwidth: float = 115.0, + flatness: float = 1.0, + shadow: float = 1.0, + dead: bool = False, + ): + super().__init__(player, position, scale, show_lives, show_death, + name_scale, name_maxwidth, flatness, shadow) + if dead: + self._name_text.opacity = 0.2 + self.node.color = (0.7, 0.3, 0.3) + self.node.opacity = 0.2 class FlagBearer(PlayerSpaz): - def handlemessage(self, msg: Any) -> Any: - super().handlemessage(msg) - if isinstance(msg, bs.PowerupMessage): - activity = self.activity - player = self.getplayer(Player) - if not player.is_alive(): - return - if activity.last_prize == 'curse': - player.team.score += 25 - activity._update_scoreboard() - elif activity.last_prize == 'land_mines': - player.team.score += 15 - activity._update_scoreboard() - self.connect_controls_to_player() - elif activity.last_prize == 'climb': - player.team.score += 50 - activity._update_scoreboard() - if msg.poweruptype == 'health': - activity.round_timer = None - bs.timer(0.2, activity.setup_next_round) + def handlemessage(self, msg: Any) -> Any: + super().handlemessage(msg) + if isinstance(msg, bs.PowerupMessage): + activity = self.activity + player = self.getplayer(Player) + if not player.is_alive(): + return + if activity.last_prize == 'curse': + player.team.score += 25 + activity._update_scoreboard() + elif activity.last_prize == 'land_mines': + player.team.score += 15 + activity._update_scoreboard() + self.connect_controls_to_player() + elif activity.last_prize == 'climb': + player.team.score += 50 + activity._update_scoreboard() + if msg.poweruptype == 'health': + activity.round_timer = None + bs.timer(0.2, activity.setup_next_round) class Player(bs.Player['Team']): - """Our player type for this game.""" + """Our player type for this game.""" + + def __init__(self) -> None: + self.dead = False + self.icons: list[Icon] = [] - def __init__(self) -> None: - self.dead = False - self.icons: list[Icon] = [] class Team(bs.Team[Player]): - """Our team type for this game.""" + """Our team type for this game.""" - def __init__(self) -> None: - self.score = 0 + def __init__(self) -> None: + self.score = 0 # ba_meta export bascenev1.GameActivity class FlagDayGame(bs.TeamGameActivity[Player, Team]): - """A game type based on acquiring kills.""" + """A game type based on acquiring kills.""" - name = name - description = description + name = name + description = description - # Print messages when players die since it matters here. - announce_player_deaths = True + # Print messages when players die since it matters here. + announce_player_deaths = True - allow_mid_activity_joins = False + allow_mid_activity_joins = False - @classmethod - def get_available_settings( - cls, sessiontype: type[bs.Session] - ) -> list[babase.Setting]: - settings = [ - bs.BoolSetting(slow_motion_deaths, default=True), - bs.BoolSetting('Epic Mode', default=False), - ] - return settings + @classmethod + def get_available_settings( + cls, sessiontype: type[bs.Session] + ) -> list[babase.Setting]: + settings = [ + bs.BoolSetting(slow_motion_deaths, default=True), + bs.BoolSetting('Epic Mode', default=False), + ] + return settings - @classmethod - def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool: - return ( - issubclass(sessiontype, bs.CoopSession) - or issubclass(sessiontype, bs.DualTeamSession) - or issubclass(sessiontype, bs.FreeForAllSession) - ) + @classmethod + def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool: + return ( + issubclass(sessiontype, bs.CoopSession) + or issubclass(sessiontype, bs.DualTeamSession) + or issubclass(sessiontype, bs.FreeForAllSession) + ) - @classmethod - def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]: - return ['Courtyard'] + @classmethod + def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]: + return ['Courtyard'] - def __init__(self, settings: dict): - super().__init__(settings) - self.credits() - self._scoreboard = Scoreboard() - self._dingsound = bui.getsound('dingSmall') - self._epic_mode = bool(settings['Epic Mode']) - self._slow_motion_deaths = bool(settings[slow_motion_deaths]) - self.current_player: Player | None = None - self.prize_recipient: Player | None = None - self.bomb_survivor: Player | None = None - self.bad_guy_cost: int = 0 - self.player_index: int = 0 - self.bombs: list = [] - self.queue_line: list = [] - self._bots: SpazBotSet | None = None - self.light: bs.Node | None = None - self.last_prize = 'none' - self._flag: Flag | None = None - self._flag2: Flag | None = None - self._flag3: Flag | None = None - self._flag4: Flag | None = None - self._flag5: Flag | None = None - self._flag6: Flag | None = None - self._flag7: Flag | None = None - self._flag8: Flag | None = None - self.set = False - self.round_timer: bs.Timer | None = None - self.give_points_timer: bs.Timer | None = None + def __init__(self, settings: dict): + super().__init__(settings) + self.credits() + self._scoreboard = Scoreboard() + self._dingsound = bui.getsound('dingSmall') + self._epic_mode = bool(settings['Epic Mode']) + self._slow_motion_deaths = bool(settings[slow_motion_deaths]) + self.current_player: Player | None = None + self.prize_recipient: Player | None = None + self.bomb_survivor: Player | None = None + self.bad_guy_cost: int = 0 + self.player_index: int = 0 + self.bombs: list = [] + self.queue_line: list = [] + self._bots: SpazBotSet | None = None + self.light: bs.Node | None = None + self.last_prize = 'none' + self._flag: Flag | None = None + self._flag2: Flag | None = None + self._flag3: Flag | None = None + self._flag4: Flag | None = None + self._flag5: Flag | None = None + self._flag6: Flag | None = None + self._flag7: Flag | None = None + self._flag8: Flag | None = None + self.set = False + self.round_timer: bs.Timer | None = None + self.give_points_timer: bs.Timer | None = None - self._jackpot_sound = bui.getsound('achievement') - self._round_sound = bui.getsound('powerup01') - self._dingsound = bui.getsound('dingSmall') + self._jackpot_sound = bui.getsound('achievement') + self._round_sound = bui.getsound('powerup01') + self._dingsound = bui.getsound('dingSmall') - # 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 - ) + # 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 on_team_join(self, team: Team) -> None: - if self.has_begun(): - self._update_scoreboard() + def on_team_join(self, team: Team) -> None: + if self.has_begun(): + self._update_scoreboard() - def on_player_leave(self, player: Player) -> None: - if player is self.current_player: - self.setup_next_round() - self._check_end_game() - super().on_player_leave(player) - self.queue_line.remove(player) - self._update_icons() + def on_player_leave(self, player: Player) -> None: + if player is self.current_player: + self.setup_next_round() + self._check_end_game() + super().on_player_leave(player) + self.queue_line.remove(player) + self._update_icons() - def on_begin(self) -> None: - super().on_begin() - for player in self.players: - if player.actor: - player.actor.handlemessage(bs.DieMessage()) - player.actor.node.delete() - self.queue_line.append(player) - self.spawn_player_spaz( - self.queue_line[self.player_index % len(self.queue_line)], - (0.0, 3.0, -2.0)) - self.current_player = self.queue_line[0] - # Declare a set of bots (enemies) that we will use later - self._bots = SpazBotSet() - self.reset_flags() - self._update_icons() - self._update_scoreboard() + def on_begin(self) -> None: + super().on_begin() + for player in self.players: + if player.actor: + player.actor.handlemessage(bs.DieMessage()) + player.actor.node.delete() + self.queue_line.append(player) + self.spawn_player_spaz( + self.queue_line[self.player_index % len(self.queue_line)], + (0.0, 3.0, -2.0)) + self.current_player = self.queue_line[0] + # Declare a set of bots (enemies) that we will use later + self._bots = SpazBotSet() + self.reset_flags() + self._update_icons() + self._update_scoreboard() - def credits(self) -> None: - bs.newnode( - 'text', - attrs={ - 'v_attach': 'bottom', - 'h_align': 'center', - 'vr_depth': 0, - 'color': (0, 0.2, 0), - 'shadow': 1.0, - 'flatness': 1.0, - 'position': (0,0), - 'scale': 0.8, - 'text': credits - }) + def credits(self) -> None: + bs.newnode( + 'text', + attrs={ + 'v_attach': 'bottom', + 'h_align': 'center', + 'vr_depth': 0, + 'color': (0, 0.2, 0), + 'shadow': 1.0, + 'flatness': 1.0, + 'position': (0, 0), + 'scale': 0.8, + 'text': credits + }) - def _update_icons(self) -> None: - # pylint: disable=too-many-branches - for player in self.queue_line: - player.icons = [] - if player == self.current_player: - xval = 0 - x_offs = -78 - player.icons.append( - Icon(player, - position=(xval, 65), - scale=1.0, - name_maxwidth=130, - name_scale=0.8, - flatness=0.0, - shadow=0.5, - show_death=True, - show_lives=False)) - elif player.dead: - xval = 65 - x_offs = 78 - player.icons.append( - Icon(player, - position=(xval, 50), - scale=0.5, - name_maxwidth=75, - name_scale=1.0, - flatness=1.0, - shadow=1.0, - show_death=False, - show_lives=False, - dead=True)) - xval += x_offs * 0.56 - else: - xval = -65 - x_offs = 78 - player.icons.append( - Icon(player, - position=(xval, 50), - 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 + def _update_icons(self) -> None: + # pylint: disable=too-many-branches + for player in self.queue_line: + player.icons = [] + if player == self.current_player: + xval = 0 + x_offs = -78 + player.icons.append( + Icon(player, + position=(xval, 65), + scale=1.0, + name_maxwidth=130, + name_scale=0.8, + flatness=0.0, + shadow=0.5, + show_death=True, + show_lives=False)) + elif player.dead: + xval = 65 + x_offs = 78 + player.icons.append( + Icon(player, + position=(xval, 50), + scale=0.5, + name_maxwidth=75, + name_scale=1.0, + flatness=1.0, + shadow=1.0, + show_death=False, + show_lives=False, + dead=True)) + xval += x_offs * 0.56 + else: + xval = -65 + x_offs = 78 + player.icons.append( + Icon(player, + position=(xval, 50), + 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 - def give_prize(self, prize: int) -> None: - if prize == 1: - # Curse him aka make him blow up in 5 seconds - # give them a nice message - bs.broadcastmessage(you_were, color=(0.1, 0.1, 0.1)) - bs.broadcastmessage(cursed_text, color=(1.0, 0.0, 0.0)) - self.make_health_box((0.0, 0.0, 0.0)) - self.last_prize = 'curse' - self.prize_recipient.actor.curse() - # bs.timer(5.5, self.setup_next_round) - if prize == 2: - self.setup_rof() - bs.broadcastmessage(run, color=(1.0, 0.2, 0.1)) - self.last_prize = 'ring_of_fire' - if prize == 3: - self.last_prize = 'climb' - self.light = bs.newnode( - 'locator', - attrs={ - 'shape': 'circle', - 'position': (0.0, 3.0, -9.0), - 'color': (1.0, 1.0, 1.0), - 'opacity': 1.0, - 'draw_beauty': True, - 'additive': True - }) - bs.broadcastmessage(climb_top, color=(0.5, 0.5, 0.5)) - bs.timer(3.0, babase.Call(self.make_health_box, (0.0, 6.0, -9.0))) - self.round_timer = bs.Timer(10.0, self.setup_next_round) - if prize == 4: - self.last_prize = 'land_mines' - self.make_health_box((6.0, 5.0, -2.0)) - self.make_land_mines() - self.prize_recipient.actor.connect_controls_to_player( - enable_bomb=False) - self.prize_recipient.actor.node.handlemessage( - bs.StandMessage(position=(-6.0, 3.0, -2.0))) - self.round_timer = bs.Timer(7.0, self.setup_next_round) - if prize == 5: - # Make it rain bombs - self.bomb_survivor = self.prize_recipient - bs.broadcastmessage(bomb_rain, color=(1.0, 0.5, 0.16)) - # Set positions for the bombs to drop - for bzz in range(-5,6): - for azz in range(-5,2): - # for each position make a bomb drop there - self.make_bomb(bzz, azz) - self.give_points_timer = bs.Timer(3.3, self.give_points) - self.last_prize = 'bombrain' - if prize == 6: - self.setup_br() - self.bomb_survivor = self.prize_recipient - self.give_points_timer = bs.Timer(7.0, self.give_points) - self.last_prize = 'bombroad' - if prize == 7: - # makes killing a bad guy worth ten points - self.bad_guy_cost = 2 - bs.broadcastmessage(lame_guys, color=(1.0, 0.5, 0.16)) - # makes a set of nine positions - for a in range(-1, 2): - for b in range(-3, 0): - # and spawns one in each position - self._bots.spawn_bot(BrawlerBotLite, pos=(a, 2.5, b)) - # and we give our player boxing gloves and a shield - self._player.equip_boxing_gloves() - self._player.equip_shields() - self.last_prize = 'lameguys' - if prize == 8: - self._jackpot_sound.play() - bs.broadcastmessage(jackpot, color=(1.0, 0.0, 0.0)) - bs.broadcastmessage(jackpot, color=(0.0, 1.0, 0.0)) - bs.broadcastmessage(jackpot, color=(0.0, 0.0, 1.0)) - team = self.prize_recipient.team - # GIVE THEM A WHOPPING 50 POINTS!!! - team.score += 50 - # and update the scores - self._update_scoreboard() - self.last_prize = 'jackpot' - bs.timer(2.0, self.setup_next_round) + def give_prize(self, prize: int) -> None: + if prize == 1: + # Curse him aka make him blow up in 5 seconds + # give them a nice message + bs.broadcastmessage(you_were, color=(0.1, 0.1, 0.1)) + bs.broadcastmessage(cursed_text, color=(1.0, 0.0, 0.0)) + self.make_health_box((0.0, 0.0, 0.0)) + self.last_prize = 'curse' + self.prize_recipient.actor.curse() + # bs.timer(5.5, self.setup_next_round) + if prize == 2: + self.setup_rof() + bs.broadcastmessage(run, color=(1.0, 0.2, 0.1)) + self.last_prize = 'ring_of_fire' + if prize == 3: + self.last_prize = 'climb' + self.light = bs.newnode( + 'locator', + attrs={ + 'shape': 'circle', + 'position': (0.0, 3.0, -9.0), + 'color': (1.0, 1.0, 1.0), + 'opacity': 1.0, + 'draw_beauty': True, + 'additive': True + }) + bs.broadcastmessage(climb_top, color=(0.5, 0.5, 0.5)) + bs.timer(3.0, babase.Call(self.make_health_box, (0.0, 6.0, -9.0))) + self.round_timer = bs.Timer(10.0, self.setup_next_round) + if prize == 4: + self.last_prize = 'land_mines' + self.make_health_box((6.0, 5.0, -2.0)) + self.make_land_mines() + self.prize_recipient.actor.connect_controls_to_player( + enable_bomb=False) + self.prize_recipient.actor.node.handlemessage( + bs.StandMessage(position=(-6.0, 3.0, -2.0))) + self.round_timer = bs.Timer(7.0, self.setup_next_round) + if prize == 5: + # Make it rain bombs + self.bomb_survivor = self.prize_recipient + bs.broadcastmessage(bomb_rain, color=(1.0, 0.5, 0.16)) + # Set positions for the bombs to drop + for bzz in range(-5, 6): + for azz in range(-5, 2): + # for each position make a bomb drop there + self.make_bomb(bzz, azz) + self.give_points_timer = bs.Timer(3.3, self.give_points) + self.last_prize = 'bombrain' + if prize == 6: + self.setup_br() + self.bomb_survivor = self.prize_recipient + self.give_points_timer = bs.Timer(7.0, self.give_points) + self.last_prize = 'bombroad' + if prize == 7: + # makes killing a bad guy worth ten points + self.bad_guy_cost = 2 + bs.broadcastmessage(lame_guys, color=(1.0, 0.5, 0.16)) + # makes a set of nine positions + for a in range(-1, 2): + for b in range(-3, 0): + # and spawns one in each position + self._bots.spawn_bot(BrawlerBotLite, pos=(a, 2.5, b)) + # and we give our player boxing gloves and a shield + self._player.equip_boxing_gloves() + self._player.equip_shields() + self.last_prize = 'lameguys' + if prize == 8: + self._jackpot_sound.play() + bs.broadcastmessage(jackpot, color=(1.0, 0.0, 0.0)) + bs.broadcastmessage(jackpot, color=(0.0, 1.0, 0.0)) + bs.broadcastmessage(jackpot, color=(0.0, 0.0, 1.0)) + team = self.prize_recipient.team + # GIVE THEM A WHOPPING 50 POINTS!!! + team.score += 50 + # and update the scores + self._update_scoreboard() + self.last_prize = 'jackpot' + bs.timer(2.0, self.setup_next_round) - def setup_next_round(self) -> None: - if self._slow_motion_deaths: - bs.getactivity().globalsnode.slow_motion = False - if self.set: - return - if self.light: - self.light.delete() - for bomb in self.bombs: - bomb.handlemessage(bs.DieMessage()) - self.kill_flags() - self._bots.clear() - self.reset_flags() - self.current_player.actor.handlemessage( - bs.DieMessage(how='game')) - self.current_player.actor.node.delete() - c = 0 - self.player_index += 1 - self.player_index %= len(self.queue_line) - if len(self.queue_line) > 0: - while self.queue_line[self.player_index].dead: - if c > len(self.queue_line): - return - self.player_index += 1 - self.player_index %= len(self.queue_line) - c += 1 - self.spawn_player_spaz( - self.queue_line[self.player_index], (0.0, 3.0, -2.0)) - self.current_player = self.queue_line[self.player_index] - self.last_prize = 'none' - self._update_icons() + def setup_next_round(self) -> None: + if self._slow_motion_deaths: + bs.getactivity().globalsnode.slow_motion = False + if self.set: + return + if self.light: + self.light.delete() + for bomb in self.bombs: + bomb.handlemessage(bs.DieMessage()) + self.kill_flags() + self._bots.clear() + self.reset_flags() + self.current_player.actor.handlemessage( + bs.DieMessage(how='game')) + self.current_player.actor.node.delete() + c = 0 + self.player_index += 1 + self.player_index %= len(self.queue_line) + if len(self.queue_line) > 0: + while self.queue_line[self.player_index].dead: + if c > len(self.queue_line): + return + self.player_index += 1 + self.player_index %= len(self.queue_line) + c += 1 + self.spawn_player_spaz( + self.queue_line[self.player_index], (0.0, 3.0, -2.0)) + self.current_player = self.queue_line[self.player_index] + self.last_prize = 'none' + self._update_icons() - def check_bots(self) -> None: - if not self._bots.have_living_bots(): - self.setup_next_round() + def check_bots(self) -> None: + if not self._bots.have_living_bots(): + self.setup_next_round() - def make_land_mines(self) -> None: - self.bombs = [] - for i in range(-11, 7): - self.bombs.append(Bomb( - position=(0.0, 6.0, i/2.0), - bomb_type='land_mine', - blast_radius=2.0)) - self.bombs[i+10].arm() + def make_land_mines(self) -> None: + self.bombs = [] + for i in range(-11, 7): + self.bombs.append(Bomb( + position=(0.0, 6.0, i/2.0), + bomb_type='land_mine', + blast_radius=2.0)) + self.bombs[i+10].arm() - def give_points(self) -> None: - if self.bomb_survivor is not None and self.bomb_survivor.is_alive(): - self.bomb_survivor.team.score += 20 - self._update_scoreboard() - self.round_timer = bs.Timer(1.0, self.setup_next_round) + def give_points(self) -> None: + if self.bomb_survivor is not None and self.bomb_survivor.is_alive(): + self.bomb_survivor.team.score += 20 + self._update_scoreboard() + self.round_timer = bs.Timer(1.0, self.setup_next_round) - def make_health_box(self, position: Sequence[float]) -> None: - if position == (0.0, 3.0, 0.0): - position = (random.randint(-6, 6), 6, random.randint(-6, 4)) - elif position == (0,0,0): - position = random.choice( - ((-7, 6, -5), (7, 6, -5), (-7, 6, 1), (7, 6, 1))) - self.health_box = PowerupBox( - position=position, poweruptype='health').autoretain() + def make_health_box(self, position: Sequence[float]) -> None: + if position == (0.0, 3.0, 0.0): + position = (random.randint(-6, 6), 6, random.randint(-6, 4)) + elif position == (0, 0, 0): + position = random.choice( + ((-7, 6, -5), (7, 6, -5), (-7, 6, 1), (7, 6, 1))) + self.health_box = PowerupBox( + position=position, poweruptype='health').autoretain() - # called in prize #5 - def make_bomb(self, xpos: float, zpos: float) -> None: - # makes a bomb at the given position then auto-retains it aka: - # makes sure it doesn't disappear because there is no reference to it - self.bombs.append(Bomb(position=(xpos, 12, zpos))) + # called in prize #5 + def make_bomb(self, xpos: float, zpos: float) -> None: + # makes a bomb at the given position then auto-retains it aka: + # makes sure it doesn't disappear because there is no reference to it + self.bombs.append(Bomb(position=(xpos, 12, zpos))) - def setup_br(self) -> None: - self.make_bomb_row(6) - self.prize_recipient.actor.handlemessage( - bs.StandMessage(position=(6.0, 3.0, -2.0))) + def setup_br(self) -> None: + self.make_bomb_row(6) + self.prize_recipient.actor.handlemessage( + bs.StandMessage(position=(6.0, 3.0, -2.0))) - def make_bomb_row(self, num: int) -> None: - if not self.prize_recipient.is_alive(): - return - if num == 0: - self.round_timer = bs.Timer(1.0, self.setup_next_round) - return - for i in range(-11, 7): - self.bombs.append( - Bomb(position=(-3, 3, i/2.0), - velocity=(12, 0.0, 0.0), - bomb_type='normal', - blast_radius=1.2)) - bs.timer(1.0, babase.Call(self.make_bomb_row, num-1)) + def make_bomb_row(self, num: int) -> None: + if not self.prize_recipient.is_alive(): + return + if num == 0: + self.round_timer = bs.Timer(1.0, self.setup_next_round) + return + for i in range(-11, 7): + self.bombs.append( + Bomb(position=(-3, 3, i/2.0), + velocity=(12, 0.0, 0.0), + bomb_type='normal', + blast_radius=1.2)) + bs.timer(1.0, babase.Call(self.make_bomb_row, num-1)) - def setup_rof(self) -> None: - self.make_blast_ring(10) - self.prize_recipient.actor.handlemessage( - bs.StandMessage(position=(0.0, 3.0, -2.0))) + def setup_rof(self) -> None: + self.make_blast_ring(10) + self.prize_recipient.actor.handlemessage( + bs.StandMessage(position=(0.0, 3.0, -2.0))) - def make_blast_ring(self, length: float) -> None: - if not self.prize_recipient.is_alive(): - return - if length == 0: - self.setup_next_round() - self.prize_recipient.team.score += 50 - self._update_scoreboard() - return - for angle in range(0, 360, 45): - angle += random.randint(0, 45) - angle %= 360 - x = length * math.cos(math.radians(angle)) - z = length * math.sin(math.radians(angle)) - blast = Blast(position=(x, 2.2, z-2), blast_radius=3.5) - bs.timer(0.75, babase.Call(self.make_blast_ring, length-1)) + def make_blast_ring(self, length: float) -> None: + if not self.prize_recipient.is_alive(): + return + if length == 0: + self.setup_next_round() + self.prize_recipient.team.score += 50 + self._update_scoreboard() + return + for angle in range(0, 360, 45): + angle += random.randint(0, 45) + angle %= 360 + x = length * math.cos(math.radians(angle)) + z = length * math.sin(math.radians(angle)) + blast = Blast(position=(x, 2.2, z-2), blast_radius=3.5) + bs.timer(0.75, babase.Call(self.make_blast_ring, length-1)) - # a method to remake the flags - def reset_flags(self) -> None: - # remake the flags - self._flag = Flag( - position=(0.0, 3.0, 1.0), touchable=True, color=(0.0, 0.0, 1.0)) - self._flag2 = Flag( - position=(0.0, 3.0, -5.0), touchable=True, color=(1.0, 0.0, 0.0)) - self._flag3 = Flag( - position=(3.0, 3.0, -2.0), touchable=True, color=(0.0, 1.0, 0.0)) - self._flag4 = Flag( - position=(-3.0, 3.0, -2.0), touchable=True, color=(1.0, 1.0, 1.0)) - self._flag5 = Flag( - position=(1.8, 3.0, 0.2), touchable=True, color=(0.0, 1.0, 1.0)) - self._flag6 = Flag( - position=(-1.8, 3.0, 0.2), touchable=True, color=(1.0, 0.0, 1.0)) - self._flag7 = Flag( - position=(1.8, 3.0, -3.8), touchable=True, color=(1.0, 1.0, 0.0)) - self._flag8 = Flag( - position=(-1.8, 3.0, -3.8), touchable=True, color=(0.0, 0.0, 0.0)) + # a method to remake the flags + def reset_flags(self) -> None: + # remake the flags + self._flag = Flag( + position=(0.0, 3.0, 1.0), touchable=True, color=(0.0, 0.0, 1.0)) + self._flag2 = Flag( + position=(0.0, 3.0, -5.0), touchable=True, color=(1.0, 0.0, 0.0)) + self._flag3 = Flag( + position=(3.0, 3.0, -2.0), touchable=True, color=(0.0, 1.0, 0.0)) + self._flag4 = Flag( + position=(-3.0, 3.0, -2.0), touchable=True, color=(1.0, 1.0, 1.0)) + self._flag5 = Flag( + position=(1.8, 3.0, 0.2), touchable=True, color=(0.0, 1.0, 1.0)) + self._flag6 = Flag( + position=(-1.8, 3.0, 0.2), touchable=True, color=(1.0, 0.0, 1.0)) + self._flag7 = Flag( + position=(1.8, 3.0, -3.8), touchable=True, color=(1.0, 1.0, 0.0)) + self._flag8 = Flag( + position=(-1.8, 3.0, -3.8), touchable=True, color=(0.0, 0.0, 0.0)) - # a method to kill the flags - def kill_flags(self) -> None: - # destroy all the flags by erasing all references to them, - # indicated by None similar to null - self._flag.node.delete() - self._flag2.node.delete() - self._flag3.node.delete() - self._flag4.node.delete() - self._flag5.node.delete() # 132, 210 ,12 - self._flag6.node.delete() - self._flag7.node.delete() - self._flag8.node.delete() + # a method to kill the flags + def kill_flags(self) -> None: + # destroy all the flags by erasing all references to them, + # indicated by None similar to null + self._flag.node.delete() + self._flag2.node.delete() + self._flag3.node.delete() + self._flag4.node.delete() + self._flag5.node.delete() # 132, 210 ,12 + self._flag6.node.delete() + self._flag7.node.delete() + self._flag8.node.delete() - def _check_end_game(self) -> None: - for player in self.queue_line: - if not player.dead: - return - self.end_game() + def _check_end_game(self) -> None: + for player in self.queue_line: + if not player.dead: + return + self.end_game() - def spawn_player_spaz( - self, - player: PlayerT, - position: Sequence[float] = (0, 0, 0), - angle: float | None = None, - ) -> PlayerSpaz: - from babase import _math - from bascenev1._gameutils import animate - from bascenev1._coopsession import CoopSession + def spawn_player_spaz( + self, + player: PlayerT, + position: Sequence[float] = (0, 0, 0), + angle: float | None = None, + ) -> PlayerSpaz: + from babase import _math + from bascenev1._gameutils import animate + from bascenev1._coopsession import CoopSession - angle = None - name = player.getname() - color = player.color - highlight = player.highlight + angle = None + name = player.getname() + color = player.color + highlight = player.highlight - light_color = _math.normalized_color(color) - display_color = babase.safecolor(color, target_intensity=0.75) + light_color = _math.normalized_color(color) + display_color = babase.safecolor(color, target_intensity=0.75) - spaz = FlagBearer(color=color, - highlight=highlight, - character=player.character, - player=player) + spaz = FlagBearer(color=color, + highlight=highlight, + character=player.character, + player=player) - player.actor = spaz - assert spaz.node + player.actor = spaz + assert spaz.node - spaz.node.name = name - spaz.node.name_color = display_color - spaz.connect_controls_to_player() + 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') - animate(light, 'intensity', {0: 0, 0.25: 1, 0.5: 0}) - bs.timer(0.5, light.delete) - return spaz + # 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') + animate(light, 'intensity', {0: 0, 0.25: 1, 0.5: 0}) + bs.timer(0.5, light.delete) + return spaz - def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, bs.PlayerDiedMessage): - # give them a nice farewell - if bs.time() < 0.5: - return - if msg.how == 'game': - return - player = msg.getplayer(Player) - bs.broadcastmessage( - diedtxt + str(player.getname()) + diedtxt2, color=player.color) - player.dead = True - if player is self.current_player: - self.round_timer = None - self.give_points_timer = None - if not msg.how is bs.DeathType.FALL: - if self._slow_motion_deaths: - bs.getactivity().globalsnode.slow_motion = True - time = 0.5 - else: - time = 0.01 - # check to see if we can end the game - self._check_end_game() - bs.timer(time, self.setup_next_round) - elif isinstance(msg, FlagPickedUpMessage): - msg.flag.last_player_to_hold = msg.node.getdelegate( - FlagBearer, True - ).getplayer(Player, True) - self._player = msg.node.getdelegate( - FlagBearer, True - ) - self.prize_recipient = msg.node.getdelegate( - FlagBearer, True - ).getplayer(Player, True) - self.kill_flags() - self.give_prize(random.randint(1, 8)) - self._round_sound.play() - self.current_player = self.prize_recipient - elif isinstance(msg, SpazBotDiedMessage): - # find out which team the last person to hold a flag was on - team = self.prize_recipient.team - # give them their points - team.score += self.bad_guy_cost - self._dingsound.play(0.5) - # update the scores - for team in self.teams: - self._scoreboard.set_team_value(team, team.score) - bs.timer(0.3, self.check_bots) - return None + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, bs.PlayerDiedMessage): + # give them a nice farewell + if bs.time() < 0.5: + return + if msg.how == 'game': + return + player = msg.getplayer(Player) + bs.broadcastmessage( + diedtxt + str(player.getname()) + diedtxt2, color=player.color) + player.dead = True + if player is self.current_player: + self.round_timer = None + self.give_points_timer = None + if not msg.how is bs.DeathType.FALL: + if self._slow_motion_deaths: + bs.getactivity().globalsnode.slow_motion = True + time = 0.5 + else: + time = 0.01 + # check to see if we can end the game + self._check_end_game() + bs.timer(time, self.setup_next_round) + elif isinstance(msg, FlagPickedUpMessage): + msg.flag.last_player_to_hold = msg.node.getdelegate( + FlagBearer, True + ).getplayer(Player, True) + self._player = msg.node.getdelegate( + FlagBearer, True + ) + self.prize_recipient = msg.node.getdelegate( + FlagBearer, True + ).getplayer(Player, True) + self.kill_flags() + self.give_prize(random.randint(1, 8)) + self._round_sound.play() + self.current_player = self.prize_recipient + elif isinstance(msg, SpazBotDiedMessage): + # find out which team the last person to hold a flag was on + team = self.prize_recipient.team + # give them their points + team.score += self.bad_guy_cost + self._dingsound.play(0.5) + # update the scores + for team in self.teams: + self._scoreboard.set_team_value(team, team.score) + bs.timer(0.3, self.check_bots) + return None - def _update_scoreboard(self) -> None: - for player in self.queue_line: - if not player.dead: - if player.team.score > 0: - self._dingsound.play() - self._scoreboard.set_team_value(player.team, player.team.score) + def _update_scoreboard(self) -> None: + for player in self.queue_line: + if not player.dead: + if player.team.score > 0: + self._dingsound.play() + self._scoreboard.set_team_value(player.team, player.team.score) - def end_game(self) -> None: - if self.set: - return - self.set = True - results = bs.GameResults() - for team in self.teams: - results.set_team_score(team, team.score) - self.end(results=results) + def end_game(self) -> None: + if self.set: + return + self.set = True + results = bs.GameResults() + for team in self.teams: + results.set_team_score(team, team.score) + self.end(results=results) diff --git a/plugins/utilities/bots_can_accept_powerups.py b/plugins/utilities/bots_can_accept_powerups.py index 7c00f67..ca7d842 100644 --- a/plugins/utilities/bots_can_accept_powerups.py +++ b/plugins/utilities/bots_can_accept_powerups.py @@ -20,6 +20,7 @@ if TYPE_CHECKING: class BotsCanAcceptPowerupsPlugin(babase.Plugin): def on_app_running(self) -> None: SpazBot.oldinit = SpazBot.__init__ + def __init__(self) -> None: self.oldinit() pam = PowerupBoxFactory.get().powerup_accept_material diff --git a/plugins/utilities/cheat_menu.py b/plugins/utilities/cheat_menu.py index 8648dea..4e1b003 100644 --- a/plugins/utilities/cheat_menu.py +++ b/plugins/utilities/cheat_menu.py @@ -49,7 +49,7 @@ Configs = { "SuperPunch": False, "ImpactOnly": False, "StickyOnly": False, - "IceOnly" : False, + "IceOnly": False, "Infinite Bombs": False, "More Are Coming": False, "Credits": False, @@ -82,7 +82,7 @@ class Plugin(babase.Plugin): if babase.app.build_number if build_number < 21282 else babase.app.env.build_number: setconfigs() self.overwrite() - + else: babase.screenmessage(f'{__name__} only works on api 8') @@ -115,7 +115,7 @@ def AllSettingsWindowInit(self, transition: str = 'in_right', origin_widget: bui # on cheat button press call Window def on_cheat_menu_btn_press(self): bui.containerwidget(edit=self._root_widget, - transition='out_scale') + transition='out_scale') bui.app.ui_v1.set_main_menu_window( CheatMenuWindow( transition='in_right').get_root_widget(), from_window=self._root_widget) @@ -161,7 +161,7 @@ class CheatMenuWindow(bui.Window): button_type='backSmall', on_activate_call=self._back) bui.containerwidget(edit=self._root_widget, - cancel_button=self._back_button) + cancel_button=self._back_button) # window title, apears in top center of window self._title_text = bui.textwidget( @@ -183,7 +183,7 @@ class CheatMenuWindow(bui.Window): self._scroll_height), selection_loops_to_parent=True) bui.widget(edit=self._scrollwidget, - right_widget=self._scrollwidget) + right_widget=self._scrollwidget) # subcontainer represents scroll widget and used as parent self._subcontainer = bui.containerwidget( @@ -222,20 +222,20 @@ class CheatMenuWindow(bui.Window): try: if change == True and config == "Fly": bui.screenmessage("Some maps may not work good for flying", - color=(1, 0, 0)) + color=(1, 0, 0)) update_config(config, change) bui.getsound('gunCocking').play() except Exception: bui.screenmessage("error", color=(1, 0, 0)) bui.getsound('error').play() - + try: if change == True and config == "SuperPunch": bui.screenmessage("SuperPunch Activated", - color=(1, 0, 0)) + color=(1, 0, 0)) elif change == False and config == "SuperPunch": - bui.screenmessage("Super Punch Deactivated", - color=(0.5,0,0)) + bui.screenmessage("Super Punch Deactivated", + color=(0.5, 0, 0)) update_config(config, change) bui.getsound('gunCocking').play() except Exception: @@ -245,10 +245,10 @@ class CheatMenuWindow(bui.Window): try: if change == True and config == "IceOnly": bui.screenmessage("Ice Bombs Activated", - color=(0.1, 1, 1)) + color=(0.1, 1, 1)) elif change == False and config == "IceOnly": bui.screenmessage("Ice Bombs Deactivated", - color=(1, 0, 0)) + color=(1, 0, 0)) update_config(config, change) bui.getsound('gunCocking').play() except Exception: @@ -257,23 +257,23 @@ class CheatMenuWindow(bui.Window): try: if change == True and config == "StickyOnly": bui.screenmessage("Sticky Bombs Activated", - color=(0, 1, 0)) + color=(0, 1, 0)) elif change == False and config == "StickyOnly": bui.screenmessage("Sticky Bombs Deactivated", - color=(1, 0, 0)) + color=(1, 0, 0)) update_config(config, change) bui.getsound('gunCocking').play() except Exception: bui.screenmessage("error", color=(1, 0, 0)) bui.getsound('spazOw').play() - + try: if change == True and config == "ImpactOnly": bui.screenmessage("Impact Bombs Activated", - color=(0.5, 0.5, 0.5)) + color=(0.5, 0.5, 0.5)) elif change == False and config == "ImpactOnly": bui.screenmessage("Impact Bombs Deactivated", - color=(1, 0, 0)) + color=(1, 0, 0)) update_config(config, change) bui.getsound('gunCocking').play() except Exception: @@ -283,17 +283,17 @@ class CheatMenuWindow(bui.Window): try: if change == True and config == "More Are Coming": bui.screenmessage("Check out https://discord.gg/2RKd9QQdQY For More Mods", - color=(4, 9, 2)) + color=(4, 9, 2)) update_config(config, change) bui.getsound('gunCocking').play() except Exception: bui.screenmessage("error", color=(1, 0, 0)) bui.getsound('cheer').play() - + try: if change == True and config == "Credits": bui.screenmessage("To Pranav Made The Mod and Emily For Ideas, Thx", - color=(4, 9, 2)) + color=(4, 9, 2)) update_config(config, change) bui.getsound('gunCocking').play() except Exception: @@ -304,7 +304,7 @@ class CheatMenuWindow(bui.Window): """Kill the window and get back to previous one """ bui.containerwidget(edit=self._root_widget, - transition='out_scale') + transition='out_scale') bui.app.ui_v1.set_main_menu_window( AllSettingsWindow( transition='in_left').get_root_widget(), from_window=self._root_widget) @@ -317,6 +317,7 @@ def ishost(): if player.inputdevice.client_id == -1: return True + def activity_loop(): if bs.get_foreground_host_activity() is not None: activity = bs.get_foreground_host_activity() @@ -337,19 +338,21 @@ def activity_loop(): player.actor._punch_power_scale = 1.2 if config["IceOnly"]: - player.actor.bomb_type = 'ice' + player.actor.bomb_type = 'ice' elif not config["IceOnly"]: - player.actor.bomb_type = 'normal' - player.actor.bomb_count= 1 - + player.actor.bomb_type = 'normal' + player.actor.bomb_count = 1 + if config["ImpactOnly"]: - player.actor.bomb_type = 'impact' - player.actor.bomb_count = 1 - + player.actor.bomb_type = 'impact' + player.actor.bomb_count = 1 + if config["StickyOnly"]: - player.actor.bomb_type = 'sticky' - player.actor.bomb_count = 1 + player.actor.bomb_type = 'sticky' + player.actor.bomb_count = 1 if config["Infinite Bombs"]: - player.actor.bomb_count = 100 -timer = babase.AppTimer(2, activity_loop,repeat=True) \ No newline at end of file + player.actor.bomb_count = 100 + + +timer = babase.AppTimer(2, activity_loop, repeat=True) From a5e88115ab01a3ba8c62a9f31f40cee433ed7339 Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Thu, 1 Feb 2024 10:09:20 +0000 Subject: [PATCH 23/36] [ci] apply-version-metadata --- plugins/minigames.json | 98 ++++++++++++++++++++++++++++++++++++------ plugins/utilities.json | 28 ++++++++++-- 2 files changed, 108 insertions(+), 18 deletions(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index db4143e..ecc1d21 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -1131,7 +1131,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "4941d0c", + "released_on": "01-02-2024", + "md5sum": "335d7191f26ba21ad10a5755d7741ce0" + } } }, "onslaught_football": { @@ -1145,7 +1150,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "4941d0c", + "released_on": "01-02-2024", + "md5sum": "e6267fec4dc7f874b1f8065863aae1cb" + } } }, "lame_fight": { @@ -1159,7 +1169,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "4941d0c", + "released_on": "01-02-2024", + "md5sum": "eb0e5a8658e82b3aac6b04b68c1c0f60" + } } }, "infinite_ninjas": { @@ -1173,7 +1188,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "4941d0c", + "released_on": "01-02-2024", + "md5sum": "1b6e28bed97bf78430135c64a1fca2c2" + } } }, "gravity_falls": { @@ -1187,7 +1207,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "4941d0c", + "released_on": "01-02-2024", + "md5sum": "6d0b06b283ef702f41837f09e457d3b8" + } } }, "bot_chase": { @@ -1201,7 +1226,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "4941d0c", + "released_on": "01-02-2024", + "md5sum": "c26e6aee6f545d911106431f3c2d8f0f" + } } }, "down_into_the_abyss": { @@ -1215,7 +1245,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "4941d0c", + "released_on": "01-02-2024", + "md5sum": "d3c488671dd35c488e22002ddeb80aef" + } } }, "better_deathmatch": { @@ -1229,7 +1264,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "4941d0c", + "released_on": "01-02-2024", + "md5sum": "0b607db2dbe3ab40aa05bd4bfd5b4afa" + } } }, "better_elimination": { @@ -1243,7 +1283,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "4941d0c", + "released_on": "01-02-2024", + "md5sum": "18bbb7f6ddc4206c7039ad3b5f5facae" + } } }, "bot_shower": { @@ -1257,7 +1302,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "4941d0c", + "released_on": "01-02-2024", + "md5sum": "1259e09ccd9b10ae82e4a6623572a4d2" + } } }, "explodo_run": { @@ -1271,7 +1321,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "4941d0c", + "released_on": "01-02-2024", + "md5sum": "af5022d1f78887e0ac2b0cfc37f4f04a" + } } }, "extinction": { @@ -1285,7 +1340,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "4941d0c", + "released_on": "01-02-2024", + "md5sum": "daf6c3e3d8663fa6d99c9e3f75033f36" + } } }, "fat_pigs": { @@ -1299,7 +1359,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "4941d0c", + "released_on": "01-02-2024", + "md5sum": "fe0d82c322ce01d8956af3131e135ad2" + } } }, "flag_day": { @@ -1313,7 +1378,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "4941d0c", + "released_on": "01-02-2024", + "md5sum": "e11fbf742e6556939ac8d986e2dd430b" + } } } } diff --git a/plugins/utilities.json b/plugins/utilities.json index b5f63eb..6cd3c8a 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -1159,7 +1159,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "4941d0c", + "released_on": "01-02-2024", + "md5sum": "4b5479f51356b0c9c80c4b9968fea910" + } } }, "xyz_tool": { @@ -1173,7 +1178,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "4941d0c", + "released_on": "01-02-2024", + "md5sum": "3f301456128f422b7277c667f6c5c47e" + } } }, "bots_can_accept_powerups": { @@ -1187,7 +1197,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "4941d0c", + "released_on": "01-02-2024", + "md5sum": "71eae7c5d0e05821809d348ea0c64837" + } } }, "cheat_menu": { @@ -1201,7 +1216,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "4941d0c", + "released_on": "01-02-2024", + "md5sum": "079e857197979aabf53f232b3cce56ba" + } } } } From eb51abd6d425d6e5964103cb85a79e13d07b60b8 Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Thu, 1 Feb 2024 13:10:08 +0300 Subject: [PATCH 24/36] ... --- plugins/utilities.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index b5f63eb..12d3190 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -1178,12 +1178,12 @@ }, "bots_can_accept_powerups": { "description": "Bots can steal your powerups", - "external_url": "", + "external_url": "https://youtu.be/Jrk5JfveYEI?si=wYXWVxdC-3XMpuCg", "authors": [ { - "name": "", + "name": "JoseAng3l", "email": "", - "discord": "" + "discord": "joseang3l" } ], "versions": { From a1efdd0e7006ffa5c21482367a6005535e2e2473 Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Thu, 1 Feb 2024 13:12:23 +0300 Subject: [PATCH 25/36] ... --- plugins/minigames.json | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index ecc1d21..48048c7 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -1093,13 +1093,7 @@ } ], "versions": { - "1.0.0": { - "api_version": 8, - "commit_sha": "718039b", - "released_on": "24-01-2024", - "md5sum": "e1d401ec8f2d06dec741d713d6602710" - } - } + "1.0.0": null }, "you_vs_bombsquad": { "description": "You against bombsquad solo or with friends", From 388e58a577933e36c7e2bdc66fb7ec579ae5ed98 Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Thu, 1 Feb 2024 13:14:44 +0300 Subject: [PATCH 26/36] work --- plugins/minigames.json | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/minigames.json b/plugins/minigames.json index 48048c7..7731067 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -1094,6 +1094,7 @@ ], "versions": { "1.0.0": null + } }, "you_vs_bombsquad": { "description": "You against bombsquad solo or with friends", From 6baf0428283c99873726c26186484f68b19c0f82 Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Thu, 1 Feb 2024 10:15:25 +0000 Subject: [PATCH 27/36] [ci] apply-version-metadata --- plugins/minigames.json | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index 7731067..9b90f8d 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -1093,7 +1093,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "388e58a", + "released_on": "01-02-2024", + "md5sum": "8fc1f9c984f9e77b0125cbeaba5c13bf" + } } }, "you_vs_bombsquad": { From 157a956e0c620f8576e642bbe4b2384838dc2604 Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Thu, 1 Feb 2024 13:16:46 +0300 Subject: [PATCH 28/36] ... --- .vscode/settings.json | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index b242572..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "githubPullRequests.ignoredPullRequestBranches": [ - "main" - ] -} \ No newline at end of file From 9ec7242e93ab99592a92d539796bd81b1aedd073 Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Thu, 1 Feb 2024 20:46:32 +0300 Subject: [PATCH 29/36] \n --- plugins/minigames.json | 27 ++++++--------------------- plugins/minigames/explodo_run.py | 10 +++++++++- 2 files changed, 15 insertions(+), 22 deletions(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index 9b90f8d..5b95822 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -1311,7 +1311,7 @@ } }, "explodo_run": { - "description": "Run For Your Life :))", + "description": "Cursed meteor shower of crazy Captain Jack trying take your soul", "external_url": "", "authors": [ { @@ -1321,12 +1321,7 @@ } ], "versions": { - "1.0.0": { - "api_version": 8, - "commit_sha": "4941d0c", - "released_on": "01-02-2024", - "md5sum": "af5022d1f78887e0ac2b0cfc37f4f04a" - } + "1.0.0": null } }, "extinction": { @@ -1349,7 +1344,7 @@ } }, "fat_pigs": { - "description": "Survive...", + "description": "Eliminate other Mels' while dodging falling stickies.", "external_url": "", "authors": [ { @@ -1359,16 +1354,11 @@ } ], "versions": { - "1.0.0": { - "api_version": 8, - "commit_sha": "4941d0c", - "released_on": "01-02-2024", - "md5sum": "fe0d82c322ce01d8956af3131e135ad2" - } + "1.0.0": null } }, "flag_day": { - "description": "Pick up flags to receive a prize.\nBut beware...", + "description": "Pick up flags to receive a prize.But beware...", "external_url": "https://youtu.be/ANDzdBicjA4?si=h8S_TPUAxSaG7nls", "authors": [ { @@ -1378,12 +1368,7 @@ } ], "versions": { - "1.0.0": { - "api_version": 8, - "commit_sha": "4941d0c", - "released_on": "01-02-2024", - "md5sum": "e11fbf742e6556939ac8d986e2dd430b" - } + "1.0.0": null } } } diff --git a/plugins/minigames/explodo_run.py b/plugins/minigames/explodo_run.py index cac6a65..f11cb34 100644 --- a/plugins/minigames/explodo_run.py +++ b/plugins/minigames/explodo_run.py @@ -51,8 +51,15 @@ class ExplodoRunGame(bs.TeamGameActivity[Player, Team]): scoreconfig = bs.ScoreConfig(label='Time', scoretype=bs.ScoreType.MILLISECONDS, lower_is_better=False) - default_music = bs.MusicType.TO_THE_DEATH + @classmethod + def get_preview_texture_name(cls) -> str: + return 'rampagePreview' + + @classmethod + def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]: + return ['Rampage'] + def __init__(self, settings: dict): settings['map'] = "Rampage" self._epic_mode = settings.get('Epic Mode', False) @@ -64,6 +71,7 @@ class ExplodoRunGame(bs.TeamGameActivity[Player, Team]): self._won = False self._bots = SpazBotSet() self.wave = 1 + self.default_music = bs.MusicType.TO_THE_DEATH def on_begin(self) -> None: super().on_begin() From ec6286e84226e6905b4a7877ecd5ffaeed4c2296 Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Thu, 1 Feb 2024 17:47:30 +0000 Subject: [PATCH 30/36] [ci] auto-format --- plugins/minigames/explodo_run.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/minigames/explodo_run.py b/plugins/minigames/explodo_run.py index f11cb34..b6bd60d 100644 --- a/plugins/minigames/explodo_run.py +++ b/plugins/minigames/explodo_run.py @@ -55,11 +55,11 @@ class ExplodoRunGame(bs.TeamGameActivity[Player, Team]): @classmethod def get_preview_texture_name(cls) -> str: return 'rampagePreview' - + @classmethod def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]: return ['Rampage'] - + def __init__(self, settings: dict): settings['map'] = "Rampage" self._epic_mode = settings.get('Epic Mode', False) From becfccc107d4fe8ca29443f960549f7d5abfb657 Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Thu, 1 Feb 2024 17:47:31 +0000 Subject: [PATCH 31/36] [ci] apply-version-metadata --- plugins/minigames.json | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index 5b95822..f55df6f 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -1321,7 +1321,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "ec6286e", + "released_on": "01-02-2024", + "md5sum": "e3cd927316b9c3bcac714b4dc8d0d73c" + } } }, "extinction": { @@ -1354,7 +1359,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "ec6286e", + "released_on": "01-02-2024", + "md5sum": "fe0d82c322ce01d8956af3131e135ad2" + } } }, "flag_day": { @@ -1368,7 +1378,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "ec6286e", + "released_on": "01-02-2024", + "md5sum": "e11fbf742e6556939ac8d986e2dd430b" + } } } } From 6e7940753caca603767ed553a03381e30c6ea800 Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Sat, 3 Feb 2024 23:33:52 +0300 Subject: [PATCH 32/36] Used IDK cause there is a modder named unkown --- plugins/minigames.json | 76 +++++++++------------------- plugins/minigames/avalanche.py | 4 +- plugins/minigames/bot_chase.py | 6 +-- plugins/minigames/extinction.py | 4 +- plugins/minigames/infection.py | 4 +- plugins/minigames/infinite_ninjas.py | 6 +-- plugins/utilities.json | 13 ++--- 7 files changed, 39 insertions(+), 74 deletions(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index 5b95822..6e74791 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -254,7 +254,7 @@ { "name": "Rikko", "email": "rikkolovescats@proton.me", - "discord": "Rikko#7383" + "discord": "rikkolovescats" } ], "versions": { @@ -360,7 +360,7 @@ { "name": "TheMikirog", "email": "", - "discord": "TheMikirog#1984" + "discord": "themikirog" } ], "versions": { @@ -601,7 +601,7 @@ { "name": "TheMikirog", "email": "", - "discord": "TheMikirog#1984" + "discord": "themikirog" }, { "name": "JoseAng3l", @@ -911,12 +911,7 @@ } ], "versions": { - "1.0.0": { - "api_version": 8, - "commit_sha": "47a1ca8", - "released_on": "22-08-2023", - "md5sum": "398cf911195c4904b281ed05767e25f4" - } + "1.0.0": null } }, "super_duel": { @@ -979,16 +974,11 @@ } ], "versions": { - "1.0.0": { - "api_version": 8, - "commit_sha": "718039b", - "released_on": "24-01-2024", - "md5sum": "c1c96450fbdb6e5b2f0d26bb4e797236" - } + "1.0.0": null } }, "hyper_race": { - "description": "Race and avoid the obsatacles", + "description": "Race and avoid the obstacles", "external_url": "", "authors": [ { @@ -998,12 +988,7 @@ } ], "versions": { - "1.0.0": { - "api_version": 8, - "commit_sha": "718039b", - "released_on": "24-01-2024", - "md5sum": "8b423bdae256bd411489528b550b8bd9" - } + "1.0.0": null } }, "meteor_shower_deluxe": { @@ -1144,7 +1129,7 @@ "external_url": "", "authors": [ { - "name": "", + "name": "IDK", "email": "", "discord": "" } @@ -1163,9 +1148,9 @@ "external_url": "", "authors": [ { - "name": "", + "name": "Blitz", "email": "", - "discord": "" + "discord": "itsmeblitz" } ], "versions": { @@ -1182,18 +1167,13 @@ "external_url": "", "authors": [ { - "name": "", + "name": "IDK", "email": "", "discord": "" } ], "versions": { - "1.0.0": { - "api_version": 8, - "commit_sha": "4941d0c", - "released_on": "01-02-2024", - "md5sum": "1b6e28bed97bf78430135c64a1fca2c2" - } + "1.0.0": null } }, "gravity_falls": { @@ -1201,7 +1181,7 @@ "external_url": "", "authors": [ { - "name": "", + "name": "IDK", "email": "", "discord": "" } @@ -1220,18 +1200,13 @@ "external_url": "", "authors": [ { - "name": "", + "name": "! JETZ", "email": "", - "discord": "" + "discord": "! JETZ#5313" } ], "versions": { - "1.0.0": { - "api_version": 8, - "commit_sha": "4941d0c", - "released_on": "01-02-2024", - "md5sum": "c26e6aee6f545d911106431f3c2d8f0f" - } + "1.0.0": null } }, "down_into_the_abyss": { @@ -1239,7 +1214,7 @@ "external_url": "", "authors": [ { - "name": "", + "name": "IDK", "email": "", "discord": "" } @@ -1296,9 +1271,9 @@ "external_url": "", "authors": [ { - "name": "", + "name": "! JETZ", "email": "", - "discord": "" + "discord": "! JETZ#5313" } ], "versions": { @@ -1315,9 +1290,9 @@ "external_url": "", "authors": [ { - "name": "", + "name": "Blitz", "email": "", - "discord": "" + "discord": "itsmeblitz" } ], "versions": { @@ -1329,18 +1304,13 @@ "external_url": "", "authors": [ { - "name": "", + "name": "IDK", "email": "", "discord": "" } ], "versions": { - "1.0.0": { - "api_version": 8, - "commit_sha": "4941d0c", - "released_on": "01-02-2024", - "md5sum": "daf6c3e3d8663fa6d99c9e3f75033f36" - } + "1.0.0": null } }, "fat_pigs": { diff --git a/plugins/minigames/avalanche.py b/plugins/minigames/avalanche.py index 1e36208..43eed2f 100644 --- a/plugins/minigames/avalanche.py +++ b/plugins/minigames/avalanche.py @@ -26,12 +26,12 @@ randomPic = ["lakeFrigidPreview", "hockeyStadiumPreview"] def ba_get_api_version(): - return 6 + return 8 def ba_get_levels(): return [ - babase._level.Level( + bs._level.Level( "Icy Emits", gametype=IcyEmitsGame, settings={}, diff --git a/plugins/minigames/bot_chase.py b/plugins/minigames/bot_chase.py index 6495ee4..deab742 100644 --- a/plugins/minigames/bot_chase.py +++ b/plugins/minigames/bot_chase.py @@ -16,11 +16,11 @@ if TYPE_CHECKING: from typing import Any, List, Type, Optional -# def ba_get_api_version(): -# return 6 +def ba_get_api_version(): + return 8 def ba_get_levels(): - return [babase._level.Level( + return [bs._level.Level( 'Bot Chase', gametype=BotChaseGame, settings={}, preview_texture_name='footballStadiumPreview')] diff --git a/plugins/minigames/extinction.py b/plugins/minigames/extinction.py index 22ca2fc..436a631 100644 --- a/plugins/minigames/extinction.py +++ b/plugins/minigames/extinction.py @@ -23,12 +23,12 @@ def ba_get_api_version(): def ba_get_levels(): - return [babase._level.Level( + return [bs._level.Level( 'Extinction', gametype=NewMeteorShowerGame, settings={'Epic Mode': False}, preview_texture_name='footballStadiumPreview'), - babase._level.Level( + bs._level.Level( 'Epic Extinction', gametype=NewMeteorShowerGame, settings={'Epic Mode': True}, diff --git a/plugins/minigames/infection.py b/plugins/minigames/infection.py index a509ec8..b46b1e2 100644 --- a/plugins/minigames/infection.py +++ b/plugins/minigames/infection.py @@ -55,11 +55,11 @@ else: def ba_get_api_version(): - return 6 + return 8 def ba_get_levels(): - return [babase._level.Level( + return [bs._level.Level( name, gametype=Infection, settings={}, diff --git a/plugins/minigames/infinite_ninjas.py b/plugins/minigames/infinite_ninjas.py index de2784f..6ff1b0a 100644 --- a/plugins/minigames/infinite_ninjas.py +++ b/plugins/minigames/infinite_ninjas.py @@ -22,15 +22,15 @@ if TYPE_CHECKING: def ba_get_api_version(): - return 6 + return 8 def ba_get_levels(): - return [babase._level.Level( + return [bs._level.Level( 'Infinite Ninjas', gametype=InfiniteNinjasGame, settings={}, preview_texture_name='footballStadiumPreview'), - babase._level.Level( + bs._level.Level( 'Epic Infinite Ninjas', gametype=InfiniteNinjasGame, settings={'Epic Mode': True}, preview_texture_name='footballStadiumPreview')] diff --git a/plugins/utilities.json b/plugins/utilities.json index 16a9ecf..c586f67 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -1115,7 +1115,7 @@ "external_url": "", "authors": [ { - "name": "", + "name": "IDK", "email": "", "discord": "" } @@ -1172,18 +1172,13 @@ "external_url": "", "authors": [ { - "name": "", + "name": "Yann", "email": "", - "discord": "" + "discord": "riyukiiyan" } ], "versions": { - "1.0.0": { - "api_version": 8, - "commit_sha": "4941d0c", - "released_on": "01-02-2024", - "md5sum": "3f301456128f422b7277c667f6c5c47e" - } + "1.0.0": null } }, "bots_can_accept_powerups": { From 50636908520eb71bdb4e485bb6de7b13e77c8b25 Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Sat, 3 Feb 2024 20:35:33 +0000 Subject: [PATCH 33/36] [ci] auto-format --- plugins/minigames/bot_chase.py | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/minigames/bot_chase.py b/plugins/minigames/bot_chase.py index deab742..7ef9e80 100644 --- a/plugins/minigames/bot_chase.py +++ b/plugins/minigames/bot_chase.py @@ -19,6 +19,7 @@ if TYPE_CHECKING: def ba_get_api_version(): return 8 + def ba_get_levels(): return [bs._level.Level( 'Bot Chase', gametype=BotChaseGame, From 3277f85f3b609e860a4489897cfbfac955d67636 Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Sat, 3 Feb 2024 20:35:34 +0000 Subject: [PATCH 34/36] [ci] apply-version-metadata --- plugins/minigames.json | 42 ++++++++++++++++++++++++++++++++++++------ plugins/utilities.json | 7 ++++++- 2 files changed, 42 insertions(+), 7 deletions(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index 73e2c23..30ac1d3 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -911,7 +911,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "5063690", + "released_on": "03-02-2024", + "md5sum": "4a9cdcd798454e5034a5ea9ce58fe586" + } } }, "super_duel": { @@ -974,7 +979,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "5063690", + "released_on": "03-02-2024", + "md5sum": "a07a171c29417056bb69ed1cf0f2864b" + } } }, "hyper_race": { @@ -988,7 +998,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "5063690", + "released_on": "03-02-2024", + "md5sum": "8b423bdae256bd411489528b550b8bd9" + } } }, "meteor_shower_deluxe": { @@ -1173,7 +1188,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "5063690", + "released_on": "03-02-2024", + "md5sum": "15e303e02e3da4636fd002c43a579180" + } } }, "gravity_falls": { @@ -1206,7 +1226,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "5063690", + "released_on": "03-02-2024", + "md5sum": "b0519f41146eb2f8b9c2d6c747376a9b" + } } }, "down_into_the_abyss": { @@ -1315,7 +1340,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "5063690", + "released_on": "03-02-2024", + "md5sum": "9fb61df79a50d010864964a7cb1de76e" + } } }, "fat_pigs": { diff --git a/plugins/utilities.json b/plugins/utilities.json index c586f67..7ed32f9 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -1178,7 +1178,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "5063690", + "released_on": "03-02-2024", + "md5sum": "3f301456128f422b7277c667f6c5c47e" + } } }, "bots_can_accept_powerups": { From 4d454d6e28ccdd56aeab2c3821673ac688035ca5 Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Sun, 4 Feb 2024 10:59:44 +0300 Subject: [PATCH 35/36] =?UTF-8?q?=F0=9F=98=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- plugins/minigames.json | 19 - plugins/minigames/ba_dark_fields.py | 296 -------- plugins/utilities.json | 19 - plugins/utilities/ba_colours.py | 1063 --------------------------- 4 files changed, 1397 deletions(-) delete mode 100644 plugins/minigames/ba_dark_fields.py delete mode 100644 plugins/utilities/ba_colours.py diff --git a/plugins/minigames.json b/plugins/minigames.json index 73e2c23..ff0e3fb 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -1105,25 +1105,6 @@ } } }, - "ba_dark_fields": { - "description": "Get to the other side and watch your step", - "external_url": "", - "authors": [ - { - "name": "Froshlee24", - "email": "", - "discord": "froshlee24" - } - ], - "versions": { - "1.0.0": { - "api_version": 8, - "commit_sha": "4941d0c", - "released_on": "01-02-2024", - "md5sum": "335d7191f26ba21ad10a5755d7741ce0" - } - } - }, "onslaught_football": { "description": "Onslaught but in football map", "external_url": "", diff --git a/plugins/minigames/ba_dark_fields.py b/plugins/minigames/ba_dark_fields.py deleted file mode 100644 index 03302ee..0000000 --- a/plugins/minigames/ba_dark_fields.py +++ /dev/null @@ -1,296 +0,0 @@ -# Ported to api 8 by brostos using baport.(https://github.com/bombsquad-community/baport) -"""Dark fields mini-game.""" - -# Minigame by Froshlee24 -# ba_meta require api 8 -# (see https://ballistica.net/wiki/meta-tag-system) - -from __future__ import annotations -import random -from typing import TYPE_CHECKING - -import _babase -import babase -import bauiv1 as bui -import bascenev1 as bs -from bascenev1lib.actor import bomb -from bascenev1._music import setmusic -from bascenev1lib.actor.scoreboard import Scoreboard -from bascenev1._gameutils import animate_array -from bascenev1lib.gameutils import SharedObjects -from bascenev1lib.actor.playerspaz import PlayerSpaz - -if TYPE_CHECKING: - from typing import Any, Sequence, Optional, List, Dict, Type, Type - - -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 DarkFieldsGame(bs.TeamGameActivity[Player, Team]): - - name = 'Dark Fields' - description = 'Get to the other side.' - available_settings = [ - bs.IntSetting('Score to Win', - min_value=1, - default=3, - ), - 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), - bs.BoolSetting('Players as center of interest', default=True), - ] - - @classmethod - def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]: - return bs.app.classic.getmaps('football') - - @classmethod - def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool: - return (issubclass(sessiontype, bs.DualTeamSession) - or issubclass(sessiontype, bs.FreeForAllSession)) - - def __init__(self, settings: dict): - super().__init__(settings) - self._epic_mode = bool(settings['Epic Mode']) - self._center_of_interest = bool(settings['Players as center of interest']) - self._score_to_win_per_player = int(settings['Score to Win']) - self._time_limit = float(settings['Time Limit']) - - self._scoreboard = Scoreboard() - - shared = SharedObjects.get() - - self._scoreRegionMaterial = bs.Material() - self._scoreRegionMaterial.add_actions( - conditions=("they_have_material", shared.player_material), - actions=(("modify_part_collision", "collide", True), - ("modify_part_collision", "physical", False), - ("call", "at_connect", self._onPlayerScores))) - - self.slow_motion = self._epic_mode - self.default_music = (bs.MusicType.EPIC if self._epic_mode else None) - - def on_transition_in(self) -> None: - super().on_transition_in() - gnode = bs.getactivity().globalsnode - gnode.tint = (0.5, 0.5, 0.5) - - a = bs.newnode('locator', attrs={'shape': 'box', 'position': (12.2, 0, .1087926362), - 'color': (5, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [2.5, 0.1, 12.8]}) - - b = bs.newnode('locator', attrs={'shape': 'box', 'position': (-12.1, 0, .1087926362), - 'color': (0, 0, 5), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [2.5, 0.1, 12.8]}) - - def on_begin(self) -> None: - # self._has_begun = False - super().on_begin() - - self.setup_standard_time_limit(self._time_limit) - self._score_to_win = (self._score_to_win_per_player * - max(1, max(len(t.players) for t in self.teams))) - self._update_scoreboard() - - self.isUpdatingMines = False - self._scoreSound = bs.getsound('dingSmall') - - for p in self.players: - if p.actor is not None: - try: - p.actor.disconnect_controls_from_player() - except Exception: - print('Can\'t connect to player') - - self._scoreRegions = [] - defs = bs.getactivity().map.defs - self._scoreRegions.append(bs.NodeActor(bs.newnode('region', - attrs={'position': defs.boxes['goal1'][0:3], - 'scale': defs.boxes['goal1'][6:9], - 'type': 'box', - 'materials': (self._scoreRegionMaterial,)}))) - self.mines = [] - self.spawnMines() - bs.timer(0.8 if self.slow_motion else 1.7, self.start) - - def start(self): - # self._has_begun = True - self._show_info() - bs.timer(random.randrange(3, 7), self.doRandomLighting) - if not self._epic_mode: - setmusic(bs.MusicType.SCARY) - animate_array(bs.getactivity().globalsnode, 'tint', 3, - {0: (0.5, 0.5, 0.5), 2: (0.2, 0.2, 0.2)}) - - for p in self.players: - self.doPlayer(p) - - def spawn_player(self, player): - if not self.has_begun(): - return - else: - self.doPlayer(player) - - def doPlayer(self, player): - pos = (-12.4, 1, random.randrange(-5, 5)) - player = self.spawn_player_spaz(player, pos) - player.connect_controls_to_player(enable_punch=False, enable_bomb=False) - player.node.is_area_of_interest = self._center_of_interest - - def _show_info(self) -> None: - if self.has_begun(): - super()._show_info() - - def on_team_join(self, team: Team) -> None: - if self.has_begun(): - self._update_scoreboard() - - def _update_scoreboard(self) -> None: - for team in self.teams: - self._scoreboard.set_team_value(team, team.score, self._score_to_win) - - def doRandomLighting(self): - bs.timer(random.randrange(3, 7), self.doRandomLighting) - if self.isUpdatingMines: - return - - delay = 0 - for mine in self.mines: - if mine.node.exists(): - pos = mine.node.position - bs.timer(delay, babase.Call(self.do_light, pos)) - delay += 0.005 if self._epic_mode else 0.01 - - def do_light(self, pos): - light = bs.newnode('light', attrs={ - 'position': pos, - 'volume_intensity_scale': 1.0, - 'radius': 0.1, - 'color': (1, 0, 0) - }) - bs.animate(light, 'intensity', {0: 2.0, 3.0: 0.0}) - bs.timer(3.0, light.delete) - - def spawnMines(self): - delay = 0 - h_range = [10, 8, 6, 4, 2, 0, -2, -4, -6, -8, -10] - for h in h_range: - for i in range(random.randint(3, 4)): - x = h+random.random() - y = random.randrange(-5, 6)+(random.random()) - pos = (x, 1, y) - bs.timer(delay, babase.Call(self.doMine, pos)) - delay += 0.015 if self._epic_mode else 0.04 - bs.timer(5.0, self.stopUpdateMines) - - def stopUpdateMines(self): - self.isUpdatingMines = False - - def updateMines(self): - if self.isUpdatingMines: - return - self.isUpdatingMines = True - for m in self.mines: - m.node.delete() - self.mines = [] - self.spawnMines() - - def doMine(self, pos): - b = bomb.Bomb(position=pos, bomb_type='land_mine').autoretain() - b.add_explode_callback(self._on_bomb_exploded) - b.arm() - self.mines.append(b) - - def _on_bomb_exploded(self, bomb: Bomb, blast: Blast) -> None: - assert blast.node - p = blast.node.position - pos = (p[0], p[1]+1, p[2]) - bs.timer(0.5, babase.Call(self.doMine, pos)) - - def _onPlayerScores(self): - player: Optional[Player] - try: - spaz = bs.getcollision().opposingnode.getdelegate(PlayerSpaz, True) - except bs.NotFoundError: - return - - if not spaz.is_alive(): - return - - try: - player = spaz.getplayer(Player, True) - except bs.NotFoundError: - return - - if player.exists() and player.is_alive(): - player.team.score += 1 - self._scoreSound.play() - pos = player.actor.node.position - - animate_array(bs.getactivity().globalsnode, 'tint', 3, { - 0: (0.5, 0.5, 0.5), 2.8: (0.2, 0.2, 0.2)}) - self._update_scoreboard() - - light = bs.newnode('light', - attrs={ - 'position': pos, - 'radius': 0.5, - 'color': (1, 0, 0) - }) - bs.animate(light, 'intensity', {0.0: 0, 0.1: 1, 0.5: 0}, loop=False) - bs.timer(1.0, light.delete) - - player.actor.handlemessage(bs.DieMessage(how=bs.DeathType.REACHED_GOAL)) - self.updateMines() - - if any(team.score >= self._score_to_win for team in self.teams): - bs.timer(0.5, self.end_game) - - 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) - - else: - return super().handlemessage(msg) - return None - - 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/utilities.json b/plugins/utilities.json index c586f67..fc48240 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -1148,25 +1148,6 @@ } } }, - "ba_colours": { - "description": "Colourful bots and more", - "external_url": "", - "authors": [ - { - "name": "Froshlee", - "email": "", - "discord": "froshlee24" - } - ], - "versions": { - "1.0.0": { - "api_version": 8, - "commit_sha": "4941d0c", - "released_on": "01-02-2024", - "md5sum": "4b5479f51356b0c9c80c4b9968fea910" - } - } - }, "xyz_tool": { "description": "Punch to save the co-ordinates", "external_url": "", diff --git a/plugins/utilities/ba_colours.py b/plugins/utilities/ba_colours.py deleted file mode 100644 index e522529..0000000 --- a/plugins/utilities/ba_colours.py +++ /dev/null @@ -1,1063 +0,0 @@ -# Ported to api 8 by brostos using baport.(https://github.com/bombsquad-community/baport) -"""Colors Mod.""" -# Mod by Froshlee14 -# ba_meta require api 8 - -from __future__ import annotations -from typing import TYPE_CHECKING - -import _babase -import babase -import bauiv1 as bui -import bascenev1 as bs - -if TYPE_CHECKING: - pass - -from bascenev1lib.actor.spazfactory import SpazFactory -from bascenev1lib.actor.scoreboard import Scoreboard -from bascenev1lib.game.elimination import EliminationGame, Icon, Player, Team -from bascenev1lib.gameutils import SharedObjects - -from bascenev1 import get_player_colors, get_player_profile_colors, get_player_profile_icon -from bauiv1lib.popup import PopupWindow -from bascenev1lib.actor import bomb, spaz -from bauiv1lib import tabs, confirm, mainmenu, popup -from bauiv1lib.colorpicker import ColorPicker -from bauiv1lib.mainmenu import MainMenuWindow -from bauiv1lib.profile.browser import * -from bascenev1lib.actor.playerspaz import * -from bascenev1lib.actor.flag import * -from bascenev1lib.actor.spazbot import * -from bascenev1lib.actor.spazfactory import SpazFactory -# from bascenev1lib.mainmenu import MainMenuActivity -import random - - -def getData(data): - return babase.app.config["colorsMod"][data] - - -def getRandomColor(): - c = random.choice(getData("colors")) - return c - - -def doColorMenu(self): - bui.containerwidget(edit=self._root_widget, transition='out_left') - openWindow() - - -def updateButton(self): - color = (random.random(), random.random(), random.random()) - try: - bui.buttonwidget(edit=self._colorsModButton, color=color) - except Exception: - self._timer = None - - -newConfig = {"colorPlayer": True, - "higlightPlayer": False, - "namePlayer": False, - "glowColor": False, - "glowHighlight": False, - "glowName": False, - "actab": 1, - "shieldColor": False, - "xplotionColor": True, - "delScorch": True, - "colorBots": False, - "glowBots": False, - "flag": True, - # "test":True, - "glowScale": 1, - "timeDelay": 500, - "activeProfiles": ['__account__'], - "colors": [color for color in get_player_colors()], - } - - -def getDefaultSettings(): - return newConfig - - -def getTranslation(text): - actLan = bs.app.lang.language - colorsModsLan = { - "title": { - "Spanish": 'Colors Mod', - "English": 'Colors Mod' - }, - "player_tab": { - "Spanish": 'Ajustes de Jugador', - "English": 'Player settings' - }, - "extras_tab": { - "Spanish": 'Ajustes Adicionales', - "English": 'Adittional settings' - }, - "general_tab": { - "Spanish": 'Ajustes Generales', - "English": 'General settings' - }, - "info_tab": { - "Spanish": 'Creditos', - "English": 'Credits' - }, - "profiles": { - "Spanish": 'Perfiles', - "English": 'Profiles' - }, - "palette": { - "Spanish": 'Paleta de Colores', - "English": 'Pallete' - }, - "change": { - "Spanish": 'Cambiar', - "English": 'Change' - }, - "glow": { - "Spanish": 'Brillar', - "English": 'Glow' - }, - "glow_scale": { - "Spanish": 'Escala de Brillo', - "English": 'Glow Scale' - }, - "time_delay": { - "Spanish": 'Intervalo de Tiempo', - "English": 'Time Delay' - }, - "reset_values": { - "Spanish": 'Reiniciar Valores', - "English": 'Reset Values' - }, - "players": { - "Spanish": 'Jugadores', - "English": 'Players' - }, - "apply_to_color": { - "Spanish": 'Color Principal', - "English": 'Main Color' - }, - "apply_to_highlight": { - "Spanish": 'Color de Resalte', - "English": 'Highlight Color' - }, - "apply_to_name": { - "Spanish": 'Color del Nombre', - "English": 'Name Color' - }, - "additional_features": { - "Spanish": 'Ajustes Adicionales', - "English": 'Additional Features' - }, - "apply_to_bots": { - "Spanish": 'Color Principal de Bots', - "English": 'Bots Main Color' - }, - "apply_to_shields": { - "Spanish": 'Escudos de Colores', - "English": 'Apply to Shields' - }, - "apply_to_explotions": { - "Spanish": 'Explosiones de Colores', - "English": 'Apply to Explotions' - }, - "apply_to_flags": { - "Spanish": 'Banderas de Colores', - "English": 'Apply to Flags' - }, - "pick_color": { - "Spanish": 'Selecciona un Color', - "English": 'Pick a Color' - }, - "add_color": { - "Spanish": 'Agregar Color', - "English": 'Add Color' - }, - "remove_color": { - "Spanish": 'Quitar Color', - "English": 'Remove Color' - }, - "clean_explotions": { - "Spanish": 'Limpiar Explosiones', - "English": 'Remove Scorch' - }, - "restore_default_settings": { - "Spanish": 'Restaurar Ajustes Por Defecto', - "English": 'Restore Default Settings' - }, - "settings_restored": { - "Spanish": 'Ajustes Restaurados', - "English": 'Settings Restored' - }, - "restore_settings": { - "Spanish": '¿Restaurar Ajustes Por Defecto?', - "English": 'Restore Default Settings?' - }, - "nothing_selected": { - "Spanish": 'Nada Seleccionado', - "English": 'Nothing Selected' - }, - "color_already": { - "Spanish": 'Este Color Ya Existe En La Paleta', - "English": 'Color Already In The Palette' - }, - "tap_color": { - "Spanish": 'Toca un color para quitarlo.', - "English": 'Tap to remove a color.' - }, - } - lans = ["Spanish", "English"] - if actLan not in lans: - actLan = "English" - return colorsModsLan[text][actLan] - - -# ba_meta export plugin -class ColorsMod(babase.Plugin): - - # PLUGINS PLUS COMPATIBILITY - version = "1.7.2" - logo = 'gameCenterIcon' - logo_color = (1, 1, 1) - plugin_type = 'mod' - - def has_settings_ui(self): - return True - - def show_settings_ui(self, button): - ColorsMenu() - - if bs.app.lang.language == "Spanish": - information = ("Modifica y aplica efectos\n" - "a los colores de tu personaje,\n" - "explosiones, bots, escudos,\n" - "entre otras cosas...\n\n" - "Programado por Froshlee14\nTraducido por CerdoGordo\n\n" - "ADVERTENCIA\nEste mod puede ocacionar\n" - "efectos de epilepsia\na personas sensibles.") - else: - information = ("Modify and add effects\n" - "to your character colours.\n" - "And other stuff...\n\n" - "Coded by Froshlee14\nTranslated by CerdoGordo\n\n" - "WARNING\nThis mod can cause epileptic\n" - "seizures especially\nwith sensitive people") - - def on_app_running(self) -> None: - - if "colorsMod" in babase.app.config: - oldConfig = babase.app.config["colorsMod"] - for setting in newConfig: - if setting not in oldConfig: - babase.app.config["colorsMod"].update({setting: newConfig[setting]}) - bs.broadcastmessage(('Colors Mod: config updated'), color=(1, 1, 0)) - - removeList = [] - for setting in oldConfig: - if setting not in newConfig: - removeList.append(setting) - for element in removeList: - babase.app.config["colorsMod"].pop(element) - bs.broadcastmessage(('Colors Mod: old config deleted'), color=(1, 1, 0)) - else: - babase.app.config["colorsMod"] = newConfig - babase.app.config.apply_and_commit() - - # MainMenuActivity.oldMakeWord = MainMenuActivity._make_word - # def newMakeWord(self, word: str, - # x: float, - # y: float, - # scale: float = 1.0, - # delay: float = 0.0, - # vr_depth_offset: float = 0.0, - # shadow: bool = False): - # self.oldMakeWord(word,x,y,scale,delay,vr_depth_offset,shadow) - # word = self._word_actors[-1] - # if word.node.getnodetype(): - # if word.node.color[3] == 1.0: - # word.node.color = getRandomColor() - # MainMenuActivity._make_word = newMakeWord - - #### GAME MODIFICATIONS #### - - # ESCUDO DE COLORES - - def new_equip_shields(self, decay: bool = False) -> None: - if not self.node: - babase.print_error('Can\'t equip shields; no node.') - return - - factory = SpazFactory.get() - if self.shield is None: - self.shield = bs.newnode('shield', owner=self.node, attrs={ - 'color': (0.3, 0.2, 2.0), 'radius': 1.3}) - self.node.connectattr('position_center', self.shield, 'position') - self.shield_hitpoints = self.shield_hitpoints_max = 650 - self.shield_decay_rate = factory.shield_decay_rate if decay else 0 - self.shield.hurt = 0 - factory.shield_up_sound.play(1.0, position=self.node.position) - - if self.shield_decay_rate > 0: - self.shield_decay_timer = bs.Timer(0.5, bs.WeakCall(self.shield_decay), repeat=True) - self.shield.always_show_health_bar = True - - def changeColor(): - if self.shield is None: - return - if getData("shieldColor"): - self.shield.color = c = getRandomColor() - self._shieldTimer = bs.Timer(getData("timeDelay") / 1000, changeColor, repeat=True) - PlayerSpaz.equip_shields = new_equip_shields - - # BOTS DE COLORES - SpazBot.oldBotInit = SpazBot.__init__ - - def newBotInit(self, *args, **kwargs): - self.oldBotInit(*args, **kwargs) - s = 1 - if getData("glowBots"): - s = getData("glowScale") - - self.node.highlight = (self.node.highlight[0]*s, - self.node.highlight[1]*s, self.node.highlight[2]*s) - - def changeColor(): - if self.is_alive(): - if getData("colorBots"): - c = getRandomColor() - self.node.highlight = (c[0]*s, c[1]*s, c[2]*s) - self._timer = bs.Timer(getData("timeDelay") / 1000, changeColor, repeat=True) - SpazBot.__init__ = newBotInit - - # BANDERA DE COLORES - Flag.oldFlagInit = Flag.__init__ - - def newFlaginit(self, position: Sequence[float] = (0.0, 1.0, 0.0), - color: Sequence[float] = (1.0, 1.0, 1.0), - materials: Sequence[bs.Material] = None, - touchable: bool = True, - dropped_timeout: int = None): - self.oldFlagInit(position, color, materials, touchable, dropped_timeout) - - def cC(): - if self.node.exists(): - if getData("flag"): - c = getRandomColor() - self.node.color = (c[0]*1.2, c[1]*1.2, c[2]*1.2) - else: - return - if touchable: - self._timer = bs.Timer(getData("timeDelay") / 1000, cC, repeat=True) - - Flag.__init__ = newFlaginit - - # JUGADORES DE COLORES - PlayerSpaz.oldInit = PlayerSpaz.__init__ - - def newInit(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', - powerups_expire: bool = True): - self.oldInit(player, color, highlight, character, powerups_expire) - - players = [] - for p in getData("activeProfiles"): - players.append(p) - - for x in range(len(players)): - if players[x] == "__account__": - players[x] = bui.app.plus.get_v1_account_name() # _babase.get_v1_account_name() - - if player.getname() in players: - s = s2 = s3 = 1 - if getData("glowColor"): - s = getData("glowScale") - if getData("glowHighlight"): - s2 = getData("glowScale") - if getData("glowName"): - s3 = getData("glowScale") - - self.node.color = (self.node.color[0]*s, self.node.color[1]*s, self.node.color[2]*s) - self.node.highlight = ( - self.node.highlight[0]*s2, self.node.highlight[1]*s2, self.node.highlight[2]*s2) - self.node.name_color = ( - self.node.name_color[0]*s3, self.node.name_color[1]*s3, self.node.name_color[2]*s3) - - def changeColor(): - if self.is_alive(): - if getData("colorPlayer"): - c = getRandomColor() - self.node.color = (c[0]*s, c[1]*s, c[2]*s) - if getData("higlightPlayer"): - c = getRandomColor() - self.node.highlight = (c[0]*s2, c[1]*s2, c[2]*s2) - if getData("namePlayer"): - c = getRandomColor() - self.node.name_color = (c[0]*s3, c[1]*s3, c[2]*s3) - self._timer = bs.Timer(getData("timeDelay") / 1000, changeColor, repeat=True) - PlayerSpaz.__init__ = newInit - - # EXPLOSIONES DE COLORES - bomb.Blast.oldBlastInit = bomb.Blast.__init__ - - def newBlastInit(self, position: Sequence[float] = (0.0, 1.0, 0.0), velocity: Sequence[float] = (0.0, 0.0, 0.0), - blast_radius: float = 2.0, blast_type: str = 'normal', source_player: bs.Player = None, - hit_type: str = 'explosion', hit_subtype: str = 'normal'): - - self.oldBlastInit(position, velocity, blast_radius, blast_type, - source_player, hit_type, hit_subtype) - - if getData("xplotionColor"): - c = getRandomColor() - - scl = random.uniform(0.6, 0.9) - scorch_radius = light_radius = self.radius - if self.blast_type == 'tnt': - light_radius *= 1.4 - scorch_radius *= 1.15 - scl *= 3.0 - - for i in range(2): - scorch = bs.newnode('scorch', attrs={ - 'position': self.node.position, 'size': scorch_radius*0.5, 'big': (self.blast_type == 'tnt')}) - if self.blast_type == 'ice': - scorch.color = (1, 1, 1.5) - else: - scorch.color = c - if getData("xplotionColor"): - if getData("delScorch"): - bs.animate(scorch, "presence", {3: 1, 13: 0}) - bs.Timer(13, scorch.delete) - - if self.blast_type == 'ice': - return - light = bs.newnode('light', attrs={'position': position, - 'volume_intensity_scale': 10.0, 'color': c}) - - iscale = 1.6 - bs.animate(light, 'intensity', { - 0: 2.0 * iscale, - scl * 0.02: 0.1 * iscale, - scl * 0.025: 0.2 * iscale, - scl * 0.05: 17.0 * iscale, - scl * 0.06: 5.0 * iscale, - scl * 0.08: 4.0 * iscale, - scl * 0.2: 0.6 * iscale, - scl * 2.0: 0.00 * iscale, - scl * 3.0: 0.0}) - bs.animate(light, 'radius', { - 0: light_radius * 0.2, - scl * 0.05: light_radius * 0.55, - scl * 0.1: light_radius * 0.3, - scl * 0.3: light_radius * 0.15, - scl * 1.0: light_radius * 0.05}) - bs.timer(scl * 3.0, light.delete) - bomb.Blast.__init__ = newBlastInit - - -class ProfilesWindow(popup.PopupWindow): - """Popup window to view achievements.""" - - def __init__(self): - uiscale = bui.app.ui_v1.uiscale - scale = (1.8 if uiscale is babase.UIScale.SMALL else - 1.65 if uiscale is babase.UIScale.MEDIUM else 1.23) - self._transitioning_out = False - self._width = 300 - self._height = (300 if uiscale is babase.UIScale.SMALL else 350) - bg_color = (0.5, 0.4, 0.6) - - self._selected = None - self._activeProfiles = getData("activeProfiles") - - self._profiles = babase.app.config.get('Player Profiles', {}) - assert self._profiles is not None - items = list(self._profiles.items()) - items.sort(key=lambda x: x[0].lower()) - - accountName: Optional[str] - if bui.app.plus.get_v1_account_state() == 'signed_in': - accountName = bui.app.plus.get_v1_account_display_string() - else: - accountName = None - # subHeight += (len(items)*45) - - # creates our _root_widget - popup.PopupWindow.__init__(self, - position=(0, 0), - size=(self._width, self._height), - scale=scale, - bg_color=bg_color) - - self._cancel_button = bui.buttonwidget(parent=self.root_widget, - position=(50, self._height - 30), size=(50, 50), - scale=0.5, label='', - color=bg_color, - on_activate_call=self._on_cancel_press, - autoselect=True, - icon=bui.gettexture('crossOut'), - iconscale=1.2) - bui.containerwidget(edit=self.root_widget, cancel_button=self._cancel_button) - - self._title_text = bui.textwidget(parent=self.root_widget, - position=(self._width * 0.5, self._height - 20), - size=(0, 0), - h_align='center', - v_align='center', - scale=01.0, - text=getTranslation('profiles'), - maxwidth=200, - color=(1, 1, 1, 0.4)) - - self._scrollwidget = bui.scrollwidget(parent=self.root_widget, - size=(self._width - 60, - self._height - 70), - position=(30, 30), - capture_arrows=True, - simple_culling_v=10) - bui.widget(edit=self._scrollwidget, autoselect=True) - - # incr = 36 - sub_width = self._width - 90 - sub_height = (len(items)*50) - - eq_rsrc = 'coopSelectWindow.powerRankingPointsEqualsText' - pts_rsrc = 'coopSelectWindow.powerRankingPointsText' - - self._subcontainer = box = bui.containerwidget(parent=self._scrollwidget, - size=(sub_width, sub_height), - background=False) - h = 20 - v = sub_height - 60 - for pName, p in items: - if pName == '__account__' and accountName is None: - continue - color, highlight = get_player_profile_colors(pName) - tval = (accountName if pName == '__account__' else - get_player_profile_icon(pName) + pName) - assert isinstance(tval, str) - # print(tval) - value = True if pName in self._activeProfiles else False - - w = bui.checkboxwidget(parent=box, position=(10, v), value=value, - on_value_change_call=bs.WeakCall(self.select, pName), - maxwidth=sub_width, size=(sub_width, 50), - textcolor=color, - text=babase.Lstr(value=tval), autoselect=True) - v -= 45 - - def addProfile(self): - if self._selected is not None: - if self._selected not in self._activeProfiles: - self._activeProfiles.append(self._selected) - babase.app.config["colorsMod"]["activeProfiles"] = self._activeProfiles - babase.app.config.apply_and_commit() - else: - bs.broadcastmessage(getTranslation('nothing_selected')) - - def removeProfile(self): - if self._selected is not None: - if self._selected in self._activeProfiles: - self._activeProfiles.remove(self._selected) - babase.app.config["colorsMod"]["activeProfiles"] = self._activeProfiles - babase.app.config.apply_and_commit() - else: - print('not found') - else: - bs.broadcastmessage(getTranslation('nothing_selected')) - - def select(self, name, m): - self._selected = name - if m == 0: - self.removeProfile() - else: - self.addProfile() - - def _on_cancel_press(self) -> None: - self._transition_out() - - def _transition_out(self) -> None: - if not self._transitioning_out: - self._transitioning_out = True - bui.containerwidget(edit=self.root_widget, transition='out_scale') - - def on_popup_cancel(self) -> None: - bui.getsound('swish').play() - self._transition_out() - - -class ColorsMenu(PopupWindow): - - def __init__(self, transition='in_right'): - # self._width = width = 650 - self._width = width = 800 - self._height = height = 450 - - self._scrollWidth = self._width*0.85 - self._scrollHeight = self._height - 120 - self._subWidth = self._scrollWidth*0.95 - self._subHeight = 200 - - self._current_tab = getData('actab') - self._timeDelay = getData("timeDelay") - self._glowScale = getData("glowScale") - - self.midwidth = self._scrollWidth*0.45 - self.qwidth = self.midwidth*0.4 - - app = bui.app.ui_v1 - uiscale = app.uiscale - - from bascenev1lib.mainmenu import MainMenuSession - self._in_game = not isinstance(bs.get_foreground_host_session(), - MainMenuSession) - - self._root_widget = bui.containerwidget(size=(width, height), transition=transition, - scale=1.5 if uiscale is babase.UIScale.SMALL else 1.0, - stack_offset=(0, -5) if uiscale is babase.UIScale.SMALL else (0, 0)) - - self._title = bui.textwidget(parent=self._root_widget, position=(50, height-40), text='', - maxwidth=self._scrollWidth, size=(self._scrollWidth, 20), - color=(0.8, 0.8, 0.8, 1.0), h_align="center", scale=1.1) - - self._backButton = b = bui.buttonwidget(parent=self._root_widget, autoselect=True, - position=(50, height-60), size=(120, 50), - scale=0.8, text_scale=1.2, label=babase.Lstr(resource='backText'), - button_type='back', on_activate_call=self._back) - bui.buttonwidget(edit=self._backButton, button_type='backSmall', size=( - 50, 50), label=babase.charstr(babase.SpecialChar.BACK)) - bui.containerwidget(edit=self._root_widget, cancel_button=b) - - self._nextButton = bui.buttonwidget(parent=self._root_widget, autoselect=True, - position=(width-60, height*0.5-20), size=(50, 50), - scale=1.0, label=babase.charstr(babase.SpecialChar.RIGHT_ARROW), - color=(0.2, 1, 0.2), button_type='square', - on_activate_call=self.nextTabContainer) - - self._prevButton = bui.buttonwidget(parent=self._root_widget, autoselect=True, - position=(10, height*0.5-20), size=(50, 50), - scale=1.0, label=babase.charstr(babase.SpecialChar.LEFT_ARROW), - color=(0.2, 1, 0.2), button_type='square', - on_activate_call=self.prevTabContainer) - - v = self._subHeight - 55 - v0 = height - 90 - - self.tabs = [ - [0, getTranslation('general_tab')], - [1, getTranslation('player_tab')], - [2, getTranslation('extras_tab')], - [3, getTranslation('info_tab')], - ] - - self._scrollwidget = sc = bui.scrollwidget(parent=self._root_widget, size=( - self._subWidth, self._scrollHeight), border_opacity=0.3, highlight=False, position=((width*0.5)-(self._scrollWidth*0.47), 50), capture_arrows=True,) - - bui.widget(edit=sc, left_widget=self._prevButton) - bui.widget(edit=sc, right_widget=self._nextButton) - bui.widget(edit=self._backButton, down_widget=sc) - - self.tabButtons = [] - h = 330 - for i in range(3): - tabButton = bui.buttonwidget(parent=self._root_widget, autoselect=True, - position=(h, 20), size=(20, 20), - scale=1.2, label='', - color=(0.3, 0.9, 0.3), - on_activate_call=babase.Call( - self._setTab, self.tabs[i][0]), - texture=bui.gettexture('nub')) - self.tabButtons.append(tabButton) - h += 50 - self._tabContainer = None - self._setTab(self._current_tab) - - def nextTabContainer(self): - tab = babase.app.config['colorsMod']['actab'] - if tab == 2: - self._setTab(0) - else: - self._setTab(tab+1) - - def prevTabContainer(self): - tab = babase.app.config['colorsMod']['actab'] - if tab == 0: - self._setTab(2) - else: - self._setTab(tab-1) - - def _setTab(self, tab): - - self._colorTimer = None - self._current_tab = tab - - babase.app.config['colorsMod']['actab'] = tab - babase.app.config.apply_and_commit() - - if self._tabContainer is not None and self._tabContainer.exists(): - self._tabContainer.delete() - self._tabData = {} - - if tab == 0: # general - subHeight = 0 - - self._tabContainer = c = bui.containerwidget(parent=self._scrollwidget, size=(self._subWidth, subHeight), - background=False, selection_loops_to_parent=True) - - bui.textwidget(edit=self._title, text=getTranslation('general_tab')) - v0 = subHeight - 30 - v = v0 - 10 - - h = self._scrollWidth*0.12 - cSpacing = self._scrollWidth*0.15 - t = bui.textwidget(parent=c, position=(0, v), - text=getTranslation('glow_scale'), - maxwidth=self.midwidth, size=(self.midwidth, 20), color=(0.8, 0.8, 0.8, 1.0), h_align="center") - v -= 45 - b = bui.buttonwidget(parent=c, position=(h-20, v-12), size=(40, 40), label="-", - autoselect=True, on_activate_call=babase.Call(self._glowScaleDecrement), repeat=True, enable_sound=True, button_type='square') - - self._glowScaleText = bui.textwidget(parent=c, position=(h+20, v), maxwidth=cSpacing, - size=(cSpacing, 20), editable=False, color=(0.3, 1.0, 0.3), h_align="center", text=str(self._glowScale)) - - b2 = bui.buttonwidget(parent=c, position=(h+cSpacing+20, v-12), size=(40, 40), label="+", - autoselect=True, on_activate_call=babase.Call(self._glowScaleIncrement), repeat=True, enable_sound=True, button_type='square') - - v -= 70 - t = bui.textwidget(parent=c, position=(0, v), - text=getTranslation('time_delay'), - maxwidth=self.midwidth, size=(self.midwidth, 20), color=(0.8, 0.8, 0.8, 1.0), h_align="center") - v -= 45 - a = bui.buttonwidget(parent=c, position=(h-20, v-12), size=(40, 40), label="-", - autoselect=True, on_activate_call=babase.Call(self._timeDelayDecrement), repeat=True, enable_sound=True, button_type='square') - - self._timeDelayText = bui.textwidget(parent=c, position=(h+20, v), maxwidth=self._scrollWidth*0.9, - size=(cSpacing, 20), editable=False, color=(0.3, 1.0, 0.3, 1.0), h_align="center", text=str(self._timeDelay)) - - a2 = bui.buttonwidget(parent=c, position=(h+cSpacing+20, v-12), size=(40, 40), label="+", - autoselect=True, on_activate_call=babase.Call(self._timeDelayIncrement), repeat=True, enable_sound=True, button_type='square') - - v -= 70 - reset = bui.buttonwidget(parent=c, autoselect=True, - position=((self._scrollWidth*0.22)-80, v-25), size=(160, 50), scale=1.0, text_scale=1.2, textcolor=(1, 1, 1), - label=getTranslation('reset_values'), on_activate_call=self._resetValues) - self._updateColorTimer() - - v = v0 - h = self._scrollWidth*0.44 - - t = bui.textwidget(parent=c, position=(h, v), - text=getTranslation('palette'), - maxwidth=self.midwidth, size=(self.midwidth, 20), - color=(0.8, 0.8, 0.8, 1.0), h_align="center") - v -= 30 - t2 = bui.textwidget(parent=c, position=(h, v), - text=getTranslation('tap_color'), scale=0.9, - maxwidth=self.midwidth, size=(self.midwidth, 20), - color=(0.6, 0.6, 0.6, 1.0), h_align="center") - v -= 20 - sp = h+45 - self.updatePalette(v, sp) - - elif tab == 1: - subHeight = self._subHeight - - self._tabContainer = c = bui.containerwidget(parent=self._scrollwidget, size=(self._subWidth, subHeight), - background=False, selection_loops_to_parent=True) - v2 = v = v0 = subHeight - bui.textwidget(edit=self._title, text=getTranslation('player_tab')) - - t = babase.app.classic.spaz_appearances['Spaz'] - tex = bui.gettexture(t.icon_texture) - tintTex = bui.gettexture(t.icon_mask_texture) - gs = getData("glowScale") - tc = (1, 1, 1) - t2c = (1, 1, 1) - - v2 -= (50+180) - self._previewImage = bui.imagewidget(parent=c, position=(self._subWidth*0.72-100, v2), size=(200, 200), - mask_texture=bui.gettexture('characterIconMask'), tint_texture=tintTex, - texture=tex, mesh_transparent=bui.getmesh( - 'image1x1'), - tint_color=(tc[0]*gs, tc[1]*gs, tc[2]*gs), tint2_color=(t2c[0]*gs, t2c[1]*gs, t2c[2]*gs)) - - self._colorTimer = bui.AppTimer(getData("timeDelay") / 1000, - babase.Call(self._updatePreview), repeat=True) - v2 -= 70 - - def doProfileWindow(): - ProfilesWindow() - - reset = bui.buttonwidget(parent=c, autoselect=True, on_activate_call=doProfileWindow, - position=(self._subWidth*0.72-100, v2), size=(200, 60), scale=1.0, text_scale=1.2, textcolor=(1, 1, 1), - label=getTranslation('profiles')) - miniBoxWidth = self.midwidth - 30 - miniBoxHeight = 80 - - v -= 18 - # Color - h = 50 - box1 = bui.containerwidget(parent=c, position=(h, v-miniBoxHeight), - size=(miniBoxWidth, miniBoxHeight), background=True) - vbox1 = miniBoxHeight - 25 - t = bui.textwidget(parent=box1, position=(10, vbox1), - text=getTranslation('apply_to_color'), - maxwidth=miniBoxWidth-20, size=(miniBoxWidth, 20), color=(0.8, 0.8, 0.8, 1.0), h_align="left") - vbox1 -= 45 - self.bw = bui.checkboxwidget(parent=box1, position=(10, vbox1), value=getData("colorPlayer"), - on_value_change_call=babase.Call(self._setSetting, 'colorPlayer'), maxwidth=self.qwidth, - text=getTranslation('change'), autoselect=True, size=(self.qwidth, 25)) - # vbox1 -= 35 - self.bw = bui.checkboxwidget(parent=box1, position=(25+self.qwidth, vbox1), value=getData("glowColor"), - on_value_change_call=babase.Call(self._setSetting, 'glowColor'), maxwidth=self.qwidth, - text=getTranslation('glow'), autoselect=True, size=(self.qwidth, 25)) - v -= (miniBoxHeight+20) - - # Highlight - box1 = bui.containerwidget(parent=c, position=(h, v-miniBoxHeight), - size=(miniBoxWidth, miniBoxHeight), background=True) - vbox1 = miniBoxHeight - 20 - t = bui.textwidget(parent=box1, position=(10, vbox1), - text=getTranslation('apply_to_highlight'), - maxwidth=miniBoxWidth-20, size=(miniBoxWidth, 20), color=(0.8, 0.8, 0.8, 1.0), h_align="left") - vbox1 -= 45 - self.bw = bui.checkboxwidget(parent=box1, position=(10, vbox1), value=getData("higlightPlayer"), - on_value_change_call=babase.Call(self._setSetting, 'higlightPlayer'), maxwidth=self.qwidth, - text=getTranslation('change'), autoselect=True, size=(self.qwidth, 25)) - # vbox1 -= 35 - self.bw = bui.checkboxwidget(parent=box1, position=(25+self.qwidth, vbox1), value=getData("glowHighlight"), - on_value_change_call=babase.Call(self._setSetting, 'glowHighlight'), maxwidth=self.qwidth, - text=getTranslation('glow'), autoselect=True, size=(self.qwidth, 25)) - v -= (miniBoxHeight+20) - # Name - box1 = bui.containerwidget(parent=c, position=(h, v-miniBoxHeight), - size=(miniBoxWidth, miniBoxHeight), background=True) - vbox1 = miniBoxHeight - 20 - t = bui.textwidget(parent=box1, position=(10, vbox1), - text=getTranslation('apply_to_name'), - maxwidth=miniBoxWidth-20, size=(miniBoxWidth, 20), color=(0.8, 0.8, 0.8, 1.0), h_align="left") - vbox1 -= 40 - self.bw = bui.checkboxwidget(parent=box1, position=(10, vbox1), value=getData("namePlayer"), - on_value_change_call=babase.Call(self._setSetting, 'namePlayer'), maxwidth=self.qwidth, - text=getTranslation('change'), autoselect=True, size=(self.qwidth, 25)) - # vbox1 -= 35 - self.bw = bui.checkboxwidget(parent=box1, position=(25+self.qwidth, vbox1), value=getData("glowName"), - on_value_change_call=babase.Call(self._setSetting, 'glowName'), maxwidth=self.qwidth, - text=getTranslation('glow'), autoselect=True, size=(self.qwidth, 25)) - v -= (miniBoxHeight+50) - - elif tab == 2: - subHeight = 0 - self._tabContainer = c = bui.containerwidget(parent=self._scrollwidget, size=(self._subWidth, subHeight), - background=False, selection_loops_to_parent=True) - v0 = subHeight - 50 - - v = v0 - h = 30 - bui.textwidget(edit=self._title, text=getTranslation('extras_tab')) - self.bw = bui.checkboxwidget(parent=c, position=(h, v), value=getData("shieldColor"), - on_value_change_call=babase.Call(self._setSetting, 'shieldColor'), maxwidth=self.midwidth, - text=getTranslation('apply_to_shields'), autoselect=True, size=(self.midwidth, 30)) - v -= 50 - self.bw = bui.checkboxwidget(parent=c, position=(h, v), value=getData("flag"), - on_value_change_call=babase.Call(self._setSetting, 'flag'), maxwidth=self.midwidth, - text=getTranslation('apply_to_flags'), autoselect=True, size=(self.midwidth, 30)) - v = v0 - h = self.midwidth - self.bw = bui.checkboxwidget(parent=c, position=(h, v), value=getData("xplotionColor"), - on_value_change_call=babase.Call(self._setSetting, 'xplotionColor'), maxwidth=self.midwidth, - text=getTranslation('apply_to_explotions'), autoselect=True, size=(self.midwidth, 30)) - v -= 50 - self.bw = bui.checkboxwidget(parent=c, position=(h, v), value=getData("delScorch"), - on_value_change_call=babase.Call(self._setSetting, 'delScorch'), maxwidth=self.midwidth, - text=getTranslation('clean_explotions'), autoselect=True, size=(self.midwidth, 30)) - v -= 35 - miniBoxWidth = self.midwidth - miniBoxHeight = 80 - - # Bots Color - box1 = bui.containerwidget(parent=c, position=((self._scrollWidth*0.45) - (miniBoxWidth/2), v-miniBoxHeight), - size=(miniBoxWidth, miniBoxHeight), background=True) - vbox1 = miniBoxHeight - 20 - t = bui.textwidget(parent=box1, position=(10, vbox1), - text=getTranslation('apply_to_bots'), - maxwidth=miniBoxWidth-20, size=(miniBoxWidth, 20), color=(0.8, 0.8, 0.8, 1.0), h_align="left") - vbox1 -= 45 - self.bw = bui.checkboxwidget(parent=box1, position=(10, vbox1), value=getData("colorBots"), - on_value_change_call=babase.Call(self._setSetting, 'colorBots'), maxwidth=self.qwidth, - text=getTranslation('change'), autoselect=True, size=(self.qwidth, 25)) - - self.bw = bui.checkboxwidget(parent=box1, position=(30+self.qwidth, vbox1), value=getData("glowBots"), - on_value_change_call=babase.Call(self._setSetting, 'glowBots'), maxwidth=self.qwidth, - text=getTranslation('glow'), autoselect=True, size=(self.qwidth, 25)) - - v -= 130 - reset = bui.buttonwidget(parent=c, autoselect=True, on_activate_call=self.restoreSettings, - position=((self._scrollWidth*0.45)-150, v-25), size=(300, 50), scale=1.0, text_scale=1.2, textcolor=(1, 1, 1), - label=getTranslation('restore_default_settings')) - - for bttn in self.tabButtons: - bui.buttonwidget(edit=bttn, color=(0.1, 0.5, 0.1)) - bui.buttonwidget(edit=self.tabButtons[tab], color=(0.1, 1, 0.1)) - - def _setSetting(self, setting, m): - babase.app.config["colorsMod"][setting] = False if m == 0 else True - babase.app.config.apply_and_commit() - - def _timeDelayDecrement(self): - self._timeDelay = max(50, self._timeDelay - 50) - bui.textwidget(edit=self._timeDelayText, text=str(self._timeDelay)) - babase.app.config["colorsMod"]["timeDelay"] = self._timeDelay - babase.app.config.apply_and_commit() - self._updateColorTimer() - - def _timeDelayIncrement(self): - self._timeDelay = self._timeDelay + 50 - bui.textwidget(edit=self._timeDelayText, text=str(self._timeDelay)) - babase.app.config["colorsMod"]["timeDelay"] = self._timeDelay - babase.app.config.apply_and_commit() - self._updateColorTimer() - - def _resetValues(self): - babase.app.config["colorsMod"]["glowScale"] = self._glowScale = 1 - babase.app.config["colorsMod"]["timeDelay"] = self._timeDelay = 500 - bui.textwidget(edit=self._glowScaleText, text=str(self._glowScale)) - bui.textwidget(edit=self._timeDelayText, text=str(self._timeDelay)) - babase.app.config.apply_and_commit() - self._updateColorTimer() - - def updatePalette(self, h, sp): - colours = getData("colors") - x = sp - y = h - 50 - cont = 1 - bttnSize = (45, 45) - l = len(colours) - - for i in range(16): - if i < l: - w = bui.buttonwidget( - parent=self._tabContainer, position=(x, y), size=bttnSize, - autoselect=False, label="", button_type="square", color=colours[i], - on_activate_call=bs.WeakCall(self.removeColor, colours[i])) - else: - w = bui.buttonwidget( - parent=self._tabContainer, position=( - x, y), size=bttnSize, color=(0.5, 0.4, 0.6), - autoselect=False, label="", texture=bui.gettexture('frameInset')) - if i == l: - bui.buttonwidget(edit=w, on_activate_call=bs.WeakCall( - self._makePicker, w), label="+") - if cont % 4 == 0: - x = sp - y -= ((bttnSize[0]) + 10) - else: - x += (bttnSize[0]) + 13 - cont += 1 - - def addColor(self, color): - if not self.colorIn(color): - babase.app.config["colorsMod"]["colors"].append(color) - babase.app.config.apply_and_commit() - self._setTab(0) - else: - bs.broadcastmessage(getTranslation('color_already')) - - def removeColor(self, color): - if color is not None: - if len(getData("colors")) >= 3: - if color in getData("colors"): - babase.app.config["colorsMod"]["colors"].remove(color) - babase.app.config.apply_and_commit() - self._setTab(0) - else: - print('not found') - else: - bs.broadcastmessage("Min. 2 colors", color=(0, 1, 0)) - else: - bs.broadcastmessage(getTranslation('nothing_selected')) - - def _makePicker(self, origin): - baseScale = 2.05 if babase.UIScale.SMALL else 1.6 if babase.UIScale.MEDIUM else 1.0 - initial_color = (0, 0.8, 0) - ColorPicker(parent=self._tabContainer, position=origin.get_screen_space_center(), - offset=(baseScale * (-100), 0), initial_color=initial_color, delegate=self, tag='color') - - def color_picker_closing(self, picker): - if not self._root_widget.exists(): - return - tag = picker.get_tag() - - def color_picker_selected_color(self, picker, color): - self.addColor(color) - - def colorIn(self, c): - sColors = getData("colors") - for sC in sColors: - if c[0] == sC[0] and c[1] == sC[1] and c[2] == sC[2]: - return True - return False - - def setColor(self, c): - self._selected = c - bui.buttonwidget(edit=self._moveOut, color=(0.8, 0, 0)) - - def _updateColorTimer(self): - self._colorTimer = bui.AppTimer(getData("timeDelay") / 1000, self._update, repeat=True) - - def _update(self): - color = (random.random(), random.random(), random.random()) - bui.textwidget(edit=self._timeDelayText, color=color) - - def _updatePreview(self): - gs = gs2 = getData("glowScale") - if not getData("glowColor"): - gs = 1 - if not getData("glowHighlight"): - gs2 = 1 - - c = (1, 1, 1) - if getData("colorPlayer"): - c = getRandomColor() - - c2 = (1, 1, 1) - if getData("higlightPlayer"): - c2 = getRandomColor() - - bui.imagewidget(edit=self._previewImage, tint_color=(c[0]*gs, c[1]*gs, c[2]*gs)) - bui.imagewidget(edit=self._previewImage, tint2_color=(c2[0]*gs2, c2[1]*gs2, c2[2]*gs2)) - - def _glowScaleDecrement(self): - self._glowScale = max(1, self._glowScale - 1) - bui.textwidget(edit=self._glowScaleText, text=str(self._glowScale)) - babase.app.config["colorsMod"]["glowScale"] = self._glowScale - babase.app.config.apply_and_commit() - - def _glowScaleIncrement(self): - self._glowScale = min(5, self._glowScale + 1) - bui.textwidget(edit=self._glowScaleText, text=str(self._glowScale)) - babase.app.config["colorsMod"]["glowScale"] = self._glowScale - babase.app.config.apply_and_commit() - - def restoreSettings(self): - def doIt(): - babase.app.config["colorsMod"] = getDefaultSettings() - babase.app.config.apply_and_commit() - self._setTab(2) - bs.broadcastmessage(getTranslation('settings_restored')) - confirm.ConfirmWindow(getTranslation('restore_settings'), - width=400, height=120, action=doIt, ok_text=babase.Lstr(resource='okText')) - - def _back(self): - bui.containerwidget(edit=self._root_widget, transition='out_right') - self._colorTimer = None - self._colorPreviewTimer = None - # if self._in_game: - # babase.app.main_menu_window = (mainmenu.MainMenuWindow(transition='in_left').get_root_widget()) - # else: - # babase.app.main_menu_window = ProfileBrowserWindow(transition='in_left').get_root_widget() - # babase.app.main_menu_window = (mainmenu.MainMenuWindow(transition='in_left').get_root_widget()) From f8b3cee591e3b2425dd94a6b798f35439d830c3d Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Sun, 4 Feb 2024 11:47:47 +0300 Subject: [PATCH 36/36] Safe zone out --- plugins/minigames.json | 19 - plugins/minigames/safe_zone.py | 737 --------------------------------- 2 files changed, 756 deletions(-) delete mode 100644 plugins/minigames/safe_zone.py diff --git a/plugins/minigames.json b/plugins/minigames.json index f101bb1..11e9e23 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -1044,25 +1044,6 @@ } } }, - "safe_zone": { - "description": "Stay in the safe zone", - "external_url": "", - "authors": [ - { - "name": "SEBASTIAN2059", - "email": "", - "discord": "sebastian2059" - } - ], - "versions": { - "1.0.0": { - "api_version": 8, - "commit_sha": "718039b", - "released_on": "24-01-2024", - "md5sum": "862fab0c26947c70397542742fb82635" - } - } - }, "snow_ball_fight": { "description": "Throw snoballs and dominate", "external_url": "https://youtu.be/uXyb_meBjGI?si=D_N_OXZT5BFh8R5C", diff --git a/plugins/minigames/safe_zone.py b/plugins/minigames/safe_zone.py deleted file mode 100644 index 5680877..0000000 --- a/plugins/minigames/safe_zone.py +++ /dev/null @@ -1,737 +0,0 @@ -# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport) -# Released under the MIT License. See LICENSE for details. -# -"""Elimination mini-game.""" - -# Maded by Froshlee14 -# Update by SEBASTIAN2059 - -# 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 _babase -import random -from bascenev1lib.actor.spazfactory import SpazFactory -from bascenev1lib.actor.scoreboard import Scoreboard -from bascenev1lib.actor import spazbot as stdbot -from bascenev1lib.gameutils import SharedObjects as so - -if TYPE_CHECKING: - from typing import (Any, Tuple, Dict, Type, List, Sequence, Optional, - Union) - - -class Icon(bs.Actor): - """Creates in in-game icon on screen.""" - - def __init__(self, - player: Player, - position: Tuple[float, float], - scale: float, - show_lives: bool = True, - show_death: bool = True, - name_scale: float = 1.0, - name_maxwidth: float = 115.0, - flatness: float = 1.0, - shadow: float = 1.0): - super().__init__() - - self._player = player - self._show_lives = show_lives - self._show_death = show_death - self._name_scale = name_scale - self._outline_tex = bs.gettexture('characterIconMask') - - icon = player.get_icon() - self.node = bs.newnode('image', - delegate=self, - attrs={ - 'texture': icon['texture'], - 'tint_texture': icon['tint_texture'], - 'tint_color': icon['tint_color'], - 'vr_depth': 400, - 'tint2_color': icon['tint2_color'], - 'mask_texture': self._outline_tex, - 'opacity': 1.0, - 'absolute_scale': True, - 'attach': 'bottomCenter' - }) - self._name_text = bs.newnode( - 'text', - owner=self.node, - attrs={ - 'text': babase.Lstr(value=player.getname()), - 'color': babase.safecolor(player.team.color), - 'h_align': 'center', - 'v_align': 'center', - 'vr_depth': 410, - 'maxwidth': name_maxwidth, - 'shadow': shadow, - 'flatness': flatness, - 'h_attach': 'center', - 'v_attach': 'bottom' - }) - if self._show_lives: - self._lives_text = bs.newnode('text', - owner=self.node, - attrs={ - 'text': 'x0', - 'color': (1, 1, 0.5), - 'h_align': 'left', - 'vr_depth': 430, - 'shadow': 1.0, - 'flatness': 1.0, - 'h_attach': 'center', - 'v_attach': 'bottom' - }) - self.set_position_and_scale(position, scale) - - def set_position_and_scale(self, position: Tuple[float, float], - scale: float) -> None: - """(Re)position the icon.""" - assert self.node - self.node.position = position - self.node.scale = [70.0 * scale] - self._name_text.position = (position[0], position[1] + scale * 52.0) - self._name_text.scale = 1.0 * scale * self._name_scale - if self._show_lives: - self._lives_text.position = (position[0] + scale * 10.0, - position[1] - scale * 43.0) - self._lives_text.scale = 1.0 * scale - - def update_for_lives(self) -> None: - """Update for the target player's current lives.""" - if self._player: - lives = self._player.lives - else: - lives = 0 - if self._show_lives: - if lives > 0: - self._lives_text.text = 'x' + str(lives - 1) - else: - self._lives_text.text = '' - if lives == 0: - self._name_text.opacity = 0.2 - assert self.node - self.node.color = (0.7, 0.3, 0.3) - self.node.opacity = 0.2 - - def handle_player_spawned(self) -> None: - """Our player spawned; hooray!""" - if not self.node: - return - self.node.opacity = 1.0 - self.update_for_lives() - - def handle_player_died(self) -> None: - """Well poo; our player died.""" - if not self.node: - return - if self._show_death: - bs.animate( - self.node, 'opacity', { - 0.00: 1.0, - 0.05: 0.0, - 0.10: 1.0, - 0.15: 0.0, - 0.20: 1.0, - 0.25: 0.0, - 0.30: 1.0, - 0.35: 0.0, - 0.40: 1.0, - 0.45: 0.0, - 0.50: 1.0, - 0.55: 0.2 - }) - lives = self._player.lives - if lives == 0: - bs.timer(0.6, self.update_for_lives) - - def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, bs.DieMessage): - self.node.delete() - return None - return super().handlemessage(msg) - - -class Player(bs.Player['Team']): - """Our player type for this game.""" - - def __init__(self) -> None: - self.lives = 0 - self.icons: List[Icon] = [] - - -class Team(bs.Team[Player]): - """Our team type for this game.""" - - def __init__(self) -> None: - self.survival_seconds: Optional[int] = None - self.spawn_order: List[Player] = [] - - -lang = bs.app.lang.language -if lang == 'Spanish': - description = 'Mantente en la zona segura.' - join_description = 'Corre hacia la zona segura.' - kill_timer = 'Kill timer: ' -else: - description = 'Stay in the safe zone.' - join_description = 'Run into the safe zone' - kill_timer = 'Kill timer: ' - -# ba_meta export bascenev1.GameActivity - - -class SafeZoneGame(bs.TeamGameActivity[Player, Team]): - """Game type where last player(s) left alive win.""" - - name = 'Safe Zone' - description = description - 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 - - @classmethod - def get_available_settings( - cls, sessiontype: Type[bs.Session]) -> List[babase.Setting]: - settings = [ - bs.IntSetting( - 'Lives Per Player', - default=2, - min_value=1, - max_value=10, - increment=1, - ), - bs.IntChoiceSetting( - 'Time Limit', - choices=[ - ('None', 0), - ('1 Minute', 60), - ('2 Minutes', 120), - ('5 Minutes', 300), - ('10 Minutes', 600), - ('20 Minutes', 1200), - ], - default=0, - ), - bs.FloatChoiceSetting( - 'Respawn Times', - choices=[ - ('Short', 0.25), - ('Normal', 0.5), - ], - default=0.5, - ), - bs.BoolSetting('Epic Mode', default=False), - ] - if issubclass(sessiontype, bs.DualTeamSession): - settings.append(bs.BoolSetting('Solo Mode', default=False)) - settings.append( - bs.BoolSetting('Balance Total Lives', default=False)) - return settings - - @classmethod - def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool: - return (issubclass(sessiontype, bs.DualTeamSession) - or issubclass(sessiontype, bs.FreeForAllSession)) - - @classmethod - def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]: - return ['Football Stadium', 'Hockey Stadium'] - - def __init__(self, settings: dict): - super().__init__(settings) - self._scoreboard = Scoreboard() - self._start_time: Optional[float] = None - self._vs_text: Optional[bs.Actor] = None - self._round_end_timer: Optional[bs.Timer] = None - self._epic_mode = bool(settings['Epic Mode']) - self._lives_per_player = int(settings['Lives Per Player']) - self._time_limit = float(settings['Time Limit']) - self._balance_total_lives = bool( - settings.get('Balance Total Lives', False)) - self._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) - - self._tick_sound = bs.getsound('tick') - - def get_instance_description(self) -> Union[str, Sequence]: - return join_description - - def get_instance_description_short(self) -> Union[str, Sequence]: - return 'last team standing wins' if isinstance( - self.session, bs.DualTeamSession) else 'last one standing wins' - - def on_player_join(self, player: Player) -> None: - - # No longer allowing mid-game joiners here; too easy to exploit. - if self.has_begun(): - - # Make sure their team has survival seconds set if they're all dead - # (otherwise blocked new ffa players are considered 'still alive' - # in score tallying). - if (self._get_total_team_lives(player.team) == 0 - and player.team.survival_seconds is None): - player.team.survival_seconds = 0 - bs.broadcastmessage( - babase.Lstr(resource='playerDelayedJoinText', - subs=[('${PLAYER}', player.getname(full=True))]), - color=(0, 1, 0), - ) - return - - player.lives = self._lives_per_player - - if self._solo_mode: - player.team.spawn_order.append(player) - self._update_solo_mode() - else: - # Create our icon and spawn. - player.icons = [Icon(player, position=(0, 50), scale=0.8)] - if player.lives > 0: - self.spawn_player(player) - - # Don't waste time doing this until begin. - if self.has_begun(): - self._update_icons() - - 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() - - bs.timer(5, self.spawn_zone) - self._bots = stdbot.SpazBotSet() - bs.timer(3, babase.Call(self.add_bot, 'left')) - bs.timer(3, babase.Call(self.add_bot, 'right')) - if len(self.initialplayerinfos) > 4: - bs.timer(5, babase.Call(self.add_bot, 'right')) - bs.timer(5, babase.Call(self.add_bot, 'left')) - - if self._solo_mode: - 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') - })) - - # If balance-team-lives is on, add lives to the smaller team until - # total lives match. - if (isinstance(self.session, bs.DualTeamSession) - and self._balance_total_lives and self.teams[0].players - and self.teams[1].players): - if self._get_total_team_lives( - self.teams[0]) < self._get_total_team_lives(self.teams[1]): - lesser_team = self.teams[0] - greater_team = self.teams[1] - else: - lesser_team = self.teams[1] - greater_team = self.teams[0] - add_index = 0 - while (self._get_total_team_lives(lesser_team) < - self._get_total_team_lives(greater_team)): - lesser_team.players[add_index].lives += 1 - add_index = (add_index + 1) % len(lesser_team.players) - - self._update_icons() - - # We could check game-over conditions at explicit trigger points, - # but lets just do the simple thing and poll it. - bs.timer(1.0, self._update, repeat=True) - - def spawn_zone(self): - self.zone_pos = (random.randrange(-10, 10), 0.05, random.randrange(-5, 5)) - self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': self.zone_pos, 'color': ( - 1, 1, 0), 'opacity': 0.8, 'draw_beauty': True, 'additive': False, 'drawShadow': False}) - self.zone_limit = bs.newnode('locator', attrs={'shape': 'circleOutline', 'position': self.zone_pos, 'color': ( - 1, 0.2, 0.2), 'opacity': 0.8, 'draw_beauty': True, 'additive': False, 'drawShadow': False}) - bs.animate_array(self.zone, 'size', 1, {0: [0], 0.3: [ - self.get_players_count()*0.85], 0.35: [self.get_players_count()*0.8]}) - bs.animate_array(self.zone_limit, 'size', 1, {0: [0], 0.3: [ - self.get_players_count()*1.2], 0.35: [self.get_players_count()*0.95]}) - self.last_players_count = self.get_players_count() - bs.getsound('laserReverse').play() - self.start_timer() - self.move_zone() - - def delete_zone(self): - self.zone.delete() - self.zone = None - self.zone_limit.delete() - self.zone_limit = None - bs.getsound('shieldDown').play() - bs.timer(1, self.spawn_zone) - - def move_zone(self): - if self.zone_pos[0] > 0: - x = random.randrange(0, 10) - else: - x = random.randrange(-10, 0) - - if self.zone_pos[2] > 0: - y = random.randrange(0, 5) - else: - y = random.randrange(-5, 0) - - new_pos = (x, 0.05, y) - bs.animate_array(self.zone, 'position', 3, {0: self.zone.position, 8: new_pos}) - bs.animate_array(self.zone_limit, 'position', 3, {0: self.zone_limit.position, 8: new_pos}) - - def start_timer(self): - count = self.get_players_count() - self._time_remaining = 10 if count > 9 else count-1 if count > 6 else count if count > 2 else count*2 - self._timer_x = bs.Timer(1.0, bs.WeakCall(self.tick), repeat=True) - # gnode = bs.getactivity().globalsnode - # tint = gnode.tint - # bs.animate_array(gnode,'tint',3,{0:tint,self._time_remaining*1.5:(1.0,0.5,0.5),self._time_remaining*1.55:tint}) - - def stop_timer(self): - self._time = None - self._timer_x = None - - def tick(self): - self.check_players() - self._time = bs.NodeActor(bs.newnode('text', - attrs={'v_attach': 'top', 'h_attach': 'center', - 'text': kill_timer+str(self._time_remaining)+'s', - 'opacity': 0.8, 'maxwidth': 100, 'h_align': 'center', - 'v_align': 'center', 'shadow': 1.0, 'flatness': 1.0, - 'color': (1, 1, 1), 'scale': 1.5, 'position': (0, -50)} - ) - ) - self._time_remaining -= 1 - self._tick_sound.play() - - def check_players(self): - if self._time_remaining <= 0: - self.stop_timer() - bs.animate_array(self.zone, 'size', 1, { - 0: [self.last_players_count*0.8], 1.4: [self.last_players_count*0.8], 1.5: [0]}) - bs.animate_array(self.zone_limit, 'size', 1, { - 0: [self.last_players_count*0.95], 1.45: [self.last_players_count*0.95], 1.5: [0]}) - bs.timer(1.5, self.delete_zone) - for player in self.players: - if not player.actor is None: - if player.actor.is_alive(): - p1 = player.actor.node.position - p2 = self.zone.position - diff = (babase.Vec3(p1[0]-p2[0], 0.0, p1[2]-p2[2])) - dist = (diff.length()) - if dist > (self.get_players_count()*0.7): - player.actor.handlemessage(bs.DieMessage()) - - def get_players_count(self): - count = 0 - for player in self.players: - if not player.actor is None: - if player.actor.is_alive(): - count += 1 - return count - - def _update_solo_mode(self) -> None: - # For both teams, find the first player on the spawn order list with - # lives remaining and spawn them if they're not alive. - for team in self.teams: - # Prune dead players from the spawn order. - team.spawn_order = [p for p in team.spawn_order if p] - for player in team.spawn_order: - assert isinstance(player, Player) - if player.lives > 0: - if not player.is_alive(): - self.spawn_player(player) - break - - 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: - player = team.players[0] - 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: - for icon in player.icons: - icon.set_position_and_scale((xval, 30), 0.7) - icon.update_for_lives() - xval += x_offs - - def _get_spawn_point(self, player: Player) -> Optional[babase.Vec3]: - del player # Unused. - - # In solo-mode, if there's an existing live player on the map, spawn at - # whichever spot is farthest from them (keeps the action spread out). - if self._solo_mode: - living_player = None - living_player_pos = None - for team in self.teams: - for tplayer in team.players: - if tplayer.is_alive(): - assert tplayer.node - ppos = tplayer.node.position - living_player = tplayer - living_player_pos = ppos - break - if living_player: - assert living_player_pos is not None - player_pos = babase.Vec3(living_player_pos) - points: List[Tuple[float, babase.Vec3]] = [] - for team in self.teams: - start_pos = babase.Vec3(self.map.get_start_position(team.id)) - points.append( - ((start_pos - player_pos).length(), start_pos)) - # Hmm.. we need to sorting vectors too? - points.sort(key=lambda x: x[0]) - return points[-1][1] - return None - - def spawn_player(self, player: Player) -> bs.Actor: - actor = self.spawn_player_spaz(player, self._get_spawn_point(player)) - if not self._solo_mode: - bs.timer(0.3, babase.Call(self._print_lives, player)) - - # spaz but *without* the ability to attack or pick stuff up. - actor.connect_controls_to_player(enable_punch=False, - enable_bomb=False, - enable_pickup=False) - - # If we have any icons, update their state. - for icon in player.icons: - icon.handle_player_spawned() - return actor - - def _print_lives(self, player: Player) -> None: - from bascenev1lib.actor import popuptext - - # We get called in a timer so it's possible our player has left/etc. - if not player or not player.is_alive() or not player.node: - return - - popuptext.PopupText('x' + str(player.lives - 1), - color=(1, 1, 0, 1), - offset=(0, -0.8, 0), - random_offset=0.0, - scale=1.8, - position=player.node.position).autoretain() - - def on_player_leave(self, player: Player) -> None: - super().on_player_leave(player) - player.icons = [] - - # Remove us from spawn-order. - if self._solo_mode: - if player in player.team.spawn_order: - player.team.spawn_order.remove(player) - - # Update icons in a moment since our team will be gone from the - # list then. - bs.timer(0, self._update_icons) - - # If the player to leave was the last in spawn order and had - # their final turn currently in-progress, mark the survival time - # for their team. - if self._get_total_team_lives(player.team) == 0: - assert self._start_time is not None - player.team.survival_seconds = int(bs.time() - self._start_time) - - def _get_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: - babase.print_error( - "Got lives < 0 in Elim; this shouldn't happen. solo:" + - str(self._solo_mode)) - 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 self._solo_mode or player.lives == 0: - SpazFactory.get().single_player_death_sound.play() - - # If we hit zero lives, we're dead (and our team might be too). - if player.lives == 0: - # If the whole team is now dead, mark their survival time. - if self._get_total_team_lives(player.team) == 0: - assert self._start_time is not None - player.team.survival_seconds = int(bs.time() - - self._start_time) - else: - # Otherwise, in regular mode, respawn. - if not self._solo_mode: - self.respawn_player(player) - - # In solo, put ourself at the back of the spawn order. - if self._solo_mode: - player.team.spawn_order.remove(player) - player.team.spawn_order.append(player) - elif isinstance(msg, stdbot.SpazBotDiedMessage): - self._on_spaz_bot_died(msg) - - def _on_spaz_bot_died(self, die_msg): - bs.timer(1, babase.Call(self.add_bot, die_msg.spazbot.node.position)) - - def _on_bot_spawn(self, spaz): - spaz.update_callback = self.move_bot - spaz_type = type(spaz) - spaz._charge_speed = self._get_bot_speed(spaz_type) - - def add_bot(self, pos=None): - if pos == 'left': - position = (-11, 0, random.randrange(-5, 5)) - elif pos == 'right': - position = (11, 0, random.randrange(-5, 5)) - else: - position = pos - self._bots.spawn_bot(self.get_random_bot(), pos=position, spawn_time=1, - on_spawn_call=babase.Call(self._on_bot_spawn)) - - def move_bot(self, bot): - p = bot.node.position - speed = -bot._charge_speed if (p[0] >= -11 and p[0] < 0) else bot._charge_speed - - if (p[0] >= -11) and (p[0] <= 11): - bot.node.move_left_right = speed - bot.node.move_up_down = 0.0 - bot.node.run = 0.0 - return True - return False - - def get_random_bot(self): - bots = [stdbot.BomberBotStatic, stdbot.TriggerBotStatic] - return (random.choice(bots)) - - def _get_bot_speed(self, bot_type): - if bot_type == stdbot.BomberBotStatic: - return 0.48 - elif bot_type == stdbot.TriggerBotStatic: - return 0.73 - else: - raise Exception('Invalid bot type to _getBotSpeed(): '+str(bot_type)) - - def _update(self) -> None: - if self._solo_mode: - # For both teams, find the first player on the spawn order - # list with lives remaining and spawn them if they're not alive. - for team in self.teams: - # Prune dead players from the spawn order. - team.spawn_order = [p for p in team.spawn_order if p] - for player in team.spawn_order: - assert isinstance(player, Player) - if player.lives > 0: - if not player.is_alive(): - self.spawn_player(player) - self._update_icons() - break - - # If we're down to 1 or fewer living teams, start a timer to end - # the game (allows the dust to settle and draws to occur if deaths - # are close enough). - if len(self._get_living_teams()) < 2: - self._round_end_timer = bs.Timer(0.5, self.end_game) - - def _get_living_teams(self) -> List[Team]: - return [ - team for team in self.teams - if len(team.players) > 0 and any(player.lives > 0 - for player in team.players) - ] - - 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)