Add files via upload

This commit is contained in:
Sarasayed0118 2024-04-09 16:29:45 +05:30 committed by GitHub
parent 53eacf8054
commit 5770706684
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 3629 additions and 1341 deletions

View file

@ -0,0 +1,268 @@
#BetterDeathMatch
#Made by your friend: @[Just] Freak#4999
"""Defines a very-customisable DeathMatch mini-game"""
# ba_meta require api 7
from __future__ import annotations
from typing import TYPE_CHECKING
import ba
from bastd.actor.playerspaz import PlayerSpaz
from bastd.actor.scoreboard import Scoreboard
if TYPE_CHECKING:
from typing import Any, Type, List, Dict, Tuple, Union, Sequence, Optional
class Player(ba.Player['Team']):
"""Our player type for this game."""
class Team(ba.Team[Player]):
"""Our team type for this game."""
def __init__(self) -> None:
self.score = 0
# ba_meta export game
class BetterDeathMatchGame(ba.TeamGameActivity[Player, Team]):
"""A game type based on acquiring kills."""
name = 'Btrr Death Match'
description = 'Kill a set number of enemies to win.\nbyFREAK'
# Print messages when players die since it matters here.
announce_player_deaths = True
@classmethod
def get_available_settings(
cls, sessiontype: Type[ba.Session]) -> List[ba.Setting]:
settings = [
ba.IntSetting(
'Kills to Win Per Player',
min_value=1,
default=5,
increment=1,
),
ba.IntChoiceSetting(
'Time Limit',
choices=[
('None', 0),
('1 Minute', 60),
('2 Minutes', 120),
('5 Minutes', 300),
('10 Minutes', 600),
('20 Minutes', 1200),
],
default=0,
),
ba.FloatChoiceSetting(
'Respawn Times',
choices=[
('Shorter', 0.25),
('Short', 0.5),
('Normal', 1.0),
('Long', 2.0),
('Longer', 4.0),
],
default=1.0,
),
ba.BoolSetting('Epic Mode', default=False),
## Add settings ##
ba.BoolSetting('Enable Gloves', False),
ba.BoolSetting('Enable Powerups', True),
ba.BoolSetting('Night Mode', False),
ba.BoolSetting('Icy Floor', False),
ba.BoolSetting('One Punch Kill', False),
ba.BoolSetting('Spawn with Shield', False),
ba.BoolSetting('Punching Only', False),
## Add settings ##
]
# In teams mode, a suicide gives a point to the other team, but in
# free-for-all it subtracts from your own score. By default we clamp
# this at zero to benefit new players, but pro players might like to
# be able to go negative. (to avoid a strategy of just
# suiciding until you get a good drop)
if issubclass(sessiontype, ba.FreeForAllSession):
settings.append(
ba.BoolSetting('Allow Negative Scores', default=False))
return settings
@classmethod
def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool:
return (issubclass(sessiontype, ba.DualTeamSession)
or issubclass(sessiontype, ba.FreeForAllSession))
@classmethod
def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]:
return ba.getmaps('melee')
def __init__(self, settings: dict):
super().__init__(settings)
self._scoreboard = Scoreboard()
self._score_to_win: Optional[int] = None
self._dingsound = ba.getsound('dingSmall')
## Take applied settings ##
self._boxing_gloves = bool(settings['Enable Gloves'])
self._enable_powerups = bool(settings['Enable Powerups'])
self._night_mode = bool(settings['Night Mode'])
self._icy_floor = bool(settings['Icy Floor'])
self._one_punch_kill = bool(settings['One Punch Kill'])
self._shield_ = bool(settings['Spawn with Shield'])
self._only_punch = bool(settings['Punching Only'])
## Take applied settings ##
self._epic_mode = bool(settings['Epic Mode'])
self._kills_to_win_per_player = int(
settings['Kills to Win Per Player'])
self._time_limit = float(settings['Time Limit'])
self._allow_negative_scores = bool(
settings.get('Allow Negative Scores', False))
# Base class overrides.
self.slow_motion = self._epic_mode
self.default_music = (ba.MusicType.EPIC if self._epic_mode else
ba.MusicType.TO_THE_DEATH)
def get_instance_description(self) -> Union[str, Sequence]:
return 'Crush ${ARG1} of your enemies. byFREAK', self._score_to_win
def get_instance_description_short(self) -> Union[str, Sequence]:
return 'kill ${ARG1} enemies. byFREAK', self._score_to_win
def on_team_join(self, team: Team) -> None:
if self.has_begun():
self._update_scoreboard()
## Run settings related: IcyFloor ##
def on_transition_in(self) -> None:
super().on_transition_in()
activity = ba.getactivity()
if self._icy_floor:
activity.map.is_hockey = True
else:
return
## Run settings related: IcyFloor ##
def on_begin(self) -> None:
super().on_begin()
self.setup_standard_time_limit(self._time_limit)
## Run settings related: NightMode,Powerups ##
if self._night_mode:
ba.getactivity().globalsnode.tint = (0.5, 0.7, 1)
else:
pass
#-# Tried return here, pfft. Took me 30mins to figure out why pwps spawning only on NightMode
#-# Now its fixed :)
if self._enable_powerups:
self.setup_standard_powerup_drops()
else:
pass
## Run settings related: NightMode,Powerups ##
# Base kills needed to win on the size of the largest team.
self._score_to_win = (self._kills_to_win_per_player *
max(1, max(len(t.players) for t in self.teams)))
self._update_scoreboard()
def handlemessage(self, msg: Any) -> Any:
if isinstance(msg, ba.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, ba.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:
ba.playsound(self._dingsound)
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
ba.playsound(self._dingsound)
# 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):
ba.timer(0.5, self.end_game)
else:
return super().handlemessage(msg)
return None
## Run settings related: Spaz ##
def spawn_player(self, player: Player) -> ba.Actor:
spaz = self.spawn_player_spaz(player)
if self._boxing_gloves:
spaz.equip_boxing_gloves()
if self._one_punch_kill:
spaz._punch_power_scale = 15
if self._shield_:
spaz.equip_shields()
if self._only_punch:
spaz.connect_controls_to_player(enable_bomb=False, enable_pickup=False)
return spaz
## Run settings related: Spaz ##
def _update_scoreboard(self) -> None:
for team in self.teams:
self._scoreboard.set_team_value(team, team.score,
self._score_to_win)
def end_game(self) -> None:
results = ba.GameResults()
for team in self.teams:
results.set_team_score(team, team.score)
self.end(results=results)

View file

@ -1,4 +1,4 @@
# ba_meta require api 6
# ba_meta require api 7
#self._has_boxing_gloves = True
from __future__ import annotations

191
dist/ba_root/mods/games/BotShower.py vendored Normal file
View file

@ -0,0 +1,191 @@
# ba_meta require api 7
from __future__ import annotations
from typing import TYPE_CHECKING
import ba, random
from bastd.actor.onscreentimer import OnScreenTimer
from bastd.actor.spazbot import (
SpazBot, SpazBotSet,
BomberBot, BrawlerBot, BouncyBot,
ChargerBot, StickyBot, TriggerBot,
ExplodeyBot)
if TYPE_CHECKING:
from typing import Any, List, Type, Optional
class Player(ba.Player['Team']):
"""Our player type for this game."""
def __init__(self) -> None:
super().__init__()
self.death_time: Optional[float] = None
class Team(ba.Team[Player]):
"""Our team type for this game."""
# ba_meta export game
class BotShowerGame(ba.TeamGameActivity[Player, Team]):
"""A ba.MeteorShowerGame but replaced with bots."""
name = 'Bot Shower'
description = 'Survive from the bots.'
available_settings = [
ba.BoolSetting('Spaz', default=True),
ba.BoolSetting('Zoe', default=True),
ba.BoolSetting('Kronk', default=True),
ba.BoolSetting('Snake Shadow', default=True),
ba.BoolSetting('Mel', default=True),
ba.BoolSetting('Jack Morgan', default=True),
ba.BoolSetting('Easter Bunny', default=True),
ba.BoolSetting('Epic Mode', default=False),
]
announce_player_deaths = True
@classmethod
def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]:
return ['Football Stadium', 'Hockey Stadium']
def __init__(self, settings: dict) -> None:
super().__init__(settings)
self._epic_mode = settings['Epic Mode']
self._last_player_death_time: Optional[float] = None
self._timer: Optional[OnScreenTimer] = None
self._bots: Optional[SpazBotSet] = None
self._bot_type: List[SpazBot] = []
if bool(settings['Spaz']) == True:
self._bot_type.append(BomberBot)
else:
if BomberBot in self._bot_type:
self._bot_type.remove(BomberBot)
if bool(settings['Zoe']) == True:
self._bot_type.append(TriggerBot)
else:
if TriggerBot in self._bot_type:
self._bot_type.remove(TriggerBot)
if bool(settings['Kronk']) == True:
self._bot_type.append(BrawlerBot)
else:
if BrawlerBot in self._bot_type:
self._bot_type.remove(BrawlerBot)
if bool(settings['Snake Shadow']) == True:
self._bot_type.append(ChargerBot)
else:
if ChargerBot in self._bot_type:
self._bot_type.remove(ChargerBot)
if bool(settings['Jack Morgan']) == True:
self._bot_type.append(ExplodeyBot)
else:
if ExplodeyBot in self._bot_type:
self._bot_type.remove(ExplodeyBot)
if bool(settings['Easter Bunny']) == True:
self._bot_type.append(BouncyBot)
else:
if BouncyBot in self._bot_type:
self._bot_type.remove(BouncyBot)
self.slow_motion = self._epic_mode
self.default_music = (ba.MusicType.EPIC
if self._epic_mode else ba.MusicType.SURVIVAL)
def on_begin(self) -> None:
super().on_begin()
self._bots = SpazBotSet()
self._timer = OnScreenTimer()
self._timer.start()
if self._epic_mode:
ba.timer(1.0, self._start_spawning_bots)
else:
ba.timer(5.0, self._start_spawning_bots)
ba.timer(5.0, self._check_end_game)
def spawn_player(self, player: Player) -> None:
spaz = self.spawn_player_spaz(player)
spaz.connect_controls_to_player(
enable_punch=False,
enable_bomb=False,
enable_pickup=False)
return spaz
def on_player_join(self, player: Player) -> None:
if self.has_begun():
ba.screenmessage(
ba.Lstr(resource='playerDelayedJoinText',
subs=[('${PLAYER}', player.getname(full=True))]),
color=(1, 1, 0),
)
assert self._timer is not None
player.death_time = self._timer.getstarttime()
return
self.spawn_player(player)
def handlemessage(self, msg: Any) -> Any:
if isinstance(msg, ba.PlayerDiedMessage):
curtime = ba.time()
msg.getplayer(Player).death_time = curtime
ba.timer(1.0, self._check_end_game)
else:
super().handlemessage(msg)
def _start_spawning_bots(self) -> None:
ba.timer(1.2, self._spawn_bot, repeat=True)
ba.timer(2.2, self._spawn_bot, repeat=True)
def _spawn_bot(self) -> None:
assert self._bots is not None
self._bots.spawn_bot(random.choice(self._bot_type), pos=(random.uniform(-11, 11), (9.8 if self.map.getname() == 'Football Stadium' else 5.0), random.uniform(-5, 5)))
def _check_end_game(self) -> None:
living_team_count = 0
for team in self.teams:
for player in team.players:
if player.is_alive():
living_team_count += 1
break
if living_team_count <= 1:
self.end_game()
def end_game(self) -> None:
cur_time = ba.time()
assert self._timer is not None
start_time = self._timer.getstarttime()
for team in self.teams:
for player in team.players:
survived = False
if player.death_time is None:
survived = True
player.death_time = cur_time + 1
score = int(player.death_time - self._timer.getstarttime())
if survived:
score += 50
self.stats.player_scored(player, score, screenmessage=False)
self._timer.stop(endtime=self._last_player_death_time)
results = ba.GameResults()
for team in self.teams:
longest_life = 0.0
for player in team.players:
assert player.death_time is not None
longest_life = max(longest_life,
player.death_time - start_time)
results.set_team_score(team, int(1000.0 * longest_life))
self.end(results=results)

