Merge branch 'bombsquad-community:main' into main

This commit is contained in:
brostos 2023-07-29 02:31:23 +03:00 committed by GitHub
commit 4baa419f8a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 4284 additions and 884 deletions

View file

@ -149,17 +149,17 @@ diff --git a/plugins/utilities/sample_plugin.py b/plugins/utilities/sample_plugi
index ebb7dcc..da2b312 100644 index ebb7dcc..da2b312 100644
--- a/plugins/utilities/sample_plugin.py --- a/plugins/utilities/sample_plugin.py
+++ b/plugins/utilities/sample_plugin.py +++ b/plugins/utilities/sample_plugin.py
@@ -5,6 +5,7 @@ import ba @@ -5,6 +5,7 @@ import babase
class Main(ba.Plugin): class Main(babase.Plugin):
def on_app_running(self): def on_app_running(self):
ba.screenmessage("Hi! I am a sample plugin!") babase.screenmessage("Hi! I am a sample plugin!")
def has_settings_ui(self): def has_settings_ui(self):
return True return True
def show_settings_ui(self, source_widget): def show_settings_ui(self, source_widget):
- ba.screenmessage("You tapped my settings!") - babase.screenmessage("You tapped my settings!")
+ ba.screenmessage("Hey! This is my new screenmessage!") + babase.screenmessage("Hey! This is my new screenmessage!")
``` ```
To name this new version as `1.1.0`, add `"1.1.0": null,` just above the previous plugin version in `utilities.json`: To name this new version as `1.1.0`, add `"1.1.0": null,` just above the previous plugin version in `utilities.json`:

View file

@ -14,6 +14,12 @@
} }
], ],
"versions": { "versions": {
"2.0.0": {
"api_version": 8,
"commit_sha": "a941899",
"released_on": "20-07-2023",
"md5sum": "19f033445a8fe30fc7f4f62d94a54444"
},
"1.0.0": { "1.0.0": {
"api_version": 7, "api_version": 7,
"commit_sha": "e59073b", "commit_sha": "e59073b",
@ -22,6 +28,44 @@
} }
} }
}, },
"icy_emits": {
"description": "Survice from icy bombs emitting through cold platform. Playable in teams/ffa/co-op",
"external_url": "",
"authors": [
{
"name": "Freaku",
"email": "",
"discord": ""
}
],
"versions": {
"1.0.0": {
"api_version": 8,
"commit_sha": "48f9302",
"released_on": "28-07-2023",
"md5sum": "cedc448a3d625065d586445e115fcd1f"
}
}
},
"frozen_one": {
"description": "Survive until the timer runs out",
"external_url": "",
"authors": [
{
"name": "Freaku",
"email": "",
"discord": ""
}
],
"versions": {
"1.0.0": {
"api_version": 8,
"commit_sha": "48f9302",
"released_on": "28-07-2023",
"md5sum": "529c8b9c9a450317d5aa75e8eab47497"
}
}
},
"simon_says": { "simon_says": {
"description": "You better do what Simon says", "description": "You better do what Simon says",
"external_url": "", "external_url": "",
@ -109,6 +153,12 @@
} }
], ],
"versions": { "versions": {
"2.0.0": {
"api_version": 8,
"commit_sha": "6263872",
"released_on": "23-07-2023",
"md5sum": "9789ad3583f1d92d4e4b7bc03d09591d"
},
"1.0.0": { "1.0.0": {
"api_version": 7, "api_version": 7,
"commit_sha": "2fda676", "commit_sha": "2fda676",
@ -187,10 +237,16 @@
{ {
"name": "Freaku", "name": "Freaku",
"email": "", "email": "",
"discord": "[Just] Freak#4999" "discord": ""
} }
], ],
"versions": { "versions": {
"2.0.0": {
"api_version": 8,
"commit_sha": "48f9302",
"released_on": "28-07-2023",
"md5sum": "2c457b80b5a35adf0cad1436af4ab3fe"
},
"1.1.0": { "1.1.0": {
"api_version": 7, "api_version": 7,
"commit_sha": "0bc9522", "commit_sha": "0bc9522",
@ -206,10 +262,16 @@
{ {
"name": "Freaku", "name": "Freaku",
"email": "", "email": "",
"discord": "[Just] Freak#4999" "discord": ""
} }
], ],
"versions": { "versions": {
"2.0.0": {
"api_version": 8,
"commit_sha": "48f9302",
"released_on": "28-07-2023",
"md5sum": "49ae645a5afc390ead44d7219b388c78"
},
"1.0.0": { "1.0.0": {
"api_version": 7, "api_version": 7,
"commit_sha": "858030b", "commit_sha": "858030b",
@ -225,10 +287,16 @@
{ {
"name": "Freaku", "name": "Freaku",
"email": "", "email": "",
"discord": "[Just] Freak#4999" "discord": ""
} }
], ],
"versions": { "versions": {
"2.0.0": {
"api_version": 8,
"commit_sha": "48f9302",
"released_on": "28-07-2023",
"md5sum": "4cb6510f9f3ce151720a53a957986864"
},
"1.0.0": { "1.0.0": {
"api_version": 7, "api_version": 7,
"commit_sha": "858030b", "commit_sha": "858030b",
@ -316,6 +384,12 @@
} }
], ],
"versions": { "versions": {
"2.0.0": {
"api_version": 8,
"commit_sha": "f54c993",
"released_on": "27-07-2023",
"md5sum": "7699483f4c379db809676ac917943d3c"
},
"1.0.0": { "1.0.0": {
"api_version": 7, "api_version": 7,
"commit_sha": "2aa1e50", "commit_sha": "2aa1e50",
@ -412,15 +486,16 @@
{ {
"name": "Freaku", "name": "Freaku",
"email": "", "email": "",
"discord": "[Just] Freak#4999" "discord": ""
},
{
"name": "LoupGarou",
"email": "LoupGarou5418@outlook.com",
"discord": "ʟօʊքɢǟʀօʊ#3063"
} }
], ],
"versions": { "versions": {
"2.0.0": {
"api_version": 8,
"commit_sha": "48f9302",
"released_on": "28-07-2023",
"md5sum": "22b51a147524d84fbc249e61f21ae424"
},
"1.1.0": { "1.1.0": {
"api_version": 7, "api_version": 7,
"commit_sha": "2e2540a", "commit_sha": "2e2540a",
@ -451,6 +526,12 @@
} }
], ],
"versions": { "versions": {
"2.0.0": {
"api_version": 8,
"commit_sha": "e8bbb61",
"released_on": "23-07-2023",
"md5sum": "1acbeecffada937bdd745f4e4d43f1be"
},
"1.0.0": { "1.0.0": {
"api_version": 7, "api_version": 7,
"commit_sha": "7219487", "commit_sha": "7219487",
@ -470,6 +551,12 @@
} }
], ],
"versions": { "versions": {
"2.0.0": {
"api_version": 8,
"commit_sha": "1a8037e",
"released_on": "23-07-2023",
"md5sum": "916e37f6e1a8a5be3dd0389ed2c4b261"
},
"1.0.0": { "1.0.0": {
"api_version": 7, "api_version": 7,
"commit_sha": "7219487", "commit_sha": "7219487",
@ -573,6 +660,25 @@
} }
} }
}, },
"quake_original": {
"description": "Good ol' Quake minigame",
"external_url": "",
"authors": [
{
"name": "Unknown",
"email": "",
"discord": ""
}
],
"versions": {
"1.0.0": {
"api_version": 8,
"commit_sha": "185480d",
"released_on": "24-07-2023",
"md5sum": "f68395cc90dc8cddb166a23b2da81b7b"
}
}
},
"ufo_fight": { "ufo_fight": {
"description": "Fight the UFO boss!", "description": "Fight the UFO boss!",
"external_url": "", "external_url": "",
@ -599,7 +705,7 @@
{ {
"name": "Freaku", "name": "Freaku",
"email": "", "email": "",
"discord": "[Just] Freak#4999" "discord": ""
} }
], ],
"versions": { "versions": {
@ -610,6 +716,87 @@
"md5sum": "197a377652ab0c3bfbe1ca07833924b4" "md5sum": "197a377652ab0c3bfbe1ca07833924b4"
} }
} }
},
"big_ball": {
"description": "Score some goals with Big Ball on Football map",
"external_url": "",
"authors": [
{
"name": "MythB",
"email": "",
"discord": ""
}
],
"versions": {
"1.0.0": {
"api_version": 8,
"commit_sha": "ca3221b",
"released_on": "27-07-2023",
"md5sum": "39c5b18efd5d5314f30c12fc0bec4931"
}
}
},
"handball": {
"description": "Score some goals with handball",
"external_url": "",
"authors": [
{
"name": "Unknown",
"email": "",
"discord": ""
}
],
"versions": {
"1.0.0": {
"api_version": 8,
"commit_sha": "2309aab",
"released_on": "24-07-2023",
"md5sum": "01b85dc9ef1d464ab604387af09f05dc"
}
}
},
"super_duel": {
"description": "Crush your enemy in a 1v1",
"external_url": "https://www.youtube.com/watch?v=hvRtiXR-oC0",
"authors": [
{
"name": "JoseAng3l",
"email": "",
"discord": "joseang3l"
}
],
"versions": {
"1.0.0": {
"api_version": 8,
"commit_sha": "ab26786",
"released_on": "27-07-2023",
"md5sum": "d0c9c0472d7b145eadf535957a462fdf"
}
}
},
"supersmash": {
"description": "Blow up your enemies off the map!",
"external_url": "",
"authors": [
{
"name": "Mrmaxmeier",
"email": "",
"discord": ""
},
{
"name": "JoseAngel",
"email": "",
"discord": "joseang3l"
}
],
"versions": {
"1.0.0": {
"api_version": 8,
"commit_sha": "68e77f2",
"released_on": "24-07-2023",
"md5sum": "1cbe5b3e85b5dfcee1eb322f33568fd4"
}
}
} }
} }
} }

View file

@ -1,17 +1,18 @@
# Ported by: Freaku / @[Just] Freak#4999 # Ported by your friend: Freaku
# Join BCS: # Join BCS:
# https://discord.gg/ucyaesh # https://discord.gg/ucyaesh
# ba_meta require api 7 # ba_meta require api 8
from __future__ import annotations from __future__ import annotations
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
import ba import babase
from bastd.actor.playerspaz import PlayerSpaz import bascenev1 as bs
from bascenev1lib.actor.playerspaz import PlayerSpaz
if TYPE_CHECKING: if TYPE_CHECKING:
from typing import Any, Type, List, Dict, Tuple, Union, Sequence, Optional from typing import Any, Type, List, Dict, Tuple, Union, Sequence, Optional
@ -30,8 +31,7 @@ class State:
self.next = None self.next = None
self.index = None self.index = None
def apply(self, player, spaz): def apply(self, spaz):
spaz.disconnect_controls_from_player() spaz.disconnect_controls_from_player()
spaz.connect_controls_to_player(enable_punch=self.punch, spaz.connect_controls_to_player(enable_punch=self.punch,
enable_bomb=self.bomb, enable_bomb=self.bomb,
@ -43,18 +43,6 @@ class State:
spaz.bomb_type = self.bomb spaz.bomb_type = self.bomb
spaz.set_score_text(self.name) spaz.set_score_text(self.name)
def set_controls():
player.actor.node.bomb_pressed = True
player.actor.on_bomb_release()
release_input = (ba.InputType.PUNCH_RELEASE, ba.InputType.PICK_UP_RELEASE)
if not self.bomb is None:
for release in release_input:
player.assigninput(
release,
set_controls
)
def get_setting(self): def get_setting(self):
return (self.name) return (self.name)
@ -68,22 +56,22 @@ states = [State(bomb='normal', name='Basic Bombs'),
State(curse=True, name='Cursed', final=True)] State(curse=True, name='Cursed', final=True)]
class Player(ba.Player['Team']): class Player(bs.Player['Team']):
"""Our player type for this game.""" """Our player type for this game."""
def __init__(self): def __init__(self):
self.state = None self.state = None
class Team(ba.Team[Player]): class Team(bs.Team[Player]):
"""Our team type for this game.""" """Our team type for this game."""
def __init__(self) -> None: def __init__(self) -> None:
self.score = 0 self.score = 0
# ba_meta export game # ba_meta export bascenev1.GameActivity
class ArmsRaceGame(ba.TeamGameActivity[Player, Team]): class ArmsRaceGame(bs.TeamGameActivity[Player, Team]):
"""A game type based on acquiring kills.""" """A game type based on acquiring kills."""
name = 'Arms Race' name = 'Arms Race'
@ -94,9 +82,9 @@ class ArmsRaceGame(ba.TeamGameActivity[Player, Team]):
@classmethod @classmethod
def get_available_settings( def get_available_settings(
cls, sessiontype: Type[ba.Session]) -> List[ba.Setting]: cls, sessiontype: Type[bs.Session]) -> List[babase.Setting]:
settings = [ settings = [
ba.IntChoiceSetting( bs.IntChoiceSetting(
'Time Limit', 'Time Limit',
choices=[ choices=[
('None', 0), ('None', 0),
@ -108,7 +96,7 @@ class ArmsRaceGame(ba.TeamGameActivity[Player, Team]):
], ],
default=0, default=0,
), ),
ba.FloatChoiceSetting( bs.FloatChoiceSetting(
'Respawn Times', 'Respawn Times',
choices=[ choices=[
('Shorter', 0.25), ('Shorter', 0.25),
@ -119,21 +107,21 @@ class ArmsRaceGame(ba.TeamGameActivity[Player, Team]):
], ],
default=1.0, default=1.0,
), ),
ba.BoolSetting('Epic Mode', default=False)] bs.BoolSetting('Epic Mode', default=False)]
for state in states: for state in states:
if not state.required: if not state.required:
settings.append(ba.BoolSetting(state.get_setting(), default=True)) settings.append(bs.BoolSetting(state.get_setting(), default=True))
return settings return settings
@classmethod @classmethod
def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool: def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool:
return (issubclass(sessiontype, ba.DualTeamSession) return (issubclass(sessiontype, bs.DualTeamSession)
or issubclass(sessiontype, ba.FreeForAllSession)) or issubclass(sessiontype, bs.FreeForAllSession))
@classmethod @classmethod
def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]:
return ba.getmaps('melee') return bs.app.classic.getmaps('melee')
def __init__(self, settings: dict): def __init__(self, settings: dict):
super().__init__(settings) super().__init__(settings)
@ -142,14 +130,14 @@ class ArmsRaceGame(ba.TeamGameActivity[Player, Team]):
if i < len(self.states) and not state.final: if i < len(self.states) and not state.final:
state.next = self.states[i + 1] state.next = self.states[i + 1]
state.index = i state.index = i
self._dingsound = ba.getsound('dingSmall') self._dingsound = bs.getsound('dingSmall')
self._epic_mode = bool(settings['Epic Mode']) self._epic_mode = bool(settings['Epic Mode'])
self._time_limit = float(settings['Time Limit']) self._time_limit = float(settings['Time Limit'])
# Base class overrides. # Base class overrides.
self.slow_motion = self._epic_mode self.slow_motion = self._epic_mode
self.default_music = (ba.MusicType.EPIC if self._epic_mode else self.default_music = (bs.MusicType.EPIC if self._epic_mode else
ba.MusicType.TO_THE_DEATH) bs.MusicType.TO_THE_DEATH)
def get_instance_description(self) -> Union[str, Sequence]: def get_instance_description(self) -> Union[str, Sequence]:
return 'Upgrade your weapon by eliminating enemies.' return 'Upgrade your weapon by eliminating enemies.'
@ -168,12 +156,11 @@ class ArmsRaceGame(ba.TeamGameActivity[Player, Team]):
self.spawn_player(player) self.spawn_player(player)
# overriding the default character spawning.. # overriding the default character spawning..
def spawn_player(self, player): def spawn_player(self, player):
if player.state is None: if player.state is None:
player.state = self.states[0] player.state = self.states[0]
super().spawn_player(player) super().spawn_player(player)
player.state.apply(player, player.actor) player.state.apply(player.actor)
def isValidKill(self, m): def isValidKill(self, m):
if m.getkillerplayer(Player) is None: if m.getkillerplayer(Player) is None:
@ -186,13 +173,12 @@ class ArmsRaceGame(ba.TeamGameActivity[Player, Team]):
def handlemessage(self, msg: Any) -> Any: def handlemessage(self, msg: Any) -> Any:
if isinstance(msg, ba.PlayerDiedMessage): if isinstance(msg, bs.PlayerDiedMessage):
if self.isValidKill(msg): if self.isValidKill(msg):
self.stats.player_scored(msg.getkillerplayer(Player), 10, kill=True) self.stats.player_scored(msg.getkillerplayer(Player), 10, kill=True)
if not msg.getkillerplayer(Player).state.final: if not msg.getkillerplayer(Player).state.final:
msg.getkillerplayer(Player).state = msg.getkillerplayer(Player).state.next msg.getkillerplayer(Player).state = msg.getkillerplayer(Player).state.next
msg.getkillerplayer(Player).state.apply( msg.getkillerplayer(Player).state.apply(msg.getkillerplayer(Player).actor)
msg.getkillerplayer(Player), msg.getkillerplayer(Player).actor)
else: else:
msg.getkillerplayer(Player).team.score += 1 msg.getkillerplayer(Player).team.score += 1
self.end_game() self.end_game()
@ -203,7 +189,7 @@ class ArmsRaceGame(ba.TeamGameActivity[Player, Team]):
return None return None
def end_game(self) -> None: def end_game(self) -> None:
results = ba.GameResults() results = bs.GameResults()
for team in self.teams: for team in self.teams:
results.set_team_score(team, team.score) results.set_team_score(team, team.score)
self.end(results=results) self.end(results=results)

View file

@ -0,0 +1,524 @@
# Made by MythB
# Ported by: MysteriousBoi
# ba_meta require api 8
from __future__ import annotations
from typing import TYPE_CHECKING
import babase
import bauiv1 as bui
import bascenev1 as bs
import random
from bascenev1lib.actor.playerspaz import PlayerSpaz
from bascenev1lib.actor.scoreboard import Scoreboard
from bascenev1lib.actor.powerupbox import PowerupBoxFactory
from bascenev1lib.gameutils import SharedObjects
from bascenev1lib.actor.flag import Flag
if TYPE_CHECKING:
from typing import Any, Sequence, Dict, Type, List, Optional, Union
class PuckDiedMessage:
"""Inform something that a puck has died."""
def __init__(self, puck: Puck):
self.puck = puck
# goalpost
class FlagKale(bs.Actor):
def __init__(self, position=(0, 2.5, 0), color=(1, 1, 1)):
super().__init__()
activity = self.getactivity()
shared = SharedObjects.get()
self.node = bs.newnode('flag',
attrs={'position': (position[0], position[1]+0.75, position[2]),
'color_texture': activity._flagKaleTex,
'color': color,
'materials': [shared.object_material, activity._kaleMaterial],
},
delegate=self)
def handleMessage(self, m):
if isinstance(m, bs.DieMessage):
if self.node.exists():
self.node.delete()
elif isinstance(m, bs.OutOfBoundsMessage):
self.handlemessage(bs.DieMessage())
else:
super().handlemessage(msg)
class Puck(bs.Actor):
def __init__(self, position: Sequence[float] = (0.0, 1.0, 0.0)):
super().__init__()
shared = SharedObjects.get()
activity = self.getactivity()
# Spawn just above the provided point.
self._spawn_pos = (position[0], position[1] + 1.0, position[2])
self.last_players_to_touch: Dict[int, Player] = {}
self.scored = False
assert activity is not None
assert isinstance(activity, BBGame)
pmats = [shared.object_material, activity.puck_material]
self.node = bs.newnode('prop',
delegate=self,
attrs={
'mesh': activity._ballModel,
'color_texture': activity._ballTex,
'body': 'sphere',
'reflection': 'soft',
'reflection_scale': [0.2],
'shadow_size': 0.8,
'is_area_of_interest': True,
'position': self._spawn_pos,
'materials': pmats,
'body_scale': 4,
'mesh_scale': 1,
'density': 0.02})
bs.animate(self.node, 'mesh_scale', {0: 0, 0.2: 1.3, 0.26: 1})
def handlemessage(self, msg: Any) -> Any:
if isinstance(msg, bs.DieMessage):
assert self.node
self.node.delete()
activity = self._activity()
if activity and not msg.immediate:
activity.handlemessage(PuckDiedMessage(self))
# If we go out of bounds, move back to where we started.
elif isinstance(msg, bs.OutOfBoundsMessage):
assert self.node
self.node.position = self._spawn_pos
elif isinstance(msg, bs.HitMessage):
assert self.node
assert msg.force_direction is not None
self.node.handlemessage(
'impulse', msg.pos[0], msg.pos[1], msg.pos[2], msg.velocity[0],
msg.velocity[1], msg.velocity[2], 1.0 * msg.magnitude,
1.0 * msg.velocity_magnitude, msg.radius, 0,
msg.force_direction[0], msg.force_direction[1],
msg.force_direction[2])
# If this hit came from a player, log them as the last to touch us.
s_player = msg.get_source_player(Player)
if s_player is not None:
activity = self._activity()
if activity:
if s_player in activity.players:
self.last_players_to_touch[s_player.team.id] = s_player
else:
super().handlemessage(msg)
# for night mode: using a actor with large shadow and little mesh scale. Better then tint i think, players and objects more visible
class NightMod(bs.Actor):
def __init__(self, position=(0, 0, 0)):
super().__init__()
shared = SharedObjects.get()
activity = self.getactivity()
# spawn just above the provided point
self._spawnPos = (position[0], position[1], position[2])
self.node = bs.newnode("prop",
attrs={'mesh': activity._nightModel,
'color_texture': activity._nightTex,
'body': 'sphere',
'reflection': 'soft',
'body_scale': 0.1,
'mesh_scale': 0.001,
'density': 0.010,
'reflection_scale': [0.23],
'shadow_size': 999999.0,
'is_area_of_interest': True,
'position': self._spawnPos,
'materials': [activity._nightMaterial]
},
delegate=self)
def handlemssage(self, m):
super().handlemessage(m)
class Player(bs.Player['Team']):
"""Our player type for this game."""
class Team(bs.Team[Player]):
"""Our team type for this game."""
def __init__(self) -> None:
self.score = 0
# ba_meta export bascenev1.GameActivity
class BBGame(bs.TeamGameActivity[Player, Team]):
name = 'Big Ball'
description = 'Score some goals.\nFlags are goalposts.\nScored team players get boxing gloves,\nNon-scored team players getting shield (if Grant Powers on Score).\nYou can also set Night Mode!'
available_settings = [
bs.IntSetting(
'Score to Win',
min_value=1,
default=1,
increment=1,
),
bs.IntChoiceSetting(
'Time Limit',
choices=[
('None', 0),
('1 Minute', 60),
('2 Minutes', 120),
('5 Minutes', 300),
('10 Minutes', 600),
('20 Minutes', 1200),
],
default=0,
),
bs.FloatChoiceSetting(
'Respawn Times',
choices=[
('Shorter', 0.25),
('Short', 0.5),
('Normal', 1.0),
('Long', 2.0),
('Longer', 4.0),
],
default=1.0,
),
bs.BoolSetting('Epic Mode', True),
bs.BoolSetting('Night Mode', False),
bs.BoolSetting('Grant Powers on Score', False)
]
default_music = bs.MusicType.HOCKEY
@classmethod
def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool:
return issubclass(sessiontype, bs.DualTeamSession)
@classmethod
def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]:
return ['Football Stadium']
def __init__(self, settings: dict):
super().__init__(settings)
shared = SharedObjects.get()
self._scoreboard = Scoreboard()
self._cheer_sound = bs.getsound('cheer')
self._chant_sound = bs.getsound('crowdChant')
self._foghorn_sound = bs.getsound('foghorn')
self._swipsound = bs.getsound('swip')
self._whistle_sound = bs.getsound('refWhistle')
self._ballModel = bs.getmesh("shield")
self._ballTex = bs.gettexture("eggTex1")
self._ballSound = bs.getsound("impactMedium2")
self._flagKaleTex = bs.gettexture("star")
self._kaleSound = bs.getsound("metalHit")
self._nightModel = bs.getmesh("shield")
self._nightTex = bs.gettexture("black")
self._kaleMaterial = bs.Material()
# add friction to flags for standing our position (as far as)
self._kaleMaterial.add_actions(conditions=("they_have_material", shared.footing_material),
actions=(("modify_part_collision", "friction", 9999.5)))
self._kaleMaterial.add_actions(conditions=(("we_are_younger_than", 1), 'and',
("they_have_material", shared.object_material)),
actions=(("modify_part_collision", "collide", False)))
self._kaleMaterial.add_actions(conditions=("they_have_material", shared.pickup_material),
actions=(("modify_part_collision", "collide", False)))
self._kaleMaterial.add_actions(
conditions=('they_have_material', shared.object_material),
actions=(('impact_sound', self._kaleSound, 2, 5)))
# we dont wanna hit the night so
self._nightMaterial = bs.Material()
self._nightMaterial.add_actions(conditions=(('they_have_material', shared.pickup_material), 'or',
('they_have_material', shared.attack_material)),
actions=(('modify_part_collision', 'collide', False)))
# we also dont want anything moving it
self._nightMaterial.add_actions(
conditions=(('they_have_material', shared.object_material), 'or',
('they_dont_have_material', shared.footing_material)),
actions=(('modify_part_collision', 'collide', False),
('modify_part_collision', 'physical', False)))
self.puck_material = bs.Material()
self.puck_material.add_actions(actions=(('modify_part_collision',
'friction', 0.5)))
self.puck_material.add_actions(conditions=('they_have_material',
shared.pickup_material),
actions=('modify_part_collision',
'collide', False))
self.puck_material.add_actions(
conditions=(
('we_are_younger_than', 100),
'and',
('they_have_material', shared.object_material),
),
actions=('modify_node_collision', 'collide', False),
)
self.puck_material.add_actions(conditions=('they_have_material',
shared.footing_material),
actions=('impact_sound',
self._ballSound, 0.2, 5))
# Keep track of which player last touched the puck
self.puck_material.add_actions(
conditions=('they_have_material', shared.player_material),
actions=(('call', 'at_connect',
self._handle_puck_player_collide), ))
# We want the puck to kill powerups; not get stopped by them
self.puck_material.add_actions(
conditions=('they_have_material',
PowerupBoxFactory.get().powerup_material),
actions=(('modify_part_collision', 'physical', False),
('message', 'their_node', 'at_connect', bs.DieMessage())))
self._score_region_material = bs.Material()
self._score_region_material.add_actions(
conditions=('they_have_material', self.puck_material),
actions=(('modify_part_collision', 'collide',
True), ('modify_part_collision', 'physical', False),
('call', 'at_connect', self._handle_score)))
self._puck_spawn_pos: Optional[Sequence[float]] = None
self._score_regions: Optional[List[bs.NodeActor]] = None
self._puck: Optional[Puck] = None
self._score_to_win = int(settings['Score to Win'])
self._time_limit = float(settings['Time Limit'])
self._nm = bool(settings['Night Mode'])
self._grant_power = bool(settings['Grant Powers on Score'])
self._epic_mode = bool(settings['Epic Mode'])
# Base class overrides.
self.slow_motion = self._epic_mode
def get_instance_description(self) -> Union[str, Sequence]:
if self._score_to_win == 1:
return 'Score a goal.'
return 'Score ${ARG1} goals.', self._score_to_win
def get_instance_description_short(self) -> Union[str, Sequence]:
if self._score_to_win == 1:
return 'score a goal'
return 'score ${ARG1} goals', self._score_to_win
def on_begin(self) -> None:
super().on_begin()
self.setup_standard_time_limit(self._time_limit)
self.setup_standard_powerup_drops()
self._puck_spawn_pos = self.map.get_flag_position(None)
self._spawn_puck()
# for night mode we need night actor. And same goodies for nigh mode
if self._nm:
self._nightSpawny(), self._flagKaleFlash()
# Set up the two score regions.
defs = self.map.defs
self._score_regions = []
self._score_regions.append(
bs.NodeActor(
bs.newnode('region',
attrs={
'position': (13.75, 0.85744967453, 0.1095578275),
'scale': (1.05, 1.1, 3.8),
'type': 'box',
'materials': [self._score_region_material]
})))
self._score_regions.append(
bs.NodeActor(
bs.newnode('region',
attrs={
'position': (-13.55, 0.85744967453, 0.1095578275),
'scale': (1.05, 1.1, 3.8),
'type': 'box',
'materials': [self._score_region_material]
})))
self._update_scoreboard()
self._chant_sound.play()
def _nightSpawny(self):
self.MythBrk = NightMod(position=(0, 0.05744967453, 0))
# spawn some goodies on nightmode for pretty visuals
def _flagKaleFlash(self):
# flags positions
kale1 = (-12.45, 0.05744967453, -2.075)
kale2 = (-12.45, 0.05744967453, 2.075)
kale3 = (12.66, 0.03986567039, 2.075)
kale4 = (12.66, 0.03986567039, -2.075)
flash = bs.newnode("light",
attrs={'position': kale1,
'radius': 0.15,
'color': (1.0, 1.0, 0.7)})
flash = bs.newnode("light",
attrs={'position': kale2,
'radius': 0.15,
'color': (1.0, 1.0, 0.7)})
flash = bs.newnode("light",
attrs={'position': kale3,
'radius': 0.15,
'color': (0.7, 1.0, 1.0)})
flash = bs.newnode("light",
attrs={'position': kale4,
'radius': 0.15,
'color': (0.7, 1.0, 1.0)})
# flags positions
def _flagKalesSpawn(self):
for team in self.teams:
if team.id == 0:
_colorTeam0 = team.color
if team.id == 1:
_colorTeam1 = team.color
self._MythB = FlagKale(position=(-12.45, 0.05744967453, -2.075), color=_colorTeam0)
self._MythB2 = FlagKale(position=(-12.45, 0.05744967453, 2.075), color=_colorTeam0)
self._MythB3 = FlagKale(position=(12.66, 0.03986567039, 2.075), color=_colorTeam1)
self._MythB4 = FlagKale(position=(12.66, 0.03986567039, -2.075), color=_colorTeam1)
def on_team_join(self, team: Team) -> None:
self._update_scoreboard()
def _handle_puck_player_collide(self) -> None:
collision = bs.getcollision()
try:
puck = collision.sourcenode.getdelegate(Puck, True)
player = collision.opposingnode.getdelegate(PlayerSpaz,
True).getplayer(
Player, True)
except bs.NotFoundError:
return
puck.last_players_to_touch[player.team.id] = player
def _kill_puck(self) -> None:
self._puck = None
def _handle_score(self) -> None:
"""A point has been scored."""
assert self._puck is not None
assert self._score_regions is not None
# Our puck might stick around for a second or two
# we don't want it to be able to score again.
if self._puck.scored:
return
region = bs.getcollision().sourcenode
index = 0
for index in range(len(self._score_regions)):
if region == self._score_regions[index].node:
break
for team in self.teams:
if team.id == index:
scoring_team = team
team.score += 1
# tell scored team players to celebrate and give them to boxing gloves
if self._grant_power:
for player in team.players:
try:
player.actor.node.handlemessage(bs.PowerupMessage('punch'))
except:
pass
# Tell all players to celebrate.
for player in team.players:
if player.actor:
player.actor.handlemessage(bs.CelebrateMessage(2.0))
# If we've got the player from the scoring team that last
# touched us, give them points.
if (scoring_team.id in self._puck.last_players_to_touch
and self._puck.last_players_to_touch[scoring_team.id]):
self.stats.player_scored(
self._puck.last_players_to_touch[scoring_team.id],
100,
big_message=True)
# End game if we won.
if team.score >= self._score_to_win:
self.end_game()
else:
if self._grant_power:
for player in team.players:
try:
player.actor.node.handlemessage(bs.PowerupMessage('shield'))
except:
pass
self._foghorn_sound.play()
self._cheer_sound.play()
self._puck.scored = True
# Kill the puck (it'll respawn itself shortly).
bs.timer(1.0, self._kill_puck)
light = bs.newnode('light',
attrs={
'position': bs.getcollision().position,
'height_attenuated': False,
'color': (1, 0, 0)
})
bs.animate(light, 'intensity', {0: 0, 0.5: 1, 1.0: 0}, loop=True)
bs.timer(1.0, light.delete)
bs.cameraflash(duration=10.0)
self._update_scoreboard()
def end_game(self) -> None:
results = bs.GameResults()
for team in self.teams:
results.set_team_score(team, team.score)
self.end(results=results)
def _update_scoreboard(self) -> None:
winscore = self._score_to_win
for team in self.teams:
self._scoreboard.set_team_value(team, team.score, winscore)
def handlemessage(self, msg: Any) -> Any:
# Respawn dead players if they're still in the game.
if isinstance(msg, bs.PlayerDiedMessage):
# Augment standard behavior...
super().handlemessage(msg)
self.respawn_player(msg.getplayer(Player))
# Respawn dead pucks.
elif isinstance(msg, PuckDiedMessage):
if not self.has_ended():
bs.timer(3.0, self._spawn_puck)
else:
super().handlemessage(msg)
def _flash_puck_spawn(self) -> None:
light = bs.newnode('light',
attrs={
'position': self._puck_spawn_pos,
'height_attenuated': False,
'color': (1, 0, 0)
})
bs.animate(light, 'intensity', {0.0: 0, 0.25: 1, 0.5: 0}, loop=True)
bs.timer(1.0, light.delete)
def _spawn_puck(self) -> None:
self._swipsound.play()
self._whistle_sound.play()
self._flagKalesSpawn()
self._flash_puck_spawn()
assert self._puck_spawn_pos is not None
self._puck = Puck(position=self._puck_spawn_pos)
self._puck.light = bs.newnode('light',
owner=self._puck.node,
attrs={'intensity': 0.3,
'height_attenuated': False,
'radius': 0.2,
'color': (0.9, 0.2, 0.9)})
self._puck.node.connectattr('position', self._puck.light, 'position')

View file