View file

@ -2,7 +2,7 @@
#
"""DeathMatch game and support classes."""
# ba_meta require api 6
# ba_meta require api 7
# (see https://ballistica.net/wiki/meta-tag-system)
from __future__ import annotations

199
dist/ba_root/mods/games/CanonFight.py vendored Normal file
View file

@ -0,0 +1,199 @@
# Released under the MIT License. See LICENSE for details.
#
"""DeathMatch game and support classes."""
# ba_meta require api 7
# (see https://ballistica.net/wiki/meta-tag-system)
from __future__ import annotations
from typing import TYPE_CHECKING
import ba
from bastd.actor.playerspaz import PlayerSpaz
from bastd.actor.scoreboard import Scoreboard
if TYPE_CHECKING:
from typing import Any, Union, Sequence, Optional
class Player(ba.Player['Team']):
"""Our player type for this game."""
class Team(ba.Team[Player]):
"""Our team type for this game."""
def __init__(self) -> None:
self.score = 0
# ba_meta export game
class CanonFightGame(ba.TeamGameActivity[Player, Team]):
"""A game type based on acquiring kills."""
name = 'Canon Fight'
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[ba.Session]) -> list[ba.Setting]:
settings = [
ba.IntSetting(
'Kills to Win Per Player',
min_value=1,
default=5,
increment=1,
),
ba.IntChoiceSetting(
'Time Limit',
choices=[
('None', 0),
('1 Minute', 60),
('2 Minutes', 120),
('5 Minutes', 300),
('10 Minutes', 600),
('20 Minutes', 1200),
],
default=0,
),
ba.FloatChoiceSetting(
'Respawn Times',
choices=[
('Shorter', 0.25),
('Short', 0.5),
('Normal', 1.0),
('Long', 2.0),
('Longer', 4.0),
],
default=1.0,
),
ba.BoolSetting('Epic Mode', default=False),
]
# In teams mode, a suicide gives a point to the other team, but in
# free-for-all it subtracts from your own score. By default we clamp
# this at zero to benefit new players, but pro players might like to
# be able to go negative. (to avoid a strategy of just
# suiciding until you get a good drop)
if issubclass(sessiontype, ba.FreeForAllSession):
settings.append(
ba.BoolSetting('Allow Negative Scores', default=False))
return settings
@classmethod
def supports_session_type(cls, sessiontype: type[ba.Session]) -> bool:
return (issubclass(sessiontype, ba.DualTeamSession)
or issubclass(sessiontype, ba.FreeForAllSession))
@classmethod
def get_supported_maps(cls, sessiontype: type[ba.Session]) -> list[str]:
return ["Step Right Up"]
def __init__(self, settings: dict):
super().__init__(settings)
self._scoreboard = Scoreboard()
self._score_to_win: Optional[int] = None
self._dingsound = ba.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 = (ba.MusicType.EPIC if self._epic_mode else
ba.MusicType.TO_THE_DEATH)
def get_instance_description(self) -> Union[str, Sequence]:
return 'Crush ${ARG1} of your enemies.', self._score_to_win
def get_instance_description_short(self) -> Union[str, Sequence]:
return 'kill ${ARG1} enemies', self._score_to_win
def on_team_join(self, team: Team) -> None:
if self.has_begun():
self._update_scoreboard()
def on_begin(self) -> None:
super().on_begin()
self.setup_standard_time_limit(self._time_limit)
self.setup_standard_powerup_drops()
# Base kills needed to win on the size of the largest team.
self._score_to_win = (self._kills_to_win_per_player *
max(1, max(len(t.players) for t in self.teams)))
self._update_scoreboard()
def handlemessage(self, msg: Any) -> Any:
if isinstance(msg, ba.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, ba.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:
ba.playsound(self._dingsound)
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
ba.playsound(self._dingsound)
# 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):
ba.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 = ba.GameResults()
for team in self.teams:
results.set_team_score(team, team.score)
self.end(results=results)

393
dist/ba_root/mods/games/Cursers.py vendored Normal file
View file

@ -0,0 +1,393 @@
# By itsre3 (:
# Just testing my abilities
# ba_meta require api 7
# (see https://ballistica.net/wiki/meta-tag-system)
from __future__ import annotations
from typing import TYPE_CHECKING
import ba
import _ba
import random
from bastd.actor.spazfactory import SpazFactory
from bastd.gameutils import SharedObjects
from bastd.actor.playerspaz import PlayerSpaz
from bastd.actor.scoreboard import Scoreboard
if TYPE_CHECKING:
from typing import Any, Union, Sequence, Optional
class WwFactory(object):
def __init__(self):
self.last_shoot_time = 0
shared = SharedObjects.get()
self.ball_material = ba.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', TouchedSpaz())),
)
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', TouchedObject()),
)
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', TouchedFootingMaterial()),
)
def give_orb_ball(self, spaz: ba.Actor) -> None:
spaz.punch_callback = self.shoot_orb_ball
self.last_shoot_time = ba.time(timetype=ba.TimeType.BASE, timeformat=ba.TimeFormat.MILLISECONDS)
def shoot_orb_ball(self, spaz: ba.Actor) -> None:
shoot_time = ba.time(timetype=ba.TimeType.BASE, timeformat=ba.TimeFormat.MILLISECONDS)
if shoot_time - self.last_shoot_time > 800:
position1 = spaz.node.position_center
position2 = spaz.node.position_forward
ball_direction = (position1[0] - position2[0], 0.0, position1[2] - position2[2])
magnitude = 10.0 / ba.Vec3(*ball_direction).length()
velocity = [v * magnitude for v in ball_direction]
OrbBall(position = spaz.node.position, velocity = (velocity[0]*2, velocity[1]*2, velocity[2]*2), owner = spaz.getplayer(playertype = ba.Player), source_player = spaz.getplayer(playertype = ba.Player)).autoretain()
class TouchedSpaz(object):
pass
class TouchedObject(object):
pass
class TouchedFootingMaterial(object):
pass
class OrbBall(ba.Actor):
def __init__(self, position = (0, 1, 0), velocity = (0, 0, 0), owner = None, source_player = None, sessiontype = type(ba.Session)) -> None:
ba.Actor.__init__(self)
factory = self.get_factory()
self.source_player = source_player
shared = SharedObjects.get()
self.node = ba.newnode("prop",
attrs = {
'position': position,
'velocity': velocity,
'model': ba.getmodel("shield"),
'body': 'sphere',
'color_texture': ba.gettexture("powerupCurse"),
'model_scale': 0.5,
'is_area_of_interest': True,
'body_scale': 1.3,
'reflection': 'soft',
'reflection_scale': [1.0],
'materials': [shared.object_material, factory.ball_material]
},
delegate = self)
self.owner = owner
self.source_player = source_player
self.light = ba.newnode("light", attrs = {"color": (0.8, 0.4, 0.2), "height_attenuated": False, "radius": 0.1})
self.node.connectattr("position", self.light, "position")
ba.animate(self.light, "intensity", {0: 1.3, 250: 1.8, 500: 1.3}, loop = True, timetype = ba.TimeType.SIM, timeformat=ba.TimeFormat.MILLISECONDS)
self.orb_ball_life_timer = ba.Timer(1, ba.WeakCall(self.die))
def die(self) -> None:
self.light.delete()
self.node.handlemessage(ba.DieMessage())
@classmethod
def get_factory(cls):
activity = ba.getactivity()
if activity is None:
raise Exception("no current activity found!")
try:
return activity._orbBallFactory
except:
f = activity._orbBallFactory = WwFactory()
return f
def handlemessage(self, msg):
super(self.__class__, self).handlemessage(msg)
if isinstance(msg, TouchedObject):
node = ba.getcollision().opposingnode
if node and node.exists():
v = self.node.velocity
m = ba.Vec3(*v).length() * 40
node.handlemessage(
ba.HitMessage(pos = self.node.position,
velocity = v,
magnitude = m,
velocity_magnitude = m,
radius = 0,
srcnode = self.node,
source_player = self.source_player,
force_direction = self.node.velocity)
)
self.node.handlemessage(ba.DieMessage())
elif isinstance(msg, ba.DieMessage):
if self.node.exists():
velocity = self.node.velocity
explosion = ba.newnode("explosion",
attrs = {'position': self.node.position,
'velocity': (velocity[0], max(-1.0, velocity[1]), velocity[2]),
'radius': 2,
'big': False
})
ba.playsound(sound = ba.getsound(random.choice(['impactHard', 'impactHard2', 'impactHard3'])), position = self.node.position)
self.node.delete()
self.emit_timer = None
elif isinstance(msg, ba.OutOfBoundsMessage):
self.node.handlemessage(ba.DieMessage())
elif isinstance(msg, ba.HitMessage):
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]
)
elif isinstance(msg, TouchedSpaz):
node = ba.getcollision().opposingnode
if node and node.exists():
node.handlemessage(
ba.PowerupMessage('curse'))
node.handlemessage('knockout', 250)
ba.playsound(sound = ba.getsound('impactHard2'))
self.node.handlemessage(ba.DieMessage())
elif isinstance(msg, TouchedFootingMaterial):
ba.playsound(sound = ba.getsound("blip"), position = self.node.position)
class Player(ba.Player['Team']):
"""Our player type for this game."""
class Team(ba.Team[Player]):
"""Our team type for this game."""
def __init__(self) -> None:
self.score = 0
# ba_meta export game
class CursersGame(ba.TeamGameActivity[Player, Team]):
"""A game type based on acquiring kills."""
name = 'Curser\'s'
description = 'Teach enemies lesson\nPress punch to summon curse'
# Print messages when players die since it matters here.
announce_player_deaths = True
@classmethod
def get_available_settings(
cls, sessiontype: type[ba.Session]) -> list[ba.Setting]:
settings = [
ba.IntSetting(
'Kills to Win Per Player',
min_value=1,
default=5,
increment=1,
),
ba.IntChoiceSetting(
'Time Limit',
choices=[
('None', 0),
('1 Minute', 60),
('2 Minutes', 120),
('5 Minutes', 300),
('10 Minutes', 600),
('20 Minutes', 1200),
],
default=0,
),
ba.FloatChoiceSetting(
'Respawn Times',
choices=[
('Shorter', 0.25),
('Short', 0.5),
('Normal', 1.0),
('Long', 2.0),
('Longer', 4.0),
],
default=1.0,
),
ba.BoolSetting('Epic Mode', default=False),
ba.BoolSetting('Credits', default=True)
]
# In teams mode, a suicide gives a point to the other team, but in
# free-for-all it subtracts from your own score. By default we clamp
# this at zero to benefit new players, but pro players might like to
# be able to go negative. (to avoid a strategy of just
# suiciding until you get a good drop)
if issubclass(sessiontype, ba.FreeForAllSession):
settings.append(
ba.BoolSetting('Allow Negative Scores', default=False))
return settings
@classmethod
def supports_session_type(cls, sessiontype: type[ba.Session]) -> bool:
return (issubclass(sessiontype, ba.DualTeamSession)
or issubclass(sessiontype, ba.FreeForAllSession))
@classmethod
def get_supported_maps(cls, sessiontype: type[ba.Session]) -> list[str]:
return ba.getmaps('melee')
def __init__(self, settings: dict):
super().__init__(settings)
self._scoreboard = Scoreboard()
self._score_to_win: Optional[int] = None
self._cd_text: Optional[ba.Actor] = None
self._dingsound = ba.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._credits = bool(settings['Credits'])
# Base class overrides.
self.slow_motion = self._epic_mode
self.default_music = (ba.MusicType.EPIC if self._epic_mode else
ba.MusicType.TO_THE_DEATH)
def get_instance_description(self) -> Union[str, Sequence]:
return 'Curse ${ARG1} of your enemies.', self._score_to_win
def get_instance_description_short(self) -> Union[str, Sequence]:
return 'Curse ${ARG1} enemies', self._score_to_win
def on_team_join(self, team: Team) -> None:
if self.has_begun():
self._update_scoreboard()
def on_begin(self) -> None:
super().on_begin()
self.setup_standard_time_limit(self._time_limit)
if self._credits:
self._cd_text = ba.NodeActor(
ba.newnode('text',
attrs={
'position': (0, 0),
'h_attach': 'center',
'h_align': 'center',
'maxwidth': 200,
'shadow': 0.5,
'vr_depth': 390,
'scale': 0.8,
'v_attach': 'bottom',
'color': (1, 1, 1),
'text': 'By itsre3'
}))
# 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 spawn_player(self, player: Player) -> ba.Actor:
spaz = self.spawn_player_spaz(player)
WwFactory().give_orb_ball(spaz)
spaz.connect_controls_to_player(enable_punch=True,
enable_bomb=False,
enable_pickup=True)
# This below overwrites default character. Vishuuuuuuuuuu lol
spaz.node.color_mask_texture = ba.gettexture('wizardColorMask')
spaz.node.color_texture = ba.gettexture('powerupCurse')
spaz.node.head_model = ba.getmodel('wizardHead')
spaz.node.hand_model = ba.getmodel('wizardHand')
spaz.node.torso_model = ba.getmodel('wizardTorso')
spaz.node.pelvis_model = ba.getmodel('wizardPelvis')
spaz.node.upper_arm_model = ba.getmodel('wizardUpperArm')
spaz.node.forearm_model = ba.getmodel('wizardForeArm')
spaz.node.upper_leg_model = ba.getmodel('wizardUpperLeg')
spaz.node.lower_leg_model = ba.getmodel('wizardLowerLeg')
spaz.node.toes_model = ba.getmodel('wizardToes')
wizard_sounds = [ba.getsound('wizard1'), ba.getsound('wizard2'), ba.getsound('wizard3'),ba.getsound('wizard4')]
spaz.node.jump_sounds = wizard_sounds
spaz.node.attack_sounds = wizard_sounds
spaz.node.impact_sounds = wizard_sounds
spaz.node.pickup_sounds = wizard_sounds
spaz.node.death_sounds = [ba.getsound('wizardDeath')]
spaz.node.fall_sounds = [ba.getsound('wizardFall')]
return spaz
def handlemessage(self, msg: Any) -> Any:
if isinstance(msg, ba.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, ba.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:
ba.playsound(self._dingsound)
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
ba.playsound(self._dingsound)
# 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):
ba.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 = ba.GameResults()
for team in self.teams:
results.set_team_score(team, team.score)
self.end(results=results)

View file

@ -1,5 +1,5 @@
# ba_meta require api 6
# ba_meta require api 7
# (see https://ballistica.net/wiki/meta-tag-system)
from __future__ import annotations

218
dist/ba_root/mods/games/FireBallFight.py vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,5 @@
# Made by Froshlee14
# ba_meta require api 6
# ba_meta require api 7
from __future__ import annotations
@ -221,7 +221,7 @@ class GetTheTargetGame(ba.TeamGameActivity[Player, Team]):
'maxwidth':100, 'h_align':'center',
'v_align':'center', 'shadow':1.0,
'flatness':1.0, 'color':(1,1,1),
'scale':2,'position':(0,-100)}))
'scale':1.2,'position':(0,-50)}))
self._time_remaining -= 1
ba.playsound(self._tick_sound)

View file

@ -7,7 +7,7 @@ from bastd.game.elimination import EliminationGame
# ba_meta require api 6
# ba_meta require api 7
# ba_meta export game
class GFGame(EliminationGame):
name = 'Gravity Falls'

View file

@ -1,4 +1,4 @@
# ba_meta require api 6
# ba_meta require api 7
# (see https://ballistica.net/wiki/meta-tag-system)
from __future__ import annotations

388
dist/ba_root/mods/games/PowerUpShower.py vendored Normal file
View file

@ -0,0 +1,388 @@
# ba_meta require api 7
#==============================================================================#
#
# version v1.0 (test, 2bugs)
# Create by Unknown_#7004
# Github https://github.com/uwu-user
#
#==============================================================================#
from __future__ import annotations
from typing import TYPE_CHECKING, cast
import ba
import _ba
import math
import random
from bastd.actor.bomb import Bomb
from bastd.actor.onscreentimer import OnScreenTimer
from bastd.actor.powerupbox import PowerupBox, PowerupBoxFactory
if TYPE_CHECKING:
from typing import Any, Sequence, Callable, List, Dict, Tuple, Optional, Union
#==============================================================================#
_version = "1.0"
_by = "Unknown_#7004"
#==============================================================================#
# custom end time
custom_time = 10 # 10s
# custom powerup drop time
custom_speed = 1.0
#==============================================================================#
class Player(ba.Player['Team']):
"""Our player type for this game."""
def __init__(self) -> None:
super().__init__()
self.death_time: Optional[float] = None
class Team(ba.Team[Player]):
"""Our team type for this game."""
#==============================================================================#
# ba_meta export game
class PowerUpShowerGame(ba.TeamGameActivity[Player, Team]):
"""Minigame involving dodging falling bombs."""
name = 'PowerUp Shower'
description = 'Becareful with the curse powerups.'
scoreconfig = ba.ScoreConfig(label='Survived',
scoretype=ba.ScoreType.MILLISECONDS,
version='B')
# Print messages when players die (since its meaningful in this game).
announce_player_deaths = True
@classmethod
def get_available_settings(
cls, sessiontype: Type[ba.Session]) -> List[ba.Setting]:
settings = [
ba.IntChoiceSetting(
'Time Limit',
choices=[ # memes
('No timer', 0),
('1 Minute', 60),
('2 Minutes', 120),
('5 Minutes', 300),
('10 Minutes', 600),
('15 Minutes', 900),
('30 Minutes', 1800),
('60 Minutes', 3600),
('2 Hours', 7200),
('3 Hours', 10800),
('4 Hours', 14400),
('5 Hours', 18000),
('6 Hours', 21600),
('7 Hours', 25200),
('8 Hours', 28800),
('9 Hours', 32400),
('10 Hours', 36000),
('11 Hours', 39600),
('12 Hours', 43200),
('13 Hours', 46800),
('14 Hours', 50400),
('15 Hours', 54000),
('16 Hours', 57600),
('17 Hours', 61200),
('18 Hours', 64800),
('19 Hours', 68400),
('20 Hours', 72000),
('21 Hours', 75600),
('22 Hours', 79200),
('23 Hours', 82800),
('1 days', 86400),
('2 days', 172800),
('3 days', 259200),
('4 days', 345600),
('5 days', 432000),
('6 days', 518400),
('7 days', 604800),
('8 days', 691200),
('9 days', 777600),
('10 days', 864000),
('11 days', 950400),
('custom', custom_time)
],
default=300,
),
ba.FloatChoiceSetting(
'Respawn Times',
choices=[
('very fast', 0.001),
('Shorter', 0.25),
('Short', 0.5),
('Normal', 1.0),
('Long', 2.0),
('Longer', 4.0)
],
default=1.0,
),
ba.FloatChoiceSetting(
'Respawn PowerUp Times',
choices=[
('Fast', 0.10),
('Normal', 0.35),
('Long', 0.7),
('Longer', 1.0),
('custom', custom_speed)
],
default=0.3
),
ba.BoolSetting('Timer on Screen', default=False),
ba.BoolSetting('PowerUp Expire', default=False),
ba.BoolSetting('Epic Mode', default=False),
ba.BoolSetting('spaz » enable punch', default=False),
ba.BoolSetting('spaz » enable bomb', default=False),
ba.BoolSetting('spaz » enable pickup', default=False),
ba.BoolSetting('PowerUp » shield', default=False),
ba.BoolSetting('PowerUp » health', default=False),
ba.BoolSetting('PowerUp » curse', default=False),
ba.BoolSetting('PowerUp » Triple bombs', default=False),
ba.BoolSetting('PowerUp » ice bombs', default=False),
ba.BoolSetting('PowerUp » impact bombs', default=False),
ba.BoolSetting('PowerUp » land mines', default=False),
ba.BoolSetting('PowerUp » sticky bombs', default=False),
ba.BoolSetting('PowerUp » random', default=True)
]
return settings
# We support teams, free-for-all, and co-op sessions.
@classmethod
def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool:
return (issubclass(sessiontype, ba.DualTeamSession)
or issubclass(sessiontype, ba.FreeForAllSession)
or issubclass(sessiontype, ba.CoopSession))
def __init__(self, settings: dict):
super().__init__(settings)
self._epic_mode = settings.get('Epic Mode', False)
self._punch_mode = settings.get('spaz » enable punch', False)
self._bomb_mode = settings.get('spaz » enable bomb', False)
self._pickup_mode = settings.get('spaz » enable pickup', False)
self._powerup_timer = settings.get('Respawn PowerUp Times', False)
self.expire_type = settings.get('PowerUp Expire', True)
self._time_limit = float(settings['Time Limit'])
self._timer_type = float(settings['Timer on Screen'])
self._powerup_shield = settings.get('PowerUp » shield', False)
self._powerup_health = settings.get('PowerUp » health', False)
self._powerup_curse = settings.get('PowerUp » curse', False)
self._powerup_triple_bombs = settings.get('PowerUp » Triple bombs', False)
self._powerup_ice_bombs = settings.get('PowerUp » ice bombs', False)
self._powerup_impact_bombs = settings.get('PowerUp » impact bombs', False)
self._powerup_land_mines = settings.get('PowerUp » land mines', False)
self._powerup_sticky_bombs = settings.get('PowerUp » sticky bombs', False)
self._powerup_random = settings.get('PowerUp » random', True)
self._last_player_death_time: Optional[float] = None
self._meteor_time = 2.0
self._timer: Optional[OnScreenTimer] = None
# Some base class overrides:
self.default_music = (ba.MusicType.EPIC
if self._epic_mode else ba.MusicType.SURVIVAL)
if self._epic_mode:
self.slow_motion = True
def on_begin(self) -> None:
super().on_begin()
self.setup_standard_time_limit(self._time_limit)
# Drop a wave every few seconds.. and every so often drop the time
# between waves ..lets have things increase faster if we have fewer
# players.
delay = 5.0 if len(self.players) > 2 else 2.5
if self._epic_mode:
delay *= 0.25
ba.timer(delay, self._decrement_meteor_time, repeat=True)
# Kick off the first wave in a few seconds.
delay = 3.0
if self._epic_mode:
delay *= 0.25
ba.timer(delay, self._set_meteor_timer)
if self._timer_type:
self._timer = OnScreenTimer()
self._timer.start()
else:
self._timer = None
if not self._time_limit == 0:
ba.timer(self._time_limit, self._check_end_game)
else: pass
def on_player_join(self, player: Player) -> None:
# Don't allow joining after we start
# (would enable leave/rejoin tomfoolery).
if self.has_begun():
ba.screenmessage(
ba.Lstr(resource='playerDelayedJoinText',
subs=[('${PLAYER}', player.getname(full=True))]),
color=(0, 1, 0),
)
# For score purposes, mark them as having died right as the
# game started.
assert self._timer is not None
player.death_time = self._timer.getstarttime()
return
self.spawn_player(player)
def on_player_leave(self, player: Player) -> None:
# Augment default behavior.
super().on_player_leave(player)
# A departing player may trigger game-over.
self._check_end_game()
# overriding the default character spawning..
def spawn_player(self, player: Player) -> ba.Actor:
spaz = self.spawn_player_spaz(player)
# Let's reconnect this player's controls to this
# spaz but *without* the ability to attack or pick stuff up.
spaz.connect_controls_to_player(enable_punch=self._punch_mode,
enable_bomb=self._bomb_mode,
enable_pickup=self._pickup_mode)
# Also lets have them make some noise when they die.
spaz.play_big_death_sound = True
return spaz
# Various high-level game events come through this method.
def handlemessage(self, msg: Any) -> Any: # Respawn
if isinstance(msg, ba.PlayerDiedMessage):
super().handlemessage(msg)
player = msg.getplayer(Player)
self.respawn_player(player)
return None
def _check_end_game(self) -> None:
living_team_count = 0
for team in self.teams:
for player in team.players:
if player.is_alive():
living_team_count += 1
break
# In co-op, we go till everyone is dead.. otherwise we go
# until one team remains.
if isinstance(self.session, ba.CoopSession):
if living_team_count <= 0:
self.end_game()
else:
if living_team_count <= 1:
self.end_game()
def _set_meteor_timer(self) -> None:
ba.timer(self._powerup_timer, self._drop_powerup_cluster)
def _drop_powerup_cluster(self) -> None:
# Random note: code like this is a handy way to plot out extents
# and debug things.
loc_test = False
if loc_test:
ba.newnode('locator', attrs={'position': (8, 6, -5.5)})
ba.newnode('locator', attrs={'position': (8, 6, -2.3)})
ba.newnode('locator', attrs={'position': (-7.3, 6, -5.5)})
ba.newnode('locator', attrs={'position': (-7.3, 6, -2.3)})
# Drop several bombs in series.
delay = 0.0
for _i in range(random.randrange(1, 3)):
# Drop them somewhere within our bounds with velocity pointing
# toward the opposite side.
pos = (-7.3 + 15.3 * random.random(), 11, -5.5 + 2.1 * random.random()*2)
dropdir = (-1.0 if pos[0] > 0 else 1.0)
vel = ((-5.0 + random.random() * 30.0) * dropdir, -4.0, 0)
if self._powerup_shield or self._powerup_health or self._powerup_curse or self._powerup_triple_bombs or self._powerup_ice_bombs or self._powerup_impact_bombs or self._powerup_land_mines or self._powerup_sticky_bombs or self._powerup_random:
if not self._powerup_random:
if self._powerup_shield: ba.timer(delay /random.random(), ba.Call(self._drop_powerup, pos, vel, "shield"))
if self._powerup_health: ba.timer(delay / random.random(), ba.Call(self._drop_powerup, pos, vel, "health"))
if self._powerup_curse: ba.timer(delay / random.random(), ba.Call(self._drop_powerup, pos, vel, "curse"))
if self._powerup_triple_bombs: ba.timer(delay / random.random(), ba.Call(self._drop_powerup, pos, vel, "triple_bombs"))
if self._powerup_ice_bombs: ba.timer(delay / random.random(), ba.Call(self._drop_powerup, pos, vel, "ice_bombs"))
if self._powerup_impact_bombs: ba.timer(delay / random.random(), ba.Call(self._drop_powerup, pos, vel, "impact_bombs"))
if self._powerup_land_mines: ba.timer(delay / random.random(), ba.Call(self._drop_powerup, pos, vel, "land_mines"))
if self._powerup_sticky_bombs: ba.timer(delay / random.random(), ba.Call(self._drop_powerup, pos, vel, "sticky_bombs"))
else:
ba.timer(delay, ba.Call(self._drop_powerup, pos, vel, PowerupBoxFactory().get_random_powerup_type()))
else: pass
delay += 0.5
self._set_meteor_timer()
def _drop_powerup(self, position: Sequence[float], velocity: Sequence[float], PowerupType) -> None:
PowerupBox(position=position,poweruptype=PowerupType,expire=self.expire_type).autoretain()
def _decrement_meteor_time(self) -> None:
self._meteor_time = max(0.01, self._meteor_time * 0.9)
def end_game(self) -> None:
cur_time = 0
assert self._timer is not None
start_time = self._timer.getstarttime()
# Mark death-time as now for any still-living players
# and award players points for how long they lasted.
# (these per-player scores are only meaningful in team-games)
for team in self.teams:
for player in team.players:
survived = True
# Throw an extra fudge factor in so teams that
# didn't die come out ahead of teams that did.
if player.death_time is None:
survived = True
player.death_time = cur_time + 1
# Award a per-player score depending on how many seconds
# they lasted (per-player scores only affect teams mode;
# everywhere else just looks at the per-team score).
score = int(player.death_time - self._timer.getstarttime())
if survived:
score += 69 # A bit extra for survivors. :p
self.stats.player_scored(player, score, screenmessage=False)
# Stop updating our time text, and set the final time to match
# exactly when our last guy died.
self._timer.stop(endtime=self._last_player_death_time)
# Ok now calc game results: set a score for each team and then tell
# the game to end.
results = ba.GameResults()
# Remember that 'free-for-all' mode is simply a special form
# of 'teams' mode where each player gets their own team, so we can
# just always deal in teams and have all cases covered.
for team in self.teams:
# Set the team score to the max time survived by any player on
# that team.
longest_life = 0.0
for player in team.players:
assert player.death_time is not None
longest_life = max(longest_life,
player.death_time - start_time)
# Submit the score value in milliseconds.
results.set_team_score(team, int(1000.0 * longest_life))
self.end(results=results)