@ -1,20 +1,22 @@
# ba_meta require api 7 # ba_meta require api 8
# (see https://ballistica.net/wiki/meta-tag-system) # (see https://ballistica.net/wiki/meta-tag-system)
from __future__ import annotations from __future__ import annotations
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
import ba import babase
from bastd.actor.playerspaz import PlayerSpaz import bauiv1 as bui
from bastd.actor.scoreboard import Scoreboard import bascenev1 as bs
from bastd.game.deathmatch import DeathMatchGame from bascenev1lib.actor.playerspaz import PlayerSpaz
from bascenev1lib.actor.scoreboard import Scoreboard
from bascenev1lib.game.deathmatch import DeathMatchGame
if TYPE_CHECKING: if TYPE_CHECKING:
from typing import Any, Sequence from typing import Any, Sequence
lang = ba.app.lang.language lang = bs.app.lang.language
if lang == 'Spanish': if lang == 'Spanish':
name = 'Super Boxeo' name = 'Super Boxeo'
@ -33,7 +35,7 @@ else:
class NewPlayerSpaz(PlayerSpaz): class NewPlayerSpaz(PlayerSpaz):
def __init__(self, def __init__(self,
player: ba.Player, player: bs.Player,
color: Sequence[float] = (1.0, 1.0, 1.0), color: Sequence[float] = (1.0, 1.0, 1.0),
highlight: Sequence[float] = (0.5, 0.5, 0.5), highlight: Sequence[float] = (0.5, 0.5, 0.5),
character: str = 'Spaz', character: str = 'Spaz',
@ -44,16 +46,16 @@ class NewPlayerSpaz(PlayerSpaz):
highlight=highlight, highlight=highlight,
character=character, character=character,
powerups_expire=powerups_expire) powerups_expire=powerups_expire)
from bastd.gameutils import SharedObjects from bascenev1lib.gameutils import SharedObjects
shared = SharedObjects.get() shared = SharedObjects.get()
self._super_jump = super_jump self._super_jump = super_jump
self.jump_mode = False self.jump_mode = False
self.super_jump_material = ba.Material() self.super_jump_material = bs.Material()
self.super_jump_material.add_actions( self.super_jump_material.add_actions(
conditions=('they_have_material', shared.footing_material), conditions=('they_have_material', shared.footing_material),
actions=( actions=(
('call', 'at_connect', ba.Call(self.jump_state, True)), ('call', 'at_connect', babase.Call(self.jump_state, True)),
('call', 'at_disconnect', ba.Call(self.jump_state, False)) ('call', 'at_disconnect', babase.Call(self.jump_state, False))
), ),
) )
self.node.roller_materials += (self.super_jump_material, ) self.node.roller_materials += (self.super_jump_material, )
@ -68,7 +70,7 @@ class NewPlayerSpaz(PlayerSpaz):
""" """
if not self.node: if not self.node:
return return
t_ms = ba.time(timeformat=ba.TimeFormat.MILLISECONDS) t_ms = int(bs.time() * 1000.0)
assert isinstance(t_ms, int) assert isinstance(t_ms, int)
if t_ms - self.last_jump_time_ms >= self._jump_cooldown: if t_ms - self.last_jump_time_ms >= self._jump_cooldown:
self.node.jump_pressed = True self.node.jump_pressed = True
@ -81,15 +83,15 @@ class NewPlayerSpaz(PlayerSpaz):
self.node.position[0], self.node.position[0],
self.node.position[1], self.node.position[1],
self.node.position[2], self.node.position[2],
0, 0, 0, 150, 150, 0, 0, 0, 1, 0 0, 0, 0, 95, 95, 0, 0, 0, 1, 0
) )
ba.timer(0.0, do_jump) bs.timer(0.0, do_jump)
ba.timer(0.1, do_jump) bs.timer(0.1, do_jump)
ba.timer(0.2, do_jump) bs.timer(0.2, do_jump)
self._turbo_filter_add_press('jump') self._turbo_filter_add_press('jump')
# ba_meta export game # ba_meta export bascenev1.GameActivity
class BoxingGame(DeathMatchGame): class BoxingGame(DeathMatchGame):
name = name name = name
@ -97,16 +99,16 @@ class BoxingGame(DeathMatchGame):
@classmethod @classmethod
def get_available_settings( def get_available_settings(
cls, sessiontype: type[ba.Session] cls, sessiontype: type[bs.Session]
) -> list[ba.Setting]: ) -> list[babase.Setting]:
settings = [ settings = [
ba.IntSetting( bs.IntSetting(
'Kills to Win Per Player', 'Kills to Win Per Player',
min_value=1, min_value=1,
default=5, default=5,
increment=1, increment=1,
), ),
ba.IntChoiceSetting( bs.IntChoiceSetting(
'Time Limit', 'Time Limit',
choices=[ choices=[
('None', 0), ('None', 0),
@ -118,7 +120,7 @@ class BoxingGame(DeathMatchGame):
], ],
default=0, default=0,
), ),
ba.FloatChoiceSetting( bs.FloatChoiceSetting(
'Respawn Times', 'Respawn Times',
choices=[ choices=[
('Shorter', 0.25), ('Shorter', 0.25),
@ -129,9 +131,9 @@ class BoxingGame(DeathMatchGame):
], ],
default=1.0, default=1.0,
), ),
ba.BoolSetting(super_jump_text, default=False), bs.BoolSetting(super_jump_text, default=False),
ba.BoolSetting(enable_powerups, default=False), bs.BoolSetting(enable_powerups, default=False),
ba.BoolSetting('Epic Mode', default=False), bs.BoolSetting('Epic Mode', default=False),
] ]
# In teams mode, a suicide gives a point to the other team, but in # In teams mode, a suicide gives a point to the other team, but in
@ -139,9 +141,9 @@ class BoxingGame(DeathMatchGame):
# this at zero to benefit new players, but pro players might like to # this at zero to benefit new players, but pro players might like to
# be able to go negative. (to avoid a strategy of just # be able to go negative. (to avoid a strategy of just
# suiciding until you get a good drop) # suiciding until you get a good drop)
if issubclass(sessiontype, ba.FreeForAllSession): if issubclass(sessiontype, bs.FreeForAllSession):
settings.append( settings.append(
ba.BoolSetting('Allow Negative Scores', default=False) bs.BoolSetting('Allow Negative Scores', default=False)
) )
return settings return settings
@ -150,7 +152,7 @@ class BoxingGame(DeathMatchGame):
super().__init__(settings) super().__init__(settings)
self._scoreboard = Scoreboard() self._scoreboard = Scoreboard()
self._score_to_win: int | None = None self._score_to_win: int | None = None
self._dingsound = ba.getsound('dingSmall') self._dingsound = bs.getsound('dingSmall')
self._epic_mode = bool(settings['Epic Mode']) self._epic_mode = bool(settings['Epic Mode'])
self._kills_to_win_per_player = int(settings['Kills to Win Per Player']) self._kills_to_win_per_player = int(settings['Kills to Win Per Player'])
self._time_limit = float(settings['Time Limit']) self._time_limit = float(settings['Time Limit'])
@ -163,11 +165,11 @@ class BoxingGame(DeathMatchGame):
# Base class overrides. # Base class overrides.
self.slow_motion = self._epic_mode self.slow_motion = self._epic_mode
self.default_music = ( self.default_music = (
ba.MusicType.EPIC if self._epic_mode else ba.MusicType.TO_THE_DEATH bs.MusicType.EPIC if self._epic_mode else bs.MusicType.TO_THE_DEATH
) )
def on_begin(self) -> None: def on_begin(self) -> None:
ba.TeamGameActivity.on_begin(self) bs.TeamGameActivity.on_begin(self)
self.setup_standard_time_limit(self._time_limit) self.setup_standard_time_limit(self._time_limit)
if self._enable_powerups: if self._enable_powerups:
self.setup_standard_powerup_drops() self.setup_standard_powerup_drops()
@ -180,7 +182,7 @@ class BoxingGame(DeathMatchGame):
def _standard_drop_powerup(self, index: int, expire: bool = True) -> None: def _standard_drop_powerup(self, index: int, expire: bool = True) -> None:
# pylint: disable=cyclic-import # pylint: disable=cyclic-import
from bastd.actor.powerupbox import PowerupBox, PowerupBoxFactory from bascenev1lib.actor.powerupbox import PowerupBox, PowerupBoxFactory
PowerupBox( PowerupBox(
position=self.map.powerup_spawn_points[index], position=self.map.powerup_spawn_points[index],
@ -191,13 +193,13 @@ class BoxingGame(DeathMatchGame):
expire=expire, expire=expire,
).autoretain() ).autoretain()
def spawn_player(self, player: Player) -> ba.Actor: def spawn_player(self, player: Player) -> bs.Actor:
import random import random
from ba import _math from babase import _math
from ba._gameutils import animate from bascenev1._gameutils import animate
from ba._coopsession import CoopSession from bascenev1._coopsession import CoopSession
if isinstance(self.session, ba.DualTeamSession): if isinstance(self.session, bs.DualTeamSession):
position = self.map.get_start_position(player.team.id) position = self.map.get_start_position(player.team.id)
else: else:
# otherwise do free-for-all spawn locations # otherwise do free-for-all spawn locations
@ -208,7 +210,7 @@ class BoxingGame(DeathMatchGame):
highlight = player.highlight highlight = player.highlight
light_color = _math.normalized_color(color) light_color = _math.normalized_color(color)
display_color = ba.safecolor(color, target_intensity=0.75) display_color = babase.safecolor(color, target_intensity=0.75)
spaz = NewPlayerSpaz(color=color, spaz = NewPlayerSpaz(color=color,
highlight=highlight, highlight=highlight,
@ -224,14 +226,14 @@ class BoxingGame(DeathMatchGame):
# Move to the stand position and add a flash of light. # Move to the stand position and add a flash of light.
spaz.handlemessage( spaz.handlemessage(
ba.StandMessage( bs.StandMessage(
position, position,
angle if angle is not None else random.uniform(0, 360))) angle if angle is not None else random.uniform(0, 360)))
ba.playsound(self._spawn_sound, 1, position=spaz.node.position) self._spawn_sound.play(1, position=spaz.node.position)
light = ba.newnode('light', attrs={'color': light_color}) light = bs.newnode('light', attrs={'color': light_color})
spaz.node.connectattr('position', light, 'position') spaz.node.connectattr('position', light, 'position')
animate(light, 'intensity', {0: 0, 0.25: 1, 0.5: 0}) animate(light, 'intensity', {0: 0, 0.25: 1, 0.5: 0})
ba.timer(0.5, light.delete) bs.timer(0.5, light.delete)
# custom # custom
spaz.connect_controls_to_player(enable_bomb=False) spaz.connect_controls_to_player(enable_bomb=False)

View file

@ -1,4 +1,4 @@
# ba_meta require api 7 # ba_meta require api 8
# (see https://ballistica.net/wiki/meta-tag-system) # (see https://ballistica.net/wiki/meta-tag-system)
''' '''
@ -31,19 +31,21 @@ import weakref
from enum import Enum from enum import Enum
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
import ba import babase
import bauiv1 as bui
import bascenev1 as bs
import random import random
from bastd.actor.flag import Flag from bascenev1lib.actor.flag import Flag
from bastd.actor.popuptext import PopupText from bascenev1lib.actor.popuptext import PopupText
from bastd.actor.playerspaz import PlayerSpaz from bascenev1lib.actor.playerspaz import PlayerSpaz
from bastd.actor.scoreboard import Scoreboard from bascenev1lib.actor.scoreboard import Scoreboard
from bastd.gameutils import SharedObjects from bascenev1lib.gameutils import SharedObjects
if TYPE_CHECKING: if TYPE_CHECKING:
from typing import Any, Sequence from typing import Any, Sequence
lang = ba.app.lang.language lang = bs.app.lang.language
if lang == 'Spanish': if lang == 'Spanish':
name = 'Coleccionista' name = 'Coleccionista'
description = ('Elimina a tus oponentes para robar sus cápsulas.\n' description = ('Elimina a tus oponentes para robar sus cápsulas.\n'
@ -99,7 +101,7 @@ class FlagState(Enum):
HELD = 3 HELD = 3
class Player(ba.Player['Team']): class Player(bs.Player['Team']):
"""Our player type for this game.""" """Our player type for this game."""
def __init__(self) -> None: def __init__(self) -> None:
@ -108,15 +110,15 @@ class Player(ba.Player['Team']):
self.light = None self.light = None
class Team(ba.Team[Player]): class Team(bs.Team[Player]):
"""Our team type for this game.""" """Our team type for this game."""
def __init__(self) -> None: def __init__(self) -> None:
self.score = 0 self.score = 0
# ba_meta export game # ba_meta export bascenev1.GameActivity
class CollectorGame(ba.TeamGameActivity[Player, Team]): class CollectorGame(bs.TeamGameActivity[Player, Team]):
name = name name = name
description = description description = description
@ -127,23 +129,23 @@ class CollectorGame(ba.TeamGameActivity[Player, Team]):
@classmethod @classmethod
def get_available_settings( def get_available_settings(
cls, sessiontype: type[ba.Session] cls, sessiontype: type[bs.Session]
) -> list[ba.Setting]: ) -> list[babase.Setting]:
settings = [ settings = [
ba.IntSetting( bs.IntSetting(
capsules_to_win, capsules_to_win,
min_value=1, min_value=1,
default=10, default=10,
increment=1, increment=1,
), ),
ba.IntSetting( bs.IntSetting(
capsules_death, capsules_death,
min_value=1, min_value=1,
max_value=10, max_value=10,
default=2, default=2,
increment=1, increment=1,
), ),
ba.IntChoiceSetting( bs.IntChoiceSetting(
'Time Limit', 'Time Limit',
choices=[ choices=[
('None', 0), ('None', 0),
@ -155,7 +157,7 @@ class CollectorGame(ba.TeamGameActivity[Player, Team]):
], ],
default=0, default=0,
), ),
ba.FloatChoiceSetting( bs.FloatChoiceSetting(
'Respawn Times', 'Respawn Times',
choices=[ choices=[
('Shorter', 0.25), ('Shorter', 0.25),
@ -166,33 +168,33 @@ class CollectorGame(ba.TeamGameActivity[Player, Team]):
], ],
default=1.0, default=1.0,
), ),
ba.BoolSetting(lucky_capsules, default=True), bs.BoolSetting(lucky_capsules, default=True),
ba.BoolSetting('Epic Mode', default=False), bs.BoolSetting('Epic Mode', default=False),
] ]
return settings return settings
@classmethod @classmethod
def supports_session_type(cls, sessiontype: type[ba.Session]) -> bool: def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool:
return issubclass(sessiontype, ba.DualTeamSession) or issubclass( return issubclass(sessiontype, bs.DualTeamSession) or issubclass(
sessiontype, ba.FreeForAllSession sessiontype, bs.FreeForAllSession
) )
@classmethod @classmethod
def get_supported_maps(cls, sessiontype: type[ba.Session]) -> list[str]: def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]:
return ba.getmaps('keep_away') return bs.app.classic.getmaps('keep_away')
def __init__(self, settings: dict): def __init__(self, settings: dict):
super().__init__(settings) super().__init__(settings)
shared = SharedObjects.get() shared = SharedObjects.get()
self._scoreboard = Scoreboard() self._scoreboard = Scoreboard()
self._score_to_win: int | None = None self._score_to_win: int | None = None
self._swipsound = ba.getsound('swip') self._swipsound = bs.getsound('swip')
self._lucky_sound = ba.getsound('ding') self._lucky_sound = bs.getsound('ding')
self._flag_pos: Sequence[float] | None = None self._flag_pos: Sequence[float] | None = None
self._flag_state: FlagState | None = None self._flag_state: FlagState | None = None
self._flag: Flag | None = None self._flag: Flag | None = None
self._flag_light: ba.Node | None = None self._flag_light: bs.Node | None = None
self._scoring_team: weakref.ref[Team] | None = None self._scoring_team: weakref.ref[Team] | None = None
self._time_limit = float(settings['Time Limit']) self._time_limit = float(settings['Time Limit'])
self._epic_mode = bool(settings['Epic Mode']) self._epic_mode = bool(settings['Epic Mode'])
@ -202,19 +204,19 @@ class CollectorGame(ba.TeamGameActivity[Player, Team]):
self._lucky_capsules = bool(settings[lucky_capsules]) self._lucky_capsules = bool(settings[lucky_capsules])
self._capsules: list[Any] = [] self._capsules: list[Any] = []
self._capsule_model = ba.getmodel('bomb') self._capsule_mesh = bs.getmesh('bomb')
self._capsule_tex = ba.gettexture('bombColor') self._capsule_tex = bs.gettexture('bombColor')
self._capsule_lucky_tex = ba.gettexture('bombStickyColor') self._capsule_lucky_tex = bs.gettexture('bombStickyColor')
self._collect_sound = ba.getsound('powerup01') self._collect_sound = bs.getsound('powerup01')
self._lucky_collect_sound = ba.getsound('cashRegister2') self._lucky_collect_sound = bs.getsound('cashRegister2')
self._capsule_material = ba.Material() self._capsule_material = bs.Material()
self._capsule_material.add_actions( self._capsule_material.add_actions(
conditions=('they_have_material', shared.player_material), conditions=('they_have_material', shared.player_material),
actions=('call', 'at_connect', self._on_capsule_player_collide), actions=('call', 'at_connect', self._on_capsule_player_collide),
) )
self._flag_region_material = ba.Material() self._flag_region_material = bs.Material()
self._flag_region_material.add_actions( self._flag_region_material.add_actions(
conditions=('they_have_material', shared.player_material), conditions=('they_have_material', shared.player_material),
actions=( actions=(
@ -223,12 +225,12 @@ class CollectorGame(ba.TeamGameActivity[Player, Team]):
( (
'call', 'call',
'at_connect', 'at_connect',
ba.Call(self._handle_player_flag_region_collide, True), babase.Call(self._handle_player_flag_region_collide, True),
), ),
( (
'call', 'call',
'at_disconnect', 'at_disconnect',
ba.Call(self._handle_player_flag_region_collide, False), babase.Call(self._handle_player_flag_region_collide, False),
), ),
), ),
) )
@ -236,7 +238,7 @@ class CollectorGame(ba.TeamGameActivity[Player, Team]):
# Base class overrides. # Base class overrides.
self.slow_motion = self._epic_mode self.slow_motion = self._epic_mode
self.default_music = ( self.default_music = (
ba.MusicType.EPIC if self._epic_mode else ba.MusicType.SCARY bs.MusicType.EPIC if self._epic_mode else bs.MusicType.SCARY
) )
def get_instance_description(self) -> str | Sequence: def get_instance_description(self) -> str | Sequence:
@ -245,7 +247,7 @@ class CollectorGame(ba.TeamGameActivity[Player, Team]):
def get_instance_description_short(self) -> str | Sequence: def get_instance_description_short(self) -> str | Sequence:
return description_short, self._score_to_win return description_short, self._score_to_win
def create_team(self, sessionteam: ba.SessionTeam) -> Team: def create_team(self, sessionteam: bs.SessionTeam) -> Team:
return Team() return Team()
def on_team_join(self, team: Team) -> None: def on_team_join(self, team: Team) -> None:
@ -263,18 +265,18 @@ class CollectorGame(ba.TeamGameActivity[Player, Team]):
) )
self._update_scoreboard() self._update_scoreboard()
if isinstance(self.session, ba.FreeForAllSession): if isinstance(self.session, bs.FreeForAllSession):
self._flag_pos = self.map.get_flag_position(random.randint(0, 1)) self._flag_pos = self.map.get_flag_position(random.randint(0, 1))
else: else:
self._flag_pos = self.map.get_flag_position(None) self._flag_pos = self.map.get_flag_position(None)
ba.timer(1.0, self._tick, repeat=True) bs.timer(1.0, self._tick, repeat=True)
self._flag_state = FlagState.NEW self._flag_state = FlagState.NEW
Flag.project_stand(self._flag_pos) Flag.project_stand(self._flag_pos)
self._flag = Flag( self._flag = Flag(
position=self._flag_pos, touchable=False, color=(1, 1, 1) position=self._flag_pos, touchable=False, color=(1, 1, 1)
) )
self._flag_light = ba.newnode( self._flag_light = bs.newnode(
'light', 'light',
attrs={ attrs={
'position': self._flag_pos, 'position': self._flag_pos,
@ -286,7 +288,7 @@ class CollectorGame(ba.TeamGameActivity[Player, Team]):
) )
# Flag region. # Flag region.
flagmats = [self._flag_region_material, shared.region_material] flagmats = [self._flag_region_material, shared.region_material]
ba.newnode( bs.newnode(
'region', 'region',
attrs={ attrs={
'position': self._flag_pos, 'position': self._flag_pos,
@ -308,7 +310,7 @@ class CollectorGame(ba.TeamGameActivity[Player, Team]):
if not scoring_team: if not scoring_team:
return return
if isinstance(self.session, ba.FreeForAllSession): if isinstance(self.session, bs.FreeForAllSession):
players = self.players players = self.players
else: else:
players = scoring_team.players players = scoring_team.players
@ -331,10 +333,7 @@ class CollectorGame(ba.TeamGameActivity[Player, Team]):
self._flag_pos[1]+1, self._flag_pos[1]+1,
self._flag_pos[2] self._flag_pos[2]
), player) ), player)
ba.playsound( self._collect_sound.play(0.8, position=self._flag_pos)
self._collect_sound,
0.8,
position=self._flag_pos)
self._update_scoreboard() self._update_scoreboard()
if player.capsules > 0: if player.capsules > 0:
@ -347,7 +346,7 @@ class CollectorGame(ba.TeamGameActivity[Player, Team]):
self.end_game() self.end_game()
def end_game(self) -> None: def end_game(self) -> None:
results = ba.GameResults() results = bs.GameResults()
for team in self.teams: for team in self.teams:
results.set_team_score(team, team.score) results.set_team_score(team, team.score)
self.end(results=results, announce_delay=0) self.end(results=results, announce_delay=0)
@ -369,7 +368,7 @@ class CollectorGame(ba.TeamGameActivity[Player, Team]):
holding_team = list(holding_teams)[0] holding_team = list(holding_teams)[0]
self._flag_state = FlagState.HELD self._flag_state = FlagState.HELD
self._scoring_team = weakref.ref(holding_team) self._scoring_team = weakref.ref(holding_team)
self._flag_light.color = ba.normalized_color(holding_team.color) self._flag_light.color = babase.normalized_color(holding_team.color)
self._flag.node.color = holding_team.color self._flag.node.color = holding_team.color
else: else:
self._flag_state = FlagState.UNCONTESTED self._flag_state = FlagState.UNCONTESTED
@ -377,12 +376,12 @@ class CollectorGame(ba.TeamGameActivity[Player, Team]):
self._flag_light.color = (0.2, 0.2, 0.2) self._flag_light.color = (0.2, 0.2, 0.2)
self._flag.node.color = (1, 1, 1) self._flag.node.color = (1, 1, 1)
if self._flag_state != prev_state: if self._flag_state != prev_state:
ba.playsound(self._swipsound) self._swipsound.play()
def _handle_player_flag_region_collide(self, colliding: bool) -> None: def _handle_player_flag_region_collide(self, colliding: bool) -> None:
try: try:
spaz = ba.getcollision().opposingnode.getdelegate(PlayerSpaz, True) spaz = bs.getcollision().opposingnode.getdelegate(PlayerSpaz, True)
except ba.NotFoundError: except bs.NotFoundError:
return return
if not spaz.is_alive(): if not spaz.is_alive():
@ -442,7 +441,7 @@ class CollectorGame(ba.TeamGameActivity[Player, Team]):
def _on_capsule_player_collide(self) -> None: def _on_capsule_player_collide(self) -> None:
if self.has_ended(): if self.has_ended():
return return
collision = ba.getcollision() collision = bs.getcollision()
# Be defensive here; we could be hitting the corpse of a player # Be defensive here; we could be hitting the corpse of a player
# who just left/etc. # who just left/etc.
@ -451,7 +450,7 @@ class CollectorGame(ba.TeamGameActivity[Player, Team]):
player = collision.opposingnode.getdelegate( player = collision.opposingnode.getdelegate(
PlayerSpaz, True PlayerSpaz, True
).getplayer(Player, True) ).getplayer(Player, True)
except ba.NotFoundError: except bs.NotFoundError:
return return
if not player.is_alive(): if not player.is_alive():
@ -465,30 +464,24 @@ class CollectorGame(ba.TeamGameActivity[Player, Team]):
scale=1.5, scale=1.5,
position=capsule.node.position position=capsule.node.position
).autoretain() ).autoretain()
ba.playsound( self._lucky_collect_sound.play(1.0, position=capsule.node.position)
self._lucky_collect_sound, bs.emitfx(
1.0,
position=capsule.node.position)
ba.emitfx(
position=capsule.node.position, position=capsule.node.position,
velocity=(0, 0, 0), velocity=(0, 0, 0),
count=int(6.4+random.random()*24), count=int(6.4+random.random()*24),
scale=1.2, scale=1.2,
spread=2.0, spread=2.0,
chunk_type='spark') chunk_type='spark')
ba.emitfx( bs.emitfx(
position=capsule.node.position, position=capsule.node.position,
velocity=(0, 0, 0), velocity=(0, 0, 0),
count=int(4.0+random.random()*6), count=int(4.0+random.random()*6),
emit_type='tendrils') emit_type='tendrils')
else: else:
player.capsules += 1 player.capsules += 1
ba.playsound( self._collect_sound.play(0.6, position=capsule.node.position)
self._collect_sound,
0.6,
position=capsule.node.position)
# create a flash # create a flash
light = ba.newnode( light = bs.newnode(
'light', 'light',
attrs={ attrs={
'position': capsule.node.position, 'position': capsule.node.position,
@ -499,27 +492,27 @@ class CollectorGame(ba.TeamGameActivity[Player, Team]):
# Create a short text informing about your inventory # Create a short text informing about your inventory
self._handle_capsule_storage(player.position, player) self._handle_capsule_storage(player.position, player)
ba.animate(light, 'intensity', { bs.animate(light, 'intensity', {
0: 0, 0: 0,
0.1: 0.5, 0.1: 0.5,
0.2: 0 0.2: 0
}, loop=False) }, loop=False)
ba.timer(0.2, light.delete) bs.timer(0.2, light.delete)
capsule.handlemessage(ba.DieMessage()) capsule.handlemessage(bs.DieMessage())
def _update_player_light(self, player: Player, capsules: int) -> None: def _update_player_light(self, player: Player, capsules: int) -> None:
if player.light: if player.light:
intensity = 0.04 * capsules intensity = 0.04 * capsules
ba.animate(player.light, 'intensity', { bs.animate(player.light, 'intensity', {
0.0: player.light.intensity, 0.0: player.light.intensity,
0.1: intensity 0.1: intensity
}) })
def newintensity(): def newintensity():
player.light.intensity = intensity player.light.intensity = intensity
ba.timer(0.1, newintensity) bs.timer(0.1, newintensity)
else: else:
player.light = ba.newnode( player.light = bs.newnode(
'light', 'light',
attrs={ attrs={
'height_attenuated': False, 'height_attenuated': False,
@ -558,7 +551,7 @@ class CollectorGame(ba.TeamGameActivity[Player, Team]):
self._update_player_light(player, capsules) self._update_player_light(player, capsules)
def handlemessage(self, msg: Any) -> Any: def handlemessage(self, msg: Any) -> Any:
if isinstance(msg, ba.PlayerDiedMessage): if isinstance(msg, bs.PlayerDiedMessage):
super().handlemessage(msg) # Augment default. super().handlemessage(msg) # Augment default.
# No longer can count as time_at_flag once dead. # No longer can count as time_at_flag once dead.
player = msg.getplayer(Player) player = msg.getplayer(Player)
@ -572,7 +565,7 @@ class CollectorGame(ba.TeamGameActivity[Player, Team]):
return super().handlemessage(msg) return super().handlemessage(msg)
class Capsule(ba.Actor): class Capsule(bs.Actor):
def __init__(self, def __init__(self,
position: Sequence[float] = (0.0, 1.0, 0.0), position: Sequence[float] = (0.0, 1.0, 0.0),
@ -586,12 +579,12 @@ class Capsule(ba.Actor):
self._spawn_pos = (position[0], position[1], position[2]) self._spawn_pos = (position[0], position[1], position[2])
if lucky: if lucky:
ba.playsound(activity._lucky_sound, 1.0, self._spawn_pos) activity._lucky_sound.play(1.0, self._spawn_pos)
self.node = ba.newnode( self.node = bs.newnode(
'prop', 'prop',
attrs={ attrs={
'model': activity._capsule_model, 'mesh': activity._capsule_mesh,
'color_texture': activity._capsule_lucky_tex if lucky else ( 'color_texture': activity._capsule_lucky_tex if lucky else (
activity._capsule_tex), activity._capsule_tex),
'body': 'crate' if lucky else 'capsule', 'body': 'crate' if lucky else 'capsule',
@ -606,12 +599,12 @@ class Capsule(ba.Actor):
shared.object_material, activity._capsule_material] shared.object_material, activity._capsule_material]
}, },
delegate=self) delegate=self)
ba.animate(self.node, 'model_scale', { bs.animate(self.node, 'mesh_scale', {
0.0: 0.0, 0.0: 0.0,
0.1: 0.9 if lucky else 0.6, 0.1: 0.9 if lucky else 0.6,
0.16: 0.8 if lucky else 0.5 0.16: 0.8 if lucky else 0.5
}) })
self._light_capsule = ba.newnode( self._light_capsule = bs.newnode(
'light', 'light',
attrs={ attrs={
'position': self._spawn_pos, 'position': self._spawn_pos,
@ -622,16 +615,16 @@ class Capsule(ba.Actor):
self.node.connectattr('position', self._light_capsule, 'position') self.node.connectattr('position', self._light_capsule, 'position')
def handlemessage(self, msg: Any): def handlemessage(self, msg: Any):
if isinstance(msg, ba.DieMessage): if isinstance(msg, bs.DieMessage):
self.node.delete() self.node.delete()
ba.animate(self._light_capsule, 'intensity', { bs.animate(self._light_capsule, 'intensity', {
0: 1.0, 0: 1.0,
0.05: 0.0 0.05: 0.0
}, loop=False) }, loop=False)
ba.timer(0.05, self._light_capsule.delete) bs.timer(0.05, self._light_capsule.delete)
elif isinstance(msg, ba.OutOfBoundsMessage): elif isinstance(msg, bs.OutOfBoundsMessage):
self.handlemessage(ba.DieMessage()) self.handlemessage(bs.DieMessage())
elif isinstance(msg, ba.HitMessage): elif isinstance(msg, bs.HitMessage):
self.node.handlemessage( self.node.handlemessage(
'impulse', 'impulse',
msg.pos[0], msg.pos[1], msg.pos[2], msg.pos[0], msg.pos[1], msg.pos[2],

View file

@ -1,5 +1,5 @@
# ba_meta require api 7 # ba_meta require api 8
""" """
DemolitionWar - BombFight on wooden floor flying in air. DemolitionWar - BombFight on wooden floor flying in air.
Author: Mr.Smoothy Author: Mr.Smoothy
@ -12,23 +12,26 @@ from __future__ import annotations
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
import ba import babase
from bastd.game.elimination import EliminationGame, Player import bauiv1 as bui
from bastd.gameutils import SharedObjects import bascenev1 as bs
from bastd.actor.bomb import BombFactory from bascenev1 import _map
from bascenev1lib.game.elimination import EliminationGame, Player
from bascenev1lib.gameutils import SharedObjects
from bascenev1lib.actor.bomb import BombFactory
import random import random
from bastd.actor.playerspaz import PlayerSpaz from bascenev1lib.actor.playerspaz import PlayerSpaz
if TYPE_CHECKING: if TYPE_CHECKING:
from typing import Any, Sequence from typing import Any, Sequence
# ba_meta export game # ba_meta export bascenev1.GameActivity
class DemolitionWar(EliminationGame): class DemolitionWar(EliminationGame):
name = 'DemolitionWar' name = 'DemolitionWar'
description = 'Last remaining alive wins.' description = 'Last remaining alive wins.'
scoreconfig = ba.ScoreConfig( scoreconfig = bs.ScoreConfig(
label='Survived', scoretype=ba.ScoreType.SECONDS, none_is_winner=True label='Survived', scoretype=bs.ScoreType.SECONDS, none_is_winner=True
) )
# Show messages when players die since it's meaningful here. # Show messages when players die since it's meaningful here.
announce_player_deaths = True announce_player_deaths = True
@ -37,17 +40,17 @@ class DemolitionWar(EliminationGame):
@classmethod @classmethod
def get_available_settings( def get_available_settings(
cls, sessiontype: type[ba.Session] cls, sessiontype: type[bs.Session]
) -> list[ba.Setting]: ) -> list[babase.Setting]:
settings = [ settings = [
ba.IntSetting( bs.IntSetting(
'Lives Per Player', 'Lives Per Player',
default=1, default=1,
min_value=1, min_value=1,
max_value=10, max_value=10,
increment=1, increment=1,
), ),
ba.IntChoiceSetting( bs.IntChoiceSetting(
'Time Limit', 'Time Limit',
choices=[ choices=[
('None', 0), ('None', 0),
@ -59,7 +62,7 @@ class DemolitionWar(EliminationGame):
], ],
default=0, default=0,
), ),
ba.FloatChoiceSetting( bs.FloatChoiceSetting(
'Respawn Times', 'Respawn Times',
choices=[ choices=[
('Shorter', 0.25), ('Shorter', 0.25),
@ -70,23 +73,23 @@ class DemolitionWar(EliminationGame):
], ],
default=1.0, default=1.0,
), ),
ba.BoolSetting('Epic Mode', default=False), bs.BoolSetting('Epic Mode', default=False),
] ]
if issubclass(sessiontype, ba.DualTeamSession): if issubclass(sessiontype, bs.DualTeamSession):
settings.append(ba.BoolSetting('Solo Mode', default=False)) settings.append(bs.BoolSetting('Solo Mode', default=False))
settings.append( settings.append(
ba.BoolSetting('Balance Total Lives', default=False) bs.BoolSetting('Balance Total Lives', default=False)
) )
return settings return settings
@classmethod @classmethod
def supports_session_type(cls, sessiontype: type[ba.Session]) -> bool: def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool:
return issubclass(sessiontype, ba.DualTeamSession) or issubclass( return issubclass(sessiontype, bs.DualTeamSession) or issubclass(
sessiontype, ba.FreeForAllSession sessiontype, bs.FreeForAllSession
) )
@classmethod @classmethod
def get_supported_maps(cls, sessiontype: type[ba.Session]) -> list[str]: def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]:
return ['Wooden Floor'] return ['Wooden Floor']
def __init__(self, settings: dict): def __init__(self, settings: dict):
@ -95,7 +98,7 @@ class DemolitionWar(EliminationGame):
self._solo_mode = False self._solo_mode = False
self._balance_total_lives = False self._balance_total_lives = False
def spawn_player(self, player: Player) -> ba.Actor: def spawn_player(self, player: Player) -> bs.Actor:
p = [-6, -4.3, -2.6, -0.9, 0.8, 2.5, 4.2, 5.9] p = [-6, -4.3, -2.6, -0.9, 0.8, 2.5, 4.2, 5.9]
q = [-4, -2.3, -0.6, 1.1, 2.8, 4.5] q = [-4, -2.3, -0.6, 1.1, 2.8, 4.5]
@ -118,23 +121,23 @@ class DemolitionWar(EliminationGame):
self.map_extend() self.map_extend()
def on_blast(self): def on_blast(self):
node = ba.getcollision().sourcenode node = bs.getcollision().sourcenode
ba.emitfx((node.position[0], 0.9, node.position[2]), bs.emitfx((node.position[0], 0.9, node.position[2]),
(0, 2, 0), 30, 1, spread=1, chunk_type='splinter') (0, 2, 0), 30, 1, spread=1, chunk_type='splinter')
ba.timer(0.1, ba.Call(node.delete)) bs.timer(0.1, babase.Call(node.delete))
def map_extend(self): def map_extend(self):
# TODO need to improve here , so we can increase size of map easily with settings # TODO need to improve here , so we can increase size of map easily with settings
p = [-6, -4.3, -2.6, -0.9, 0.8, 2.5, 4.2, 5.9] p = [-6, -4.3, -2.6, -0.9, 0.8, 2.5, 4.2, 5.9]
q = [-4, -2.3, -0.6, 1.1, 2.8, 4.5] q = [-4, -2.3, -0.6, 1.1, 2.8, 4.5]
factory = BombFactory.get() factory = BombFactory.get()
self.ramp_bomb = ba.Material() self.ramp_bomb = bs.Material()
self.ramp_bomb.add_actions( self.ramp_bomb.add_actions(
conditions=('they_have_material', factory.bomb_material), conditions=('they_have_material', factory.bomb_material),
actions=( actions=(
('modify_part_collision', 'collide', True), ('modify_part_collision', 'collide', True),
('modify_part_collision', 'physical', True), ('modify_part_collision', 'physical', True),
('call', 'at_connect', ba.Call(self.on_blast)) ('call', 'at_connect', babase.Call(self.on_blast))
)) ))
self.ramps = [] self.ramps = []
for i in p: for i in p:
@ -144,7 +147,7 @@ class DemolitionWar(EliminationGame):
def create_ramp(self, x, z): def create_ramp(self, x, z):
shared = SharedObjects.get() shared = SharedObjects.get()
self._real_collied_material = ba.Material() self._real_collied_material = bs.Material()
self._real_collied_material.add_actions( self._real_collied_material.add_actions(
actions=( actions=(
@ -152,32 +155,32 @@ class DemolitionWar(EliminationGame):
('modify_part_collision', 'physical', True) ('modify_part_collision', 'physical', True)
)) ))
self.mat = ba.Material() self.mat = bs.Material()
self.mat.add_actions( self.mat.add_actions(
actions=(('modify_part_collision', 'physical', False), actions=(('modify_part_collision', 'physical', False),
('modify_part_collision', 'collide', False)) ('modify_part_collision', 'collide', False))
) )
pos = (x, 0, z) pos = (x, 0, z)
ud_1_r = ba.newnode('region', attrs={'position': pos, 'scale': (1.5, 1, 1.5), 'type': 'box', 'materials': [ ud_1_r = bs.newnode('region', attrs={'position': pos, 'scale': (1.5, 1, 1.5), 'type': 'box', 'materials': [
shared.footing_material, self._real_collied_material, self.ramp_bomb]}) shared.footing_material, self._real_collied_material, self.ramp_bomb]})
node = ba.newnode('prop', node = bs.newnode('prop',
owner=ud_1_r, owner=ud_1_r,
attrs={ attrs={
'model': ba.getmodel('image1x1'), 'mesh': bs.getmesh('image1x1'),
'light_model': ba.getmodel('powerupSimple'), 'light_mesh': bs.getmesh('powerupSimple'),
'position': (2, 7, 2), 'position': (2, 7, 2),
'body': 'puck', 'body': 'puck',
'shadow_size': 0.0, 'shadow_size': 0.0,
'velocity': (0, 0, 0), 'velocity': (0, 0, 0),
'color_texture': ba.gettexture('tnt'), 'color_texture': bs.gettexture('tnt'),
'model_scale': 1.5, 'mesh_scale': 1.5,
'reflection_scale': [1.5], 'reflection_scale': [1.5],
'materials': [self.mat, shared.object_material, shared.footing_material], 'materials': [self.mat, shared.object_material, shared.footing_material],
'density': 9000000000 'density': 9000000000
}) })
node.changerotation(1, 0, 0) # node.changerotation(1, 0, 0)
mnode = ba.newnode('math', mnode = bs.newnode('math',
owner=ud_1_r, owner=ud_1_r,
attrs={ attrs={
'input1': (0, 0.6, 0), 'input1': (0, 0.6, 0),
@ -218,7 +221,7 @@ class mapdefs:
points['tnt1'] = (-0.08421587483, 0.9515026107, -0.7762602271) points['tnt1'] = (-0.08421587483, 0.9515026107, -0.7762602271)
class WoodenFloor(ba.Map): class WoodenFloor(bs._map.Map): # ahdunno if this is correct way, change if u find better way
"""Stadium map for football games.""" """Stadium map for football games."""
defs = mapdefs defs = mapdefs
defs.points['spawn1'] = (-12.03866341, 0.02275111462, 0.0) + (0.5, 1.0, 4.0) defs.points['spawn1'] = (-12.03866341, 0.02275111462, 0.0) + (0.5, 1.0, 4.0)
@ -238,15 +241,15 @@ class WoodenFloor(ba.Map):
def on_preload(cls) -> Any: def on_preload(cls) -> Any:
data: dict[str, Any] = { data: dict[str, Any] = {
'model_bg': ba.getmodel('doomShroomBG'), 'mesh_bg': bs.getmesh('doomShroomBG'),
'bg_vr_fill_model': ba.getmodel('natureBackgroundVRFill'), 'bg_vr_fill_mesh': bs.getmesh('natureBackgroundVRFill'),
'collide_model': ba.getcollidemodel('bridgitLevelCollide'), 'collide_mesh': bs.getcollisionmesh('bridgitLevelCollide'),
'tex': ba.gettexture('bridgitLevelColor'), 'tex': bs.gettexture('bridgitLevelColor'),
'model_bg_tex': ba.gettexture('doomShroomBGColor'), 'mesh_bg_tex': bs.gettexture('doomShroomBGColor'),
'collide_bg': ba.getcollidemodel('natureBackgroundCollide'), 'collide_bg': bs.getcollisionmesh('natureBackgroundCollide'),
'railing_collide_model': 'railing_collide_mesh':
(ba.getcollidemodel('bridgitLevelRailingCollide')), (bs.getcollisionmesh('bridgitLevelRailingCollide')),
'bg_material': ba.Material() 'bg_material': bs.Material()
} }
data['bg_material'].add_actions(actions=('modify_part_collision', data['bg_material'].add_actions(actions=('modify_part_collision',
'friction', 10.0)) 'friction', 10.0))
@ -255,23 +258,23 @@ class WoodenFloor(ba.Map):
def __init__(self) -> None: def __init__(self) -> None:
super().__init__() super().__init__()
shared = SharedObjects.get() shared = SharedObjects.get()
self.background = ba.newnode( self.background = bs.newnode(
'terrain', 'terrain',
attrs={ attrs={
'model': self.preloaddata['model_bg'], 'mesh': self.preloaddata['mesh_bg'],
'lighting': False, 'lighting': False,
'background': True, 'background': True,
'color_texture': self.preloaddata['model_bg_tex'] 'color_texture': self.preloaddata['mesh_bg_tex']
}) })
self.vr = ba.newnode('terrain', self.vr = bs.newnode('terrain',
attrs={ attrs={
'model': self.preloaddata['bg_vr_fill_model'], 'mesh': self.preloaddata['bg_vr_fill_mesh'],
'lighting': False, 'lighting': False,
'vr_only': True, 'vr_only': True,
'background': True, 'background': True,
'color_texture': self.preloaddata['model_bg_tex'] 'color_texture': self.preloaddata['mesh_bg_tex']
}) })
gnode = ba.getactivity().globalsnode gnode = bs.getactivity().globalsnode
gnode.tint = (1.3, 1.2, 1.0) gnode.tint = (1.3, 1.2, 1.0)
gnode.ambient_color = (1.3, 1.2, 1.0) gnode.ambient_color = (1.3, 1.2, 1.0)
gnode.vignette_outer = (0.57, 0.57, 0.57) gnode.vignette_outer = (0.57, 0.57, 0.57)
@ -280,7 +283,7 @@ class WoodenFloor(ba.Map):
gnode.vr_near_clip = 0.5 gnode.vr_near_clip = 0.5
def is_point_near_edge(self, def is_point_near_edge(self,
point: ba.Vec3, point: babase.Vec3,
running: bool = False) -> bool: running: bool = False) -> bool:
box_position = self.defs.boxes['edge_box'][0:3] box_position = self.defs.boxes['edge_box'][0:3]
box_scale = self.defs.boxes['edge_box'][6:9] box_scale = self.defs.boxes['edge_box'][6:9]
@ -290,15 +293,15 @@ class WoodenFloor(ba.Map):
def _handle_player_collide(self): def _handle_player_collide(self):
try: try:
player = ba.getcollision().opposingnode.getdelegate( player = bs.getcollision().opposingnode.getdelegate(
PlayerSpaz, True) PlayerSpaz, True)
except ba.NotFoundError: except bs.NotFoundError:
return return
if player.is_alive(): if player.is_alive():
player.shatter(True) player.shatter(True)
try: try:
ba._map.register_map(WoodenFloor) bs._map.register_map(WoodenFloor)
except: except:
pass pass

View file

@ -6,18 +6,20 @@
# Feel free to edit. # Feel free to edit.
# ba_meta require api 7 # ba_meta require api 8
from __future__ import annotations from __future__ import annotations
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
import ba import babase
import bauiv1 as bui
import bascenev1 as bs
from random import choice from random import choice
from enum import Enum from enum import Enum
from bastd.actor.bomb import Blast from bascenev1lib.actor.bomb import Blast
from bastd.actor.popuptext import PopupText from bascenev1lib.actor.popuptext import PopupText
from bastd.actor.powerupbox import PowerupBox from bascenev1lib.actor.powerupbox import PowerupBox
from bastd.actor.onscreencountdown import OnScreenCountdown from bascenev1lib.actor.onscreencountdown import OnScreenCountdown
from bastd.gameutils import SharedObjects from bascenev1lib.gameutils import SharedObjects
if TYPE_CHECKING: if TYPE_CHECKING:
from typing import NoReturn, Sequence, Any from typing import NoReturn, Sequence, Any
@ -48,13 +50,13 @@ ball_type_dict: dict[BallType, int] = {
} }
class Ball(ba.Actor): class Ball(bs.Actor):
""" Shooting Ball """ """ Shooting Ball """
def __init__(self, def __init__(self,
position: Sequence[float], position: Sequence[float],
velocity: Sequence[float], velocity: Sequence[float],
texture: ba.Texture, texture: babase.Texture,
body_scale: float = 1.0, body_scale: float = 1.0,
gravity_scale: float = 1.0, gravity_scale: float = 1.0,
) -> NoReturn: ) -> NoReturn:
@ -63,7 +65,7 @@ class Ball(ba.Actor):
shared = SharedObjects.get() shared = SharedObjects.get()
ball_material = ba.Material() ball_material = bs.Material()
ball_material.add_actions( ball_material.add_actions(
conditions=( conditions=(
( (
@ -77,7 +79,7 @@ class Ball(ba.Actor):
actions=('modify_node_collision', 'collide', False), actions=('modify_node_collision', 'collide', False),
) )
self.node = ba.newnode( self.node = bs.newnode(
'prop', 'prop',
delegate=self, delegate=self,
attrs={ attrs={
@ -85,8 +87,8 @@ class Ball(ba.Actor):
'position': position, 'position': position,
'velocity': velocity, 'velocity': velocity,
'body_scale': body_scale, 'body_scale': body_scale,
'model': ba.getmodel('frostyPelvis'), 'mesh': bs.getmesh('frostyPelvis'),
'model_scale': body_scale, 'mesh_scale': body_scale,
'color_texture': texture, 'color_texture': texture,
'gravity_scale': gravity_scale, 'gravity_scale': gravity_scale,
'density': 4.0, # increase density of ball so ball collide with player with heavy force. # ammm very bad grammer 'density': 4.0, # increase density of ball so ball collide with player with heavy force. # ammm very bad grammer
@ -95,19 +97,19 @@ class Ball(ba.Actor):
) )
# die the ball manually incase the ball doesn't fall the outside of the map # die the ball manually incase the ball doesn't fall the outside of the map
ba.timer(2.5, ba.WeakCall(self.handlemessage, ba.DieMessage())) bs.timer(2.5, bs.WeakCall(self.handlemessage, bs.DieMessage()))
# i am not handling anything in this ball Class(except for diemessage). # i am not handling anything in this ball Class(except for diemessage).
# all game things and logics going to be in the box class # all game things and logics going to be in the box class
def handlemessage(self, msg: Any) -> Any: def handlemessage(self, msg: Any) -> Any:
if isinstance(msg, ba.DieMessage): if isinstance(msg, bs.DieMessage):
self.node.delete() self.node.delete()
else: else:
super().handlemessage(msg) super().handlemessage(msg)
class Box(ba.Actor): class Box(bs.Actor):
""" A box that spawn midle of map as a decoration perpose """ """ A box that spawn midle of map as a decoration perpose """
def __init__(self, def __init__(self,
@ -119,7 +121,7 @@ class Box(ba.Actor):
shared = SharedObjects.get() shared = SharedObjects.get()
# self.ball_jump = 0.0; # self.ball_jump = 0.0;
no_hit_material = ba.Material() no_hit_material = bs.Material()
# we don't need that the box was move and collide with objects. # we don't need that the box was move and collide with objects.
no_hit_material.add_actions( no_hit_material.add_actions(
conditions=( conditions=(
@ -142,25 +144,25 @@ class Box(ba.Actor):
), ),
) )
self.node = ba.newnode( self.node = bs.newnode(
'prop', 'prop',
delegate=self, delegate=self,
attrs={ attrs={
'body': 'box', 'body': 'box',
'position': position, 'position': position,
'model': ba.getmodel('powerup'), 'mesh': bs.getmesh('powerup'),
'light_model': ba.getmodel('powerupSimple'), 'light_mesh': bs.getmesh('powerupSimple'),
'shadow_size': 0.5, 'shadow_size': 0.5,
'body_scale': 1.4, 'body_scale': 1.4,
'model_scale': 1.4, 'mesh_scale': 1.4,
'color_texture': ba.gettexture('landMineLit'), 'color_texture': bs.gettexture('landMineLit'),
'reflection': 'powerup', 'reflection': 'powerup',
'reflection_scale': [1.0], 'reflection_scale': [1.0],
'materials': (no_hit_material,), 'materials': (no_hit_material,),
}, },
) )
# light # light
self.light = ba.newnode( self.light = bs.newnode(
"light", "light",
owner=self.node, owner=self.node,
attrs={ attrs={
@ -173,7 +175,7 @@ class Box(ba.Actor):
# Drawing circle and circleOutline in radius of 3, # Drawing circle and circleOutline in radius of 3,
# so player can see that how close he is to the box. # so player can see that how close he is to the box.
# If player is inside this circle the ball speed will increase. # If player is inside this circle the ball speed will increase.
circle = ba.newnode( circle = bs.newnode(
"locator", "locator",
owner=self.node, owner=self.node,
attrs={ attrs={
@ -187,7 +189,7 @@ class Box(ba.Actor):
) )
self.node.connectattr("position", circle, "position") self.node.connectattr("position", circle, "position")
# also adding a outline cause its look nice. # also adding a outline cause its look nice.
circle_outline = ba.newnode( circle_outline = bs.newnode(
"locator", "locator",
owner=self.node, owner=self.node,
attrs={ attrs={
@ -203,17 +205,17 @@ class Box(ba.Actor):
# all ball attribute that we need. # all ball attribute that we need.
self.ball_type: BallType = BallType.EASY self.ball_type: BallType = BallType.EASY
self.shoot_timer: ba.Timer | None = None self.shoot_timer: bs.Timer | None = None
self.shoot_speed: float = 0.0 self.shoot_speed: float = 0.0
# this force the shoot if player is inside the red circle. # this force the shoot if player is inside the red circle.
self.force_shoot_speed: float = 0.0 self.force_shoot_speed: float = 0.0
self.ball_mag = 3000 self.ball_mag = 3000
self.ball_gravity: float = 1.0 self.ball_gravity: float = 1.0
self.ball_tex: ba.Texture | None = None self.ball_tex: babase.Texture | None = None
# only for Hard ball_type # only for Hard ball_type
self.player_facing_direction: list[float, float] = [0.0, 0.0] self.player_facing_direction: list[float, float] = [0.0, 0.0]
# ball shoot soound. # ball shoot soound.
self.shoot_sound = ba.getsound('laserReverse') self.shoot_sound = bs.getsound('laserReverse')
# same as "powerupdist" # same as "powerupdist"
self.ball_type_dist: list[BallType] = [] self.ball_type_dist: list[BallType] = []
@ -240,7 +242,7 @@ class Box(ba.Actor):
# to finding difference between player and box. # to finding difference between player and box.
# we just need to subtract player pos and ball pos. # we just need to subtract player pos and ball pos.
# Same logic as eric applied in Target Practice Gamemode. # Same logic as eric applied in Target Practice Gamemode.
difference = ba.Vec3(target_player.position) - ba.Vec3(self.node.position) difference = babase.Vec3(target_player.position) - babase.Vec3(self.node.position)
# discard Y position so ball shoot more straight. # discard Y position so ball shoot more straight.
difference[1] = 0.0 difference[1] = 0.0
@ -301,7 +303,7 @@ class Box(ba.Actor):
difference[2] + self.player_facing_direction[1], # force direction Z difference[2] + self.player_facing_direction[1], # force direction Z
) )
# creating our timer and shoot the ball again.(and we create a loop) # creating our timer and shoot the ball again.(and we create a loop)
self.shoot_timer = ba.Timer(self.shoot_speed, self.start_shoot) self.shoot_timer = bs.Timer(self.shoot_speed, self.start_shoot)
def upgrade_ball_type(self, ball_type: BallType) -> NoReturn: def upgrade_ball_type(self, ball_type: BallType) -> NoReturn:
@ -316,7 +318,7 @@ class Box(ba.Actor):
self.ball_mag = 3000 self.ball_mag = 3000
# box light color and ball tex # box light color and ball tex
self.light.color = (1.0, 1.0, 0.0) self.light.color = (1.0, 1.0, 0.0)
self.ball_tex = ba.gettexture('egg4') self.ball_tex = bs.gettexture('egg4')
elif ball_type == BallType.MEDIUM: elif ball_type == BallType.MEDIUM:
self.ball_mag = 3000 self.ball_mag = 3000
# decrease the gravity scale so, ball shoot without falling and straight. # decrease the gravity scale so, ball shoot without falling and straight.
@ -325,7 +327,7 @@ class Box(ba.Actor):
self.shoot_speed = 0.4 self.shoot_speed = 0.4
# box light color and ball tex. # box light color and ball tex.
self.light.color = (1.0, 0.0, 1.0) self.light.color = (1.0, 0.0, 1.0)
self.ball_tex = ba.gettexture('egg3') self.ball_tex = bs.gettexture('egg3')
elif ball_type == BallType.HARD: elif ball_type == BallType.HARD:
self.ball_mag = 2500 self.ball_mag = 2500
self.ball_gravity = 0.0 self.ball_gravity = 0.0
@ -333,25 +335,26 @@ class Box(ba.Actor):
self.shoot_speed = 0.6 self.shoot_speed = 0.6
# box light color and ball tex. # box light color and ball tex.
self.light.color = (1.0, 0.2, 1.0) self.light.color = (1.0, 0.2, 1.0)
self.ball_tex = ba.gettexture('egg1') self.ball_tex = bs.gettexture('egg1')
def shoot_animation(self) -> NoReturn: def shoot_animation(self) -> NoReturn:
ba.animate( bs.animate(
self.node, self.node,
"model_scale", { "mesh_scale", {
0.00: 1.4, 0.00: 1.4,
0.05: 1.7, 0.05: 1.7,
0.10: 1.4, 0.10: 1.4,
} }
) )
# playing shoot sound. # playing shoot sound.
ba.playsound(self.shoot_sound, position=self.node.position) # self.shoot_sound, position = self.node.position.play();
self.shoot_sound.play()
def highlight_target_player(self, player: ba.Player) -> NoReturn: def highlight_target_player(self, player: bs.Player) -> NoReturn:
# adding light # adding light
light = ba.newnode( light = bs.newnode(
"light", "light",
owner=self.node, owner=self.node,
attrs={ attrs={
@ -360,7 +363,7 @@ class Box(ba.Actor):
'color': (1.0, 0.0, 0.0), 'color': (1.0, 0.0, 0.0),
} }
) )
ba.animate( bs.animate(
light, light,
"radius", { "radius", {
0.05: 0.02, 0.05: 0.02,
@ -374,7 +377,7 @@ class Box(ba.Actor):
} }
) )
# And a circle outline with ugly animation. # And a circle outline with ugly animation.
circle_outline = ba.newnode( circle_outline = bs.newnode(
"locator", "locator",
owner=player.actor.node, owner=player.actor.node,
attrs={ attrs={
@ -385,7 +388,7 @@ class Box(ba.Actor):
'additive': True, 'additive': True,
}, },
) )
ba.animate_array( bs.animate_array(
circle_outline, circle_outline,
'size', 'size',
1, { 1, {
@ -406,10 +409,10 @@ class Box(ba.Actor):
# immediately delete the node after another player has been targeted. # immediately delete the node after another player has been targeted.
self.shoot_speed = 0.5 if self.shoot_speed == 0.0 else self.shoot_speed self.shoot_speed = 0.5 if self.shoot_speed == 0.0 else self.shoot_speed
ba.timer(self.shoot_speed, light.delete) bs.timer(self.shoot_speed, light.delete)
ba.timer(self.shoot_speed, circle_outline.delete) bs.timer(self.shoot_speed, circle_outline.delete)
def calculate_player_analog_stick(self, player: ba.Player, distance: float) -> NoReturn: def calculate_player_analog_stick(self, player: bs.Player, distance: float) -> NoReturn:
# at first i was very confused how i can read the player analog stick \ # at first i was very confused how i can read the player analog stick \
# then i saw TheMikirog#1984 autorun plugin code. # then i saw TheMikirog#1984 autorun plugin code.
# and i got it how analog stick values are works. # and i got it how analog stick values are works.
@ -461,48 +464,48 @@ class Box(ba.Actor):
self.shoot_timer = None self.shoot_timer = None
class Player(ba.Player['Team']): class Player(bs.Player['Team']):
"""Our player type for this game.""" """Our player type for this game."""
class Team(ba.Team[Player]): class Team(bs.Team[Player]):
"""Our team type for this game.""" """Our team type for this game."""
# almost 80 % for game we done in box class. # almost 80 % for game we done in box class.
# now remain things, like name, seetings, scoring, cooldonw, # now remain things, like name, seetings, scoring, cooldonw,
# and main thing don't allow player to camp inside of box are going in this class. # and main thing don't allow player to camp inside of box are going in this class.
# ba_meta export game # ba_meta export bascenev1.GameActivity
class DodgeTheBall(ba.TeamGameActivity[Player, Team]): class DodgeTheBall(bs.TeamGameActivity[Player, Team]):
# defining name, description and settings.. # defining name, description and settings..
name = 'Dodge the ball' name = 'Dodge the ball'
description = 'Survive from shooting balls' description = 'Survive from shooting balls'
available_settings = [ available_settings = [
ba.IntSetting( bs.IntSetting(
'Cooldown', 'Cooldown',
min_value=20, min_value=20,
default=45, default=45,
increment=5, increment=5,
), ),
ba.BoolSetting('Epic Mode', default=False) bs.BoolSetting('Epic Mode', default=False)
] ]
# Don't allow joining after we start. # Don't allow joining after we start.
allow_mid_activity_joins = False allow_mid_activity_joins = False
@classmethod @classmethod
def supports_session_type(cls, sessiontype: type[ba.Session]) -> bool: def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool:
# We support team and ffa sessions. # We support team and ffa sessions.
return issubclass(sessiontype, ba.FreeForAllSession) or issubclass( return issubclass(sessiontype, bs.FreeForAllSession) or issubclass(
sessiontype, ba.DualTeamSession, sessiontype, bs.DualTeamSession,
) )
@classmethod @classmethod
def get_supported_maps(cls, sessiontype: type[ba.Session]) -> list[str]: def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]:
# This Game mode need a flat and perfect shape map where can player fall outside map. # This Game mode need a flat and perfect shape map where can player fall outside map.
# bombsquad have "Doom Shroom" map. # bombsquad have "Doom Shroom" map.
# Not perfect map for this game mode but its fine for this gamemode. # Not perfect map for this game mode but its fine for this gamemode.
@ -514,21 +517,21 @@ class DodgeTheBall(ba.TeamGameActivity[Player, Team]):
self._epic_mode = bool(settings['Epic Mode']) self._epic_mode = bool(settings['Epic Mode'])
self.countdown_time = int(settings['Cooldown']) self.countdown_time = int(settings['Cooldown'])
self.check_player_pos_timer: ba.Timer | None = None self.check_player_pos_timer: bs.Timer | None = None
self.shield_drop_timer: ba.Timer | None = None self.shield_drop_timer: bs.Timer | None = None
# cooldown and Box # cooldown and Box
self._countdown: OnScreenCountdown | None = None self._countdown: OnScreenCountdown | None = None
self.box: Box | None = None self.box: Box | None = None
# this lists for scoring. # this lists for scoring.
self.joined_player_list: list[ba.Player] = [] self.joined_player_list: list[bs.Player] = []
self.dead_player_list: list[ba.Player] = [] self.dead_player_list: list[bs.Player] = []
# normally play RUN AWAY music cause is match with our gamemode at.. my point, # normally play RUN AWAY music cause is match with our gamemode at.. my point,
# but in epic switch to EPIC. # but in epic switch to EPIC.
self.slow_motion = self._epic_mode self.slow_motion = self._epic_mode
self.default_music = ( self.default_music = (
ba.MusicType.EPIC if self._epic_mode else ba.MusicType.RUN_AWAY bs.MusicType.EPIC if self._epic_mode else bs.MusicType.RUN_AWAY
) )
def get_instance_description(self) -> str | Sequence: def get_instance_description(self) -> str | Sequence:
@ -554,19 +557,19 @@ class DodgeTheBall(ba.TeamGameActivity[Player, Team]):
) )
# and starts the cooldown and shootes. # and starts the cooldown and shootes.
ba.timer(5.0, self._countdown.start) bs.timer(5.0, self._countdown.start)
ba.timer(5.0, self.box.start_shoot) bs.timer(5.0, self.box.start_shoot)
# start checking all player pos. # start checking all player pos.
ba.timer(5.0, self.check_player_pos) bs.timer(5.0, self.check_player_pos)
# drop shield every ten Seconds # drop shield every ten Seconds
# need five seconds delay Because shootes start after 5 seconds. # need five seconds delay Because shootes start after 5 seconds.
ba.timer(15.0, self.drop_shield) bs.timer(15.0, self.drop_shield)
# This function returns all alive players in game. # This function returns all alive players in game.
# i thinck you see this function in Box class. # i thinck you see this function in Box class.
def get_alive_players(self) -> Sequence[ba.Player]: def get_alive_players(self) -> Sequence[bs.Player]:
alive_players = [] alive_players = []
@ -583,7 +586,7 @@ class DodgeTheBall(ba.TeamGameActivity[Player, Team]):
for player in self.get_alive_players(): for player in self.get_alive_players():
# same logic as applied for the ball # same logic as applied for the ball
difference = ba.Vec3(player.position) - ba.Vec3(self.box.node.position) difference = babase.Vec3(player.position) - babase.Vec3(self.box.node.position)
distance = difference.length() distance = difference.length()
@ -609,7 +612,7 @@ class DodgeTheBall(ba.TeamGameActivity[Player, Team]):
).autoretain() ).autoretain()
# create our timer and start looping it # create our timer and start looping it
self.check_player_pos_timer = ba.Timer(0.1, self.check_player_pos) self.check_player_pos_timer = bs.Timer(0.1, self.check_player_pos)
# drop useless shield's too give player temptation. # drop useless shield's too give player temptation.
def drop_shield(self) -> NoReturn: def drop_shield(self) -> NoReturn:
@ -626,7 +629,7 @@ class DodgeTheBall(ba.TeamGameActivity[Player, Team]):
poweruptype='shield', poweruptype='shield',
).autoretain() ).autoretain()
self.shield_drop_timer = ba.Timer(10.0, self.drop_shield) self.shield_drop_timer = bs.Timer(10.0, self.drop_shield)
# when cooldown time up i don't want that the game end immediately. # when cooldown time up i don't want that the game end immediately.
def play_victory_sound_and_end(self) -> NoReturn: def play_victory_sound_and_end(self) -> NoReturn:
@ -636,7 +639,7 @@ class DodgeTheBall(ba.TeamGameActivity[Player, Team]):
self.check_player_pos_timer = None self.check_player_pos_timer = None
self.shield_drop_timer = None self.shield_drop_timer = None
ba.timer(2.0, self.end_game) bs.timer(2.0, self.end_game)
# this function runs when A player spawn in map # this function runs when A player spawn in map
def spawn_player(self, player: Player) -> NoReturn: def spawn_player(self, player: Player) -> NoReturn:
@ -682,7 +685,7 @@ class DodgeTheBall(ba.TeamGameActivity[Player, Team]):
# this gamemode needs to handle only one msg "PlayerDiedMessage". # this gamemode needs to handle only one msg "PlayerDiedMessage".
def handlemessage(self, msg: Any) -> Any: def handlemessage(self, msg: Any) -> Any:
if isinstance(msg, ba.PlayerDiedMessage): if isinstance(msg, bs.PlayerDiedMessage):
# Augment standard behavior. # Augment standard behavior.
super().handlemessage(msg) super().handlemessage(msg)
@ -691,7 +694,7 @@ class DodgeTheBall(ba.TeamGameActivity[Player, Team]):
self.dead_player_list.append(msg.getplayer(Player)) self.dead_player_list.append(msg.getplayer(Player))
# check the end game. # check the end game.
ba.timer(1.0, self._check_end_game) bs.timer(1.0, self._check_end_game)
def end_game(self): def end_game(self):
# kill timers # kill timers
@ -736,7 +739,7 @@ class DodgeTheBall(ba.TeamGameActivity[Player, Team]):
# Ok now calc game results: set a score for each team and then tell \ # Ok now calc game results: set a score for each team and then tell \
# the game to end. # the game to end.
results = ba.GameResults() results = bs.GameResults()
# Remember that 'free-for-all' mode is simply a special form \ # Remember that 'free-for-all' mode is simply a special form \
# of 'teams' mode where each player gets their own team, so we can \ # of 'teams' mode where each player gets their own team, so we can \

View file

@ -0,0 +1,18 @@
# Ported by your friend: Freaku
import babase
import bascenev1 as bs
from bascenev1lib.game.chosenone import Player, ChosenOneGame
# ba_meta require api 8
# ba_meta export bascenev1.GameActivity
class FrozenOneGame(ChosenOneGame):
name = 'Frozen One'
def _set_chosen_one_player(self, player: Player) -> None:
super()._set_chosen_one_player(player)
if hasattr(player, 'actor'):
player.actor.frozen = True
player.actor.node.frozen = 1

View file

@ -0,0 +1,383 @@
# Released under the MIT License. See LICENSE for details.
#
"""Hockey game and support classes."""
# ba_meta require api 8
# (see https://ballistica.net/wiki/meta-tag-system)
from __future__ import annotations
from typing import TYPE_CHECKING
import babase
import bauiv1 as bui
import bascenev1 as bs
from bascenev1lib.actor.playerspaz import PlayerSpaz
from bascenev1lib.actor.scoreboard import Scoreboard
from bascenev1lib.actor.powerupbox import PowerupBoxFactory
from bascenev1lib.gameutils import SharedObjects
if TYPE_CHECKING:
from typing import Any, Sequence, Optional, Union
class PuckDiedMessage:
"""Inform something that a puck has died."""
def __init__(self, puck: Puck):
self.puck = puck
class Puck(bs.Actor):
"""A lovely giant hockey puck."""
def __init__(self, position: Sequence[float] = (0.0, 1.0, 0.0)):
super().__init__()
shared = SharedObjects.get()
activity = self.getactivity()
# Spawn just above the provided point.
self._spawn_pos = (position[0], position[1] + 1.0, position[2])
self.last_players_to_touch: dict[int, Player] = {}
self.scored = False
assert activity is not None
assert isinstance(activity, HockeyGame)
pmats = [shared.object_material, activity.puck_material]
self.node = bs.newnode('prop',
delegate=self,
attrs={
'mesh': activity.puck_mesh,
'color_texture': activity.puck_tex,
'body': 'sphere',
'reflection': 'soft',
'reflection_scale': [0.2],
'shadow_size': 0.8,
'is_area_of_interest': True,
'position': self._spawn_pos,
'materials': pmats
})
bs.animate(self.node, 'mesh_scale', {0: 0, 0.2: 1.3, 0.26: 1})
def handlemessage(self, msg: Any) -> Any:
if isinstance(msg, bs.DieMessage):
assert self.node
self.node.delete()
activity = self._activity()
if activity and not msg.immediate:
activity.handlemessage(PuckDiedMessage(self))
# If we go out of bounds, move back to where we started.
elif isinstance(msg, bs.OutOfBoundsMessage):
assert self.node
self.node.position = self._spawn_pos
elif isinstance(msg, bs.HitMessage):
assert self.node
assert msg.force_direction is not None
self.node.handlemessage(
'impulse', msg.pos[0], msg.pos[1], msg.pos[2], msg.velocity[0],
msg.velocity[1], msg.velocity[2], 1.0 * msg.magnitude,
1.0 * msg.velocity_magnitude, msg.radius, 0,
msg.force_direction[0], msg.force_direction[1],
msg.force_direction[2])
# If this hit came from a player, log them as the last to touch us.
s_player = msg.get_source_player(Player)
if s_player is not None:
activity = self._activity()
if activity:
if s_player in activity.players:
self.last_players_to_touch[s_player.team.id] = s_player
else:
super().handlemessage(msg)
class Player(bs.Player['Team']):
"""Our player type for this game."""
class Team(bs.Team[Player]):
"""Our team type for this game."""
def __init__(self) -> None:
self.score = 0
# ba_meta export bascenev1.GameActivity
class HockeyGame(bs.TeamGameActivity[Player, Team]):
"""Ice hockey game."""
name = 'Handball'
description = 'Score some goals.'
available_settings = [
bs.IntSetting(
'Score to Win',
min_value=1,
default=1,
increment=1,
),
bs.IntChoiceSetting(
'Time Limit',
choices=[
('None', 0),
('1 Minute', 60),
('2 Minutes', 120),
('5 Minutes', 300),
('10 Minutes', 600),
('20 Minutes', 1200),
],
default=0,
),
bs.FloatChoiceSetting(
'Respawn Times',
choices=[
('Shorter', 0.25),
('Short', 0.5),
('Normal', 1.0),
('Long', 2.0),
('Longer', 4.0),
],
default=1.0,
),
bs.BoolSetting('Epic Mode', default=False),
]
default_music = bs.MusicType.HOCKEY
@classmethod
def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool:
return issubclass(sessiontype, bs.DualTeamSession)
@classmethod
def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]:
return bs.app.classic.getmaps('hockey')
def __init__(self, settings: dict):
super().__init__(settings)
shared = SharedObjects.get()
self._scoreboard = Scoreboard()
self._cheer_sound = bs.getsound('cheer')
self._chant_sound = bs.getsound('crowdChant')
self._foghorn_sound = bs.getsound('foghorn')
self._swipsound = bs.getsound('swip')
self._whistle_sound = bs.getsound('refWhistle')
self.puck_mesh = bs.getmesh('bomb')
self.puck_tex = bs.gettexture('bonesColor')
self._puck_sound = bs.getsound('metalHit')
self._epic_mode = bool(settings['Epic Mode'])
self.slow_motion = self._epic_mode
self.default_music = (bs.MusicType.EPIC
if self._epic_mode else bs.MusicType.FOOTBALL)
self.puck_material = bs.Material()
self.puck_material.add_actions(actions=(('modify_part_collision',
'friction', 0.5)))
self.puck_material.add_actions(conditions=('they_have_material',
shared.pickup_material),
actions=('modify_part_collision',
'collide', False))
self.puck_material = bs.Material()
self.puck_material.add_actions(actions=(('modify_part_collision',
'friction', 0.5)))
self.puck_material.add_actions(conditions=('they_have_material',
shared.pickup_material),
actions=('modify_part_collision',
'collide', True))
self.puck_material.add_actions(
conditions=(
('we_are_younger_than', 100),
'and',
('they_have_material', shared.object_material),
),
actions=('modify_node_collision', 'collide', False),
)
self.puck_material.add_actions(conditions=('they_have_material',
shared.footing_material),
actions=('impact_sound',
self._puck_sound, 0.2, 5))
# Keep track of which player last touched the puck
self.puck_material.add_actions(
conditions=('they_have_material', shared.player_material),
actions=(('call', 'at_connect',
self._handle_puck_player_collide), ))
# We want the puck to kill powerups; not get stopped by them
self.puck_material.add_actions(
conditions=('they_have_material',
PowerupBoxFactory.get().powerup_material),
actions=(('modify_part_collision', 'physical', False),
('message', 'their_node', 'at_connect', bs.DieMessage())))
self._score_region_material = bs.Material()
self._score_region_material.add_actions(
conditions=('they_have_material', self.puck_material),
actions=(('modify_part_collision', 'collide',
True), ('modify_part_collision', 'physical', False),
('call', 'at_connect', self._handle_score)))
self._puck_spawn_pos: Optional[Sequence[float]] = None
self._score_regions: Optional[list[bs.NodeActor]] = None
self._puck: Optional[Puck] = None
self._score_to_win = int(settings['Score to Win'])
self._time_limit = float(settings['Time Limit'])
def get_instance_description(self) -> Union[str, Sequence]:
if self._score_to_win == 1:
return 'Score a goal.'
return 'Score ${ARG1} goals.', self._score_to_win
def get_instance_description_short(self) -> Union[str, Sequence]:
if self._score_to_win == 1:
return 'score a goal'
return 'score ${ARG1} goals', self._score_to_win
def on_begin(self) -> None:
super().on_begin()
self.setup_standard_time_limit(self._time_limit)
self.setup_standard_powerup_drops()
self._puck_spawn_pos = self.map.get_flag_position(None)
self._spawn_puck()
# Set up the two score regions.
defs = self.map.defs
self._score_regions = []
self._score_regions.append(
bs.NodeActor(
bs.newnode('region',
attrs={
'position': defs.boxes['goal1'][0:3],
'scale': defs.boxes['goal1'][6:9],
'type': 'box',
'materials': [self._score_region_material]
})))
self._score_regions.append(
bs.NodeActor(
bs.newnode('region',
attrs={
'position': defs.boxes['goal2'][0:3],
'scale': defs.boxes['goal2'][6:9],
'type': 'box',
'materials': [self._score_region_material]
})))
self._update_scoreboard()
self._chant_sound.play()
def on_team_join(self, team: Team) -> None:
self._update_scoreboard()
def _handle_puck_player_collide(self) -> None:
collision = bs.getcollision()
try:
puck = collision.sourcenode.getdelegate(Puck, True)
player = collision.opposingnode.getdelegate(PlayerSpaz,
True).getplayer(
Player, True)
except bs.NotFoundError:
return
puck.last_players_to_touch[player.team.id] = player
def _kill_puck(self) -> None:
self._puck = None
def _handle_score(self) -> None:
"""A point has been scored."""
assert self._puck is not None
assert self._score_regions is not None
# Our puck might stick around for a second or two
# we don't want it to be able to score again.
if self._puck.scored:
return
region = bs.getcollision().sourcenode
index = 0
for index, score_region in enumerate(self._score_regions):
if region == score_region.node:
break
for team in self.teams:
if team.id == index:
scoring_team = team
team.score += 1
# Tell all players to celebrate.
for player in team.players:
if player.actor:
player.actor.handlemessage(bs.CelebrateMessage(2.0))
# If we've got the player from the scoring team that last
# touched us, give them points.
if (scoring_team.id in self._puck.last_players_to_touch
and self._puck.last_players_to_touch[scoring_team.id]):
self.stats.player_scored(
self._puck.last_players_to_touch[scoring_team.id],
100,
big_message=True)
# End game if we won.
if team.score >= self._score_to_win:
self.end_game()
self._foghorn_sound.play()
self._cheer_sound.play()
self._puck.scored = True
# Kill the puck (it'll respawn itself shortly).
bs.timer(1.0, self._kill_puck)
light = bs.newnode('light',
attrs={
'position': bs.getcollision().position,
'height_attenuated': False,
'color': (1, 0, 0)
})
bs.animate(light, 'intensity', {0: 0, 0.5: 1, 1.0: 0}, loop=True)
bs.timer(1.0, light.delete)
bs.cameraflash(duration=10.0)
self._update_scoreboard()
def end_game(self) -> None:
results = bs.GameResults()
for team in self.teams:
results.set_team_score(team, team.score)
self.end(results=results)
def _update_scoreboard(self) -> None:
winscore = self._score_to_win
for team in self.teams:
self._scoreboard.set_team_value(team, team.score, winscore)
def handlemessage(self, msg: Any) -> Any:
# Respawn dead players if they're still in the game.
if isinstance(msg, bs.PlayerDiedMessage):
# Augment standard behavior...
super().handlemessage(msg)
self.respawn_player(msg.getplayer(Player))
# Respawn dead pucks.
elif isinstance(msg, PuckDiedMessage):
if not self.has_ended():
bs.timer(3.0, self._spawn_puck)
else:
super().handlemessage(msg)
def _flash_puck_spawn(self) -> None:
light = bs.newnode('light',
attrs={
'position': self._puck_spawn_pos,
'height_attenuated': False,
'color': (1, 0, 0)
})
bs.animate(light, 'intensity', {0.0: 0, 0.25: 1, 0.5: 0}, loop=True)
bs.timer(1.0, light.delete)
def _spawn_puck(self) -> None:
self._swipsound.play()
self._whistle_sound.play()
self._flash_puck_spawn()
assert self._puck_spawn_pos is not None
self._puck = Puck(position=self._puck_spawn_pos)

View file

@ -0,0 +1,48 @@
# Made by your friend: Freaku
import babase
import bascenev1 as bs
import random
from bascenev1lib.actor.bomb import Bomb
from bascenev1lib.game.meteorshower import Player, MeteorShowerGame
# ba_meta require api 8
# ba_meta export bascenev1.GameActivity
class IcyEmitsGame(MeteorShowerGame):
name = 'Icy Emits'
@classmethod
def get_supported_maps(cls, sessiontype):
return ['Lake Frigid', 'Hockey Stadium']
def _drop_bomb_cluster(self) -> None:
delay = 0.0
for _i in range(random.randrange(1, 3)):
# Drop them somewhere within our bounds with velocity pointing
# toward the opposite side.
pos = (-7.3 + 15.3 * random.random(), 5.3,
-5.5 + 2.1 * random.random())
dropdir = (-1.0 if pos[0] > 0 else 1.0)
vel = (0, 10, 0)
bs.timer(delay, babase.Call(self._drop_bomb, pos, vel))
delay += 0.1
self._set_meteor_timer()
def _drop_bomb(self, position, velocity):
random_xpositions = [-10, -9, -8, -7, -6, -5, -
4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
random_zpositions = [-5, -4.5, -4, -3.5, -3, -2.5, -2, -
1.5, -1, -0.5, 0, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5]
bomb_position = (random.choice(random_xpositions), 0.2, random.choice(random_zpositions))
Bomb(position=bomb_position, velocity=velocity, bomb_type='ice').autoretain()
# ba_meta export plugin
class byFreaku(babase.Plugin):
def __init__(self):
## Campaign support ##
randomPic = ['lakeFrigidPreview', 'hockeyStadiumPreview']
babase.app.classic.add_coop_practice_level(bs.Level(
name='Icy Emits', displayname='${GAME}', gametype=IcyEmitsGame, settings={}, preview_texture_name=random.choice(randomPic)))

View file

@ -2,7 +2,7 @@ from __future__ import annotations
## Original creator: byANG3L ## ## Original creator: byANG3L ##
## Made by: Freaku / @[Just] Freak#4999 ## ## Made by: Freaku ##
## From: BSWorld Modpack (https://youtu.be/1TN56NLlShE) ## ## From: BSWorld Modpack (https://youtu.be/1TN56NLlShE) ##
@ -16,73 +16,63 @@ from __future__ import annotations
# def spawnAllMap(self) # def spawnAllMap(self)
# ba_meta require api 7 # ba_meta require api 8
from typing import TYPE_CHECKING, overload from typing import TYPE_CHECKING, overload
import _ba import _babase
import ba import babase
import random import random
from bastd.gameutils import SharedObjects import bascenev1 as bs
from bascenev1lib.gameutils import SharedObjects
if TYPE_CHECKING: if TYPE_CHECKING:
from typing import Any, Sequence, Optional, List, Dict, Type, Union, Any, Literal from typing import Any, Sequence, Optional, List, Dict, Type, Union, Any, Literal
class OnTimer(ba.Actor): class OnTimer(bs.Actor):
"""Timer which counts but doesn't show on-screen""" """Timer which counts but doesn't show on-screen"""
def __init__(self) -> None: def __init__(self) -> None:
super().__init__() super().__init__()
self._starttime_ms: Optional[int] = None self._starttime_ms: int | None = None
self.node = ba.newnode('text', attrs={'v_attach': 'top', 'h_attach': 'center', 'h_align': 'center', 'color': ( self.node = bs.newnode('text', attrs={'v_attach': 'top', 'h_attach': 'center', 'h_align': 'center', 'color': (
1, 1, 0.5, 1), 'flatness': 0.5, 'shadow': 0.5, 'position': (0, -70), 'scale': 0, 'text': ''}) 1, 1, 0.5, 1), 'flatness': 0.5, 'shadow': 0.5, 'position': (0, -70), 'scale': 0, 'text': ''})
self.inputnode = ba.newnode('timedisplay', attrs={ self.inputnode = bs.newnode(
'timemin': 0, 'showsubseconds': True}) 'timedisplay', attrs={'timemin': 0, 'showsubseconds': True}
)
self.inputnode.connectattr('output', self.node, 'text') self.inputnode.connectattr('output', self.node, 'text')
def start(self) -> None: def start(self) -> None:
tval = ba.time(timeformat=ba.TimeFormat.MILLISECONDS) """Start the timer."""
tval = int(bs.time() * 1000.0)
assert isinstance(tval, int) assert isinstance(tval, int)
self._starttime_ms = tval self._starttime_ms = tval
self.inputnode.time1 = self._starttime_ms self.inputnode.time1 = self._starttime_ms
ba.getactivity().globalsnode.connectattr('time', self.inputnode, 'time2') bs.getactivity().globalsnode.connectattr(
'time', self.inputnode, 'time2'
)
def has_started(self) -> bool: def has_started(self) -> bool:
"""Return whether this timer has started yet."""
return self._starttime_ms is not None return self._starttime_ms is not None
def stop(self, def stop(self, endtime: int | float | None = None) -> None:
endtime: Union[int, float] = None, """End the timer.
timeformat: ba.TimeFormat = ba.TimeFormat.SECONDS) -> None:
If 'endtime' is not None, it is used when calculating
the final display time; otherwise the current time is used.
"""
if endtime is None: if endtime is None:
endtime = ba.time(timeformat=ba.TimeFormat.MILLISECONDS) endtime = bs.time()
timeformat = ba.TimeFormat.MILLISECONDS
if self._starttime_ms is None: if self._starttime_ms is None:
print('Warning: OnTimer.stop() called without start() first') logging.warning(
'OnScreenTimer.stop() called without first calling start()'
)
else: else:
endtime_ms: int endtime_ms = int(endtime * 1000)
if timeformat is ba.TimeFormat.SECONDS:
endtime_ms = int(endtime * 1000)
elif timeformat is ba.TimeFormat.MILLISECONDS:
assert isinstance(endtime, int)
endtime_ms = endtime
else:
raise ValueError(f'invalid timeformat: {timeformat}')
self.inputnode.timemax = endtime_ms - self._starttime_ms self.inputnode.timemax = endtime_ms - self._starttime_ms
# Overloads so type checker knows our exact return type based in args.
@overload def getstarttime(self) -> float:
def getstarttime(self, timeformat: Literal[ba.TimeFormat.SECONDS] = ba.TimeFormat.SECONDS) -> float: """Return the scene-time when start() was called.
...
@overload
def getstarttime(self,
timeformat: Literal[ba.TimeFormat.MILLISECONDS]) -> int:
...
def getstarttime(
self,
timeformat: ba.TimeFormat = ba.TimeFormat.SECONDS
) -> Union[int, float]:
"""Return the sim-time when start() was called.
Time will be returned in seconds if timeformat is SECONDS or Time will be returned in seconds if timeformat is SECONDS or
milliseconds if it is MILLISECONDS. milliseconds if it is MILLISECONDS.
@ -90,15 +80,11 @@ class OnTimer(ba.Actor):
val_ms: Any val_ms: Any
if self._starttime_ms is None: if self._starttime_ms is None:
print('WARNING: getstarttime() called on un-started timer') print('WARNING: getstarttime() called on un-started timer')
val_ms = ba.time(timeformat=ba.TimeFormat.MILLISECONDS) val_ms = int(bs.time() * 1000.0)
else: else:
val_ms = self._starttime_ms val_ms = self._starttime_ms
assert isinstance(val_ms, int) assert isinstance(val_ms, int)
if timeformat is ba.TimeFormat.SECONDS: return 0.001 * val_ms
return 0.001 * val_ms
if timeformat is ba.TimeFormat.MILLISECONDS:
return val_ms
raise ValueError(f'invalid timeformat: {timeformat}')
@property @property
def starttime(self) -> float: def starttime(self) -> float:
@ -107,12 +93,12 @@ class OnTimer(ba.Actor):
def handlemessage(self, msg: Any) -> Any: def handlemessage(self, msg: Any) -> Any:
# if we're asked to die, just kill our node/timer # if we're asked to die, just kill our node/timer
if isinstance(msg, ba.DieMessage): if isinstance(msg, bs.DieMessage):
if self.node: if self.node:
self.node.delete() self.node.delete()
class Player(ba.Player['Team']): class Player(bs.Player['Team']):
"""Our player type for this game.""" """Our player type for this game."""
def __init__(self) -> None: def __init__(self) -> None:
@ -120,33 +106,33 @@ class Player(ba.Player['Team']):
self.death_time: Optional[float] = None self.death_time: Optional[float] = None
class Team(ba.Team[Player]): class Team(bs.Team[Player]):
"""Our team type for this game.""" """Our team type for this game."""
# ba_meta export game # ba_meta export bascenev1.GameActivity
class MGgame(ba.TeamGameActivity[Player, Team]): class MGgame(bs.TeamGameActivity[Player, Team]):
name = 'Memory Game' name = 'Memory Game'
description = 'Memories tiles and survive till the end!' description = 'Memories tiles and survive till the end!'
available_settings = [ba.BoolSetting( available_settings = [bs.BoolSetting(
'Epic Mode', default=False), ba.BoolSetting('Enable Bottom Credits', True)] 'Epic Mode', default=False), bs.BoolSetting('Enable Bottom Credits', True)]
scoreconfig = ba.ScoreConfig(label='Survived', scoretype=ba.ScoreType.MILLISECONDS, version='B') scoreconfig = bs.ScoreConfig(label='Survived', scoretype=bs.ScoreType.MILLISECONDS, version='B')
# Print messages when players die (since its meaningful in this game). # Print messages when players die (since its meaningful in this game).
announce_player_deaths = True announce_player_deaths = True
# we're currently hard-coded for one map.. # we're currently hard-coded for one map..
@classmethod @classmethod
def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]:
return ['Sky Tiles'] return ['Sky Tiles']
# We support teams, free-for-all, and co-op sessions. # We support teams, free-for-all, and co-op sessions.
@classmethod @classmethod
def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool: def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool:
return (issubclass(sessiontype, ba.DualTeamSession) return (issubclass(sessiontype, bs.DualTeamSession)
or issubclass(sessiontype, ba.FreeForAllSession) or issubclass(sessiontype, bs.FreeForAllSession)
or issubclass(sessiontype, ba.CoopSession)) or issubclass(sessiontype, babase.CoopSession))
def __init__(self, settings: dict): def __init__(self, settings: dict):
super().__init__(settings) super().__init__(settings)
@ -157,14 +143,14 @@ class MGgame(ba.TeamGameActivity[Player, Team]):
self.credit_text = bool(settings['Enable Bottom Credits']) self.credit_text = bool(settings['Enable Bottom Credits'])
# Some base class overrides: # Some base class overrides:
self.default_music = (ba.MusicType.EPIC self.default_music = (bs.MusicType.EPIC
if self._epic_mode else ba.MusicType.SURVIVAL) if self._epic_mode else bs.MusicType.SURVIVAL)
if self._epic_mode: if self._epic_mode:
self.slow_motion = True self.slow_motion = True
shared = SharedObjects.get() shared = SharedObjects.get()
self._collide_with_player = ba.Material() self._collide_with_player = bs.Material()
self._collide_with_player.add_actions(actions=(('modify_part_collision', 'collide', True))) self._collide_with_player.add_actions(actions=(('modify_part_collision', 'collide', True)))
self.dont_collide = ba.Material() self.dont_collide = bs.Material()
self.dont_collide.add_actions(actions=(('modify_part_collision', 'collide', False))) self.dont_collide.add_actions(actions=(('modify_part_collision', 'collide', False)))
self._levelStage = 0 self._levelStage = 0
@ -172,46 +158,46 @@ class MGgame(ba.TeamGameActivity[Player, Team]):
self._lastPlayerDeathTime = None self._lastPlayerDeathTime = None
self._spawnCenter = (-3.17358, 2.75764, -2.99124) self._spawnCenter = (-3.17358, 2.75764, -2.99124)
self._mapFGPModel = ba.getmodel('buttonSquareOpaque') self._mapFGPModel = bs.getmesh('buttonSquareOpaque')
self._mapFGPDefaultTex = ba.gettexture('achievementOffYouGo') self._mapFGPDefaultTex = bs.gettexture('achievementOffYouGo')
self._mapFGCurseTex = ba.gettexture('powerupCurse') self._mapFGCurseTex = bs.gettexture('powerupCurse')
self._mapFGHealthTex = ba.gettexture('powerupHealth') self._mapFGHealthTex = bs.gettexture('powerupHealth')
self._mapFGIceTex = ba.gettexture('powerupIceBombs') self._mapFGIceTex = bs.gettexture('powerupIceBombs')
self._mapFGImpactTex = ba.gettexture('powerupImpactBombs') self._mapFGImpactTex = bs.gettexture('powerupImpactBombs')
self._mapFGMinesTex = ba.gettexture('powerupLandMines') self._mapFGMinesTex = bs.gettexture('powerupLandMines')
self._mapFGPunchTex = ba.gettexture('powerupPunch') self._mapFGPunchTex = bs.gettexture('powerupPunch')
self._mapFGShieldTex = ba.gettexture('powerupShield') self._mapFGShieldTex = bs.gettexture('powerupShield')
self._mapFGStickyTex = ba.gettexture('powerupStickyBombs') self._mapFGStickyTex = bs.gettexture('powerupStickyBombs')
self._mapFGSpaz = ba.gettexture('neoSpazIcon') self._mapFGSpaz = bs.gettexture('neoSpazIcon')
self._mapFGZoe = ba.gettexture('zoeIcon') self._mapFGZoe = bs.gettexture('zoeIcon')
self._mapFGSnake = ba.gettexture('ninjaIcon') self._mapFGSnake = bs.gettexture('ninjaIcon')
self._mapFGKronk = ba.gettexture('kronkIcon') self._mapFGKronk = bs.gettexture('kronkIcon')
self._mapFGMel = ba.gettexture('melIcon') self._mapFGMel = bs.gettexture('melIcon')
self._mapFGJack = ba.gettexture('jackIcon') self._mapFGJack = bs.gettexture('jackIcon')
self._mapFGSanta = ba.gettexture('santaIcon') self._mapFGSanta = bs.gettexture('santaIcon')
self._mapFGFrosty = ba.gettexture('frostyIcon') self._mapFGFrosty = bs.gettexture('frostyIcon')
self._mapFGBones = ba.gettexture('bonesIcon') self._mapFGBones = bs.gettexture('bonesIcon')
self._mapFGBernard = ba.gettexture('bearIcon') self._mapFGBernard = bs.gettexture('bearIcon')
self._mapFGPascal = ba.gettexture('penguinIcon') self._mapFGPascal = bs.gettexture('penguinIcon')
self._mapFGAli = ba.gettexture('aliIcon') self._mapFGAli = bs.gettexture('aliIcon')
self._mapFGRobot = ba.gettexture('cyborgIcon') self._mapFGRobot = bs.gettexture('cyborgIcon')
self._mapFGAgent = ba.gettexture('agentIcon') self._mapFGAgent = bs.gettexture('agentIcon')
self._mapFGGrumbledorf = ba.gettexture('wizardIcon') self._mapFGGrumbledorf = bs.gettexture('wizardIcon')
self._mapFGPixel = ba.gettexture('pixieIcon') self._mapFGPixel = bs.gettexture('pixieIcon')
self._imageTextDefault = ba.gettexture('bg') self._imageTextDefault = bs.gettexture('bg')
self._circleTex = ba.gettexture('circleShadow') self._circleTex = bs.gettexture('circleShadow')
self._image = ba.newnode('image', self._image = bs.newnode('image',
attrs={'texture': self._imageTextDefault, attrs={'texture': self._imageTextDefault,
'position': (0, -100), 'position': (0, -100),
'scale': (100, 100), 'scale': (100, 100),
'opacity': 0.0, 'opacity': 0.0,
'attach': 'topCenter'}) 'attach': 'topCenter'})
self._textCounter = ba.newnode('text', self._textCounter = bs.newnode('text',
attrs={'text': '10', attrs={'text': '10',
'position': (0, -100), 'position': (0, -100),
'scale': 2.3, 'scale': 2.3,
@ -223,7 +209,7 @@ class MGgame(ba.TeamGameActivity[Player, Team]):
'h_align': 'center', 'h_align': 'center',
'v_align': 'center'}) 'v_align': 'center'})
self._textLevel = ba.newnode('text', self._textLevel = bs.newnode('text',
attrs={'text': 'Level ' + str(self._levelStage), attrs={'text': 'Level ' + str(self._levelStage),
'position': (0, -28), 'position': (0, -28),
'scale': 1.3, 'scale': 1.3,
@ -236,21 +222,21 @@ class MGgame(ba.TeamGameActivity[Player, Team]):
'h_align': 'center', 'h_align': 'center',
'v_align': 'center'}) 'v_align': 'center'})
self._imageCircle = ba.newnode('image', self._imageCircle = bs.newnode('image',
attrs={'texture': self._circleTex, attrs={'texture': self._circleTex,
'position': (75, -75), 'position': (75, -75),
'scale': (20, 20), 'scale': (20, 20),
'color': (0.2, 0.2, 0.2), 'color': (0.2, 0.2, 0.2),
'opacity': 0.0, 'opacity': 0.0,
'attach': 'topCenter'}) 'attach': 'topCenter'})
self._imageCircle2 = ba.newnode('image', self._imageCircle2 = bs.newnode('image',
attrs={'texture': self._circleTex, attrs={'texture': self._circleTex,
'position': (75, -100), 'position': (75, -100),
'scale': (20, 20), 'scale': (20, 20),
'color': (0.2, 0.2, 0.2), 'color': (0.2, 0.2, 0.2),
'opacity': 0.0, 'opacity': 0.0,
'attach': 'topCenter'}) 'attach': 'topCenter'})
self._imageCircle3 = ba.newnode('image', self._imageCircle3 = bs.newnode('image',
attrs={'texture': self._circleTex, attrs={'texture': self._circleTex,
'position': (75, -125), 'position': (75, -125),
'scale': (20, 20), 'scale': (20, 20),
@ -260,12 +246,12 @@ class MGgame(ba.TeamGameActivity[Player, Team]):
def on_transition_in(self) -> None: def on_transition_in(self) -> None:
super().on_transition_in() super().on_transition_in()
self._bellLow = ba.getsound('bellLow') self._bellLow = bs.getsound('bellLow')
self._bellMed = ba.getsound('bellMed') self._bellMed = bs.getsound('bellMed')
self._bellHigh = ba.getsound('bellHigh') self._bellHigh = bs.getsound('bellHigh')
self._tickSound = ba.getsound('tick') self._tickSound = bs.getsound('tick')
self._tickFinal = ba.getsound('powerup01') self._tickFinal = bs.getsound('powerup01')
self._scoreSound = ba.getsound('score') self._scoreSound = bs.getsound('score')
self._image.opacity = 1 self._image.opacity = 1
self._textCounter.opacity = 1 self._textCounter.opacity = 1
@ -282,8 +268,8 @@ class MGgame(ba.TeamGameActivity[Player, Team]):
if self._levelStage == 1: if self._levelStage == 1:
timeStart = 6 timeStart = 6
ba.timer(timeStart, self._randomPlatform) bs.timer(timeStart, self._randomPlatform)
ba.timer(timeStart, self.startCounter) bs.timer(timeStart, self.startCounter)
def on_begin(self) -> None: def on_begin(self) -> None:
super().on_begin() super().on_begin()
@ -308,7 +294,7 @@ class MGgame(ba.TeamGameActivity[Player, Team]):
self.coldel15 = True self.coldel15 = True
self.coldel16 = True self.coldel16 = True
if self.credit_text: if self.credit_text:
t = ba.newnode('text', t = bs.newnode('text',
attrs={'text': "Made by Freaku\nOriginally for 1.4: byANG3L", # Disable 'Enable Bottom Credits' when making playlist, No need to edit this lovely... attrs={'text': "Made by Freaku\nOriginally for 1.4: byANG3L", # Disable 'Enable Bottom Credits' when making playlist, No need to edit this lovely...
'scale': 0.7, 'scale': 0.7,
'position': (0, 0), 'position': (0, 0),
@ -317,13 +303,13 @@ class MGgame(ba.TeamGameActivity[Player, Team]):
'color': (1, 1, 1), 'color': (1, 1, 1),
'h_align': 'center', 'h_align': 'center',
'v_attach': 'bottom'}) 'v_attach': 'bottom'})
self.spawnAllMap() self.spawnAllMap()
self.flashHide() self.flashHide()
# Check for immediate end (if we've only got 1 player, etc). # Check for immediate end (if we've only got 1 player, etc).
ba.timer(5, self._check_end_game) bs.timer(5, self._check_end_game)
self._dingSound = ba.getsound('dingSmall') self._dingSound = bs.getsound('dingSmall')
self._dingSoundHigh = ba.getsound('dingSmallHigh') self._dingSoundHigh = bs.getsound('dingSmallHigh')
def startCounter(self): def startCounter(self):
self._textCounter.text = '10' self._textCounter.text = '10'
@ -339,44 +325,44 @@ class MGgame(ba.TeamGameActivity[Player, Team]):
def count1(): def count1():
def countFinal(): def countFinal():
self._textCounter.text = '' self._textCounter.text = ''
ba.playsound(self._tickFinal) self._tickFinal.play()
self._stop() self._stop()
self._textCounter.text = '1' self._textCounter.text = '1'
ba.playsound(self._tickSound) self._tickSound.play()
ba.timer(1, countFinal) bs.timer(1, countFinal)
self._textCounter.text = '2' self._textCounter.text = '2'
ba.playsound(self._tickSound) self._tickSound.play()
ba.timer(1, count1) bs.timer(1, count1)
self._textCounter.text = '3' self._textCounter.text = '3'
ba.playsound(self._tickSound) self._tickSound.play()
ba.timer(1, count2) bs.timer(1, count2)
self._textCounter.text = '4' self._textCounter.text = '4'
ba.playsound(self._tickSound) self._tickSound.play()
ba.timer(1, count3) bs.timer(1, count3)
self._textCounter.text = '5' self._textCounter.text = '5'
ba.playsound(self._tickSound) self._tickSound.play()
ba.timer(1, count4) bs.timer(1, count4)
self._textCounter.text = '6' self._textCounter.text = '6'
ba.playsound(self._tickSound) self._tickSound.play()
ba.timer(1, count5) bs.timer(1, count5)
self._textCounter.text = '7' self._textCounter.text = '7'
ba.playsound(self._tickSound) self._tickSound.play()
ba.timer(1, count6) bs.timer(1, count6)
self._textCounter.text = '8' self._textCounter.text = '8'
ba.playsound(self._tickSound) self._tickSound.play()
ba.timer(1, count7) bs.timer(1, count7)
self._textCounter.text = '9' self._textCounter.text = '9'
ba.playsound(self._tickSound) self._tickSound.play()
ba.timer(1, count8) bs.timer(1, count8)
ba.timer(1, count9) bs.timer(1, count9)
def on_player_join(self, player: Player) -> None: def on_player_join(self, player: Player) -> None:
# Don't allow joining after we start # Don't allow joining after we start
# (would enable leave/rejoin tomfoolery). # (would enable leave/rejoin tomfoolery).
if self.has_begun(): if self.has_begun():
ba.screenmessage( bs.broadcastmessage(
ba.Lstr(resource='playerDelayedJoinText', babase.Lstr(resource='playerDelayedJoinText',
subs=[('${PLAYER}', player.getname(full=True))]), subs=[('${PLAYER}', player.getname(full=True))]),
color=(0, 1, 0), transient=True, clients=[player.sessionplayer.inputdevice.client_id]) color=(0, 1, 0), transient=True, clients=[player.sessionplayer.inputdevice.client_id])
# For score purposes, mark them as having died right as the # For score purposes, mark them as having died right as the
# game started. # game started.
@ -393,12 +379,12 @@ class MGgame(ba.TeamGameActivity[Player, Team]):
self._check_end_game() self._check_end_game()
# overriding the default character spawning.. # overriding the default character spawning..
def spawn_player(self, player: Player) -> ba.Actor: def spawn_player(self, player: Player) -> bs.Actor:
spaz = self.spawn_player_spaz(player) spaz = self.spawn_player_spaz(player)
pos = (self._spawnCenter[0] + random.uniform(-1.5, 2.5), pos = (self._spawnCenter[0] + random.uniform(-1.5, 2.5),
self._spawnCenter[1], self._spawnCenter[2] + random.uniform(-2.5, 1.5)) self._spawnCenter[1], self._spawnCenter[2] + random.uniform(-2.5, 1.5))
spaz.connect_controls_to_player(enable_punch=False, enable_bomb=False, enable_pickup=False) spaz.connect_controls_to_player(enable_punch=False, enable_bomb=False, enable_pickup=False)
spaz.handlemessage(ba.StandMessage(pos)) spaz.handlemessage(bs.StandMessage(pos))
return spaz return spaz
def _randomSelect(self): def _randomSelect(self):
@ -453,17 +439,17 @@ class MGgame(ba.TeamGameActivity[Player, Team]):
def circle3(): def circle3():
self._imageCircle3.color = (0.0, 1.0, 0.0) self._imageCircle3.color = (0.0, 1.0, 0.0)
self._imageCircle3.opacity = 1.0 self._imageCircle3.opacity = 1.0
ba.playsound(self._bellHigh) self._bellHigh.play()
ba.timer(0.2, self._doDelete) bs.timer(0.2, self._doDelete)
self._imageCircle2.color = (1.0, 1.0, 0.0) self._imageCircle2.color = (1.0, 1.0, 0.0)
self._imageCircle2.opacity = 1.0 self._imageCircle2.opacity = 1.0
ba.playsound(self._bellMed) self._bellMed.play()
ba.timer(1, circle3) bs.timer(1, circle3)
self._imageCircle.color = (1.0, 0.0, 0.0) self._imageCircle.color = (1.0, 0.0, 0.0)
self._imageCircle.opacity = 1.0 self._imageCircle.opacity = 1.0
ba.playsound(self._bellLow) self._bellLow.play()
ba.timer(1, circle2) bs.timer(1, circle2)
ba.timer(1, circle) bs.timer(1, circle)
def _randomPlatform(self): def _randomPlatform(self):
if self._levelStage == 1: if self._levelStage == 1:
@ -564,13 +550,13 @@ class MGgame(ba.TeamGameActivity[Player, Team]):
self._mixPlatform() self._mixPlatform()
def _mixPlatform(self): def _mixPlatform(self):
ba.timer(1, self.flashShow) bs.timer(1, self.flashShow)
ba.timer(3, self.flashHide) bs.timer(3, self.flashHide)
ba.timer(4, self.flashShow) bs.timer(4, self.flashShow)
ba.timer(6, self.flashHide) bs.timer(6, self.flashHide)
ba.timer(7, self.flashShow) bs.timer(7, self.flashShow)
ba.timer(9, self.flashHide) bs.timer(9, self.flashHide)
ba.timer(13.2, self.flashShow) bs.timer(13.2, self.flashShow)
def flashHide(self): def flashHide(self):
self.mapFGP.color_texture = self._mapFGPDefaultTex self.mapFGP.color_texture = self._mapFGPDefaultTex
@ -674,14 +660,14 @@ class MGgame(ba.TeamGameActivity[Player, Team]):
self.mapFGP16col.delete() self.mapFGP16col.delete()
self.coldel16 = True self.coldel16 = True
ba.timer(3.3, self._platformTexDefault) bs.timer(3.3, self._platformTexDefault)
def spawnAllMap(self): def spawnAllMap(self):
""" """
# Here's how it works: # Here's how it works:
# First, create prop with a gravity scale of 0 # First, create prop with a gravity scale of 0
# Then use a in-game model which will suit it (For this one I didn't chose box, since it will look kinda weird) Right? # Then use a in-game mesh which will suit it (For this one I didn't chose box, since it will look kinda weird) Right?
# Instead I used a 2d model (which is nothing but a button in menu) # Instead I used a 2d mesh (which is nothing but a button in menu)
# This prop SHOULD NOT collide with anything, since it has gravity_scale of 0 if it'll get weight it will fall down :(( # This prop SHOULD NOT collide with anything, since it has gravity_scale of 0 if it'll get weight it will fall down :((
# These are where we change those color-textures and is seen in-game # These are where we change those color-textures and is seen in-game
@ -696,130 +682,130 @@ class MGgame(ba.TeamGameActivity[Player, Team]):
""" """
shared = SharedObjects.get() shared = SharedObjects.get()
if self.coldel: if self.coldel:
self.mapFGP = ba.newnode('prop', self.mapFGP = bs.newnode('prop',
attrs={'body': 'puck', 'position': (3, 2, -9), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) attrs={'body': 'puck', 'position': (4.5, 2, -9), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]})
self.mapFGPTex = None self.mapFGPTex = None
self.mapFGPcol = ba.newnode('region', attrs={'position': (3, 2, -9), 'scale': ( self.mapFGPcol = bs.newnode('region', attrs={'position': (4.5, 2, -9), 'scale': (
3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)})
self.coldel = False self.coldel = False
if self.coldel2: if self.coldel2:
self.mapFGP2 = ba.newnode('prop', self.mapFGP2 = bs.newnode('prop',
attrs={'body': 'puck', 'position': (3, 2, -6), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) attrs={'body': 'puck', 'position': (4.5, 2, -6), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]})
self.mapFGP2Tex = None self.mapFGP2Tex = None
self.mapFGP2col = ba.newnode('region', attrs={'position': (3, 2, -6), 'scale': ( self.mapFGP2col = bs.newnode('region', attrs={'position': (4.5, 2, -6), 'scale': (
3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)})
self.coldel2 = False self.coldel2 = False
if self.coldel3: if self.coldel3:
self.mapFGP3 = ba.newnode('prop', self.mapFGP3 = bs.newnode('prop',
attrs={'body': 'puck', 'position': (3, 2, -3), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) attrs={'body': 'puck', 'position': (4.5, 2, -3), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]})
self.mapFGP3Tex = None self.mapFGP3Tex = None
self.mapFGP3col = ba.newnode('region', attrs={'position': (3, 2, -3), 'scale': ( self.mapFGP3col = bs.newnode('region', attrs={'position': (4.5, 2, -3), 'scale': (
3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)})
self.coldel3 = False self.coldel3 = False
if self.coldel4: if self.coldel4:
self.mapFGP4 = ba.newnode('prop', self.mapFGP4 = bs.newnode('prop',
attrs={'body': 'puck', 'position': (3, 2, 0), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) attrs={'body': 'puck', 'position': (4.5, 2, 0), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]})
self.mapFGP4Tex = None self.mapFGP4Tex = None
self.mapFGP4col = ba.newnode('region', attrs={'position': (3, 2, 0), 'scale': ( self.mapFGP4col = bs.newnode('region', attrs={'position': (4.5, 2, 0), 'scale': (
3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)})
self.coldel4 = False self.coldel4 = False
if self.coldel5: if self.coldel5:
self.mapFGP5 = ba.newnode('prop', self.mapFGP5 = bs.newnode('prop',
attrs={'body': 'puck', 'position': (0, 2, -9), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) attrs={'body': 'puck', 'position': (1.5, 2, -9), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]})
self.mapFGP5Tex = None self.mapFGP5Tex = None
self.mapFGP5col = ba.newnode('region', attrs={'position': (0, 2, -9), 'scale': ( self.mapFGP5col = bs.newnode('region', attrs={'position': (1.5, 2, -9), 'scale': (
3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)})
self.coldel5 = False self.coldel5 = False
if self.coldel6: if self.coldel6:
self.mapFGP6 = ba.newnode('prop', self.mapFGP6 = bs.newnode('prop',
attrs={'body': 'puck', 'position': (0, 2, -6), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) attrs={'body': 'puck', 'position': (1.5, 2, -6), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]})
self.mapFGP6Tex = None self.mapFGP6Tex = None
self.mapFGP6col = ba.newnode('region', attrs={'position': (0, 2, -6), 'scale': ( self.mapFGP6col = bs.newnode('region', attrs={'position': (1.5, 2, -6), 'scale': (
3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)})
self.coldel6 = False self.coldel6 = False
if self.coldel7: if self.coldel7:
self.mapFGP7 = ba.newnode('prop', self.mapFGP7 = bs.newnode('prop',
attrs={'body': 'puck', 'position': (0, 2, -3), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) attrs={'body': 'puck', 'position': (1.5, 2, -3), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]})
self.mapFGP7Tex = None self.mapFGP7Tex = None
self.mapFGP7col = ba.newnode('region', attrs={'position': (0, 2, -3), 'scale': ( self.mapFGP7col = bs.newnode('region', attrs={'position': (1.5, 2, -3), 'scale': (
3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)})
self.coldel7 = False self.coldel7 = False
if self.coldel8: if self.coldel8:
self.mapFGP8 = ba.newnode('prop', self.mapFGP8 = bs.newnode('prop',
attrs={'body': 'puck', 'position': (0, 2, 0), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) attrs={'body': 'puck', 'position': (1.5, 2, 0), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]})
self.mapFGP8Tex = None self.mapFGP8Tex = None
self.mapFGP8col = ba.newnode('region', attrs={'position': (0, 2, 0), 'scale': ( self.mapFGP8col = bs.newnode('region', attrs={'position': (1.5, 2, 0), 'scale': (
3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)})
self.coldel8 = False self.coldel8 = False
if self.coldel9: if self.coldel9:
self.mapFGP9 = ba.newnode('prop', self.mapFGP9 = bs.newnode('prop',
attrs={'body': 'puck', 'position': (-3, 2, -9), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) attrs={'body': 'puck', 'position': (-1.5, 2, -9), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]})
self.mapFGP9Tex = None self.mapFGP9Tex = None
self.mapFGP9col = ba.newnode('region', attrs={'position': (-3, 2, -9), 'scale': ( self.mapFGP9col = bs.newnode('region', attrs={'position': (-1.5, 2, -9), 'scale': (
3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)})
self.coldel9 = False self.coldel9 = False
if self.coldel10: if self.coldel10:
self.mapFGP10 = ba.newnode('prop', self.mapFGP10 = bs.newnode('prop',
attrs={'body': 'puck', 'position': (-3, 2, -6), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) attrs={'body': 'puck', 'position': (-1.5, 2, -6), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]})
self.mapFGP10Tex = None self.mapFGP10Tex = None
self.mapFGP10col = ba.newnode('region', attrs={'position': (-3, 2, -6), 'scale': ( self.mapFGP10col = bs.newnode('region', attrs={'position': (-1.5, 2, -6), 'scale': (
3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)})
self.coldel10 = False self.coldel10 = False
if self.coldel11: if self.coldel11:
self.mapFGP11 = ba.newnode('prop', self.mapFGP11 = bs.newnode('prop',
attrs={'body': 'puck', 'position': (-3, 2, -3), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) attrs={'body': 'puck', 'position': (-1.5, 2, -3), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]})
self.mapFGP11Tex = None self.mapFGP11Tex = None
self.mapFGP11col = ba.newnode('region', attrs={'position': (-3, 2, -3), 'scale': ( self.mapFGP11col = bs.newnode('region', attrs={'position': (-1.5, 2, -3), 'scale': (
3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)})
self.coldel11 = False self.coldel11 = False
if self.coldel12: if self.coldel12:
self.mapFGP12 = ba.newnode('prop', self.mapFGP12 = bs.newnode('prop',
attrs={'body': 'puck', 'position': (-3, 2, 0), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) attrs={'body': 'puck', 'position': (-1.5, 2, 0), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]})
self.mapFGP12Tex = None self.mapFGP12Tex = None
self.mapFGP12col = ba.newnode('region', attrs={'position': (-3, 2, 0), 'scale': ( self.mapFGP12col = bs.newnode('region', attrs={'position': (-1.5, 2, 0), 'scale': (
3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)})
self.coldel12 = False self.coldel12 = False
if self.coldel13: if self.coldel13:
self.mapFGP13 = ba.newnode('prop', self.mapFGP13 = bs.newnode('prop',
attrs={'body': 'puck', 'position': (-6, 2, -9), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) attrs={'body': 'puck', 'position': (-4.5, 2, -9), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]})
self.mapFGP13Tex = None self.mapFGP13Tex = None
self.mapFGP13col = ba.newnode('region', attrs={'position': (-6, 2, -9), 'scale': ( self.mapFGP13col = bs.newnode('region', attrs={'position': (-4.5, 2, -9), 'scale': (
3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)})
self.coldel13 = False self.coldel13 = False
if self.coldel14: if self.coldel14:
self.mapFGP14 = ba.newnode('prop', self.mapFGP14 = bs.newnode('prop',
attrs={'body': 'puck', 'position': (-6, 2, -6), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) attrs={'body': 'puck', 'position': (-4.5, 2, -6), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]})
self.mapFGP14Tex = None self.mapFGP14Tex = None
self.mapFGP14col = ba.newnode('region', attrs={'position': (-6, 2, -6), 'scale': ( self.mapFGP14col = bs.newnode('region', attrs={'position': (-4.5, 2, -6), 'scale': (
3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)})
self.coldel14 = False self.coldel14 = False
if self.coldel15: if self.coldel15:
self.mapFGP15 = ba.newnode('prop', self.mapFGP15 = bs.newnode('prop',
attrs={'body': 'puck', 'position': (-6, 2, -3), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) attrs={'body': 'puck', 'position': (-4.5, 2, -3), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]})
self.mapFGP15Tex = None self.mapFGP15Tex = None
self.mapFGP15col = ba.newnode('region', attrs={'position': (-6, 2, -3), 'scale': ( self.mapFGP15col = bs.newnode('region', attrs={'position': (-4.5, 2, -3), 'scale': (
3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)})
self.coldel15 = False self.coldel15 = False
if self.coldel16: if self.coldel16:
self.mapFGP16 = ba.newnode('prop', self.mapFGP16 = bs.newnode('prop',
attrs={'body': 'puck', 'position': (-6, 2, 0), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) attrs={'body': 'puck', 'position': (-4.5, 2, 0), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]})
self.mapFGP16Tex = None self.mapFGP16Tex = None
self.mapFGP16col = ba.newnode('region', attrs={'position': (-6, 2, 0), 'scale': ( self.mapFGP16col = bs.newnode('region', attrs={'position': (-4.5, 2, 0), 'scale': (
3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)})
self.coldel16 = False self.coldel16 = False
@ -843,27 +829,27 @@ class MGgame(ba.TeamGameActivity[Player, Team]):
timeStart = 6 timeStart = 6
else: else:
timeStart = 2 timeStart = 2
ba.playsound(self._scoreSound) self._scoreSound.play()
activity = _ba.get_foreground_host_activity() activity = bs.get_foreground_host_activity()
for i in activity.players: for i in activity.players:
try: try:
i.actor.node.handlemessage(ba.CelebrateMessage(2.0)) i.actor.node.handlemessage(bs.CelebrateMessage(2.0))
except: except:
pass pass
ba.timer(timeStart, self._randomPlatform) bs.timer(timeStart, self._randomPlatform)
ba.timer(timeStart, self.startCounter) bs.timer(timeStart, self.startCounter)
self.spawnAllMap() self.spawnAllMap()
self.flashHide() self.flashHide()
# Various high-level game events come through this method. # Various high-level game events come through this method.
def handlemessage(self, msg: Any) -> Any: def handlemessage(self, msg: Any) -> Any:
if isinstance(msg, ba.PlayerDiedMessage): if isinstance(msg, bs.PlayerDiedMessage):
# Augment standard behavior. # Augment standard behavior.
super().handlemessage(msg) super().handlemessage(msg)
curtime = ba.time() curtime = bs.time()
# Record the player's moment of death. # Record the player's moment of death.
# assert isinstance(msg.spaz.player # assert isinstance(msg.spaz.player
@ -873,15 +859,15 @@ class MGgame(ba.TeamGameActivity[Player, Team]):
# (more accurate looking). # (more accurate looking).
# In teams/ffa, allow a one-second fudge-factor so we can # In teams/ffa, allow a one-second fudge-factor so we can
# get more draws if players die basically at the same time. # get more draws if players die basically at the same time.
if isinstance(self.session, ba.CoopSession): if isinstance(self.session, bs.CoopSession):
# Teams will still show up if we check now.. check in # Teams will still show up if we check now.. check in
# the next cycle. # the next cycle.
ba.pushcall(self._check_end_game) babase.pushcall(self._check_end_game)
# Also record this for a final setting of the clock. # Also record this for a final setting of the clock.
self._last_player_death_time = curtime self._last_player_death_time = curtime
else: else:
ba.timer(1.0, self._check_end_game) bs.timer(1.0, self._check_end_game)
else: else:
# Default handler: # Default handler:
return super().handlemessage(msg) return super().handlemessage(msg)
@ -897,7 +883,7 @@ class MGgame(ba.TeamGameActivity[Player, Team]):
# In co-op, we go till everyone is dead.. otherwise we go # In co-op, we go till everyone is dead.. otherwise we go
# until one team remains. # until one team remains.
if isinstance(self.session, ba.CoopSession): if isinstance(self.session, bs.CoopSession):
if living_team_count <= 0: if living_team_count <= 0:
self.end_game() self.end_game()
else: else:
@ -905,7 +891,7 @@ class MGgame(ba.TeamGameActivity[Player, Team]):
self.end_game() self.end_game()
def end_game(self) -> None: def end_game(self) -> None:
cur_time = ba.time() cur_time = bs.time()
assert self._timer is not None assert self._timer is not None
start_time = self._timer.getstarttime() start_time = self._timer.getstarttime()
@ -936,7 +922,7 @@ class MGgame(ba.TeamGameActivity[Player, Team]):
# Ok now calc game results: set a score for each team and then tell # Ok now calc game results: set a score for each team and then tell
# the game to end. # the game to end.
results = ba.GameResults() results = bs.GameResults()
# Remember that 'free-for-all' mode is simply a special form # Remember that 'free-for-all' mode is simply a special form
# of 'teams' mode where each player gets their own team, so we can # of 'teams' mode where each player gets their own team, so we can
@ -965,7 +951,7 @@ class MGdefs():
(0.0, 0.0, 0.0) + (29.23565494, 14.19991443, 29.92689344) (0.0, 0.0, 0.0) + (29.23565494, 14.19991443, 29.92689344)
class MGmap(ba.Map): class MGmap(bs.Map):
defs = MGdefs() defs = MGdefs()
name = 'Sky Tiles' name = 'Sky Tiles'
@ -981,23 +967,23 @@ class MGmap(ba.Map):
@classmethod @classmethod
def on_preload(cls) -> Any: def on_preload(cls) -> Any:
data: Dict[str, Any] = { data: Dict[str, Any] = {
'bgtex': ba.gettexture('menuBG'), 'bgtex': bs.gettexture('menuBG'),
'bgmodel': ba.getmodel('thePadBG') 'bgmesh': bs.getmesh('thePadBG')
} }
return data return data
def __init__(self) -> None: def __init__(self) -> None:
super().__init__() super().__init__()
shared = SharedObjects.get() shared = SharedObjects.get()
self.node = ba.newnode( self.node = bs.newnode(
'terrain', 'terrain',
attrs={ attrs={
'model': self.preloaddata['bgmodel'], 'mesh': self.preloaddata['bgmesh'],
'lighting': False, 'lighting': False,
'background': True, 'background': True,
'color_texture': self.preloaddata['bgtex'] 'color_texture': self.preloaddata['bgtex']
}) })
gnode = ba.getactivity().globalsnode gnode = bs.getactivity().globalsnode
gnode.tint = (1.3, 1.2, 1.0) gnode.tint = (1.3, 1.2, 1.0)
gnode.ambient_color = (1.3, 1.2, 1.0) gnode.ambient_color = (1.3, 1.2, 1.0)
gnode.vignette_outer = (0.57, 0.57, 0.57) gnode.vignette_outer = (0.57, 0.57, 0.57)
@ -1006,12 +992,12 @@ class MGmap(ba.Map):
gnode.vr_near_clip = 0.5 gnode.vr_near_clip = 0.5
ba._map.register_map(MGmap) bs._map.register_map(MGmap)
# ba_meta export plugin # ba_meta export plugin
class byFreaku(ba.Plugin): class byFreaku(babase.Plugin):
def __init__(self): def __init__(self):
## Campaign support ## ## Campaign support ##
ba.app.add_coop_practice_level(ba.Level(name='Memory Game', displayname='${GAME}', gametype=MGgame, settings={ babase.app.classic.add_coop_practice_level(bs.Level(
}, preview_texture_name='achievementOffYouGo')) name='Memory Game', displayname='${GAME}', gametype=MGgame, settings={}, preview_texture_name='achievementOffYouGo'))

View file

@ -1,5 +1,5 @@
# Made by MattZ45986 on GitHub # Made by MattZ45986 on GitHub
# Ported by: Freaku / @[Just] Freak#4999 # Ported by your friend: Freaku
# Bug Fixes & Improvements as well... # Bug Fixes & Improvements as well...
@ -10,76 +10,69 @@
from __future__ import annotations from __future__ import annotations
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
import _ba import _babase
import ba
import random import random
import math import math
from bastd.actor.flag import Flag, FlagPickedUpMessage import bascenev1 as bs
from bastd.actor.playerspaz import PlayerSpaz from bascenev1lib.actor.flag import Flag, FlagPickedUpMessage
from bascenev1lib.actor.playerspaz import PlayerSpaz
if TYPE_CHECKING: if TYPE_CHECKING:
from typing import Any, Type, List, Dict, Tuple, Union, Sequence, Optional from typing import Any, Type, List, Dict, Tuple, Union, Sequence, Optional
class Player(ba.Player['Team']): class Player(bs.Player['Team']):
def __init__(self) -> None: def __init__(self) -> None:
self.done: bool = False self.done: bool = False
self.survived: bool = True self.survived: bool = True
class Team(ba.Team[Player]): class Team(bs.Team[Player]):
def __init__(self) -> None: def __init__(self) -> None:
self.score = 0 self.score = 0
# ba_meta require api 7 # ba_meta require api 8
# ba_meta export game # ba_meta export bascenev1.GameActivity
class MFGame(ba.TeamGameActivity[Player, Team]): class MFGame(bs.TeamGameActivity[Player, Team]):
name = 'Musical Flags' name = 'Musical Flags'
description = "Don't be the one stuck without a flag!" description = "Don't be the one stuck without a flag!"
@classmethod @classmethod
def get_available_settings( def get_available_settings(
cls, sessiontype: Type[ba.Session]) -> List[ba.Setting]: cls, sessiontype: Type[bs.Session]) -> List[babase.Setting]:
settings = [ settings = [
ba.IntChoiceSetting( bs.IntSetting(
'Time Limit', 'Max Round Time',
choices=[ min_value=15,
('None', 0), default=25,
('1 Minute', 60), increment=5,
('2 Minutes', 120),
('5 Minutes', 300),
('10 Minutes', 600),
('20 Minutes', 1200),
],
default=0,
), ),
ba.BoolSetting('Epic Mode', default=False), bs.BoolSetting('Epic Mode', default=False),
ba.BoolSetting('Enable Running', default=True), bs.BoolSetting('Enable Running', default=True),
ba.BoolSetting('Enable Punching', default=False), bs.BoolSetting('Enable Punching', default=False),
ba.BoolSetting('Enable Bottom Credit', True) bs.BoolSetting('Enable Bottom Credit', True)
] ]
return settings return settings
@classmethod @classmethod
def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool: def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool:
return (issubclass(sessiontype, ba.DualTeamSession) return (issubclass(sessiontype, bs.DualTeamSession)
or issubclass(sessiontype, ba.FreeForAllSession)) or issubclass(sessiontype, bs.FreeForAllSession))
@classmethod @classmethod
def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]:
return ['Doom Shroom'] return ['Doom Shroom']
def __init__(self, settings: dict): def __init__(self, settings: dict):
super().__init__(settings) super().__init__(settings)
self.nodes = [] self.nodes = []
self._dingsound = ba.getsound('dingSmall') self._dingsound = bs.getsound('dingSmall')
self._epic_mode = bool(settings['Epic Mode']) self._epic_mode = bool(settings['Epic Mode'])
self.credit_text = bool(settings['Enable Bottom Credit']) self.credit_text = bool(settings['Enable Bottom Credit'])
self._time_limit = float(settings['Time Limit'])
self.is_punch = bool(settings['Enable Punching']) self.is_punch = bool(settings['Enable Punching'])
self.is_run = bool(settings['Enable Running']) self.is_run = bool(settings['Enable Running'])
self._textRound = ba.newnode('text', self._textRound = bs.newnode('text',
attrs={'text': '', attrs={'text': '',
'position': (0, -38), 'position': (0, -38),
'scale': 1, 'scale': 1,
@ -91,10 +84,16 @@ class MFGame(ba.TeamGameActivity[Player, Team]):
'h_attach': 'center', 'h_attach': 'center',
'h_align': 'center', 'h_align': 'center',
'v_align': 'center'}) 'v_align': 'center'})
self.round_time = int(settings['Max Round Time'])
self.reset_round_time = int(settings['Max Round Time'])
self.should_die_occur = True
self.round_time_textnode = bs.newnode('text',
attrs={
'text': "", 'flatness': 1.0, 'h_align': 'center', 'h_attach': 'center', 'v_attach': 'top', 'v_align': 'center', 'position': (0, -15), 'scale': 0.9, 'color': (1, 0.7, 0.9)})
self.slow_motion = self._epic_mode self.slow_motion = self._epic_mode
# A cool music, matching our gamemode theme # A cool music, matching our gamemode theme
self.default_music = ba.MusicType.FLAG_CATCHER self.default_music = bs.MusicType.FLAG_CATCHER
def get_instance_description(self) -> Union[str, Sequence]: def get_instance_description(self) -> Union[str, Sequence]:
return 'Catch Flag for yourself' return 'Catch Flag for yourself'
@ -104,8 +103,8 @@ class MFGame(ba.TeamGameActivity[Player, Team]):
def on_player_join(self, player: Player) -> None: def on_player_join(self, player: Player) -> None:
if self.has_begun(): if self.has_begun():
ba.screenmessage( bs.broadcastmessage(
ba.Lstr(resource='playerDelayedJoinText', bs.Lstr(resource='playerDelayedJoinText',
subs=[('${PLAYER}', player.getname(full=True))]), subs=[('${PLAYER}', player.getname(full=True))]),
color=(0, 1, 0), transient=True) color=(0, 1, 0), transient=True)
player.survived = False player.survived = False
@ -115,7 +114,7 @@ class MFGame(ba.TeamGameActivity[Player, Team]):
def on_player_leave(self, player: Player) -> None: def on_player_leave(self, player: Player) -> None:
super().on_player_leave(player) super().on_player_leave(player)
# A departing player may trigger game-over. # A departing player may trigger game-over.
self.checkEnd() bs.timer(0, self.checkEnd)
def on_begin(self) -> None: def on_begin(self) -> None:
super().on_begin() super().on_begin()
@ -124,9 +123,8 @@ class MFGame(ba.TeamGameActivity[Player, Team]):
self.nodes = [] self.nodes = []
self.flags = [] self.flags = []
self.spawned = [] self.spawned = []
self.setup_standard_time_limit(self._time_limit)
if self.credit_text: if self.credit_text:
t = ba.newnode('text', t = bs.newnode('text',
attrs={'text': "Ported by Freaku\nMade by MattZ45986", # Disable 'Enable Bottom Credits' when making playlist, No need to edit this lovely... attrs={'text': "Ported by Freaku\nMade by MattZ45986", # Disable 'Enable Bottom Credits' when making playlist, No need to edit this lovely...
'scale': 0.7, 'scale': 0.7,
'position': (0, 0), 'position': (0, 0),
@ -137,7 +135,32 @@ class MFGame(ba.TeamGameActivity[Player, Team]):
'v_attach': 'bottom'}) 'v_attach': 'bottom'})
self.makeRound() self.makeRound()
self._textRound.text = 'Round ' + str(self.roundNum) self._textRound.text = 'Round ' + str(self.roundNum)
ba.timer(5, self.checkEnd) bs.timer(3, self.checkEnd)
self.keepcalling = bs.timer(1, self._timeround, True)
def _timeround(self):
if self.round_time == 0 and self.should_die_occur:
self.should_die_occur = False
self.round_time_textnode.opacity = 0
bs.broadcastmessage('Proceeding Round...')
for player in self.spawned:
if not player.done:
try:
player.survived = False
player.actor.handlemessage(bs.StandMessage((0, 3, -2)))
bs.timer(0.5, bs.Call(player.actor.handlemessage, bs.FreezeMessage()))
bs.timer(1.5, bs.Call(player.actor.handlemessage, bs.FreezeMessage()))
bs.timer(2.5, bs.Call(player.actor.handlemessage, bs.FreezeMessage()))
bs.timer(3, bs.Call(player.actor.handlemessage, bs.ShouldShatterMessage()))
except:
pass
bs.timer(3.5, self.killRound)
bs.timer(3.55, self.makeRound)
self.round_time_textnode.opacity = 0
self.round_time = self.reset_round_time
else:
self.round_time_textnode.text = "Time: " + str(self.round_time)
self.round_time -= 1
def makeRound(self): def makeRound(self):
for player in self.players: for player in self.players:
@ -147,6 +170,9 @@ class MFGame(ba.TeamGameActivity[Player, Team]):
self._textRound.text = 'Round ' + str(self.roundNum) self._textRound.text = 'Round ' + str(self.roundNum)
self.flags = [] self.flags = []
self.spawned = [] self.spawned = []
self.should_die_occur = True
self.round_time = self.reset_round_time
self.round_time_textnode.opacity = 1
angle = random.randint(0, 359) angle = random.randint(0, 359)
c = 0 c = 0
for player in self.players: for player in self.players:
@ -165,6 +191,13 @@ class MFGame(ba.TeamGameActivity[Player, Team]):
self.checkEnd() self.checkEnd()
colors = [(1, 0, 0), (0, 1, 0), (0, 0, 1), (1, 1, 0), (1, 0, 1), (0, 1, 1), (0, 0, 0), colors = [(1, 0, 0), (0, 1, 0), (0, 0, 1), (1, 1, 0), (1, 0, 1), (0, 1, 1), (0, 0, 0),
(0.5, 0.8, 0), (0, 0.8, 0.5), (0.8, 0.25, 0.7), (0, 0.27, 0.55), (2, 2, 0.6), (0.4, 3, 0.85)] (0.5, 0.8, 0), (0, 0.8, 0.5), (0.8, 0.25, 0.7), (0, 0.27, 0.55), (2, 2, 0.6), (0.4, 3, 0.85)]
# Add support for more than 13 players
if c > 12:
for i in range(c-12):
colors.append((random.uniform(0.1, 1), random.uniform(
0.1, 1), random.uniform(0.1, 1)))
# Smart Mathematics: # Smart Mathematics:
# All Flags spawn same distance from the players # All Flags spawn same distance from the players
for i in range(c-1): for i in range(c-1):
@ -179,19 +212,19 @@ class MFGame(ba.TeamGameActivity[Player, Team]):
self.numPickedUp = 0 self.numPickedUp = 0
for player in self.players: for player in self.players:
if player.is_alive(): if player.is_alive():
player.actor.handlemessage(ba.DieMessage()) player.actor.handlemessage(bs.DieMessage())
for flag in self.flags: for flag in self.flags:
flag.node.delete() flag.node.delete()
for light in self.nodes: for light in self.nodes:
light.delete() light.delete()
def spawn_player(self, player: Player, pos: tuple = (0, 0, 0)) -> ba.Actor: def spawn_player(self, player: Player, pos: tuple = (0, 0, 0)) -> bs.Actor:
spaz = self.spawn_player_spaz(player) spaz = self.spawn_player_spaz(player)
if pos == (0, 0, 0): if pos == (0, 0, 0):
pos = (-.5+random.random()*2, 3+random.random()*2, -5+random.random()*2) pos = (-.5+random.random()*2, 3+random.random()*2, -5+random.random()*2)
spaz.connect_controls_to_player(enable_punch=self.is_punch, spaz.connect_controls_to_player(enable_punch=self.is_punch,
enable_bomb=False, enable_run=self.is_run) enable_bomb=False, enable_run=self.is_run)
spaz.handlemessage(ba.StandMessage(pos)) spaz.handlemessage(bs.StandMessage(pos))
return spaz return spaz
def check_respawn(self, player): def check_respawn(self, player):
@ -200,36 +233,38 @@ class MFGame(ba.TeamGameActivity[Player, Team]):
def handlemessage(self, msg: Any) -> Any: def handlemessage(self, msg: Any) -> Any:
if isinstance(msg, ba.PlayerDiedMessage): if isinstance(msg, bs.PlayerDiedMessage):
super().handlemessage(msg) super().handlemessage(msg)
player = msg.getplayer(Player) player = msg.getplayer(Player)
ba.timer(0.1, ba.Call(self.check_respawn, player)) bs.timer(0.1, bs.Call(self.check_respawn, player))
ba.timer(0.5, self.checkEnd) bs.timer(0.5, self.checkEnd)
elif isinstance(msg, FlagPickedUpMessage): elif isinstance(msg, FlagPickedUpMessage):
self.numPickedUp += 1 self.numPickedUp += 1
msg.node.getdelegate(PlayerSpaz, True).getplayer(Player, True).done = True msg.node.getdelegate(PlayerSpaz, True).getplayer(Player, True).done = True
l = ba.newnode('light', l = bs.newnode('light',
owner=None, owner=None,
attrs={'color': msg.node.color, attrs={'color': msg.node.color,
'position': (msg.node.position_center), 'position': (msg.node.position_center),
'intensity': 1}) 'intensity': 1})
self.nodes.append(l) self.nodes.append(l)
msg.flag.handlemessage(ba.DieMessage()) msg.flag.handlemessage(bs.DieMessage())
msg.node.handlemessage(ba.DieMessage()) msg.node.handlemessage(bs.DieMessage())
msg.node.delete() msg.node.delete()
if self.numPickedUp == len(self.flags): if self.numPickedUp == len(self.flags):
self.round_time_textnode.opacity = 0
self.round_time = self.reset_round_time
for player in self.spawned: for player in self.spawned:
if not player.done: if not player.done:
try: try:
player.survived = False player.survived = False
ba.screenmessage("No Flag? "+player.getname()) bs.broadcastmessage("No Flag? "+player.getname())
player.actor.handlemessage(ba.StandMessage((0, 3, -2))) player.actor.handlemessage(bs.StandMessage((0, 3, -2)))
ba.timer(0.5, ba.Call(player.actor.handlemessage, ba.FreezeMessage())) bs.timer(0.5, bs.Call(player.actor.handlemessage, bs.FreezeMessage()))
ba.timer(3, ba.Call(player.actor.handlemessage, ba.ShouldShatterMessage())) bs.timer(3, bs.Call(player.actor.handlemessage, bs.ShouldShatterMessage()))
except: except:
pass pass
ba.timer(3.5, self.killRound) bs.timer(3.5, self.killRound)
ba.timer(3.55, self.makeRound) bs.timer(3.55, self.makeRound)
else: else:
return super().handlemessage(msg) return super().handlemessage(msg)
return None return None
@ -243,10 +278,10 @@ class MFGame(ba.TeamGameActivity[Player, Team]):
for player in self.players: for player in self.players:
if player.survived: if player.survived:
player.team.score += 10 player.team.score += 10
ba.timer(2.5, self.end_game) bs.timer(2.5, self.end_game)
def end_game(self) -> None: def end_game(self) -> None:
results = ba.GameResults() results = bs.GameResults()
for team in self.teams: for team in self.teams:
results.set_team_score(team, team.score) results.set_team_score(team, team.score)
self.end(results=results) self.end(results=results)

View file

@ -0,0 +1,624 @@
# Created By Idk
# Ported to 1.7 by Yan
# ba_meta require api 8
from __future__ import annotations
from typing import TYPE_CHECKING
from bascenev1lib.actor.powerupbox import PowerupBox as Powerup
from bascenev1lib.actor.playerspaz import PlayerSpaz
from bascenev1lib.actor.scoreboard import Scoreboard
from bascenev1lib.gameutils import SharedObjects
import bascenev1lib.actor.bomb
import bascenev1lib.actor.spaz
import weakref
import random
import math
import babase
import bauiv1 as bui
import bascenev1 as bs
if TYPE_CHECKING:
pass
class TouchedToSpaz(object):
pass
class TouchedToAnything(object):
pass
class TouchedToFootingMaterial(object):
pass
class QuakeBallFactory(object):
"""Components used by QuakeBall stuff
category: Game Classes
"""
_STORENAME = babase.storagename()
@classmethod
def get(cls) -> QuakeBallFactory:
"""Get/create a shared bascenev1lib.actor.bomb.BombFactory object."""
activity = bs.getactivity()
factory = activity.customdata.get(cls._STORENAME)
if factory is None:
factory = QuakeBallFactory()
activity.customdata[cls._STORENAME] = factory
assert isinstance(factory, QuakeBallFactory)
return factory
def __init__(self):
shared = SharedObjects.get()
self.ball_material = bs.Material()
self.ball_material.add_actions(
conditions=((('we_are_younger_than', 5), 'or', ('they_are_younger_than', 50)),
'and', ('they_have_material', shared.object_material)),
actions=(('modify_node_collision', 'collide', False)))
self.ball_material.add_actions(
conditions=('they_have_material', shared.pickup_material),
actions=(('modify_part_collision', 'use_node_collide', False)))
self.ball_material.add_actions(
actions=('modify_part_collision', 'friction', 0))
self.ball_material.add_actions(
conditions=('they_have_material', shared.player_material),
actions=(('modify_part_collision', 'physical', False),
('message', 'our_node', 'at_connect', TouchedToSpaz())))
self.ball_material.add_actions(
conditions=(('they_dont_have_material', shared.player_material), 'and',
('they_have_material', shared.object_material)),
actions=('message', 'our_node', 'at_connect', TouchedToAnything()))
self.ball_material.add_actions(
conditions=(('they_dont_have_material', shared.player_material), 'and',
('they_have_material', shared.footing_material)),
actions=('message', 'our_node', 'at_connect', TouchedToFootingMaterial()))
def give(self, spaz):
spaz.punch_callback = self.shot
self.last_shot = int(bs.time() * 1000)
def shot(self, spaz):
time = int(bs.time() * 1000)
if time - self.last_shot > 0.6:
self.last_shot = time
p1 = spaz.node.position_center
p2 = spaz.node.position_forward
direction = [p1[0]-p2[0], p2[1]-p1[1], p1[2]-p2[2]]
direction[1] = 0.0
mag = 10.0/babase.Vec3(*direction).length()
vel = [v * mag for v in direction]
QuakeBall(
position=spaz.node.position,
velocity=(vel[0]*2, vel[1]*2, vel[2]*2),
owner=spaz._player,
source_player=spaz._player,
color=spaz.node.color).autoretain()
class QuakeBall(bs.Actor):
def __init__(self,
position=(0, 5, 0),
velocity=(0, 2, 0),
source_player=None,
owner=None,
color=(random.random(), random.random(), random.random()),
light_radius=0
):
super().__init__()
shared = SharedObjects.get()
b_shared = QuakeBallFactory.get()
self.source_player = source_player
self.owner = owner
self.node = bs.newnode('prop', delegate=self, attrs={
'position': position,
'velocity': velocity,
'mesh': bs.getmesh('impactBomb'),
'body': 'sphere',
'color_texture': bs.gettexture('bunnyColor'),
'mesh_scale': 0.2,
'is_area_of_interest': True,
'body_scale': 0.8,
'materials': [shared.object_material,
b_shared.ball_material]})
self.light_node = bs.newnode('light', attrs={
'position': position,
'color': color,
'radius': 0.1+light_radius,
'volume_intensity_scale': 15.0})
self.node.connectattr('position', self.light_node, 'position')
self.emit_time = bs.Timer(0.015, bs.WeakCall(self.emit), repeat=True)
self.life_time = bs.Timer(5.0, bs.WeakCall(self.handlemessage, bs.DieMessage()))
def emit(self):
bs.emitfx(
position=self.node.position,
velocity=self.node.velocity,
count=10,
scale=0.4,
spread=0.01,
chunk_type='spark')
def handlemessage(self, m):
if isinstance(m, TouchedToAnything):
node = bs.getcollision().opposingnode
if node is not None and node.exists():
v = self.node.velocity
t = self.node.position
hitdir = self.node.velocity
m = self.node
node.handlemessage(
bs.HitMessage(
pos=t,
velocity=v,
magnitude=babase.Vec3(*v).length()*40,
velocity_magnitude=babase.Vec3(*v).length()*40,
radius=0,
srcnode=self.node,
source_player=self.source_player,
force_direction=hitdir))
self.node.handlemessage(bs.DieMessage())
elif isinstance(m, bs.DieMessage):
if self.node.exists():
velocity = self.node.velocity
explosion = bs.newnode('explosion', attrs={
'position': self.node.position,
'velocity': (velocity[0], max(-1.0, velocity[1]), velocity[2]),
'radius': 1,
'big': False})
bs.getsound(random.choice(['impactHard', 'impactHard2', 'impactHard3'])).play(),
position = self.node.position
self.emit_time = None
self.light_node.delete()
self.node.delete()
elif isinstance(m, bs.OutOfBoundsMessage):
self.handlemessage(bs.DieMessage())
elif isinstance(m, bs.HitMessage):
self.node.handlemessage('impulse', m.pos[0], m.pos[1], m.pos[2],
m.velocity[0], m.velocity[1], m.velocity[2],
1.0*m.magnitude, 1.0*m.velocity_magnitude, m.radius, 0,
m.force_direction[0], m.force_direction[1], m.force_direction[2])
elif isinstance(m, TouchedToSpaz):
node = bs.getcollision() .opposingnode
if node is not None and node.exists() and node != self.owner \
and node.getdelegate(object)._player.team != self.owner.team:
node.handlemessage(bs.FreezeMessage())
v = self.node.velocity
t = self.node.position
hitdir = self.node.velocity
node.handlemessage(
bs.HitMessage(
pos=t,
velocity=(10, 10, 10),
magnitude=50,
velocity_magnitude=50,
radius=0,
srcnode=self.node,
source_player=self.source_player,
force_direction=hitdir))
self.node.handlemessage(bs.DieMessage())
elif isinstance(m, TouchedToFootingMaterial):
bs.getsound('blip').play(),
position = self.node.position
else:
super().handlemessage(m)
class Player(bs.Player['Team']):
...
class Team(bs.Team[Player]):
"""Our team type for this game."""
def __init__(self) -> None:
self.score = 0
# ba_meta export bascenev1.GameActivity
class QuakeGame(bs.TeamGameActivity[Player, Team]):
"""A game type based on acquiring kills."""
name = 'Quake'
description = 'Kill a set number of enemies to win.'
# Print messages when players die since it matters here.
announce_player_deaths = True
@classmethod
def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool:
return issubclass(sessiontype, bs.DualTeamSession) or issubclass(
sessiontype, bs.FreeForAllSession
)
@classmethod
def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]:
return ['Doom Shroom', 'Monkey Face', 'Football Stadium']
@classmethod
def get_available_settings(
cls, sessiontype: type[bs.Session]
) -> list[babase.Setting]:
settings = [
bs.IntSetting(
'Kills to Win Per Player',
min_value=1,
default=5,
increment=1,
),
bs.IntChoiceSetting(
'Time Limit',
choices=[
('None', 0),
('1 Minute', 60),
('2 Minutes', 120),
('5 Minutes', 300),
('10 Minutes', 600),
('20 Minutes', 1200),
],
default=0,
),
bs.FloatChoiceSetting(
'Respawn Times',
choices=[
('Shorter', 0.25),
('Short', 0.5),
('Normal', 1.0),
('Long', 2.0),
('Longer', 4.0),
],
default=1.0,
),
bs.IntChoiceSetting(
'Graphics',
choices=[
('Normal', 1),
('High', 2)
],
default=1),
bs.BoolSetting('Fast Movespeed', default=True),
bs.BoolSetting('Enable Jump', default=False),
bs.BoolSetting('Enable Pickup', default=False),
bs.BoolSetting('Enable Bomb', default=False),
bs.BoolSetting('Obstacles', default=False),
bs.IntChoiceSetting(
'Obstacles Shape',
choices=[
('Cube', 1),
('Sphere', 2),
('Puck', 3),
('Egg', 4),
('Random', 5),
],
default=1),
bs.BoolSetting('Obstacles Bounces Shots', default=False),
bs.IntSetting(
'Obstacle Count',
min_value=1,
default=16,
increment=1,
),
bs.BoolSetting('Random Obstacle Color', default=True),
bs.BoolSetting('Epic Mode', default=False),
]
return settings
def __init__(self, settings: dict):
super().__init__(settings)
self._scoreboard = Scoreboard()
self._score_to_win: int | None = None
self._dingsound = bs.getsound('dingSmall')
self._epic_mode = bool(settings['Epic Mode'])
self._kills_to_win_per_player = int(settings['Kills to Win Per Player'])
self._time_limit = float(settings['Time Limit'])
self._allow_negative_scores = bool(
settings.get('Allow Negative Scores', False)
)
# Base class overrides.
self.slow_motion = self._epic_mode
self.default_music = (
bs.MusicType.EPIC if self._epic_mode else bs.MusicType.TO_THE_DEATH
)
self.settings = settings
def get_instance_description(self) -> str | Sequence:
return 'Crush ${ARG1} of your enemies.', self._score_to_win
def get_instance_description_short(self) -> str | Sequence:
return 'kill ${ARG1} enemies', self._score_to_win
def on_team_join(self, team: Team) -> None:
if self.has_begun():
self._update_scoreboard()
def on_begin(self) -> None:
super().on_begin()
self.dingsound = bs.getsound('dingSmall')
self.setup_standard_time_limit(self._time_limit)
self.drop_shield()
self.drop_shield_timer = bs.Timer(8.001, bs.WeakCall(self.drop_shield), repeat=True)
shared = SharedObjects.get()
if self.settings['Obstacles']:
count = self.settings['Obstacle Count']
map = bs.getactivity()._map.getname()
for i in range(count):
if map == 'Football Stadium':
radius = (random.uniform(-10, 1),
6,
random.uniform(-4.5, 4.5)) \
if i > count/2 else (random.uniform(10, 1), 6, random.uniform(-4.5, 4.5))
else:
radius = (random.uniform(-10, 1),
6,
random.uniform(-8, 8)) \
if i > count/2 else (random.uniform(10, 1), 6, random.uniform(-8, 8))
Obstacle(
position=radius,
graphics=self.settings['Graphics'],
random_color=self.settings['Random Obstacle Color'],
rebound=self.settings['Obstacles Bounces Shots'],
shape=int(self.settings['Obstacles Shape'])).autoretain()
if self.settings['Graphics'] == 2:
bs.getactivity().globalsnode.tint = (bs.getactivity(
).globalsnode.tint[0]-0.6, bs.getactivity().globalsnode.tint[1]-0.6, bs.getactivity().globalsnode.tint[2]-0.6)
light = bs.newnode('light', attrs={
'position': (9, 10, 0) if map == 'Football Stadium' else (6, 7, -2)
if not map == 'Rampage' else (6, 11, -2) if not map == 'The Pad' else (6, 8.5, -2),
'color': (0.4, 0.4, 0.45),
'radius': 1,
'intensity': 6,
'volume_intensity_scale': 10.0})
light2 = bs.newnode('light', attrs={
'position': (-9, 10, 0) if map == 'Football Stadium' else (-6, 7, -2)
if not map == 'Rampage' else (-6, 11, -2) if not map == 'The Pad' else (-6, 8.5, -2),
'color': (0.4, 0.4, 0.45),
'radius': 1,
'intensity': 6,
'volume_intensity_scale': 10.0})
if len(self.teams) > 0:
self._score_to_win = self.settings['Kills to Win Per Player'] * \
max(1, max(len(t.players) for t in self.teams))
else:
self._score_to_win = self.settings['Kills to Win Per Player']
self._update_scoreboard()
def drop_shield(self):
p = Powerup(
poweruptype='shield',
position=(random.uniform(-10, 10), 6, random.uniform(-5, 5))).autoretain()
bs.getsound('dingSmall').play()
p_light = bs.newnode('light', attrs={
'position': (0, 0, 0),
'color': (0.3, 0.0, 0.4),
'radius': 0.3,
'intensity': 2,
'volume_intensity_scale': 10.0})
p.node.connectattr('position', p_light, 'position')
bs.animate(p_light, 'intensity', {0: 2, 8000: 0})
def check_exists():
if p is None or p.node.exists() == False:
delete_light()
del_checker()
self._checker = bs.Timer(0.1, babase.Call(check_exists), repeat=True)
def del_checker():
if self._checker is not None:
self._checker = None
def delete_light():
if p_light.exists():
p_light.delete()
bs.timer(6.9, babase.Call(del_checker))
bs.timer(7.0, babase.Call(delete_light))
def spawn_player(self, player: bs.Player):
spaz = self.spawn_player_spaz(player)
QuakeBallFactory().give(spaz)
spaz.connect_controls_to_player(
enable_jump=self.settings['Enable Jump'],
enable_punch=True,
enable_pickup=self.settings['Enable Pickup'],
enable_bomb=self.settings['Enable Bomb'],
enable_run=True,
enable_fly=False)
if self.settings['Fast Movespeed']:
spaz.node.hockey = True
spaz.spaz_light = bs.newnode('light', attrs={
'position': (0, 0, 0),
'color': spaz.node.color,
'radius': 0.12,
'intensity': 1,
'volume_intensity_scale': 10.0})
spaz.node.connectattr('position', spaz.spaz_light, 'position')
def handlemessage(self, msg: Any) -> Any:
if isinstance(msg, bs.PlayerDiedMessage):
# Augment standard behavior.
super().handlemessage(msg)
player = msg.getplayer(Player)
self.respawn_player(player)
killer = msg.getkillerplayer(Player)
if hasattr(player.actor, 'spaz_light'):
player.actor.spaz_light.delete()
if killer is None:
return None
# Handle team-kills.
if killer.team is player.team:
# In free-for-all, killing yourself loses you a point.
if isinstance(self.session, bs.FreeForAllSession):
new_score = player.team.score - 1
if not self._allow_negative_scores:
new_score = max(0, new_score)
player.team.score = new_score
# In teams-mode it gives a point to the other team.
else:
self._dingsound.play()
for team in self.teams:
if team is not killer.team:
team.score += 1
# Killing someone on another team nets a kill.
else:
killer.team.score += 1
self._dingsound.play()
# In FFA show scores since its hard to find on the scoreboard.
if isinstance(killer.actor, PlayerSpaz) and killer.actor:
killer.actor.set_score_text(
str(killer.team.score) + '/' + str(self._score_to_win),
color=killer.team.color,
flash=True,
)
self._update_scoreboard()
# If someone has won, set a timer to end shortly.
# (allows the dust to clear and draws to occur if deaths are
# close enough)
assert self._score_to_win is not None
if any(team.score >= self._score_to_win for team in self.teams):
bs.timer(0.5, self.end_game)
else:
return super().handlemessage(msg)
return None
def _update_scoreboard(self) -> None:
for team in self.teams:
self._scoreboard.set_team_value(
team, team.score, self._score_to_win
)
def end_game(self) -> None:
results = bs.GameResults()
for team in self.teams:
results.set_team_score(team, team.score)
self.end(results=results)
class Obstacle(bs.Actor):
def __init__(self,
position: tuple(float, float, float),
graphics: bool,
random_color: bool,
rebound: bool,
shape: int) -> None:
super().__init__()
shared = SharedObjects.get()
if shape == 1:
mesh = 'tnt'
body = 'crate'
elif shape == 2:
mesh = 'bomb'
body = 'sphere'
elif shape == 3:
mesh = 'puck'
body = 'puck'
elif shape == 4:
mesh = 'egg'
body = 'capsule'
elif shape == 5:
pair = random.choice([
{'mesh': 'tnt', 'body': 'crate'},
{'mesh': 'bomb', 'body': 'sphere'},
{'mesh': 'puckModel', 'body': 'puck'},
{'mesh': 'egg', 'body': 'capsule'}
])
mesh = pair['mesh']
body = pair['body']
self.node = bs.newnode('prop', delegate=self, attrs={
'position': position,
'mesh': bs.getmesh(mesh),
'body': body,
'body_scale': 1.3,
'mesh_scale': 1.3,
'reflection': 'powerup',
'reflection_scale': [0.7],
'color_texture': bs.gettexture('bunnyColor'),
'materials': [shared.footing_material if rebound else shared.object_material,
shared.footing_material]})
if graphics == 2:
self.light_node = bs.newnode('light', attrs={
'position': (0, 0, 0),
'color': ((0.8, 0.2, 0.2) if i < count/2 else (0.2, 0.2, 0.8))
if not random_color else ((random.uniform(0, 1.1), random.uniform(0, 1.1), random.uniform(0, 1.1))),
'radius': 0.2,
'intensity': 1,
'volume_intensity_scale': 10.0})
self.node.connectattr('position', self.light_node, 'position')
def handlemessage(self, m):
if isinstance(m, bs.DieMessage):
if self.node.exists():
if hasattr(self, 'light_node'):
self.light_node.delete()
self.node.delete()
elif isinstance(m, bs.OutOfBoundsMessage):
if self.node.exists():
self.handlemessage(bs.DieMessage())
elif isinstance(m, bs.HitMessage):
self.node.handlemessage('impulse', m.pos[0], m.pos[1], m.pos[2],
m.velocity[0], m.velocity[1], m.velocity[2],
m.magnitude, m.velocity_magnitude, m.radius, 0,
m.velocity[0], m.velocity[1], m.velocity[2])

View file

@ -2,18 +2,20 @@
# BY Stary_Agent # BY Stary_Agent
"""Hockey game and support classes.""" """Hockey game and support classes."""
# ba_meta require api 7 # ba_meta require api 8
# (see https://ballistica.net/wiki/meta-tag-system) # (see https://ballistica.net/wiki/meta-tag-system)
from __future__ import annotations from __future__ import annotations
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
import ba import babase
from bastd.actor.playerspaz import PlayerSpaz import bauiv1 as bui
from bastd.actor.scoreboard import Scoreboard import bascenev1 as bs
from bastd.actor.powerupbox import PowerupBoxFactory from bascenev1lib.actor.playerspaz import PlayerSpaz
from bastd.gameutils import SharedObjects from bascenev1lib.actor.scoreboard import Scoreboard
from bascenev1lib.actor.powerupbox import PowerupBoxFactory
from bascenev1lib.gameutils import SharedObjects
if TYPE_CHECKING: if TYPE_CHECKING:
from typing import Any, Sequence, Dict, Type, List, Optional, Union from typing import Any, Sequence, Dict, Type, List, Optional, Union
@ -26,7 +28,7 @@ class PuckDiedMessage:
self.puck = puck self.puck = puck
class Puck(ba.Actor): class Puck(bs.Actor):
"""A lovely giant hockey puck.""" """A lovely giant hockey puck."""
def __init__(self, position: Sequence[float] = (0.0, 1.0, 0.0)): def __init__(self, position: Sequence[float] = (0.0, 1.0, 0.0)):
@ -41,10 +43,10 @@ class Puck(ba.Actor):
assert activity is not None assert activity is not None
assert isinstance(activity, HockeyGame) assert isinstance(activity, HockeyGame)
pmats = [shared.object_material, activity.puck_material] pmats = [shared.object_material, activity.puck_material]
self.node = ba.newnode('prop', self.node = bs.newnode('prop',
delegate=self, delegate=self,
attrs={ attrs={
'model': activity.puck_model, 'mesh': activity.puck_model,
'color_texture': activity.puck_tex, 'color_texture': activity.puck_tex,
'body': 'sphere', 'body': 'sphere',
'reflection': 'soft', 'reflection': 'soft',
@ -54,10 +56,10 @@ class Puck(ba.Actor):
'position': self._spawn_pos, 'position': self._spawn_pos,
'materials': pmats 'materials': pmats
}) })
ba.animate(self.node, 'model_scale', {0: 0, 0.2: 1.3, 0.26: 1}) bs.animate(self.node, 'mesh_scale', {0: 0, 0.2: 1.3, 0.26: 1})
def handlemessage(self, msg: Any) -> Any: def handlemessage(self, msg: Any) -> Any:
if isinstance(msg, ba.DieMessage): if isinstance(msg, bs.DieMessage):
assert self.node assert self.node
self.node.delete() self.node.delete()
activity = self._activity() activity = self._activity()
@ -65,11 +67,11 @@ class Puck(ba.Actor):
activity.handlemessage(PuckDiedMessage(self)) activity.handlemessage(PuckDiedMessage(self))
# If we go out of bounds, move back to where we started. # If we go out of bounds, move back to where we started.
elif isinstance(msg, ba.OutOfBoundsMessage): elif isinstance(msg, bs.OutOfBoundsMessage):
assert self.node assert self.node
self.node.position = self._spawn_pos self.node.position = self._spawn_pos
elif isinstance(msg, ba.HitMessage): elif isinstance(msg, bs.HitMessage):
assert self.node assert self.node
assert msg.force_direction is not None assert msg.force_direction is not None
self.node.handlemessage( self.node.handlemessage(
@ -90,31 +92,31 @@ class Puck(ba.Actor):
super().handlemessage(msg) super().handlemessage(msg)
class Player(ba.Player['Team']): class Player(bs.Player['Team']):
"""Our player type for this game.""" """Our player type for this game."""
class Team(ba.Team[Player]): class Team(bs.Team[Player]):
"""Our team type for this game.""" """Our team type for this game."""
def __init__(self) -> None: def __init__(self) -> None:
self.score = 0 self.score = 0
# ba_meta export game # ba_meta export bascenev1.GameActivity
class HockeyGame(ba.TeamGameActivity[Player, Team]): class HockeyGame(bs.TeamGameActivity[Player, Team]):
"""Ice hockey game.""" """Ice hockey game."""
name = 'Epic Soccer' name = 'Epic Soccer'
description = 'Score some goals.' description = 'Score some goals.'
available_settings = [ available_settings = [
ba.IntSetting( bs.IntSetting(
'Score to Win', 'Score to Win',
min_value=1, min_value=1,
default=1, default=1,
increment=1, increment=1,
), ),
ba.IntChoiceSetting( bs.IntChoiceSetting(
'Time Limit', 'Time Limit',
choices=[ choices=[
('None', 0), ('None', 0),
@ -126,7 +128,7 @@ class HockeyGame(ba.TeamGameActivity[Player, Team]):
], ],
default=0, default=0,
), ),
ba.FloatChoiceSetting( bs.FloatChoiceSetting(
'Respawn Times', 'Respawn Times',
choices=[ choices=[
('Shorter', 0.1), ('Shorter', 0.1),
@ -138,31 +140,32 @@ class HockeyGame(ba.TeamGameActivity[Player, Team]):
default=1.0, default=1.0,
), ),
] ]
default_music = ba.MusicType.HOCKEY default_music = bs.MusicType.HOCKEY
@classmethod @classmethod
def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool: def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool:
return issubclass(sessiontype, ba.DualTeamSession) return issubclass(sessiontype, bs.DualTeamSession)
@classmethod @classmethod
def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]:
return ba.getmaps('football') assert babase.app.classic is not None
return babase.app.classic.getmaps('football')
def __init__(self, settings: dict): def __init__(self, settings: dict):
super().__init__(settings) super().__init__(settings)
shared = SharedObjects.get() shared = SharedObjects.get()
self.slow_motion = True self.slow_motion = True
self._scoreboard = Scoreboard() self._scoreboard = Scoreboard()
self._cheer_sound = ba.getsound('cheer') self._cheer_sound = bui.getsound('cheer')
self._chant_sound = ba.getsound('crowdChant') self._chant_sound = bui.getsound('crowdChant')
self._foghorn_sound = ba.getsound('foghorn') self._foghorn_sound = bui.getsound('foghorn')
self._swipsound = ba.getsound('swip') self._swipsound = bui.getsound('swip')
self._whistle_sound = ba.getsound('refWhistle') self._whistle_sound = bui.getsound('refWhistle')
self.puck_model = ba.getmodel('bomb') self.puck_model = bs.getmesh('bomb')
self.puck_tex = ba.gettexture('landMine') self.puck_tex = bs.gettexture('landMine')
self.puck_scored_tex = ba.gettexture('landMineLit') self.puck_scored_tex = bs.gettexture('landMineLit')
self._puck_sound = ba.getsound('metalHit') self._puck_sound = bs.getsound('metalHit')
self.puck_material = ba.Material() self.puck_material = bs.Material()
self.puck_material.add_actions(actions=(('modify_part_collision', self.puck_material.add_actions(actions=(('modify_part_collision',
'friction', 0.5))) 'friction', 0.5)))
self.puck_material.add_actions(conditions=('they_have_material', self.puck_material.add_actions(conditions=('they_have_material',
@ -193,15 +196,15 @@ class HockeyGame(ba.TeamGameActivity[Player, Team]):
conditions=('they_have_material', conditions=('they_have_material',
PowerupBoxFactory.get().powerup_material), PowerupBoxFactory.get().powerup_material),
actions=(('modify_part_collision', 'physical', False), actions=(('modify_part_collision', 'physical', False),
('message', 'their_node', 'at_connect', ba.DieMessage()))) ('message', 'their_node', 'at_connect', bs.DieMessage())))
self._score_region_material = ba.Material() self._score_region_material = bs.Material()
self._score_region_material.add_actions( self._score_region_material.add_actions(
conditions=('they_have_material', self.puck_material), conditions=('they_have_material', self.puck_material),
actions=(('modify_part_collision', 'collide', actions=(('modify_part_collision', 'collide',
True), ('modify_part_collision', 'physical', False), True), ('modify_part_collision', 'physical', False),
('call', 'at_connect', self._handle_score))) ('call', 'at_connect', self._handle_score)))
self._puck_spawn_pos: Optional[Sequence[float]] = None self._puck_spawn_pos: Optional[Sequence[float]] = None
self._score_regions: Optional[List[ba.NodeActor]] = None self._score_regions: Optional[List[bs.NodeActor]] = None
self._puck: Optional[Puck] = None self._puck: Optional[Puck] = None
self._score_to_win = int(settings['Score to Win']) self._score_to_win = int(settings['Score to Win'])
self._time_limit = float(settings['Time Limit']) self._time_limit = float(settings['Time Limit'])
@ -228,8 +231,8 @@ class HockeyGame(ba.TeamGameActivity[Player, Team]):
defs = self.map.defs defs = self.map.defs
self._score_regions = [] self._score_regions = []
self._score_regions.append( self._score_regions.append(
ba.NodeActor( bs.NodeActor(
ba.newnode('region', bs.newnode('region',
attrs={ attrs={
'position': defs.boxes['goal1'][0:3], 'position': defs.boxes['goal1'][0:3],
'scale': defs.boxes['goal1'][6:9], 'scale': defs.boxes['goal1'][6:9],
@ -237,8 +240,8 @@ class HockeyGame(ba.TeamGameActivity[Player, Team]):
'materials': [self._score_region_material] 'materials': [self._score_region_material]
}))) })))
self._score_regions.append( self._score_regions.append(
ba.NodeActor( bs.NodeActor(
ba.newnode('region', bs.newnode('region',
attrs={ attrs={
'position': defs.boxes['goal2'][0:3], 'position': defs.boxes['goal2'][0:3],
'scale': defs.boxes['goal2'][6:9], 'scale': defs.boxes['goal2'][6:9],
@ -246,19 +249,19 @@ class HockeyGame(ba.TeamGameActivity[Player, Team]):
'materials': [self._score_region_material] 'materials': [self._score_region_material]
}))) })))
self._update_scoreboard() self._update_scoreboard()
ba.playsound(self._chant_sound) self._chant_sound.play()
def on_team_join(self, team: Team) -> None: def on_team_join(self, team: Team) -> None:
self._update_scoreboard() self._update_scoreboard()
def _handle_puck_player_collide(self) -> None: def _handle_puck_player_collide(self) -> None:
collision = ba.getcollision() collision = bs.getcollision()
try: try:
puck = collision.sourcenode.getdelegate(Puck, True) puck = collision.sourcenode.getdelegate(Puck, True)
player = collision.opposingnode.getdelegate(PlayerSpaz, player = collision.opposingnode.getdelegate(PlayerSpaz,
True).getplayer( True).getplayer(
Player, True) Player, True)
except ba.NotFoundError: except bs.NotFoundError:
return return
puck.last_players_to_touch[player.team.id] = player puck.last_players_to_touch[player.team.id] = player
@ -277,7 +280,7 @@ class HockeyGame(ba.TeamGameActivity[Player, Team]):
if self._puck.scored: if self._puck.scored:
return return
region = ba.getcollision().sourcenode region = bs.getcollision().sourcenode
index = 0 index = 0
for index in range(len(self._score_regions)): for index in range(len(self._score_regions)):
if region == self._score_regions[index].node: if region == self._score_regions[index].node:
@ -291,7 +294,7 @@ class HockeyGame(ba.TeamGameActivity[Player, Team]):
# Tell all players to celebrate. # Tell all players to celebrate.
for player in team.players: for player in team.players:
if player.actor: if player.actor:
player.actor.handlemessage(ba.CelebrateMessage(2.0)) player.actor.handlemessage(bs.CelebrateMessage(2.0))
# If we've got the player from the scoring team that last # If we've got the player from the scoring team that last
# touched us, give them points. # touched us, give them points.
@ -306,30 +309,30 @@ class HockeyGame(ba.TeamGameActivity[Player, Team]):
if team.score >= self._score_to_win: if team.score >= self._score_to_win:
self.end_game() self.end_game()
ba.playsound(self._foghorn_sound) self._foghorn_sound.play()
ba.playsound(self._cheer_sound) self._cheer_sound.play()
self._puck.scored = True self._puck.scored = True
# Change puck texture to something cool # Change puck texture to something cool
self._puck.node.color_texture = self.puck_scored_tex self._puck.node.color_texture = self.puck_scored_tex
# Kill the puck (it'll respawn itself shortly). # Kill the puck (it'll respawn itself shortly).
ba.timer(1.0, self._kill_puck) bs.timer(1.0, self._kill_puck)
light = ba.newnode('light', light = bs.newnode('light',
attrs={ attrs={
'position': ba.getcollision().position, 'position': bs.getcollision().position,
'height_attenuated': False, 'height_attenuated': False,
'color': (1, 0, 0) 'color': (1, 0, 0)
}) })
ba.animate(light, 'intensity', {0: 0, 0.5: 1, 1.0: 0}, loop=True) bs.animate(light, 'intensity', {0: 0, 0.5: 1, 1.0: 0}, loop=True)
ba.timer(1.0, light.delete) bs.timer(1.0, light.delete)
ba.cameraflash(duration=10.0) bs.cameraflash(duration=10.0)
self._update_scoreboard() self._update_scoreboard()
def end_game(self) -> None: def end_game(self) -> None:
results = ba.GameResults() results = bs.GameResults()
for team in self.teams: for team in self.teams:
results.set_team_score(team, team.score) results.set_team_score(team, team.score)
self.end(results=results) self.end(results=results)
@ -342,7 +345,7 @@ class HockeyGame(ba.TeamGameActivity[Player, Team]):
def handlemessage(self, msg: Any) -> Any: def handlemessage(self, msg: Any) -> Any:
# Respawn dead players if they're still in the game. # Respawn dead players if they're still in the game.
if isinstance(msg, ba.PlayerDiedMessage): if isinstance(msg, bs.PlayerDiedMessage):
# Augment standard behavior... # Augment standard behavior...
super().handlemessage(msg) super().handlemessage(msg)
self.respawn_player(msg.getplayer(Player)) self.respawn_player(msg.getplayer(Player))
@ -350,23 +353,23 @@ class HockeyGame(ba.TeamGameActivity[Player, Team]):
# Respawn dead pucks. # Respawn dead pucks.
elif isinstance(msg, PuckDiedMessage): elif isinstance(msg, PuckDiedMessage):
if not self.has_ended(): if not self.has_ended():
ba.timer(3.0, self._spawn_puck) bs.timer(3.0, self._spawn_puck)
else: else:
super().handlemessage(msg) super().handlemessage(msg)
def _flash_puck_spawn(self) -> None: def _flash_puck_spawn(self) -> None:
light = ba.newnode('light', light = bs.newnode('light',
attrs={ attrs={
'position': self._puck_spawn_pos, 'position': self._puck_spawn_pos,
'height_attenuated': False, 'height_attenuated': False,
'color': (1, 0, 0) 'color': (1, 0, 0)
}) })
ba.animate(light, 'intensity', {0.0: 0, 0.25: 1, 0.5: 0}, loop=True) bs.animate(light, 'intensity', {0.0: 0, 0.25: 1, 0.5: 0}, loop=True)
ba.timer(1.0, light.delete) bs.timer(1.0, light.delete)
def _spawn_puck(self) -> None: def _spawn_puck(self) -> None:
ba.playsound(self._swipsound) self._swipsound.play()
ba.playsound(self._whistle_sound) self._whistle_sound.play()
self._flash_puck_spawn() self._flash_puck_spawn()
assert self._puck_spawn_pos is not None assert self._puck_spawn_pos is not None
self._puck = Puck(position=self._puck_spawn_pos) self._puck = Puck(position=self._puck_spawn_pos)

View file

@ -0,0 +1,602 @@
"""New Duel / Created by: byANG3L"""
# ba_meta require api 8
# (see https://ballistica.net/wiki/meta-tag-system)
from __future__ import annotations
from typing import TYPE_CHECKING
import babase
import bauiv1 as bui
import bascenev1 as bs
import random
from bascenev1lib.actor.playerspaz import PlayerSpaz
from bascenev1lib.actor.scoreboard import Scoreboard
from bascenev1lib.game.elimination import Icon
if TYPE_CHECKING:
from typing import Any, Type, List, Dict, Tuple, Union, Sequence, Optional
class SuperSpaz(PlayerSpaz):
def __init__(self,
player: bs.Player,
color: Sequence[float] = (1.0, 1.0, 1.0),
highlight: Sequence[float] = (0.5, 0.5, 0.5),
character: str = 'Spaz',
super_punch: bool = False,
powerups_expire: bool = True):
super().__init__(player=player,
color=color,
highlight=highlight,
character=character,
powerups_expire=powerups_expire)
self._super_punch = super_punch
def handlemessage(self, msg: Any) -> Any:
from bascenev1lib.actor.spaz import PunchHitMessage
from bascenev1lib.actor.bomb import Blast
if isinstance(msg, PunchHitMessage):
super().handlemessage(msg)
node = bs.getcollision().opposingnode
if self._super_punch:
if node.getnodetype() == 'spaz':
if not node.frozen:
node.frozen = True
node.handlemessage(babase.FreezeMessage())
bs.getsound('freeze').play()
bs.getsound('superPunch').play()
bs.getsound('punchStrong02').play()
Blast(position=node.position,
velocity=node.velocity,
blast_radius=0.0,
blast_type='normal').autoretain()
else:
return super().handlemessage(msg)
return None
class Player(bs.Player['Team']):
"""Our player type for this game."""
def __init__(self) -> None:
self.icons: List[Icon] = []
self.in_game: bool = False
self.playervs1: bool = False
self.playervs2: bool = False
self.light: bool = False
class Team(bs.Team[Player]):
"""Our team type for this game."""
def __init__(self) -> None:
self.score = 0
lang = bs.app.lang.language
if lang == 'Spanish':
enable_powerups = 'Habilitar Potenciadores'
night_mode = 'Modo Noche'
fight_delay = 'Tiempo entre Pelea'
very_fast = 'Muy Rápido'
fast = 'Rápido'
normal = 'Normal'
slow = 'Lento'
very_slow = 'Muy Lento'
none = 'Ninguno'
super_punch = 'Super Golpe'
box_mode = 'Modo Caja'
boxing_gloves = 'Guantes de Boxeo'
else:
enable_powerups = 'Enable Powerups'
night_mode = 'Night Mode'
fight_delay = 'Fight Delay'
very_fast = 'Very Fast'
fast = 'Fast'
normal = 'Normal'
slow = 'Slow'
very_slow = 'Very Slow'
super_punch = 'Super Punch'
box_mode = 'Box Mode'
boxing_gloves = 'Boxing Gloves'
# ba_meta export bascenev1.GameActivity
class NewDuelGame(bs.TeamGameActivity[Player, Team]):
"""A game type based on acquiring kills."""
name = 'Duel'
description = 'Kill a set number of enemies to win.'
# Print messages when players die since it matters here.
announce_player_deaths = True
@classmethod
def get_available_settings(
cls, sessiontype: Type[bs.Session]) -> List[babase.Setting]:
settings = [
bs.IntSetting(
'Kills to Win Per Player',
min_value=1,
default=5,
increment=1,
),
bs.IntChoiceSetting(
'Time Limit',
choices=[
('None', 0),
('1 Minute', 60),
('2 Minutes', 120),
('5 Minutes', 300),
('10 Minutes', 600),
('20 Minutes', 1200),
],
default=0,
),
bs.BoolSetting(enable_powerups, default=False),
bs.BoolSetting(boxing_gloves, default=False),
bs.BoolSetting(night_mode, default=False),
bs.BoolSetting(super_punch, default=False),
bs.BoolSetting(box_mode, default=False),
bs.BoolSetting('Epic Mode', default=False),
bs.BoolSetting('Allow Negative Scores', default=False),
]
return settings
@classmethod
def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool:
return (issubclass(sessiontype, bs.FreeForAllSession))
@classmethod
def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]:
return bs.app.classic.getmaps('melee')
def __init__(self, settings: dict):
super().__init__(settings)
self._scoreboard = Scoreboard()
self._score_to_win: Optional[int] = None
self._dingsound = bs.getsound('dingSmall')
self._epic_mode = bool(settings['Epic Mode'])
self._kills_to_win_per_player = int(
settings['Kills to Win Per Player'])
self._enable_powerups = bool(settings[enable_powerups])
self._night_mode = bool(settings[night_mode])
self._fight_delay: float = 0
self._time_limit = float(settings['Time Limit'])
self._allow_negative_scores = bool(
settings.get('Allow Negative Scores', False))
self._super_punch = bool(settings[super_punch])
self._box_mode = bool(settings[box_mode])
self._boxing_gloves = bool(settings[boxing_gloves])
self._vs_text: Optional[bs.Actor] = None
self.spawn_order: List[Player] = []
self._players_vs_1: bool = False
self._players_vs_2: bool = False
self._first_countdown: bool = True
self._count_1 = bs.getsound('announceOne')
self._count_2 = bs.getsound('announceTwo')
self._count_3 = bs.getsound('announceThree')
self._boxing_bell = bs.getsound('boxingBell')
# Base class overrides.
self.slow_motion = self._epic_mode
self.default_music = (bs.MusicType.EPIC if self._epic_mode else
bs.MusicType.TO_THE_DEATH)
def get_instance_description(self) -> Union[str, Sequence]:
return 'Crush ${ARG1} of your enemies.', self._score_to_win
def get_instance_description_short(self) -> Union[str, Sequence]:
return 'kill ${ARG1} enemies', self._score_to_win
def on_player_join(self, player: Player) -> None:
self.spawn_order.append(player)
self._update_order()
def on_player_leave(self, player: Player) -> None:
super().on_player_leave(player)
player.icons = []
if player.playervs1:
player.playervs1 = False
self._players_vs_1 = False
player.in_game = False
elif player.playervs2:
player.playervs2 = False
self._players_vs_2 = False
player.in_game = False
if player in self.spawn_order:
self.spawn_order.remove(player)
bs.timer(0.2, self._update_order)
def on_transition_in(self) -> None:
super().on_transition_in()
if self._night_mode:
gnode = bs.getactivity().globalsnode
gnode.tint = (0.3, 0.3, 0.3)
def on_team_join(self, team: Team) -> None:
if self.has_begun():
self._update_scoreboard()
def on_begin(self) -> None:
super().on_begin()
self.setup_standard_time_limit(self._time_limit)
if self._enable_powerups:
self.setup_standard_powerup_drops()
self._vs_text = bs.NodeActor(
bs.newnode('text',
attrs={
'position': (0, 105),
'h_attach': 'center',
'h_align': 'center',
'maxwidth': 200,
'shadow': 0.5,
'vr_depth': 390,
'scale': 0.6,
'v_attach': 'bottom',
'color': (0.8, 0.8, 0.3, 1.0),
'text': babase.Lstr(resource='vsText')
}))
# Base kills needed to win on the size of the largest team.
self._score_to_win = (self._kills_to_win_per_player *
max(1, max(len(t.players) for t in self.teams)))
self._update_scoreboard()
bs.timer(1.0, self._update, repeat=True)
def _update(self) -> None:
if len(self.players) == 1:
'self.end_game()'
def spawn_player(self, player: PlayerType) -> bs.Actor:
# pylint: disable=too-many-locals
# pylint: disable=cyclic-import
from babase import _math
from bascenev1._coopsession import CoopSession
from bascenev1lib.actor.spazfactory import SpazFactory
factory = SpazFactory.get()
name = player.getname()
color = player.color
highlight = player.highlight
light_color = _math.normalized_color(color)
display_color = babase.safecolor(color, target_intensity=0.75)
spaz = SuperSpaz(color=color,
highlight=highlight,
character=player.character,
player=player,
super_punch=True if self._super_punch else False)
player.actor = spaz
assert spaz.node
# If this is co-op and we're on Courtyard or Runaround, add the
# material that allows us to collide with the player-walls.
# FIXME: Need to generalize this.
if isinstance(self.session, CoopSession) and self.map.getname() in [
'Courtyard', 'Tower D'
]:
mat = self.map.preloaddata['collide_with_wall_material']
assert isinstance(spaz.node.materials, tuple)
assert isinstance(spaz.node.roller_materials, tuple)
spaz.node.materials += (mat, )
spaz.node.roller_materials += (mat, )
spaz.node.name = name
spaz.node.name_color = display_color
spaz.connect_controls_to_player()
self._spawn_sound.play(1, position=spaz.node.position)
light = bs.newnode('light', attrs={'color': light_color})
spaz.node.connectattr('position', light, 'position')
bs.animate(light, 'intensity', {0: 0, 0.25: 1, 0.5: 0})
bs.timer(0.5, light.delete)
pos1 = [self.map.get_start_position(0), 90]
pos2 = [self.map.get_start_position(1), 270]
pos3 = []
for x in self.players:
if x.is_alive():
if x is player:
continue
p = x.actor.node.position
if 0.0 not in (p[0], p[2]):
if p[0] <= 0:
pos3.append(pos2[0])
else:
pos3.append(pos1[0])
spaz.handlemessage(bs.StandMessage(pos1[0] if player.playervs1 else pos2[0],
pos1[1] if player.playervs1 else pos2[1]))
if any(pos3):
spaz.handlemessage(bs.StandMessage(pos3[0]))
if self._super_punch:
spaz._punch_power_scale = factory.punch_power_scale_gloves = 10
spaz.equip_boxing_gloves()
lfx = bs.newnode(
'light',
attrs={
'color': color,
'radius': 0.3,
'intensity': 0.3})
def sp_fx():
if not spaz.node:
lfx.delete()
return
bs.emitfx(position=spaz.node.position,
velocity=spaz.node.velocity,
count=5,
scale=0.5,
spread=0.5,
chunk_type='spark')
bs.emitfx(position=spaz.node.position,
velocity=spaz.node.velocity,
count=2,
scale=0.8,
spread=0.3,
chunk_type='spark')
if lfx:
spaz.node.connectattr('position', lfx, 'position')
bs.timer(0.1, sp_fx, repeat=True)
if self._box_mode:
spaz.node.color_texture = bs.gettexture('tnt')
spaz.node.color_mask_texture = bs.gettexture('tnt')
spaz.node.color = (1, 1, 1)
spaz.node.highlight = (1, 1, 1)
spaz.node.head_mesh = None
spaz.node.torso_mesh = bs.getmesh('tnt')
spaz.node.style = 'cyborg'
if self._boxing_gloves:
spaz.equip_boxing_gloves()
return spaz
def _update_spawn(self) -> None:
if self._players_vs_1 or self._players_vs_2:
for player in self.players:
if player.playervs1 or player.playervs2:
if not player.is_alive():
self.spawn_player(player)
# player.actor.disconnect_controls_from_player()
if self._night_mode:
if not player.light:
player.light = True
light = bs.newnode(
'light',
owner=player.node,
attrs={
'radius': 0.3,
'intensity': 0.6,
'height_attenuated': False,
'color': player.color
})
player.node.connectattr(
'position', light, 'position')
else:
player.actor.disconnect_controls_from_player()
bs.timer(0.0, self._countdown)
# bs.timer(0.1, self._clear_all_objects)
def _countdown(self) -> None:
self._first_countdown = False
if self._fight_delay == 0:
for player in self.players:
if player.playervs1 or player.playervs2:
if not player.is_alive():
return
else:
player.actor.connect_controls_to_player()
else:
bs.timer(self._fight_delay, self.count3)
def start(self) -> None:
self._count_text('FIGHT')
self._boxing_bell.play()
for player in self.players:
if player.playervs1 or player.playervs2:
if not player.is_alive():
return
else:
player.actor.connect_controls_to_player()
def count(self) -> None:
self._count_text('1')
self._count_1.play()
bs.timer(self._fight_delay, self.start)
def count2(self) -> None:
self._count_text('2')
self._count_2.play()
bs.timer(self._fight_delay, self.count)
def count3(self) -> None:
self._count_text('3')
self._count_3.play()
bs.timer(self._fight_delay, self.count2)
def _count_text(self, num: str) -> None:
self.node = bs.newnode('text',
attrs={
'v_attach': 'center',
'h_attach': 'center',
'h_align': 'center',
'color': (1, 1, 0.5, 1),
'flatness': 0.5,
'shadow': 0.5,
'position': (0, 18),
'text': num
})
if self._fight_delay == 0.7:
bs.animate(self.node, 'scale',
{0: 0, 0.1: 3.9, 0.64: 4.3, 0.68: 0})
elif self._fight_delay == 0.4:
bs.animate(self.node, 'scale',
{0: 0, 0.1: 3.9, 0.34: 4.3, 0.38: 0})
else:
bs.animate(self.node, 'scale',
{0: 0, 0.1: 3.9, 0.92: 4.3, 0.96: 0})
cmb = bs.newnode('combine', owner=self.node, attrs={'size': 4})
cmb.connectattr('output', self.node, 'color')
bs.animate(cmb, 'input0', {0: 1.0, 0.15: 1.0}, loop=True)
bs.animate(cmb, 'input1', {0: 1.0, 0.15: 0.5}, loop=True)
bs.animate(cmb, 'input2', {0: 0.1, 0.15: 0.0}, loop=True)
cmb.input3 = 1.0
bs.timer(self._fight_delay, self.node.delete)
def _update_order(self) -> None:
for player in self.spawn_order:
assert isinstance(player, Player)
if not player.is_alive():
if not self._players_vs_1:
self._players_vs_1 = True
player.playervs1 = True
player.in_game = True
self.spawn_order.remove(player)
self._update_spawn()
elif not self._players_vs_2:
self._players_vs_2 = True
player.playervs2 = True
player.in_game = True
self.spawn_order.remove(player)
self._update_spawn()
self._update_icons()
def _update_icons(self) -> None:
# pylint: disable=too-many-branches
for player in self.players:
player.icons = []
if player.in_game:
if player.playervs1:
xval = -60
x_offs = -78
elif player.playervs2:
xval = 60
x_offs = 78
player.icons.append(
Icon(player,
position=(xval, 40),
scale=1.0,
name_maxwidth=130,
name_scale=0.8,
flatness=0.0,
shadow=0.5,
show_death=True,
show_lives=False))
else:
xval = 125
xval2 = -125
x_offs = 78
for player in self.spawn_order:
player.icons.append(
Icon(player,
position=(xval, 25),
scale=0.5,
name_maxwidth=75,
name_scale=1.0,
flatness=1.0,
shadow=1.0,
show_death=False,
show_lives=False))
xval += x_offs * 0.56
player.icons.append(
Icon(player,
position=(xval2, 25),
scale=0.5,
name_maxwidth=75,
name_scale=1.0,
flatness=1.0,
shadow=1.0,
show_death=False,
show_lives=False))
xval2 -= x_offs * 0.56
def handlemessage(self, msg: Any) -> Any:
if isinstance(msg, bs.PlayerDiedMessage):
# Augment standard behavior.
super().handlemessage(msg)
player = msg.getplayer(Player)
if player.playervs1:
player.playervs1 = False
self._players_vs_1 = False
player.in_game = False
self.spawn_order.append(player)
elif player.playervs2:
player.playervs2 = False
self._players_vs_2 = False
player.in_game = False
self.spawn_order.append(player)
bs.timer(0.2, self._update_order)
killer = msg.getkillerplayer(Player)
if killer is None:
return None
# Handle team-kills.
if killer.team is player.team:
# In free-for-all, killing yourself loses you a point.
if isinstance(self.session, bs.FreeForAllSession):
new_score = player.team.score - 1
if not self._allow_negative_scores:
new_score = max(0, new_score)
player.team.score = new_score
# In teams-mode it gives a point to the other team.
else:
self._dingsound.play()
for team in self.teams:
if team is not killer.team:
team.score += 1
# Killing someone on another team nets a kill.
else:
killer.team.score += 1
self._dingsound.play()
# In FFA show scores since its hard to find on the scoreboard.
if isinstance(killer.actor, PlayerSpaz) and killer.actor:
killer.actor.set_score_text(str(killer.team.score) + '/' +
str(self._score_to_win),
color=killer.team.color,
flash=True)
self._update_scoreboard()
# If someone has won, set a timer to end shortly.
# (allows the dust to clear and draws to occur if deaths are
# close enough)
assert self._score_to_win is not None
if any(team.score >= self._score_to_win for team in self.teams):
bs.timer(0.5, self.end_game)
else:
return super().handlemessage(msg)
return None
def _update_scoreboard(self) -> None:
for team in self.teams:
self._scoreboard.set_team_value(team, team.score,
self._score_to_win)
def end_game(self) -> None:
results = bs.GameResults()
for team in self.teams:
results.set_team_score(team, team.score)
self.end(results=results)

View file

@ -0,0 +1,956 @@
# To learn more, see https://ballistica.net/wiki/meta-tag-system
# ba_meta require api 8
from __future__ import annotations
from typing import TYPE_CHECKING
import babase
import random
import bauiv1 as bui
import bascenev1 as bs
from babase import _math
from bascenev1lib.actor.spaz import Spaz
from bascenev1lib.actor.spazfactory import SpazFactory
from bascenev1lib.actor.scoreboard import Scoreboard
from bascenev1lib.game import elimination
from bascenev1lib.game.elimination import Icon, Player, Team
from bascenev1lib.actor.bomb import Bomb, Blast
from bascenev1lib.actor.playerspaz import PlayerSpaz, PlayerSpazHurtMessage
if TYPE_CHECKING:
from typing import Any, Type, List, Sequence, Optional
class Icon(Icon):
def update_for_lives(self) -> None:
"""Update for the target player's current lives."""
if self._player:
lives = self._player.lives
else:
lives = 0
if self._show_lives:
if lives > 1:
self._lives_text.text = 'x' + str(lives - 1)
else:
self._lives_text.text = ''
if lives == 0:
self._name_text.opacity = 0.2
assert self.node
self.node.color = (0.7, 0.3, 0.3)
self.node.opacity = 0.2
class PowBox(Bomb):
def __init__(self,
position: Sequence[float] = (0.0, 1.0, 0.0),
velocity: Sequence[float] = (0.0, 0.0, 0.0)) -> None:
Bomb.__init__(self,
position,
velocity,
bomb_type='tnt',
blast_radius=2.5,
source_player=None,
owner=None)
self.set_pow_text()
def set_pow_text(self) -> None:
m = bs.newnode('math',
owner=self.node,
attrs={'input1': (0, 0.7, 0),
'operation': 'add'})
self.node.connectattr('position', m, 'input2')
self._pow_text = bs.newnode('text',
owner=self.node,
attrs={'text': 'POW!',
'in_world': True,
'shadow': 1.0,
'flatness': 1.0,
'color': (1, 1, 0.4),
'scale': 0.0,
'h_align': 'center'})
m.connectattr('output', self._pow_text, 'position')
bs.animate(self._pow_text, 'scale', {0: 0.0, 1.0: 0.01})
def pow(self) -> None:
self.explode()
def handlemessage(self, m: Any) -> Any:
if isinstance(m, babase.PickedUpMessage):
self._heldBy = m.node
elif isinstance(m, bs.DroppedMessage):
bs.timer(0.6, self.pow)
Bomb.handlemessage(self, m)
class SSPlayerSpaz(PlayerSpaz):
multiplyer = 1
is_dead = False
def oob_effect(self) -> None:
if self.is_dead:
return
self.is_dead = True
if self.multiplyer > 1.25:
blast_type = 'tnt'
radius = min(self.multiplyer * 5, 20)
else:
# penalty for killing people with low multiplyer
blast_type = 'ice'
radius = 7.5
Blast(position=self.node.position,
blast_radius=radius,
blast_type=blast_type).autoretain()
def handlemessage(self, msg: Any) -> Any:
if isinstance(msg, bs.HitMessage):
if not self.node:
return None
if self.node.invincible:
SpazFactory.get().block_sound.play(1.0, position=self.node.position)
return True
# If we were recently hit, don't count this as another.
# (so punch flurries and bomb pileups essentially count as 1 hit)
local_time = int(bs.time() * 1000)
assert isinstance(local_time, int)
if (self._last_hit_time is None
or local_time - self._last_hit_time > 1000):
self._num_times_hit += 1
self._last_hit_time = local_time
mag = msg.magnitude * self.impact_scale
velocity_mag = msg.velocity_magnitude * self.impact_scale
damage_scale = 0.22
# If they've got a shield, deliver it to that instead.
if self.shield:
if msg.flat_damage:
damage = msg.flat_damage * self.impact_scale
else:
# Hit our spaz with an impulse but tell it to only return
# theoretical damage; not apply the impulse.
assert msg.force_direction is not None
self.node.handlemessage(
'impulse', msg.pos[0], msg.pos[1], msg.pos[2],
msg.velocity[0], msg.velocity[1], msg.velocity[2], mag,
velocity_mag, msg.radius, 1, msg.force_direction[0],
msg.force_direction[1], msg.force_direction[2])
damage = damage_scale * self.node.damage
assert self.shield_hitpoints is not None
self.shield_hitpoints -= int(damage)
self.shield.hurt = (
1.0 -
float(self.shield_hitpoints) / self.shield_hitpoints_max)
# Its a cleaner event if a hit just kills the shield
# without damaging the player.
# However, massive damage events should still be able to
# damage the player. This hopefully gives us a happy medium.
max_spillover = SpazFactory.get().max_shield_spillover_damage
if self.shield_hitpoints <= 0:
# FIXME: Transition out perhaps?
self.shield.delete()
self.shield = None
SpazFactory.get().shield_down_sound.play(1.0, position=self.node.position)
# Emit some cool looking sparks when the shield dies.
npos = self.node.position
bs.emitfx(position=(npos[0], npos[1] + 0.9, npos[2]),
velocity=self.node.velocity,
count=random.randrange(20, 30),
scale=1.0,
spread=0.6,
chunk_type='spark')
else:
SpazFactory.get().shield_hit_sound.play(0.5, position=self.node.position)
# Emit some cool looking sparks on shield hit.
assert msg.force_direction is not None
bs.emitfx(position=msg.pos,
velocity=(msg.force_direction[0] * 1.0,
msg.force_direction[1] * 1.0,
msg.force_direction[2] * 1.0),
count=min(30, 5 + int(damage * 0.005)),
scale=0.5,
spread=0.3,
chunk_type='spark')
# If they passed our spillover threshold,
# pass damage along to spaz.
if self.shield_hitpoints <= -max_spillover:
leftover_damage = -max_spillover - self.shield_hitpoints
shield_leftover_ratio = leftover_damage / damage
# Scale down the magnitudes applied to spaz accordingly.
mag *= shield_leftover_ratio
velocity_mag *= shield_leftover_ratio
else:
return True # Good job shield!
else:
shield_leftover_ratio = 1.0
if msg.flat_damage:
damage = int(msg.flat_damage * self.impact_scale *
shield_leftover_ratio)
else:
# Hit it with an impulse and get the resulting damage.
assert msg.force_direction is not None
self.node.handlemessage(
'impulse', msg.pos[0], msg.pos[1], msg.pos[2],
msg.velocity[0], msg.velocity[1], msg.velocity[2], mag,
velocity_mag, msg.radius, 0, msg.force_direction[0],
msg.force_direction[1], msg.force_direction[2])
damage = int(damage_scale * self.node.damage)
self.node.handlemessage('hurt_sound')
# Play punch impact sound based on damage if it was a punch.
if msg.hit_type == 'punch':
self.on_punched(damage)
# If damage was significant, lets show it.
# if damage > 350:
# assert msg.force_direction is not None
# babase.show_damage_count('-' + str(int(damage / 10)) + '%',
# msg.pos, msg.force_direction)
# Let's always add in a super-punch sound with boxing
# gloves just to differentiate them.
if msg.hit_subtype == 'super_punch':
SpazFactory.get().punch_sound_stronger.play(1.0, position=self.node.position)
if damage > 500:
sounds = SpazFactory.get().punch_sound_strong
sound = sounds[random.randrange(len(sounds))]
else:
sound = SpazFactory.get().punch_sound
sound.play(1.0, position=self.node.position)
# Throw up some chunks.
assert msg.force_direction is not None
bs.emitfx(position=msg.pos,
velocity=(msg.force_direction[0] * 0.5,
msg.force_direction[1] * 0.5,
msg.force_direction[2] * 0.5),
count=min(10, 1 + int(damage * 0.0025)),
scale=0.3,
spread=0.03)
bs.emitfx(position=msg.pos,
chunk_type='sweat',
velocity=(msg.force_direction[0] * 1.3,
msg.force_direction[1] * 1.3 + 5.0,
msg.force_direction[2] * 1.3),
count=min(30, 1 + int(damage * 0.04)),
scale=0.9,
spread=0.28)
# Momentary flash.
hurtiness = damage * 0.003
punchpos = (msg.pos[0] + msg.force_direction[0] * 0.02,
msg.pos[1] + msg.force_direction[1] * 0.02,
msg.pos[2] + msg.force_direction[2] * 0.02)
flash_color = (1.0, 0.8, 0.4)
light = bs.newnode(
'light',
attrs={
'position': punchpos,
'radius': 0.12 + hurtiness * 0.12,
'intensity': 0.3 * (1.0 + 1.0 * hurtiness),
'height_attenuated': False,
'color': flash_color
})
bs.timer(0.06, light.delete)
flash = bs.newnode('flash',
attrs={
'position': punchpos,
'size': 0.17 + 0.17 * hurtiness,
'color': flash_color
})
bs.timer(0.06, flash.delete)
if msg.hit_type == 'impact':
assert msg.force_direction is not None
bs.emitfx(position=msg.pos,
velocity=(msg.force_direction[0] * 2.0,
msg.force_direction[1] * 2.0,
msg.force_direction[2] * 2.0),
count=min(10, 1 + int(damage * 0.01)),
scale=0.4,
spread=0.1)
if self.hitpoints > 0:
# It's kinda crappy to die from impacts, so lets reduce
# impact damage by a reasonable amount *if* it'll keep us alive
if msg.hit_type == 'impact' and damage > self.hitpoints:
# Drop damage to whatever puts us at 10 hit points,
# or 200 less than it used to be whichever is greater
# (so it *can* still kill us if its high enough)
newdamage = max(damage - 200, self.hitpoints - 10)
damage = newdamage
self.node.handlemessage('flash')
# If we're holding something, drop it.
if damage > 0.0 and self.node.hold_node:
self.node.hold_node = None
# self.hitpoints -= damage
self.multiplyer += min(damage / 2000, 0.15)
if damage/2000 > 0.05:
self.set_score_text(str(int((self.multiplyer-1)*100))+'%')
# self.node.hurt = 1.0 - float(
# self.hitpoints) / self.hitpoints_max
self.node.hurt = 0.0
# If we're cursed, *any* damage blows us up.
if self._cursed and damage > 0:
bs.timer(
0.05,
bs.WeakCall(self.curse_explode,
msg.get_source_player(bs.Player)))
# If we're frozen, shatter.. otherwise die if we hit zero
# if self.frozen and (damage > 200 or self.hitpoints <= 0):
# self.shatter()
# elif self.hitpoints <= 0:
# self.node.handlemessage(
# bs.DieMessage(how=babase.DeathType.IMPACT))
# If we're dead, take a look at the smoothed damage value
# (which gives us a smoothed average of recent damage) and shatter
# us if its grown high enough.
# if self.hitpoints <= 0:
# damage_avg = self.node.damage_smoothed * damage_scale
# if damage_avg > 1000:
# self.shatter()
source_player = msg.get_source_player(type(self._player))
if source_player:
self.last_player_attacked_by = source_player
self.last_attacked_time = bs.time()
self.last_attacked_type = (msg.hit_type, msg.hit_subtype)
Spaz.handlemessage(self, bs.HitMessage) # Augment standard behavior.
activity = self._activity()
if activity is not None and self._player.exists():
activity.handlemessage(PlayerSpazHurtMessage(self))
elif isinstance(msg, bs.DieMessage):
self.oob_effect()
super().handlemessage(msg)
elif isinstance(msg, bs.PowerupMessage):
if msg.poweruptype == 'health':
if self.multiplyer > 2:
self.multiplyer *= 0.5
else:
self.multiplyer *= 0.75
self.multiplyer = max(1, self.multiplyer)
self.set_score_text(str(int((self.multiplyer-1)*100))+"%")
super().handlemessage(msg)
else:
super().handlemessage(msg)
class Player(bs.Player['Team']):
"""Our player type for this game."""
class Team(bs.Team[Player]):
"""Our team type for this game."""
def __init__(self) -> None:
self.score = 0
# ba_meta export bascenev1.GameActivity
class SuperSmash(bs.TeamGameActivity[Player, Team]):
name = 'Super Smash'
description = 'Knock everyone off the map.'
# Print messages when players die since it matters here.
announce_player_deaths = True
@classmethod
def get_available_settings(
cls, sessiontype: Type[bs.Session]) -> List[babase.Setting]:
settings = [
bs.IntSetting(
'Kills to Win Per Player',
min_value=1,
default=5,
increment=1,
),
bs.IntChoiceSetting(
'Time Limit',
choices=[
('None', 0),
('1 Minute', 60),
('2 Minutes', 120),
('5 Minutes', 300),
('10 Minutes', 600),
('20 Minutes', 1200),
],
default=0,
),
bs.FloatChoiceSetting(
'Respawn Times',
choices=[
('Shorter', 0.25),
('Short', 0.5),
('Normal', 1.0),
('Long', 2.0),
('Longer', 4.0),
],
default=1.0,
),
bs.BoolSetting('Boxing Gloves', default=False),
bs.BoolSetting('Epic Mode', default=False),
]
if issubclass(sessiontype, bs.FreeForAllSession):
settings.append(
bs.BoolSetting('Allow Negative Scores', default=False))
return settings
@classmethod
def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool:
return (issubclass(sessiontype, bs.DualTeamSession)
or issubclass(sessiontype, bs.FreeForAllSession))
@classmethod
def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]:
maps = bs.app.classic.getmaps('melee')
for m in ['Lake Frigid', 'Hockey Stadium', 'Football Stadium']:
# remove maps without bounds
maps.remove(m)
return maps
def __init__(self, settings: dict):
super().__init__(settings)
self._scoreboard = Scoreboard()
self._score_to_win: int | None = None
self._dingsound = bs.getsound('dingSmall')
self._epic_mode = bool(settings['Epic Mode'])
self._kills_to_win_per_player = int(
settings['Kills to Win Per Player'])
self._time_limit = float(settings['Time Limit'])
self._allow_negative_scores = bool(
settings.get('Allow Negative Scores', False))
self._boxing_gloves = bool(settings['Boxing Gloves'])
# Base class overrides.
self.slow_motion = self._epic_mode
self.default_music = (bs.MusicType.EPIC if self._epic_mode else
bs.MusicType.SURVIVAL)
def get_instance_description(self) -> str | Sequence:
return 'Knock everyone off the map.'
def get_instance_description_short(self) -> str | Sequence:
return 'Knock off the map.'
def on_begin(self) -> None:
super().on_begin()
self._start_time = bs.time()
self.setup_standard_time_limit(self._time_limit)
self.setup_standard_powerup_drops(enable_tnt=False)
self._pow = None
self._tnt_drop_timer = bs.timer(1.0 * 0.30,
bs.WeakCall(self._drop_pow_box),
repeat=True)
# Base kills needed to win on the size of the largest team.
self._score_to_win = (self._kills_to_win_per_player *
max(1, max(len(t.players) for t in self.teams)))
self._update_scoreboard()
def _drop_pow_box(self) -> None:
if self._pow is not None and self._pow:
return
if len(self.map.tnt_points) == 0:
return
pos = random.choice(self.map.tnt_points)
pos = (pos[0], pos[1] + 1, pos[2])
self._pow = PowBox(position=pos, velocity=(0.0, 1.0, 0.0))
def spawn_player(self, player: Player) -> bs.Actor:
if isinstance(self.session, bs.DualTeamSession):
position = self.map.get_start_position(player.team.id)
else:
# otherwise do free-for-all spawn locations
position = self.map.get_ffa_start_position(self.players)
angle = None
name = player.getname()
light_color = _math.normalized_color(player.color)
display_color = babase.safecolor(player.color, target_intensity=0.75)
spaz = SSPlayerSpaz(color=player.color,
highlight=player.highlight,
character=player.character,
player=player)
player.actor = spaz
assert spaz.node
# If this is co-op and we're on Courtyard or Runaround, add the
# material that allows us to collide with the player-walls.
# FIXME: Need to generalize this.
if isinstance(self.session, bs.CoopSession) and self.map.getname() in [
'Courtyard', 'Tower D'
]:
mat = self.map.preloaddata['collide_with_wall_material']
assert isinstance(spaz.node.materials, tuple)
assert isinstance(spaz.node.roller_materials, tuple)
spaz.node.materials += (mat, )
spaz.node.roller_materials += (mat, )
spaz.node.name = name
spaz.node.name_color = display_color
spaz.connect_controls_to_player()
# Move to the stand position and add a flash of light.
spaz.handlemessage(
bs.StandMessage(
position,
angle if angle is not None else random.uniform(0, 360)))
self._spawn_sound.play(1, position=spaz.node.position)
light = bs.newnode('light', attrs={'color': light_color})
spaz.node.connectattr('position', light, 'position')
bs.animate(light, 'intensity', {0: 0, 0.25: 1, 0.5: 0})
bs.timer(0.5, light.delete)
if self._boxing_gloves:
spaz.equip_boxing_gloves()
return spaz
def handlemessage(self, msg: Any) -> Any:
if isinstance(msg, bs.PlayerDiedMessage):
# Augment standard behavior.
super().handlemessage(msg)
player = msg.getplayer(Player)
self.respawn_player(player)
killer = msg.getkillerplayer(Player)
if killer is None:
return None
# Handle team-kills.
if killer.team is player.team:
# In free-for-all, killing yourself loses you a point.
if isinstance(self.session, bs.FreeForAllSession):
new_score = player.team.score - 1
if not self._allow_negative_scores:
new_score = max(0, new_score)
player.team.score = new_score
# In teams-mode it gives a point to the other team.
else:
self._dingsound.play()
for team in self.teams:
if team is not killer.team:
team.score += 1
# Killing someone on another team nets a kill.
else:
killer.team.score += 1
self._dingsound.play()
# In FFA show scores since its hard to find on the scoreboard.
if isinstance(killer.actor, SSPlayerSpaz) and killer.actor:
killer.actor.set_score_text(str(killer.team.score) + '/' +
str(self._score_to_win),
color=killer.team.color,
flash=True)
self._update_scoreboard()
# If someone has won, set a timer to end shortly.
# (allows the dust to clear and draws to occur if deaths are
# close enough)
assert self._score_to_win is not None
if any(team.score >= self._score_to_win for team in self.teams):
bs.timer(0.5, self.end_game)
else:
return super().handlemessage(msg)
return None
def _update_scoreboard(self) -> None:
for team in self.teams:
self._scoreboard.set_team_value(team, team.score,
self._score_to_win)
def end_game(self) -> None:
results = bs.GameResults()
for team in self.teams:
results.set_team_score(team, team.score)
self.end(results=results)
class Player2(bs.Player['Team']):
"""Our player type for this game."""
def __init__(self) -> None:
self.lives = 0
self.icons: List[Icon] = []
class Team2(bs.Team[Player]):
"""Our team type for this game."""
def __init__(self) -> None:
self.survival_seconds: Optional[int] = None
self.spawn_order: List[Player] = []
# ba_meta export bascenev1.GameActivity
class SuperSmashElimination(bs.TeamGameActivity[Player2, Team2]):
name = 'Super Smash Elimination'
description = 'Knock everyone off the map.'
scoreconfig = bs.ScoreConfig(label='Survived',
scoretype=bs.ScoreType.SECONDS,
none_is_winner=True)
# Print messages when players die since it matters here.
announce_player_deaths = True
@classmethod
def get_available_settings(
cls, sessiontype: Type[bs.Session]) -> List[babase.Setting]:
settings = [
bs.IntSetting(
'Lives (0 = Unlimited)',
min_value=0,
default=3,
increment=1,
),
bs.IntChoiceSetting(
'Time Limit',
choices=[
('None', 0),
('1 Minute', 60),
('2 Minutes', 120),
('5 Minutes', 300),
('10 Minutes', 600),
('20 Minutes', 1200),
],
default=0,
),
bs.FloatChoiceSetting(
'Respawn Times',
choices=[
('Shorter', 0.25),
('Short', 0.5),
('Normal', 1.0),
('Long', 2.0),
('Longer', 4.0),
],
default=1.0,
),
bs.BoolSetting('Boxing Gloves', default=False),
bs.BoolSetting('Epic Mode', default=False),
]
return settings
@classmethod
def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool:
return (issubclass(sessiontype, bs.DualTeamSession)
or issubclass(sessiontype, bs.FreeForAllSession))
@classmethod
def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]:
maps = bs.app.classic.getmaps('melee')
for m in ['Lake Frigid', 'Hockey Stadium', 'Football Stadium']:
# remove maps without bounds
maps.remove(m)
return maps
def __init__(self, settings: dict):
super().__init__(settings)
self.lives = int(settings['Lives (0 = Unlimited)'])
self.time_limit_only = (self.lives == 0)
if self.time_limit_only:
settings['Time Limit'] = max(60, settings['Time Limit'])
self._epic_mode = bool(settings['Epic Mode'])
self._time_limit = float(settings['Time Limit'])
self._start_time: Optional[float] = 1.0
self._boxing_gloves = bool(settings['Boxing Gloves'])
self._solo_mode = bool(settings.get('Solo Mode', False))
# Base class overrides.
self.slow_motion = self._epic_mode
self.default_music = (bs.MusicType.EPIC if self._epic_mode else
bs.MusicType.SURVIVAL)
def get_instance_description(self) -> str | Sequence:
return 'Knock everyone off the map.'
def get_instance_description_short(self) -> str | Sequence:
return 'Knock off the map.'
def on_begin(self) -> None:
super().on_begin()
self._start_time = bs.time()
self.setup_standard_time_limit(self._time_limit)
self.setup_standard_powerup_drops(enable_tnt=False)
self._pow = None
self._tnt_drop_timer = bs.timer(1.0 * 0.30,
bs.WeakCall(self._drop_pow_box),
repeat=True)
self._update_icons()
bs.timer(1.0, self.check_end_game, repeat=True)
def _drop_pow_box(self) -> None:
if self._pow is not None and self._pow:
return
if len(self.map.tnt_points) == 0:
return
pos = random.choice(self.map.tnt_points)
pos = (pos[0], pos[1] + 1, pos[2])
self._pow = PowBox(position=pos, velocity=(0.0, 1.0, 0.0))
def on_player_join(self, player: Player) -> None:
if self.has_begun():
if (all(teammate.lives == 0 for teammate in player.team.players)
and player.team.survival_seconds is None):
player.team.survival_seconds = 0
bs.broadcastmessage(
babase.Lstr(resource='playerDelayedJoinText',
subs=[('${PLAYER}', player.getname(full=True))]),
color=(0, 1, 0),
)
return
player.lives = self.lives
# create our icon and spawn
player.icons = [Icon(player,
position=(0.0, 50),
scale=0.8)]
if player.lives > 0 or self.time_limit_only:
self.spawn_player(player)
# dont waste time doing this until begin
if self.has_begun():
self._update_icons()
def on_player_leave(self, player: Player) -> None:
super().on_player_leave(player)
player.icons = None
# update icons in a moment since our team
# will be gone from the list then
bs.timer(0.0, self._update_icons)
bs.timer(0.1, self.check_end_game, repeat=True)
def _update_icons(self) -> None:
# pylint: disable=too-many-branches
# In free-for-all mode, everyone is just lined up along the bottom.
if isinstance(self.session, bs.FreeForAllSession):
count = len(self.teams)
x_offs = 85
xval = x_offs * (count - 1) * -0.5
for team in self.teams:
if len(team.players) > 1:
print('WTF have', len(team.players), 'players in ffa team')
elif len(team.players) == 1:
player = team.players[0]
if len(player.icons) != 1:
print(
'WTF have',
len(player.icons),
'icons in non-solo elim')
for icon in player.icons:
icon.set_position_and_scale((xval, 30), 0.7)
icon.update_for_lives()
xval += x_offs
# In teams mode we split up teams.
else:
if self._solo_mode:
# First off, clear out all icons.
for player in self.players:
player.icons = []
# Now for each team, cycle through our available players
# adding icons.
for team in self.teams:
if team.id == 0:
xval = -60
x_offs = -78
else:
xval = 60
x_offs = 78
is_first = True
test_lives = 1
while True:
players_with_lives = [
p for p in team.spawn_order
if p and p.lives >= test_lives
]
if not players_with_lives:
break
for player in players_with_lives:
player.icons.append(
Icon(player,
position=(xval, (40 if is_first else 25)),
scale=1.0 if is_first else 0.5,
name_maxwidth=130 if is_first else 75,
name_scale=0.8 if is_first else 1.0,
flatness=0.0 if is_first else 1.0,
shadow=0.5 if is_first else 1.0,
show_death=is_first,
show_lives=False))
xval += x_offs * (0.8 if is_first else 0.56)
is_first = False
test_lives += 1
# Non-solo mode.
else:
for team in self.teams:
if team.id == 0:
xval = -50
x_offs = -85
else:
xval = 50
x_offs = 85
for player in team.players:
if len(player.icons) != 1:
print(
'WTF have',
len(player.icons),
'icons in non-solo elim')
for icon in player.icons:
icon.set_position_and_scale((xval, 30), 0.7)
icon.update_for_lives()
xval += x_offs
# overriding the default character spawning..
def spawn_player(self, player: Player) -> bs.Actor:
if isinstance(self.session, bs.DualTeamSession):
position = self.map.get_start_position(player.team.id)
else:
# otherwise do free-for-all spawn locations
position = self.map.get_ffa_start_position(self.players)
angle = None
name = player.getname()
light_color = _math.normalized_color(player.color)
display_color = babase.safecolor(player.color, target_intensity=0.75)
spaz = SSPlayerSpaz(color=player.color,
highlight=player.highlight,
character=player.character,
player=player)
player.actor = spaz
assert spaz.node
# If this is co-op and we're on Courtyard or Runaround, add the
# material that allows us to collide with the player-walls.
# FIXME: Need to generalize this.
if isinstance(self.session, bs.CoopSession) and self.map.getname() in [
'Courtyard', 'Tower D'
]:
mat = self.map.preloaddata['collide_with_wall_material']
assert isinstance(spaz.node.materials, tuple)
assert isinstance(spaz.node.roller_materials, tuple)
spaz.node.materials += (mat, )
spaz.node.roller_materials += (mat, )
spaz.node.name = name
spaz.node.name_color = display_color
spaz.connect_controls_to_player()
# Move to the stand position and add a flash of light.
spaz.handlemessage(
bs.StandMessage(
position,
angle if angle is not None else random.uniform(0, 360)))
self._spawn_sound.play(1, position=spaz.node.position)
light = bs.newnode('light', attrs={'color': light_color})
spaz.node.connectattr('position', light, 'position')
bs.animate(light, 'intensity', {0: 0, 0.25: 1, 0.5: 0})
bs.timer(0.5, light.delete)
# If we have any icons, update their state.
for icon in player.icons:
icon.handle_player_spawned()
if self._boxing_gloves:
spaz.equip_boxing_gloves()
return spaz
def _get_total_team_lives(self, team: Team) -> int:
return sum(player.lives for player in team.players)
def handlemessage(self, msg: Any) -> Any:
if isinstance(msg, bs.PlayerDiedMessage):
# Augment standard behavior.
super().handlemessage(msg)
player: Player = msg.getplayer(Player)
player.lives -= 1
if player.lives < 0:
player.lives = 0
# if we have any icons, update their state
for icon in player.icons:
icon.handle_player_died()
# play big death sound on our last death
# or for every one in solo mode
if player.lives == 0:
SpazFactory.get().single_player_death_sound.play()
# if we hit zero lives we're dead and the game might be over
if player.lives == 0 and not self.time_limit_only:
# If the whole team is now dead, mark their survival time.
if self._get_total_team_lives(player.team) == 0:
assert self._start_time is not None
player.team.survival_seconds = int(bs.time() -
self._start_time)
# we still have lives; yay!
else:
self.respawn_player(player)
bs.timer(0.1, self.check_end_game, repeat=True)
else:
return super().handlemessage(msg)
return None
def check_end_game(self) -> None:
if len(self._get_living_teams()) < 2:
bs.timer(0.5, self.end_game)
def _get_living_teams(self) -> List[Team]:
return [
team for team in self.teams
if len(team.players) > 0 and any(player.lives > 0
for player in team.players)
]
def end_game(self) -> None:
if self.has_ended():
return
results = bs.GameResults()
self._vs_text = None # Kill our 'vs' if its there.
for team in self.teams:
results.set_team_score(team, team.survival_seconds)
self.end(results=results)

View file

@ -1,6 +1,6 @@
# Volley Ball (final) # Volley Ball (final)
# Made by your friend: Freaku / @[Just] Freak#4999 # Made by your friend: Freaku
# Join BCS: # Join BCS:
@ -28,25 +28,24 @@
## 2022 ## 2022
- Code cleanup - Code cleanup
- No longer requires a plugin
- More accurate Goal positions - More accurate Goal positions
""" """
# ba_meta require api 7 # ba_meta require api 8
from __future__ import annotations from __future__ import annotations
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
import _ba import babase
import ba
import random import random
from bastd.actor.playerspaz import PlayerSpaz import bascenev1 as bs
from bastd.actor.scoreboard import Scoreboard from bascenev1lib.actor.playerspaz import PlayerSpaz
from bastd.actor.powerupbox import PowerupBoxFactory from bascenev1lib.actor.scoreboard import Scoreboard
from bastd.actor.bomb import BombFactory from bascenev1lib.actor.powerupbox import PowerupBoxFactory
from bastd.gameutils import SharedObjects from bascenev1lib.actor.bomb import BombFactory
from bascenev1lib.gameutils import SharedObjects
if TYPE_CHECKING: if TYPE_CHECKING:
from typing import Any, Sequence, Dict, Type, List, Optional, Union from typing import Any, Sequence, Dict, Type, List, Optional, Union
@ -59,7 +58,7 @@ class PuckDiedMessage:
self.puck = puck self.puck = puck
class Puck(ba.Actor): class Puck(bs.Actor):
def __init__(self, position: Sequence[float] = (0.0, 1.0, 0.0)): def __init__(self, position: Sequence[float] = (0.0, 1.0, 0.0)):
super().__init__() super().__init__()
shared = SharedObjects.get() shared = SharedObjects.get()
@ -72,16 +71,16 @@ class Puck(ba.Actor):
assert activity is not None assert activity is not None
assert isinstance(activity, VolleyBallGame) assert isinstance(activity, VolleyBallGame)
pmats = [shared.object_material, activity.puck_material] pmats = [shared.object_material, activity.puck_material]
self.node = ba.newnode('prop', self.node = bs.newnode('prop',
delegate=self, delegate=self,
attrs={ attrs={
'model': activity.puck_model, 'mesh': activity.puck_mesh,
'color_texture': activity.puck_tex, 'color_texture': activity.puck_tex,
'body': 'sphere', 'body': 'sphere',
'reflection': 'soft', 'reflection': 'soft',
'reflection_scale': [0.2], 'reflection_scale': [0.2],
'shadow_size': 0.6, 'shadow_size': 0.6,
'model_scale': 0.4, 'mesh_scale': 0.4,
'body_scale': 1.07, 'body_scale': 1.07,
'is_area_of_interest': True, 'is_area_of_interest': True,
'position': self._spawn_pos, 'position': self._spawn_pos,
@ -91,11 +90,11 @@ class Puck(ba.Actor):
# Since it rolls on spawn, lets make gravity # Since it rolls on spawn, lets make gravity
# to 0, and when another node (bomb/spaz) # to 0, and when another node (bomb/spaz)
# touches it. It'll act back as our normie puck! # touches it. It'll act back as our normie puck!
ba.animate(self.node, 'gravity_scale', {0: -0.1, 0.2: 1}, False) bs.animate(self.node, 'gravity_scale', {0: -0.1, 0.2: 1}, False)
# When other node touches, it realises its new gravity_scale # When other node touches, it realises its new gravity_scale
def handlemessage(self, msg: Any) -> Any: def handlemessage(self, msg: Any) -> Any:
if isinstance(msg, ba.DieMessage): if isinstance(msg, bs.DieMessage):
assert self.node assert self.node
self.node.delete() self.node.delete()
activity = self._activity() activity = self._activity()
@ -103,11 +102,11 @@ class Puck(ba.Actor):
activity.handlemessage(PuckDiedMessage(self)) activity.handlemessage(PuckDiedMessage(self))
# If we go out of bounds, move back to where we started. # If we go out of bounds, move back to where we started.
elif isinstance(msg, ba.OutOfBoundsMessage): elif isinstance(msg, bs.OutOfBoundsMessage):
assert self.node assert self.node
self.node.position = self._spawn_pos self.node.position = self._spawn_pos
elif isinstance(msg, ba.HitMessage): elif isinstance(msg, bs.HitMessage):
assert self.node assert self.node
assert msg.force_direction is not None assert msg.force_direction is not None
self.node.handlemessage( self.node.handlemessage(
@ -128,29 +127,29 @@ class Puck(ba.Actor):
super().handlemessage(msg) super().handlemessage(msg)
class Player(ba.Player['Team']): class Player(bs.Player['Team']):
"""Our player type for this game.""" """Our player type for this game."""
class Team(ba.Team[Player]): class Team(bs.Team[Player]):
"""Our team type for this game.""" """Our team type for this game."""
def __init__(self) -> None: def __init__(self) -> None:
self.score = 0 self.score = 0
# ba_meta export game # ba_meta export bascenev1.GameActivity
class VolleyBallGame(ba.TeamGameActivity[Player, Team]): class VolleyBallGame(bs.TeamGameActivity[Player, Team]):
name = 'Volley Ball' name = 'Volley Ball'
description = 'Score some goals.\nby \ue048Freaku' description = 'Score some goals.\nby \ue048Freaku'
available_settings = [ available_settings = [
ba.IntSetting( bs.IntSetting(
'Score to Win', 'Score to Win',
min_value=1, min_value=1,
default=1, default=1,
increment=1, increment=1,
), ),
ba.IntChoiceSetting( bs.IntChoiceSetting(
'Time Limit', 'Time Limit',
choices=[ choices=[
('None', 0), ('None', 0),
@ -162,7 +161,7 @@ class VolleyBallGame(ba.TeamGameActivity[Player, Team]):
], ],
default=0, default=0,
), ),
ba.FloatChoiceSetting( bs.FloatChoiceSetting(
'Respawn Times', 'Respawn Times',
choices=[ choices=[
('Shorter', 0.25), ('Shorter', 0.25),
@ -173,36 +172,36 @@ class VolleyBallGame(ba.TeamGameActivity[Player, Team]):
], ],
default=1.0, default=1.0,
), ),
ba.BoolSetting('Epic Mode', True), bs.BoolSetting('Epic Mode', True),
ba.BoolSetting('Night Mode', False), bs.BoolSetting('Night Mode', False),
ba.BoolSetting('Icy Floor', True), bs.BoolSetting('Icy Floor', True),
ba.BoolSetting('Disable Punch', False), bs.BoolSetting('Disable Punch', False),
ba.BoolSetting('Disable Bombs', False), bs.BoolSetting('Disable Bombs', False),
ba.BoolSetting('Enable Bottom Credits', True), bs.BoolSetting('Enable Bottom Credits', True),
] ]
default_music = ba.MusicType.HOCKEY default_music = bs.MusicType.HOCKEY
@classmethod @classmethod
def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool: def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool:
return issubclass(sessiontype, ba.DualTeamSession) return issubclass(sessiontype, bs.DualTeamSession)
@classmethod @classmethod
def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]:
return ['Open Field', 'Closed Arena'] return ['Open Field', 'Closed Arena']
def __init__(self, settings: dict): def __init__(self, settings: dict):
super().__init__(settings) super().__init__(settings)
shared = SharedObjects.get() shared = SharedObjects.get()
self._scoreboard = Scoreboard() self._scoreboard = Scoreboard()
self._cheer_sound = ba.getsound('cheer') self._cheer_sound = bs.getsound('cheer')
self._chant_sound = ba.getsound('crowdChant') self._chant_sound = bs.getsound('crowdChant')
self._foghorn_sound = ba.getsound('foghorn') self._foghorn_sound = bs.getsound('foghorn')
self._swipsound = ba.getsound('swip') self._swipsound = bs.getsound('swip')
self._whistle_sound = ba.getsound('refWhistle') self._whistle_sound = bs.getsound('refWhistle')
self.puck_model = ba.getmodel('shield') self.puck_mesh = bs.getmesh('shield')
self.puck_tex = ba.gettexture('gameCircleIcon') self.puck_tex = bs.gettexture('gameCircleIcon')
self._puck_sound = ba.getsound('metalHit') self._puck_sound = bs.getsound('metalHit')
self.puck_material = ba.Material() self.puck_material = bs.Material()
self.puck_material.add_actions(actions=(('modify_part_collision', self.puck_material.add_actions(actions=(('modify_part_collision',
'friction', 0.5))) 'friction', 0.5)))
self.puck_material.add_actions(conditions=('they_have_material', self.puck_material.add_actions(conditions=('they_have_material',
@ -233,16 +232,16 @@ class VolleyBallGame(ba.TeamGameActivity[Player, Team]):
conditions=('they_have_material', conditions=('they_have_material',
PowerupBoxFactory.get().powerup_material), PowerupBoxFactory.get().powerup_material),
actions=(('modify_part_collision', 'physical', False), actions=(('modify_part_collision', 'physical', False),
('message', 'their_node', 'at_connect', ba.DieMessage()))) ('message', 'their_node', 'at_connect', bs.DieMessage())))
self._score_region_material = ba.Material() self._score_region_material = bs.Material()
self._score_region_material.add_actions( self._score_region_material.add_actions(
conditions=('they_have_material', self.puck_material), conditions=('they_have_material', self.puck_material),
actions=(('modify_part_collision', 'collide', actions=(('modify_part_collision', 'collide',
True), ('modify_part_collision', 'physical', False), True), ('modify_part_collision', 'physical', False),
('call', 'at_connect', self._handle_score))) ('call', 'at_connect', self._handle_score)))
self._wall_material = ba.Material() self._wall_material = bs.Material()
self._fake_wall_material = ba.Material() self._fake_wall_material = bs.Material()
self._wall_material.add_actions( self._wall_material.add_actions(
actions=( actions=(
@ -282,7 +281,7 @@ class VolleyBallGame(ba.TeamGameActivity[Player, Team]):
)) ))
self.blocks = [] self.blocks = []
self._net_wall_material = ba.Material() self._net_wall_material = bs.Material()
self._net_wall_material.add_actions( self._net_wall_material.add_actions(
conditions=('they_have_material', shared.player_material), conditions=('they_have_material', shared.player_material),
actions=( actions=(
@ -309,7 +308,7 @@ class VolleyBallGame(ba.TeamGameActivity[Player, Team]):
self.net_blocc = [] self.net_blocc = []
self._puck_spawn_pos: Optional[Sequence[float]] = None self._puck_spawn_pos: Optional[Sequence[float]] = None
self._score_regions: Optional[List[ba.NodeActor]] = None self._score_regions: Optional[List[bs.NodeActor]] = None
self._puck: Optional[Puck] = None self._puck: Optional[Puck] = None
self._score_to_win = int(settings['Score to Win']) self._score_to_win = int(settings['Score to Win'])
self._punchie_ = bool(settings['Disable Punch']) self._punchie_ = bool(settings['Disable Punch'])
@ -321,8 +320,8 @@ class VolleyBallGame(ba.TeamGameActivity[Player, Team]):
self._epic_mode = bool(settings['Epic Mode']) self._epic_mode = bool(settings['Epic Mode'])
# Base class overrides. # Base class overrides.
self.slow_motion = self._epic_mode self.slow_motion = self._epic_mode
self.default_music = (ba.MusicType.EPIC if self._epic_mode else self.default_music = (bs.MusicType.EPIC if self._epic_mode else
ba.MusicType.TO_THE_DEATH) bs.MusicType.TO_THE_DEATH)
def get_instance_description(self) -> Union[str, Sequence]: def get_instance_description(self) -> Union[str, Sequence]:
if self._score_to_win == 1: if self._score_to_win == 1:
@ -339,15 +338,15 @@ class VolleyBallGame(ba.TeamGameActivity[Player, Team]):
self.setup_standard_time_limit(self._time_limit) self.setup_standard_time_limit(self._time_limit)
if self._night_mode: if self._night_mode:
ba.getactivity().globalsnode.tint = (0.5, 0.7, 1) bs.getactivity().globalsnode.tint = (0.5, 0.7, 1)
self._puck_spawn_pos = self.map.get_flag_position(None) self._puck_spawn_pos = self.map.get_flag_position(None)
self._spawn_puck() self._spawn_puck()
# Set up the two score regions. # Set up the two score regions.
self._score_regions = [] self._score_regions = []
self._score_regions.append( self._score_regions.append(
ba.NodeActor( bs.NodeActor(
ba.newnode('region', bs.newnode('region',
attrs={ attrs={
'position': (5.7, 0, -0.065), 'position': (5.7, 0, -0.065),
'scale': (10.7, 0.001, 8), 'scale': (10.7, 0.001, 8),
@ -355,8 +354,8 @@ class VolleyBallGame(ba.TeamGameActivity[Player, Team]):
'materials': [self._score_region_material] 'materials': [self._score_region_material]
}))) })))
self._score_regions.append( self._score_regions.append(
ba.NodeActor( bs.NodeActor(
ba.newnode('region', bs.newnode('region',
attrs={ attrs={
'position': (-5.7, 0, -0.065), 'position': (-5.7, 0, -0.065),
'scale': (10.7, 0.001, 8), 'scale': (10.7, 0.001, 8),
@ -364,9 +363,9 @@ class VolleyBallGame(ba.TeamGameActivity[Player, Team]):
'materials': [self._score_region_material] 'materials': [self._score_region_material]
}))) })))
self._update_scoreboard() self._update_scoreboard()
ba.playsound(self._chant_sound) self._chant_sound.play()
if self.credit_text: if self.credit_text:
t = ba.newnode('text', t = bs.newnode('text',
attrs={'text': "Created by Freaku\nVolleyBall", # Disable 'Enable Bottom Credits' when making playlist, No need to edit this lovely... attrs={'text': "Created by Freaku\nVolleyBall", # Disable 'Enable Bottom Credits' when making playlist, No need to edit this lovely...
'scale': 0.7, 'scale': 0.7,
'position': (0, 0), 'position': (0, 0),
@ -376,23 +375,23 @@ class VolleyBallGame(ba.TeamGameActivity[Player, Team]):
'h_align': 'center', 'h_align': 'center',
'v_attach': 'bottom'}) 'v_attach': 'bottom'})
shared = SharedObjects.get() shared = SharedObjects.get()
self.blocks.append(ba.NodeActor(ba.newnode('region', attrs={'position': (0, 2.4, 0), 'scale': ( self.blocks.append(bs.NodeActor(bs.newnode('region', attrs={'position': (0, 2.4, 0), 'scale': (
0.8, 6, 20), 'type': 'box', 'materials': (self._fake_wall_material, )}))) 0.8, 6, 20), 'type': 'box', 'materials': (self._fake_wall_material, )})))
self.net_blocc.append(ba.NodeActor(ba.newnode('region', attrs={'position': (0, 0, 0), 'scale': ( self.net_blocc.append(bs.NodeActor(bs.newnode('region', attrs={'position': (0, 0, 0), 'scale': (
0.6, 2.4, 20), 'type': 'box', 'materials': (self._net_wall_material, )}))) 0.6, 2.4, 20), 'type': 'box', 'materials': (self._net_wall_material, )})))
def on_team_join(self, team: Team) -> None: def on_team_join(self, team: Team) -> None:
self._update_scoreboard() self._update_scoreboard()
def _handle_puck_player_collide(self) -> None: def _handle_puck_player_collide(self) -> None:
collision = ba.getcollision() collision = bs.getcollision()
try: try:
puck = collision.sourcenode.getdelegate(Puck, True) puck = collision.sourcenode.getdelegate(Puck, True)
player = collision.opposingnode.getdelegate(PlayerSpaz, player = collision.opposingnode.getdelegate(PlayerSpaz,
True).getplayer( True).getplayer(
Player, True) Player, True)
except ba.NotFoundError: except bs.NotFoundError:
return return
puck.last_players_to_touch[player.team.id] = player puck.last_players_to_touch[player.team.id] = player
@ -409,7 +408,7 @@ class VolleyBallGame(ba.TeamGameActivity[Player, Team]):
if self._puck.scored: if self._puck.scored:
return return
region = ba.getcollision().sourcenode region = bs.getcollision().sourcenode
index = 0 index = 0
for index in range(len(self._score_regions)): for index in range(len(self._score_regions)):
if region == self._score_regions[index].node: if region == self._score_regions[index].node:
@ -431,7 +430,7 @@ class VolleyBallGame(ba.TeamGameActivity[Player, Team]):
for player in team.players: for player in team.players:
if player.actor: if player.actor:
player.actor.handlemessage(ba.CelebrateMessage(2.0)) player.actor.handlemessage(bs.CelebrateMessage(2.0))
# If we've got the player from the scoring team that last # If we've got the player from the scoring team that last
# touched us, give them points. # touched us, give them points.
@ -446,28 +445,28 @@ class VolleyBallGame(ba.TeamGameActivity[Player, Team]):
if team.score >= self._score_to_win: if team.score >= self._score_to_win:
self.end_game() self.end_game()
ba.playsound(self._foghorn_sound) self._foghorn_sound.play()
ba.playsound(self._cheer_sound) self._cheer_sound.play()
self._puck.scored = True self._puck.scored = True
# Kill the puck (it'll respawn itself shortly). # Kill the puck (it'll respawn itself shortly).
ba.emitfx(position=ba.getcollision().position, count=int( bs.emitfx(position=bs.getcollision().position, count=int(
6.0 + 7.0 * 12), scale=3, spread=0.5, chunk_type='spark') 6.0 + 7.0 * 12), scale=3, spread=0.5, chunk_type='spark')
ba.timer(0.7, self._kill_puck) bs.timer(0.7, self._kill_puck)
ba.cameraflash(duration=7.0) bs.cameraflash(duration=7.0)
self._update_scoreboard() self._update_scoreboard()
def end_game(self) -> None: def end_game(self) -> None:
results = ba.GameResults() results = bs.GameResults()
for team in self.teams: for team in self.teams:
results.set_team_score(team, team.score) results.set_team_score(team, team.score)
self.end(results=results) self.end(results=results)
def on_transition_in(self) -> None: def on_transition_in(self) -> None:
super().on_transition_in() super().on_transition_in()
activity = ba.getactivity() activity = bs.getactivity()
if self._icy_flooor: if self._icy_flooor:
activity.map.is_hockey = True activity.map.is_hockey = True
@ -477,7 +476,7 @@ class VolleyBallGame(ba.TeamGameActivity[Player, Team]):
self._scoreboard.set_team_value(team, team.score, winscore) self._scoreboard.set_team_value(team, team.score, winscore)
# overriding the default character spawning.. # overriding the default character spawning..
def spawn_player(self, player: Player) -> ba.Actor: def spawn_player(self, player: Player) -> bs.Actor:
spaz = self.spawn_player_spaz(player) spaz = self.spawn_player_spaz(player)
if self._bombies_: if self._bombies_:
@ -493,7 +492,7 @@ class VolleyBallGame(ba.TeamGameActivity[Player, Team]):
def handlemessage(self, msg: Any) -> Any: def handlemessage(self, msg: Any) -> Any:
# Respawn dead players if they're still in the game. # Respawn dead players if they're still in the game.
if isinstance(msg, ba.PlayerDiedMessage): if isinstance(msg, bs.PlayerDiedMessage):
# Augment standard behavior... # Augment standard behavior...
super().handlemessage(msg) super().handlemessage(msg)
self.respawn_player(msg.getplayer(Player)) self.respawn_player(msg.getplayer(Player))
@ -501,18 +500,18 @@ class VolleyBallGame(ba.TeamGameActivity[Player, Team]):
# Respawn dead pucks. # Respawn dead pucks.
elif isinstance(msg, PuckDiedMessage): elif isinstance(msg, PuckDiedMessage):
if not self.has_ended(): if not self.has_ended():
ba.timer(2.2, self._spawn_puck) bs.timer(2.2, self._spawn_puck)
else: else:
super().handlemessage(msg) super().handlemessage(msg)
def _flash_puck_spawn(self) -> None: def _flash_puck_spawn(self) -> None:
# Effect >>>>>> Flashly # Effect >>>>>> Flashly
ba.emitfx(position=self._puck_spawn_pos, count=int( bs.emitfx(position=self._puck_spawn_pos, count=int(
6.0 + 7.0 * 12), scale=1.7, spread=0.4, chunk_type='spark') 6.0 + 7.0 * 12), scale=1.7, spread=0.4, chunk_type='spark')
def _spawn_puck(self) -> None: def _spawn_puck(self) -> None:
ba.playsound(self._swipsound) self._swipsound.play()
ba.playsound(self._whistle_sound) self._whistle_sound.play()
self._flash_puck_spawn() self._flash_puck_spawn()
assert self._puck_spawn_pos is not None assert self._puck_spawn_pos is not None
self._puck = Puck(position=self._puck_spawn_pos) self._puck = Puck(position=self._puck_spawn_pos)
@ -538,7 +537,7 @@ class PointzzforH:
points['spawn2'] = (6.857415055, 0.03938567998, 0.0) + (1.0, 1.0, 3.0) points['spawn2'] = (6.857415055, 0.03938567998, 0.0) + (1.0, 1.0, 3.0)
class VolleyBallMap(ba.Map): class VolleyBallMap(bs.Map):
defs = Pointzz() defs = Pointzz()
name = "Open Field" name = "Open Field"
@ -553,10 +552,10 @@ class VolleyBallMap(ba.Map):
@classmethod @classmethod
def on_preload(cls) -> Any: def on_preload(cls) -> Any:
data: Dict[str, Any] = { data: Dict[str, Any] = {
'model': ba.getmodel('footballStadium'), 'mesh': bs.getmesh('footballStadium'),
'vr_fill_model': ba.getmodel('footballStadiumVRFill'), 'vr_fill_mesh': bs.getmesh('footballStadiumVRFill'),
'collide_model': ba.getcollidemodel('footballStadiumCollide'), 'collision_mesh': bs.getcollisionmesh('footballStadiumCollide'),
'tex': ba.gettexture('footballStadium') 'tex': bs.gettexture('footballStadium')
} }
return data return data
@ -565,60 +564,60 @@ class VolleyBallMap(ba.Map):
shared = SharedObjects.get() shared = SharedObjects.get()
x = -5 x = -5
while x < 5: while x < 5:
self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (0, 0, x), self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (0, 0, x),
'color': (1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) 'color': (1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]})
self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (0, .25, x), self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (0, .25, x),
'color': (1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) 'color': (1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]})
self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (0, .5, x), self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (0, .5, x),
'color': (1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) 'color': (1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]})
self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (0, .75, x), self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (0, .75, x),
'color': (1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) 'color': (1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]})
self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (0, 1, x), self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (0, 1, x),
'color': (1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) 'color': (1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]})
x = x + 0.5 x = x + 0.5
y = -1 y = -1
while y > -11: while y > -11:
self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (y, 0.01, 4), self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (y, 0.01, 4),
'color': (0, 0, 1), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) 'color': (0, 0, 1), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]})
self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (y, 0.01, -4), self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (y, 0.01, -4),
'color': (0, 0, 1), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) 'color': (0, 0, 1), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]})
self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (-y, 0.01, 4), self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (-y, 0.01, 4),
'color': (1, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) 'color': (1, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]})
self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (-y, 0.01, -4), self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (-y, 0.01, -4),
'color': (1, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) 'color': (1, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]})
y -= 1 y -= 1
z = 0 z = 0
while z < 5: while z < 5:
self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (11, 0.01, z), self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (11, 0.01, z),
'color': (1, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) 'color': (1, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]})
self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (11, 0.01, -z), self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (11, 0.01, -z),
'color': (1, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) 'color': (1, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]})
self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (-11, 0.01, z), self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (-11, 0.01, z),
'color': (0, 0, 1), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) 'color': (0, 0, 1), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]})
self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (-11, 0.01, -z), self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (-11, 0.01, -z),
'color': (0, 0, 1), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) 'color': (0, 0, 1), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]})
z += 1 z += 1
self.node = ba.newnode( self.node = bs.newnode(
'terrain', 'terrain',
delegate=self, delegate=self,
attrs={ attrs={
'model': self.preloaddata['model'], 'mesh': self.preloaddata['mesh'],
'collide_model': self.preloaddata['collide_model'], 'collision_mesh': self.preloaddata['collision_mesh'],
'color_texture': self.preloaddata['tex'], 'color_texture': self.preloaddata['tex'],
'materials': [shared.footing_material] 'materials': [shared.footing_material]
}) })
ba.newnode('terrain', bs.newnode('terrain',
attrs={ attrs={
'model': self.preloaddata['vr_fill_model'], 'mesh': self.preloaddata['vr_fill_mesh'],
'lighting': False, 'lighting': False,
'vr_only': True, 'vr_only': True,
'background': True, 'background': True,
'color_texture': self.preloaddata['tex'] 'color_texture': self.preloaddata['tex']
}) })
gnode = ba.getactivity().globalsnode gnode = bs.getactivity().globalsnode
gnode.tint = (1.3, 1.2, 1.0) gnode.tint = (1.3, 1.2, 1.0)
gnode.ambient_color = (1.3, 1.2, 1.0) gnode.ambient_color = (1.3, 1.2, 1.0)
gnode.vignette_outer = (0.57, 0.57, 0.57) gnode.vignette_outer = (0.57, 0.57, 0.57)
@ -627,7 +626,7 @@ class VolleyBallMap(ba.Map):
gnode.vr_near_clip = 0.5 gnode.vr_near_clip = 0.5
class VolleyBallMapH(ba.Map): class VolleyBallMapH(bs.Map):
defs = PointzzforH() defs = PointzzforH()
name = 'Closed Arena' name = 'Closed Arena'
@ -642,13 +641,13 @@ class VolleyBallMapH(ba.Map):
@classmethod @classmethod
def on_preload(cls) -> Any: def on_preload(cls) -> Any:
data: Dict[str, Any] = { data: Dict[str, Any] = {
'models': (ba.getmodel('hockeyStadiumOuter'), 'meshs': (bs.getmesh('hockeyStadiumOuter'),
ba.getmodel('hockeyStadiumInner')), bs.getmesh('hockeyStadiumInner')),
'vr_fill_model': ba.getmodel('footballStadiumVRFill'), 'vr_fill_mesh': bs.getmesh('footballStadiumVRFill'),
'collide_model': ba.getcollidemodel('hockeyStadiumCollide'), 'collision_mesh': bs.getcollisionmesh('hockeyStadiumCollide'),
'tex': ba.gettexture('hockeyStadium'), 'tex': bs.gettexture('hockeyStadium'),
} }
mat = ba.Material() mat = bs.Material()
mat.add_actions(actions=('modify_part_collision', 'friction', 0.01)) mat.add_actions(actions=('modify_part_collision', 'friction', 0.01))
data['ice_material'] = mat data['ice_material'] = mat
return data return data
@ -658,66 +657,66 @@ class VolleyBallMapH(ba.Map):
shared = SharedObjects.get() shared = SharedObjects.get()
x = -5 x = -5
while x < 5: while x < 5:
self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (0, 0, x), self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (0, 0, x),
'color': (1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) 'color': (1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]})
self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (0, .25, x), self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (0, .25, x),
'color': (1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) 'color': (1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]})
self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (0, .5, x), self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (0, .5, x),
'color': (1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) 'color': (1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]})
self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (0, .75, x), self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (0, .75, x),
'color': (1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) 'color': (1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]})
self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (0, 1, x), self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (0, 1, x),
'color': (1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) 'color': (1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]})
x = x + 0.5 x = x + 0.5
y = -1 y = -1
while y > -11: while y > -11:
self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (y, 0.01, 4), self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (y, 0.01, 4),
'color': (0, 0, 1), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) 'color': (0, 0, 1), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]})
self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (y, 0.01, -4), self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (y, 0.01, -4),
'color': (0, 0, 1), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) 'color': (0, 0, 1), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]})
self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (-y, 0.01, 4), self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (-y, 0.01, 4),
'color': (1, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) 'color': (1, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]})
self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (-y, 0.01, -4), self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (-y, 0.01, -4),
'color': (1, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) 'color': (1, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]})
y -= 1 y -= 1
z = 0 z = 0
while z < 5: while z < 5:
self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (11, 0.01, z), self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (11, 0.01, z),
'color': (1, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) 'color': (1, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]})
self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (11, 0.01, -z), self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (11, 0.01, -z),
'color': (1, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) 'color': (1, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]})
self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (-11, 0.01, z), self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (-11, 0.01, z),
'color': (0, 0, 1), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) 'color': (0, 0, 1), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]})
self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (-11, 0.01, -z), self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (-11, 0.01, -z),
'color': (0, 0, 1), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) 'color': (0, 0, 1), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]})
z += 1 z += 1
self.node = ba.newnode('terrain', self.node = bs.newnode('terrain',
delegate=self, delegate=self,
attrs={ attrs={
'model': 'mesh':
None, None,
'collide_model': 'collision_mesh':
# we dont want Goalposts... # we dont want Goalposts...
ba.getcollidemodel('footballStadiumCollide'), bs.getcollisionmesh('footballStadiumCollide'),
'color_texture': 'color_texture':
self.preloaddata['tex'], self.preloaddata['tex'],
'materials': [ 'materials': [
shared.footing_material] shared.footing_material]
}) })
ba.newnode('terrain', bs.newnode('terrain',
attrs={ attrs={
'model': self.preloaddata['vr_fill_model'], 'mesh': self.preloaddata['vr_fill_mesh'],
'vr_only': True, 'vr_only': True,
'lighting': False, 'lighting': False,
'background': True, 'background': True,
}) })
mats = [shared.footing_material] mats = [shared.footing_material]
self.floor = ba.newnode('terrain', self.floor = bs.newnode('terrain',
attrs={ attrs={
'model': self.preloaddata['models'][1], 'mesh': self.preloaddata['meshs'][1],
'color_texture': self.preloaddata['tex'], 'color_texture': self.preloaddata['tex'],
'opacity': 0.92, 'opacity': 0.92,
'opacity_in_low_or_medium_quality': 1.0, 'opacity_in_low_or_medium_quality': 1.0,
@ -725,16 +724,16 @@ class VolleyBallMapH(ba.Map):
'color': (0.4, 0.9, 0) 'color': (0.4, 0.9, 0)
}) })
self.background = ba.newnode( self.background = bs.newnode(
'terrain', 'terrain',
attrs={ attrs={
'model': ba.getmodel('natureBackground'), 'mesh': bs.getmesh('natureBackground'),
'lighting': False, 'lighting': False,
'background': True, 'background': True,
'color': (0.5, 0.30, 0.4) 'color': (0.5, 0.30, 0.4)
}) })
gnode = ba.getactivity().globalsnode gnode = bs.getactivity().globalsnode
gnode.floor_reflection = True gnode.floor_reflection = True
gnode.debris_friction = 0.3 gnode.debris_friction = 0.3
gnode.debris_kill_height = -0.3 gnode.debris_kill_height = -0.3
@ -747,5 +746,17 @@ class VolleyBallMapH(ba.Map):
#self.is_hockey = True #self.is_hockey = True
ba._map.register_map(VolleyBallMap) bs._map.register_map(VolleyBallMap)
ba._map.register_map(VolleyBallMapH) bs._map.register_map(VolleyBallMapH)
# ba_meta export plugin
class byFreaku(babase.Plugin):
def __init__(self):
# Reason of plugin:
# To register maps.
#
# Then why not include function here?
# On server upon first launch, plugins are not activated,
# (same can be case for user if disabled auto-enable plugins)
pass

View file

@ -293,10 +293,16 @@
{ {
"name": "Freaku", "name": "Freaku",
"email": "", "email": "",
"discord": "[Just] Freak#4999" "discord": ""
} }
], ],
"versions": { "versions": {
"2.0.0": {
"api_version": 8,
"commit_sha": "48f9302",
"released_on": "28-07-2023",
"md5sum": "31df84f027c98e86336a420aa509e47f"
},
"1.0.0": { "1.0.0": {
"api_version": 7, "api_version": 7,
"commit_sha": "6beb8ddf", "commit_sha": "6beb8ddf",
@ -312,10 +318,16 @@
{ {
"name": "Freaku", "name": "Freaku",
"email": "", "email": "",
"discord": "[Just] Freak#4999" "discord": ""
} }
], ],
"versions": { "versions": {
"2.0.0": {
"api_version": 8,
"commit_sha": "48f9302",
"released_on": "28-07-2023",
"md5sum": "ef2dbcac9190a61753e2c3c0f8afc22c"
},
"1.1.0": { "1.1.0": {
"api_version": 7, "api_version": 7,
"commit_sha": "383f774", "commit_sha": "383f774",
@ -505,10 +517,16 @@
{ {
"name": "Freaku", "name": "Freaku",
"email": "", "email": "",
"discord": "[Just] Freak#4999" "discord": ""
} }
], ],
"versions": { "versions": {
"2.0.0": {
"api_version": 8,
"commit_sha": "48f9302",
"released_on": "28-07-2023",
"md5sum": "8a63ad58d24e2b61bb63645f74d876e8"
},
"1.0.0": { "1.0.0": {
"api_version": 7, "api_version": 7,
"commit_sha": "b581d90", "commit_sha": "b581d90",

View file

@ -1,4 +1,4 @@
# Ported by: Freaku / @[Just] Freak#4999 # Ported by your friend: Freaku
# Join BCS: # Join BCS:
# https://discord.gg/ucyaesh # https://discord.gg/ucyaesh
@ -8,27 +8,30 @@
# https://github.com/Freaku17/BombSquad-Mods-byFreaku # https://github.com/Freaku17/BombSquad-Mods-byFreaku
# ba_meta require api 7 # ba_meta require api 8
from __future__ import annotations from __future__ import annotations
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
import _ba import _babase
import ba import babase
import random import random
import math import math
from bastd.gameutils import SharedObjects import bauiv1 as bui
from bastd.actor.bomb import Bomb import bascenev1 as bs
from bastd.actor.popuptext import PopupText from bascenev1lib.gameutils import SharedObjects
from bascenev1lib.actor.bomb import Bomb
from bascenev1lib.actor.popuptext import PopupText
from bauiv1lib.party import PartyWindow
if TYPE_CHECKING: if TYPE_CHECKING:
from typing import Optional from typing import Optional
class Floater(ba.Actor): class Floater(bs.Actor):
def __init__(self, bounds): def __init__(self, bounds):
super().__init__() super().__init__()
shared = SharedObjects.get() shared = SharedObjects.get()
self.controlled = False self.controlled = False
self.source_player = None self.source_player = None
self.floaterMaterial = ba.Material() self.floaterMaterial = bs.Material()
self.floaterMaterial.add_actions( self.floaterMaterial.add_actions(
conditions=('they_have_material', conditions=('they_have_material',
shared.player_material), shared.player_material),
@ -48,21 +51,21 @@ class Floater(ba.Actor):
self.py = "random.uniform(self.pos[1],self.pos[4])" self.py = "random.uniform(self.pos[1],self.pos[4])"
self.pz = "random.uniform(self.pos[2],self.pos[5])" self.pz = "random.uniform(self.pos[2],self.pos[5])"
self.node = ba.newnode( self.node = bs.newnode(
'prop', 'prop',
delegate=self, delegate=self,
owner=None, owner=None,
attrs={ attrs={
'position': (eval(self.px), eval(self.py), eval(self.pz)), 'position': (eval(self.px), eval(self.py), eval(self.pz)),
'model': 'mesh':
ba.getmodel('landMine'), bs.getmesh('landMine'),
'light_model': 'light_mesh':
ba.getmodel('landMine'), bs.getmesh('landMine'),
'body': 'body':
'landMine', 'landMine',
'body_scale': 'body_scale':
3, 3,
'model_scale': 'mesh_scale':
3.1, 3.1,
'shadow_size': 'shadow_size':
0.25, 0.25,
@ -71,21 +74,21 @@ class Floater(ba.Actor):
'gravity_scale': 'gravity_scale':
0.0, 0.0,
'color_texture': 'color_texture':
ba.gettexture('achievementFlawlessVictory'), bs.gettexture('achievementFlawlessVictory'),
'reflection': 'reflection':
'soft', 'soft',
'reflection_scale': [0.25], 'reflection_scale': [0.25],
'materials': 'materials':
[shared.footing_material, self.floaterMaterial] [shared.footing_material, self.floaterMaterial]
}) })
self.node2 = ba.newnode( self.node2 = bs.newnode(
'prop', 'prop',
owner=self.node, owner=self.node,
attrs={ attrs={
'position': (0, 0, 0), 'position': (0, 0, 0),
'body': 'body':
'sphere', 'sphere',
'model': 'mesh':
None, None,
'color_texture': 'color_texture':
None, None,
@ -96,7 +99,7 @@ class Floater(ba.Actor):
'density': 'density':
999999, 999999,
'reflection_scale': [1.0], 'reflection_scale': [1.0],
'model_scale': 'mesh_scale':
1.0, 1.0,
'gravity_scale': 'gravity_scale':
0, 0,
@ -110,7 +113,7 @@ class Floater(ba.Actor):
self.node.connectattr('position', self.node2, 'position') self.node.connectattr('position', self.node2, 'position')
def pop(self): PopupText(text="Ported by \ue048Freaku", scale=1.3, position=( def pop(self): PopupText(text="Ported by \ue048Freaku", scale=1.3, position=(
self.node.position[0], self.node.position[1]-1, self.node.position[2]), color=(0, 1, 1)).autoretain() # Edit = YouNoob... self.node.position[0], self.node.position[1]-1, self.node.position[2]), color=(0, 1, 1)).autoretain()
def checkCanControl(self): def checkCanControl(self):
if not self.node.exists(): if not self.node.exists():
@ -172,7 +175,7 @@ class Floater(ba.Actor):
if self.source_player is None: if self.source_player is None:
return return
if self.source_player.is_alive(): if self.source_player.is_alive():
ba.timer(1, self.checkPlayerDie) bs.timer(1, self.checkPlayerDie)
return return
else: else:
self.dis() self.dis()
@ -199,22 +202,22 @@ class Floater(ba.Actor):
pn = self.node.position pn = self.node.position
dist = self.distance(pn[0], pn[1], pn[2], px, py, pz) dist = self.distance(pn[0], pn[1], pn[2], px, py, pz)
self.node.velocity = ((px - pn[0]) / dist, (py - pn[1]) / dist, (pz - pn[2]) / dist) self.node.velocity = ((px - pn[0]) / dist, (py - pn[1]) / dist, (pz - pn[2]) / dist)
ba.timer(dist-1, ba.WeakCall(self.move), suppress_format_warning=True) bs.timer(dist-1, bs.WeakCall(self.move)) # suppress_format_warning=True)
def handlemessage(self, msg): def handlemessage(self, msg):
if isinstance(msg, ba.DieMessage): if isinstance(msg, bs.DieMessage):
self.node.delete() self.node.delete()
self.node2.delete() self.node2.delete()
self.controlled = False self.controlled = False
elif isinstance(msg, ba.OutOfBoundsMessage): elif isinstance(msg, bs.OutOfBoundsMessage):
self.handlemessage(ba.DieMessage()) self.handlemessage(bs.DieMessage())
else: else:
super().handlemessage(msg) super().handlemessage(msg)
def assignFloInputs(clientID: int): def assignFloInputs(clientID: int):
with ba.Context(_ba.get_foreground_host_activity()): activity = bs.get_foreground_host_activity()
activity = ba.getactivity() with activity.context:
if not hasattr(activity, 'flo') or not activity.flo.node.exists(): if not hasattr(activity, 'flo') or not activity.flo.node.exists():
try: try:
activity.flo = Floater(activity.map.get_def_bound_box('map_bounds')) activity.flo = Floater(activity.map.get_def_bound_box('map_bounds'))
@ -222,13 +225,13 @@ def assignFloInputs(clientID: int):
return # Perhaps using in main-menu/score-screen return # Perhaps using in main-menu/score-screen
floater = activity.flo floater = activity.flo
if floater.controlled: if floater.controlled:
ba.screenmessage('Floater is already being controlled', bs.broadcastmessage('Floater is already being controlled',
color=(1, 0, 0), transient=True, clients=[clientID]) color=(1, 0, 0), transient=True, clients=[clientID])
return return
ba.screenmessage('You Gained Control Over The Floater!\n Press Bomb to Throw Bombs and Punch to leave!', clients=[ bs.broadcastmessage('You Gained Control Over The Floater!\n Press Bomb to Throw Bombs and Punch to leave!', clients=[
clientID], transient=True, color=(0, 1, 1)) clientID], transient=True, color=(0, 1, 1))
for i in _ba.get_foreground_host_activity().players: for i in activity.players:
if i.sessionplayer.inputdevice.client_id == clientID: if i.sessionplayer.inputdevice.client_id == clientID:
def dis(i, floater): def dis(i, floater):
i.actor.node.invincible = False i.actor.node.invincible = False
@ -238,41 +241,54 @@ def assignFloInputs(clientID: int):
ps = i.actor.node.position ps = i.actor.node.position
i.actor.node.invincible = True i.actor.node.invincible = True
floater.node.position = (ps[0], ps[1] + 1.0, ps[2]) floater.node.position = (ps[0], ps[1] + 1.0, ps[2])
ba.timer(1, floater.pop) bs.timer(1, floater.pop)
i.actor.node.hold_node = ba.Node(None) i.actor.node.hold_node = bs.Node(None)
i.actor.node.hold_node = floater.node2 i.actor.node.hold_node = floater.node2
i.actor.connect_controls_to_player() i.actor.connect_controls_to_player()
i.actor.disconnect_controls_from_player() i.actor.disconnect_controls_from_player()
i.resetinput() i.resetinput()
floater.source_player = i floater.source_player = i
floater.con() floater.con()
i.assigninput(ba.InputType.PICK_UP_PRESS, floater.up) i.assigninput(babase.InputType.PICK_UP_PRESS, floater.up)
i.assigninput(ba.InputType.PICK_UP_RELEASE, floater.upR) i.assigninput(babase.InputType.PICK_UP_RELEASE, floater.upR)
i.assigninput(ba.InputType.JUMP_PRESS, floater.down) i.assigninput(babase.InputType.JUMP_PRESS, floater.down)
i.assigninput(ba.InputType.BOMB_PRESS, floater.drop) i.assigninput(babase.InputType.BOMB_PRESS, floater.drop)
i.assigninput(ba.InputType.PUNCH_PRESS, ba.Call(dis, i, floater)) i.assigninput(babase.InputType.PUNCH_PRESS, babase.Call(dis, i, floater))
i.assigninput(ba.InputType.UP_DOWN, floater.updown) i.assigninput(babase.InputType.UP_DOWN, floater.updown)
i.assigninput(ba.InputType.LEFT_RIGHT, floater.leftright) i.assigninput(babase.InputType.LEFT_RIGHT, floater.leftright)
old_fcm = _ba.chatmessage # Display chat icon, but if user open/close gather it may disappear
bui.set_party_icon_always_visible(True)
def new_chat_message(msg: Union[str, ba.Lstr], clients: Sequence[int] = None, sender_override: str = None): old_piv = bui.set_party_icon_always_visible
old_fcm(msg, clients, sender_override)
if msg == '/floater':
def new_piv(*args, **kwargs):
# Do not let chat icon go away
old_piv(True)
bui.set_party_icon_always_visible = new_piv
old_fcm = bs.chatmessage
def new_chat_message(*args, **kwargs):
old_fcm(*args, **kwargs)
if args[0] == '/floater':
try: try:
assignFloInputs(-1) assignFloInputs(-1)
except: except:
pass pass
_ba.chatmessage = new_chat_message bs.chatmessage = new_chat_message
if not _ba.is_party_icon_visible():
_ba.set_party_icon_always_visible(True)
# ba_meta export plugin # ba_meta export plugin
class byFreaku(ba.Plugin): class byFreaku(babase.Plugin):
def __init__(self): pass def __init__(self): pass

View file

@ -1,4 +1,4 @@
# Made by: Freaku / @[Just] Freak#4999 # Made by your friend: Freaku
# • Icon Keyboard • # • Icon Keyboard •
# Make your chats look even more cooler! # Make your chats look even more cooler!
@ -6,51 +6,52 @@
# Double tap the space to change between keyboards... # Double tap the space to change between keyboards...
# ba_meta require api 7 # ba_meta require api 8
from __future__ import annotations from __future__ import annotations
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
import ba import babase
from _ba import charstr as uwu import bascenev1 as bs
from babase import charstr as uwu
if TYPE_CHECKING: if TYPE_CHECKING:
from typing import Any, Optional, Dict, List, Tuple, Type, Iterable from typing import Any, Optional, Dict, List, Tuple, Type, Iterable
# ba_meta export keyboard # ba_meta export keyboard
class IconKeyboard_byFreaku(ba.Keyboard): class IconKeyboard_byFreaku(babase.Keyboard):
"""Keyboard go brrrrrrr""" """Keyboard go brrrrrrr"""
name = 'Icons by \ue048Freaku' name = 'Icons by \ue048Freaku'
chars = [(uwu(ba.SpecialChar.TICKET), chars = [(uwu(babase.SpecialChar.TICKET),
uwu(ba.SpecialChar.CROWN), uwu(babase.SpecialChar.CROWN),
uwu(ba.SpecialChar.DRAGON), uwu(babase.SpecialChar.DRAGON),
uwu(ba.SpecialChar.SKULL), uwu(babase.SpecialChar.SKULL),
uwu(ba.SpecialChar.HEART), uwu(babase.SpecialChar.HEART),
uwu(ba.SpecialChar.FEDORA), uwu(babase.SpecialChar.FEDORA),
uwu(ba.SpecialChar.HAL), uwu(babase.SpecialChar.HAL),
uwu(ba.SpecialChar.YIN_YANG), uwu(babase.SpecialChar.YIN_YANG),
uwu(ba.SpecialChar.EYE_BALL), uwu(babase.SpecialChar.EYE_BALL),
uwu(ba.SpecialChar.HELMET), uwu(babase.SpecialChar.HELMET),
uwu(ba.SpecialChar.OUYA_BUTTON_U)), uwu(babase.SpecialChar.OUYA_BUTTON_U)),
(uwu(ba.SpecialChar.MUSHROOM), (uwu(babase.SpecialChar.MUSHROOM),
uwu(ba.SpecialChar.NINJA_STAR), uwu(babase.SpecialChar.NINJA_STAR),
uwu(ba.SpecialChar.VIKING_HELMET), uwu(babase.SpecialChar.VIKING_HELMET),
uwu(ba.SpecialChar.MOON), uwu(babase.SpecialChar.MOON),
uwu(ba.SpecialChar.SPIDER), uwu(babase.SpecialChar.SPIDER),
uwu(ba.SpecialChar.FIREBALL), uwu(babase.SpecialChar.FIREBALL),
uwu(ba.SpecialChar.MIKIROG), uwu(babase.SpecialChar.MIKIROG),
uwu(ba.SpecialChar.OUYA_BUTTON_O), uwu(babase.SpecialChar.OUYA_BUTTON_O),
uwu(ba.SpecialChar.LOCAL_ACCOUNT), uwu(babase.SpecialChar.LOCAL_ACCOUNT),
uwu(ba.SpecialChar.LOGO)), uwu(babase.SpecialChar.LOGO)),
(uwu(ba.SpecialChar.TICKET), (uwu(babase.SpecialChar.TICKET),
uwu(ba.SpecialChar.FLAG_INDIA), uwu(babase.SpecialChar.FLAG_INDIA),
uwu(ba.SpecialChar.OCULUS_LOGO), uwu(babase.SpecialChar.OCULUS_LOGO),
uwu(ba.SpecialChar.STEAM_LOGO), uwu(babase.SpecialChar.STEAM_LOGO),
uwu(ba.SpecialChar.NVIDIA_LOGO), uwu(babase.SpecialChar.NVIDIA_LOGO),
uwu(ba.SpecialChar.GAME_CENTER_LOGO), uwu(babase.SpecialChar.GAME_CENTER_LOGO),
uwu(ba.SpecialChar.GOOGLE_PLAY_GAMES_LOGO), uwu(babase.SpecialChar.GOOGLE_PLAY_GAMES_LOGO),
uwu(ba.SpecialChar.ALIBABA_LOGO))] uwu(babase.SpecialChar.EXPLODINARY_LOGO))]
nums = [] nums = []
pages: Dict[str, Tuple[str, ...]] = {} pages: Dict[str, Tuple[str, ...]] = {}

View file

@ -1,8 +1,9 @@
# By Freaku / @[Just] Freak#4999 # Made by your friend: Freaku
import ba import babase
from bastd.maps import TowerD import bascenev1 as bs
from bascenev1lib.maps import TowerD
@classmethod @classmethod
@ -11,8 +12,8 @@ def new_play_types(cls):
return ['melee', 'keep_away', 'team_flag', 'king_of_the_hill'] return ['melee', 'keep_away', 'team_flag', 'king_of_the_hill']
# ba_meta require api 7 # ba_meta require api 8
# ba_meta export plugin # ba_meta export plugin
class byFreaku(ba.Plugin): class byFreaku(babase.Plugin):
def on_app_running(self): def on_app_running(self):
TowerD.get_play_types = new_play_types TowerD.get_play_types = new_play_types