339
dist/ba_root/mods/games/Runners.py vendored Normal file
View file

@ -0,0 +1,339 @@
# Made by: Froshlee14
# Ported by: Freaku / @[Just] Freak#4999
from __future__ import annotations
from typing import TYPE_CHECKING
import ba, random
from bastd.actor import bomb, spazbot, powerupbox, bomb
from bastd.gameutils import SharedObjects
from bastd.actor.onscreentimer import OnScreenTimer
if TYPE_CHECKING:
from typing import Any, Sequence, Union, Optional, List, Dict, Type, Literal
## MoreMinigames.py support ##
def ba_get_api_version():
return 6
def ba_get_levels():
return [ba._level.Level('Runners',gametype=RunnersGame, settings={}, preview_texture_name = 'achievementGotTheMoves')]
## MoreMinigames.py support ##
class SpookyBot(spazbot.BrawlerBot):
character = 'Bones'
color = (1,1,1)
class Player(ba.Player['Team']):
"""Our player type for this game."""
def __init__(self) -> None:
super().__init__()
self.death_time: Optional[float] = None
class Team(ba.Team[Player]):
"""Our team type for this game."""
# ba_meta require api 7
# ba_meta export game
class RunnersGame(ba.TeamGameActivity[Player, Team]):
name = 'Runners'
description = 'Run for your Life!'
available_settings = [ba.BoolSetting('Epic Mode', default=False)]
scoreconfig = ba.ScoreConfig(label='Survived',
scoretype=ba.ScoreType.MILLISECONDS,
version='B')
# Print messages when players die (since its meaningful in this game).
announce_player_deaths = True
# we're currently hard-coded for one map..
@classmethod
def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]:
return ['Dak']
# We support teams, free-for-all, and co-op sessions.
@classmethod
def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool:
return (issubclass(sessiontype, ba.DualTeamSession)
or issubclass(sessiontype, ba.FreeForAllSession)
or issubclass(sessiontype, ba.CoopSession))
def __init__(self, settings: dict):
super().__init__(settings)
self._epic_mode = settings.get('Epic Mode', False)
self._last_player_death_time: Optional[float] = None
self._timer: Optional[OnScreenTimer] = None
self._time2Object = 1 if self._epic_mode else 1.5
# Some base class overrides:
self.default_music = (ba.MusicType.EPIC
if self._epic_mode else ba.MusicType.SURVIVAL)
if self._epic_mode:
self.slow_motion = True
def on_begin(self) -> None:
super().on_begin()
self._timer = OnScreenTimer()
self._timer.start()
# Check for immediate end (if we've only got 1 player, etc).
ba.timer(5.0, self._check_end_game)
self._bots = spazbot.SpazBotSet()
for i in range(6+len(self.players)):
self.addBot()
self.obstacleTime = 5
ba.timer(3,self.start)
def start(self):
self._obsTimer = ba.timer(self._time2Object,self.doObstacle,repeat=True)
self._move = ba.timer(0.8,ba.WeakCall(self.movePlayers),repeat=True)
self._fast = ba.timer(5,ba.WeakCall(self.faster),repeat=True)
def faster(self):
if self.obstacleTime > 1:
self.obstacleTime -= 0.1
def addBot(self):
ba.timer(1, ba.Call(self._bots.spawn_bot, SpookyBot, pos=(random.randint(-4,4),5,-7.3), spawn_time=0))
def doObstacle(self):
for i in range(random.randrange(4,8)):
type = random.choice(['tnt','land_mine','land_mine','land_mine','powerup','land_mine','land_mine','land_mine','tnt','tnt','land_mine'])
pos = (random.randrange(-5,5),4.8 if type != 'land_mine' else 4.6,8)
if type == 'powerup':
b = powerupbox.PowerupBox(position=pos,poweruptype=random.choice(['health','shield'])).autoretain()
b.node.model_scale = 0.6
else:
b = bomb.Bomb(position=pos,velocity=(0,0,0),bomb_type = type, bomb_scale = 0.6).autoretain()
if type == 'land_mine': b.arm()
pos = b.node.position
ba.animate_array(b.node,'position',3,{0:b.node.position,self.obstacleTime:(pos[0],pos[1],pos[2]-16)})
def movePlayers(self):
for p in self.players:
if p.is_alive():
p.actor.node.move_up_down = -10
def on_player_join(self, player: Player) -> None:
# Don't allow joining after we start
# (would enable leave/rejoin tomfoolery).
if self.has_begun():
ba.screenmessage(
ba.Lstr(resource='playerDelayedJoinText',
subs=[('${PLAYER}', player.getname(full=True))]),
color=(0, 1, 0),
)
# For score purposes, mark them as having died right as the
# game started.
assert self._timer is not None
player.death_time = self._timer.getstarttime()
return
self.spawn_player(player)
def on_player_leave(self, player: Player) -> None:
# Augment default behavior.
super().on_player_leave(player)
# A departing player may trigger game-over.
self._check_end_game()
# overriding the default character spawning..
def spawn_player(self, player: Player) -> ba.Actor:
spaz = self.spawn_player_spaz(player, self.map.defs.points['spawn'])
# Let's reconnect this player's controls to this
# spaz but *without* the ability to attack or pick stuff up.
spaz.connect_controls_to_player(enable_punch=False,
enable_bomb=False,
enable_pickup=False)
# Also lets have them make some noise when they die.
spaz.play_big_death_sound = True
return spaz
# Various high-level game events come through this method.
def handlemessage(self, msg: Any) -> Any:
if isinstance(msg, ba.PlayerDiedMessage):
# Augment standard behavior.
super().handlemessage(msg)
curtime = ba.time()
# Record the player's moment of death.
# assert isinstance(msg.spaz.player
msg.getplayer(Player).death_time = curtime
# In co-op mode, end the game the instant everyone dies
# (more accurate looking).
# In teams/ffa, allow a one-second fudge-factor so we can
# get more draws if players die basically at the same time.
if isinstance(self.session, ba.CoopSession):
# Teams will still show up if we check now.. check in
# the next cycle.
ba.pushcall(self._check_end_game)
# Also record this for a final setting of the clock.
self._last_player_death_time = curtime
else:
ba.timer(1.0, self._check_end_game)
elif isinstance(msg, spazbot.SpazBotDiedMessage):
self.addBot()
else:
# Default handler:
return super().handlemessage(msg)
return None
def _check_end_game(self) -> None:
living_team_count = 0
for team in self.teams:
for player in team.players:
if player.is_alive():
living_team_count += 1
break
# In co-op, we go till everyone is dead.. otherwise we go
# until one team remains.
if isinstance(self.session, ba.CoopSession):
if living_team_count <= 0:
self.end_game()
else:
if living_team_count <= 1:
self.end_game()
def end_game(self) -> None:
cur_time = ba.time()
assert self._timer is not None
start_time = self._timer.getstarttime()
# Mark death-time as now for any still-living players
# and award players points for how long they lasted.
# (these per-player scores are only meaningful in team-games)
for team in self.teams:
for player in team.players:
survived = False
# Throw an extra fudge factor in so teams that
# didn't die come out ahead of teams that did.
if player.death_time is None:
survived = True
player.death_time = cur_time + 1
# Award a per-player score depending on how many seconds
# they lasted (per-player scores only affect teams mode;
# everywhere else just looks at the per-team score).
score = int(player.death_time - self._timer.getstarttime())
if survived:
score += 50 # A bit extra for survivors.
self.stats.player_scored(player, score, screenmessage=False)
# Stop updating our time text, and set the final time to match
# exactly when our last guy died.
self._timer.stop(endtime=self._last_player_death_time)
# Ok now calc game results: set a score for each team and then tell
# the game to end.
results = ba.GameResults()
# Remember that 'free-for-all' mode is simply a special form
# of 'teams' mode where each player gets their own team, so we can
# just always deal in teams and have all cases covered.
for team in self.teams:
# Set the team score to the max time survived by any player on
# that team.
longest_life = 0.0
for player in team.players:
assert player.death_time is not None
longest_life = max(longest_life,
player.death_time - start_time)
# Submit the score value in milliseconds.
results.set_team_score(team, int(1000.0 * longest_life))
self.end(results=results)
class dakDefs():
points = {}
boxes = {}
points['spawn'] = (0,5,0) + (0, 0, 0) + (10,0,0.5)
boxes['area_of_interest_bounds'] = (0,-1,-5) + (0, 0, 0) + (0, 0, 0)
boxes['map_bounds'] = (0,5,0) + (0, 0, 0) + (10,10,16)
class dakMap(ba.Map):
defs = dakDefs()
name = 'Dak'
@classmethod
def get_play_types(cls) -> List[str]:
"""Return valid play types for this map."""
return []
@classmethod
def get_preview_texture_name(cls) -> str:
return 'achievementGotTheMoves'
@classmethod
def on_preload(cls) -> Any:
data: Dict[str, Any] = {
'tex': ba.gettexture('white'),
'bgmodel': ba.getmodel('thePadBG')
}
return data
def __init__(self) -> None:
super().__init__()
shared = SharedObjects.get()
self._playMaterial = ba.Material()
self._playMaterial.add_actions(
conditions=("they_have_material",shared.player_material),
actions=(("modify_part_collision","collide",True),("modify_part_collision","physical",True)))
self._bombMaterial = ba.Material()
self._bombMaterial.add_actions(
conditions=("they_have_material",bomb.BombFactory.get().bomb_material),
actions=(("modify_part_collision","collide",True),("modify_part_collision","physical",True)))
self.ground = ba.newnode('region', attrs={'position':(0,4,0),'scale':(10,1,20),'type': 'box',
'materials':(self._playMaterial,self._bombMaterial,shared.footing_material)})
self.playWall = ba.newnode('region', attrs={'position':(0,4,1.5),'scale':(10,10,0.5),'type': 'box',
'materials':(self._playMaterial,shared.footing_material)})
self.botWall = ba.newnode('region', attrs={'position':(0,4,-1),'scale':(10,10,0.25),'type': 'box',
'materials':(self._playMaterial,shared.footing_material)})
self.rightWall = ba.newnode('region', attrs={'position':(4,4,0),'scale':(0.5,10,10),'type': 'box',
'materials':(self._playMaterial,shared.footing_material)})
self.leftWall = ba.newnode('region', attrs={'position':(-4,4,0),'scale':(0.5,10,10),'type': 'box',
'materials':(self._playMaterial,shared.footing_material)})
self.bg = ba.newnode(
'terrain',
attrs={
'model': self.preloaddata['bgmodel'],
'lighting': False,
'background': True,
'color_texture': self.preloaddata['tex']
})
gnode = ba.getactivity().globalsnode
gnode.tint = (1.3, 1.2, 1.0)
gnode.ambient_color = (1.3, 1.2, 1.0)
gnode.vignette_outer = (0.57, 0.57, 0.57)
gnode.vignette_inner = (0.9, 0.9, 0.9)
gnode.vr_camera_offset = (0, -0.8, -1.1)
gnode.vr_near_clip = 0.5
ba._map.register_map(dakMap)

View file

@ -1,6 +1,6 @@
"""Defines a Tnt-dodging mini-game."""
# ba_meta require api 6
# ba_meta require api 7
from __future__ import annotations

View file

@ -2,7 +2,7 @@
#
"""Defines assault minigame."""
# ba_meta require api 6
# ba_meta require api 7
# (see https://ballistica.net/wiki/meta-tag-system)
from __future__ import annotations
@ -160,8 +160,8 @@ class BaseRaidGame(ba.TeamGameActivity[Player, Team]):
'color': (0.7,0.88,1.0,1.1),
'shadow': 1.0,
'flatness': 1.0,
'position': (0, -120),
'scale': 1.7,
'position': (0, -70),
'scale': 0.8,
'text': "..."})
self.setup_standard_time_limit(self._time_limit)
ba.timer(4.5, ba.WeakCall(self.selection, first_run = True))

View file

@ -0,0 +1,296 @@
# Released under the MIT License. See LICENSE for details.
#
"""Defines a bomb-dodging mini-game."""
# ba_meta require api 7
# (see https://ballistica.net/wiki/meta-tag-system)
from __future__ import annotations
import random
from typing import TYPE_CHECKING
import ba
from bastd.actor.bomb import Bomb
from bastd.actor.onscreentimer import OnScreenTimer
if TYPE_CHECKING:
from typing import Any, Sequence, Optional, List, Dict, Type, Type
class Player(ba.Player['Team']):
"""Our player type for this game."""
def __init__(self) -> None:
super().__init__()
self.death_time: Optional[float] = None
class Team(ba.Team[Player]):
"""Our team type for this game."""
# ba_meta export game
class MeteorShowerModGame(ba.TeamGameActivity[Player, Team]):
"""Minigame involving dodging falling bombs."""
name = 'Meteor Shower+'
description = 'Dodge the falling bombs.'
available_settings = [
ba.BoolSetting('Epic Mode', default=False),
ba.BoolSetting('Normal Bombs', default=True),
ba.BoolSetting('Frozen Bombs', default=False),
ba.BoolSetting('Impact Bombs', default=False),
ba.BoolSetting('Sticky Bombs', default=False),
ba.BoolSetting('TNTs', default=False),
ba.IntSetting('Bomb Drop Rate',min_value=0.05,default=2.0,increment=0.05),
ba.IntChoiceSetting('Bomb Velocity',choices=[
('Random', 1),('No Velocity', 2),
],
default=1,
)]
scoreconfig = ba.ScoreConfig(label='Survived',
scoretype=ba.ScoreType.MILLISECONDS,
version='B')
# Print messages when players die (since its meaningful in this game).
announce_player_deaths = True
# we're currently hard-coded for one map..
@classmethod
def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]:
return ['Rampage']
# We support teams, free-for-all, and co-op sessions.
@classmethod
def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool:
return (issubclass(sessiontype, ba.DualTeamSession)
or issubclass(sessiontype, ba.FreeForAllSession)
or issubclass(sessiontype, ba.CoopSession))
def __init__(self, settings: dict):
super().__init__(settings)
self._epic_mode = settings.get('Epic Mode', False)
self._last_player_death_time: Optional[float] = None
self._meteor_time = 2.0
self._bomb_entries = []
if settings.get('Normal Bombs',True):
self._bomb_entries += ['normal']
if settings.get('Frozen Bombs',True):
self._bomb_entries += ['ice']
if settings.get('Impact Bombs',True):
self._bomb_entries += ['impact']
if settings.get('Sticky Bombs',True):
self._bomb_entries += ['sticky']
if settings.get('TNTs',True):
self._bomb_entries += ['tnt']
if self._bomb_entries == []: self._bomb_entries = ['normal']
self._bool = settings.get('Bomb Velocity')
self._bool_2 = settings.get('Bomb Drop Rate')
self._timer: Optional[OnScreenTimer] = None
# Some base class overrides:
self.default_music = (ba.MusicType.EPIC
if self._epic_mode else ba.MusicType.SURVIVAL)
if self._epic_mode:
self.slow_motion = True
def on_begin(self) -> None:
super().on_begin()
# Drop a wave every few seconds.. and every so often drop the time
# between waves ..lets have things increase faster if we have fewer
# players.
delay = 5.0 if len(self.players) > 2 else 2.5
if self._epic_mode:
delay *= 0.25
ba.timer(delay, self._decrement_meteor_time, repeat=True)
# Kick off the first wave in a few seconds.
delay = 3.0
if self._epic_mode:
delay *= 0.25
ba.timer(delay, self._set_meteor_timer)
self._timer = OnScreenTimer()
self._timer.start()
# Check for immediate end (if we've only got 1 player, etc).
#ba.timer(5.0, self._check_end_game)
def on_player_join(self, player: Player) -> None:
# Don't allow joining after we start
# (would enable leave/rejoin tomfoolery).
if self.has_begun():
ba.screenmessage(
ba.Lstr(resource='playerDelayedJoinText',
subs=[('${PLAYER}', player.getname(full=True))]),
color=(0, 1, 0),
)
# For score purposes, mark them as having died right as the
# game started.
assert self._timer is not None
player.death_time = self._timer.getstarttime()
return
self.spawn_player(player)
def on_player_leave(self, player: Player) -> None:
# Augment default behavior.
super().on_player_leave(player)
# A departing player may trigger game-over.
self._check_end_game()
# overriding the default character spawning..
def spawn_player(self, player: Player) -> ba.Actor:
spaz = self.spawn_player_spaz(player)
# Let's reconnect this player's controls to this
# spaz but *without* the ability to attack or pick stuff up.
spaz.connect_controls_to_player(enable_punch=False,
enable_bomb=False,
enable_pickup=False)
# Also lets have them make some noise when they die.
spaz.play_big_death_sound = True
return spaz
# Various high-level game events come through this method.
def handlemessage(self, msg: Any) -> Any:
if isinstance(msg, ba.PlayerDiedMessage):
# Augment standard behavior.
super().handlemessage(msg)
curtime = ba.time()
# Record the player's moment of death.
# assert isinstance(msg.spaz.player
msg.getplayer(Player).death_time = curtime
# In co-op mode, end the game the instant everyone dies
# (more accurate looking).
# In teams/ffa, allow a one-second fudge-factor so we can
# get more draws if players die basically at the same time.
if isinstance(self.session, ba.CoopSession):
# Teams will still show up if we check now.. check in
# the next cycle.
ba.pushcall(self._check_end_game)
# Also record this for a final setting of the clock.
self._last_player_death_time = curtime
else:
ba.timer(1.0, self._check_end_game)
else:
# Default handler:
return super().handlemessage(msg)
return None
def _check_end_game(self) -> None:
living_team_count = 0
for team in self.teams:
for player in team.players:
if player.is_alive():
living_team_count += 1
break
# In co-op, we go till everyone is dead.. otherwise we go
# until one team remains.
if isinstance(self.session, ba.CoopSession):
if living_team_count <= 0:
self.end_game()
else:
if living_team_count <= 1:
self.end_game()
def _set_meteor_timer(self) -> None:
ba.timer(int((1 + self._bool_2 * random.random())) * self._meteor_time,
self._drop_bomb_cluster)
def _drop_bomb_cluster(self) -> None:
# Random note: code like this is a handy way to plot out extents
# and debug things.
loc_test = False
if loc_test:
ba.newnode('locator', attrs={'position': (8, 6, -5.5)})
ba.newnode('locator', attrs={'position': (8, 6, -2.3)})
ba.newnode('locator', attrs={'position': (-7.3, 6, -5.5)})
ba.newnode('locator', attrs={'position': (-7.3, 6, -2.3)})
# Drop several bombs in series.
delay = 0.0
for _i in range(random.randrange(1, 3)):
# Drop them somewhere within our bounds with velocity pointing
# toward the opposite side.
pos = (-7.3 + 15.3 * random.random(), 11,
-6.3 + random.uniform(0.1,4.2))
dropdir = (-1.0 if pos[0] > 0 else 1.0)
if self._bool == 2:
vel = ((-5.0 + random.random() * 30.0) * dropdir, -4.0, 0)
else:
vel = (0,0,0)
ba.timer(delay, ba.Call(self._drop_bomb, pos, vel))
delay += 0.1
self._set_meteor_timer()
def _drop_bomb(self, position: Sequence[float],
velocity: Sequence[float]) -> None:
Bomb(position=position, velocity=velocity, bomb_type=random.choice(self._bomb_entries)).autoretain()
def _decrement_meteor_time(self) -> None:
self._meteor_time = max(0.01, self._meteor_time * 0.9)
def end_game(self) -> None:
cur_time = ba.time()
assert self._timer is not None
start_time = self._timer.getstarttime()
# Mark death-time as now for any still-living players
# and award players points for how long they lasted.
# (these per-player scores are only meaningful in team-games)
for team in self.teams:
for player in team.players:
survived = False
# Throw an extra fudge factor in so teams that
# didn't die come out ahead of teams that did.
if player.death_time is None:
survived = True
player.death_time = cur_time + 1
# Award a per-player score depending on how many seconds
# they lasted (per-player scores only affect teams mode;
# everywhere else just looks at the per-team score).
score = int(player.death_time - self._timer.getstarttime())
if survived:
score += 50 # A bit extra for survivors.
self.stats.player_scored(player, score, screenmessage=False)
# Stop updating our time text, and set the final time to match
# exactly when our last guy died.
self._timer.stop(endtime=self._last_player_death_time)
# Ok now calc game results: set a score for each team and then tell
# the game to end.
results = ba.GameResults()
# Remember that 'free-for-all' mode is simply a special form
# of 'teams' mode where each player gets their own team, so we can
# just always deal in teams and have all cases covered.
for team in self.teams:
# Set the team score to the max time survived by any player on
# that team.
longest_life = 0.0
for player in team.players:
assert player.death_time is not None
longest_life = max(longest_life,
player.death_time - start_time)
# Submit the score value in milliseconds.
results.set_team_score(team, int(1000.0 * longest_life))
self.end(results=results)

File diff suppressed because it is too large Load diff