few api 8 minigames

This commit is contained in:
Vishal 2024-11-18 20:23:04 +05:30 committed by GitHub
parent e113b5844d
commit c73d92665c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 2958 additions and 0 deletions

603
dist/ba_root/mods/games/duel.py vendored Normal file
View file

@ -0,0 +1,603 @@
# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport)
# ba_meta require api 8
# (see https://ballistica.net/wiki/meta-tag-system)
from __future__ import annotations
from typing import TYPE_CHECKING
import babase
import bauiv1 as bui
import bascenev1 as bs
import _babase
import random
from bascenev1lib.actor.spaz import Spaz
from bascenev1lib.actor.playerspaz import PlayerSpaz
from bascenev1lib.actor.scoreboard import Scoreboard
from bascenev1lib.game.elimination import Icon
from bascenev1lib.game import elimination
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(bs.FreezeMessage())
bui.getsound('freeze').play()
bui.getsound('superPunch').play()
bui.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 = bui.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 = bui.getsound('announceOne')
self._count_2 = bui.getsound('announceTwo')
self._count_3 = bui.getsound('announceThree')
self._boxing_bell = bui.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: PlayerT) -> 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 = bui.gettexture('tnt')
spaz.node.color_mask_texture = bui.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,309 @@
# Released under AGPL-3.0-or-later. See LICENSE for details.
#
# This file incorporates work covered by the following permission notice:
# Released under the MIT License. See LICENSE for details.
#
"""Provides an easter egg hunt game; but on happy thoughts."""
# ba_meta require api 8
# (see https://ballistica.net/wiki/meta-tag-system)
from __future__ import annotations
import random
from typing import TYPE_CHECKING
import bascenev1 as bs
from bascenev1lib.actor.bomb import Bomb
from bascenev1lib.actor.playerspaz import PlayerSpaz
from bascenev1lib.actor.onscreencountdown import OnScreenCountdown
from bascenev1lib.actor.scoreboard import Scoreboard
from bascenev1lib.actor.respawnicon import RespawnIcon
from bascenev1lib.gameutils import SharedObjects
if TYPE_CHECKING:
from typing import Any
class Player(bs.Player['Team']):
"""Our player type for this game."""
def __init__(self) -> None:
self.respawn_timer: bs.Timer | None = None
self.respawn_icon: RespawnIcon | None = None
class Team(bs.Team[Player]):
"""Our team type for this game."""
def __init__(self) -> None:
self.score = 0
# ba_meta export bascenev1.GameActivity
class EggHuntInTheSkyGame(bs.TeamGameActivity[Player, Team]):
"""A game where score is based on collecting eggs."""
name = 'Egg Hunt in the Sky'
description = 'Gather eggs!'
available_settings = [
bs.BoolSetting('Pro Mode', default=False),
bs.BoolSetting('Epic Mode', default=False),
]
scoreconfig = bs.ScoreConfig(label='Score', scoretype=bs.ScoreType.POINTS)
# We're currently hard-coded for one map.
@classmethod
def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]:
return ['Happy Thoughts']
# We support teams, free-for-all, and co-op sessions.
@classmethod
def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool:
return (
issubclass(sessiontype, bs.CoopSession)
or issubclass(sessiontype, bs.DualTeamSession)
or issubclass(sessiontype, bs.FreeForAllSession)
)
def __init__(self, settings: dict):
super().__init__(settings)
shared = SharedObjects.get()
self._last_player_death_time = None
self._scoreboard = Scoreboard()
self.egg_mesh = bs.getmesh('egg')
self.egg_tex_1 = bs.gettexture('eggTex1')
self.egg_tex_2 = bs.gettexture('eggTex2')
self.egg_tex_3 = bs.gettexture('eggTex3')
self._collect_sound = bs.getsound('powerup01')
self._pro_mode = settings.get('Pro Mode', False)
self._epic_mode = settings.get('Epic Mode', False)
self._max_eggs = 4.0
self.egg_material = bs.Material()
self.egg_material.add_actions(
conditions=('they_have_material', shared.player_material),
actions=(('call', 'at_connect', self._on_egg_player_collide),),
)
self._eggs: list[Egg] = []
self._update_timer: bs.Timer | None = None
self._countdown: OnScreenCountdown | None = None
# Base class overrides
self.slow_motion = self._epic_mode
self.default_music = (
bs.MusicType.EPIC if self._epic_mode else bs.MusicType.FORWARD_MARCH
)
def on_team_join(self, team: Team) -> None:
if self.has_begun():
self._update_scoreboard()
# Called when our game actually starts.
def on_begin(self) -> None:
super().on_begin()
self._update_scoreboard()
self._update_timer = bs.Timer(0.25, self._update, repeat=True)
self._countdown = OnScreenCountdown(120, endcall=self.end_game)
bs.timer(4.0, self._countdown.start)
# Overriding the default character spawning.
def spawn_player(self, player: Player) -> bs.Actor:
spaz = self.spawn_player_spaz(player)
spaz.connect_controls_to_player()
return spaz
def _on_egg_player_collide(self) -> None:
if self.has_ended():
return
collision = bs.getcollision()
# Be defensive here; we could be hitting the corpse of a player
# who just left/etc.
try:
egg = collision.sourcenode.getdelegate(Egg, True)
player = collision.opposingnode.getdelegate(
PlayerSpaz, True
).getplayer(Player, True)
except bs.NotFoundError:
return
player.team.score += 1
# Displays a +1 (and adds to individual player score in
# teams mode).
self.stats.player_scored(player, 1, screenmessage=False)
if self._max_eggs < 9:
self._max_eggs += 2.0
elif self._max_eggs < 14:
self._max_eggs += 1.0
elif self._max_eggs < 34:
self._max_eggs += 0.6
self._update_scoreboard()
self._collect_sound.play(0.5, position=egg.node.position)
# Create a flash.
light = bs.newnode(
'light',
attrs={
'position': egg.node.position,
'height_attenuated': False,
'radius': 0.1,
'color': (1, 1, 0),
},
)
bs.animate(light, 'intensity', {0: 0, 0.1: 1.0, 0.2: 0}, loop=False)
bs.timer(0.200, light.delete)
egg.handlemessage(bs.DieMessage())
def _update(self) -> None:
# Misc. periodic updating.
mb = self.map.get_def_bound_box('area_of_interest_bounds')
assert mb
xpos = random.uniform(mb[0], mb[3])
ypos = random.uniform(mb[1], mb[4])
zpos = random.uniform(mb[2], mb[5])
# Prune dead eggs from our list.
self._eggs = [e for e in self._eggs if e]
# Spawn more eggs if we've got space.
if len(self._eggs) < int(self._max_eggs):
# Occasionally spawn a bomb in addition.
if self._pro_mode and random.random() < 0.4:
actor = Bomb(
position=(xpos, ypos, zpos), bomb_type='impact'
).autoretain()
else:
actor = Egg(position=(xpos, ypos, zpos))
self._eggs.append(actor)
if actor.node:
# We want everything to float
actor.node.gravity_scale = 0.0
# Some velocity so the game doesn't look stiff
nvelocity = bs.Vec3(
random.uniform(-1.0, 1.0), random.uniform(-1.0, 1.0), 0
).normalized()
s = random.uniform(-0.4, 0.4)
# Let's make it a bit more spicy since we don't have any bots
if self._pro_mode:
s *= 10
actor.node.velocity = (
nvelocity[0] * s, nvelocity[1] * s, nvelocity[2] * s
)
# Various high-level game events come through this method.
def handlemessage(self, msg: Any) -> Any:
# Respawn dead players.
if isinstance(msg, bs.PlayerDiedMessage):
# Augment standard behavior.
super().handlemessage(msg)
# Respawn them shortly.
player = msg.getplayer(Player)
assert self.initialplayerinfos is not None
respawn_time = 2.0 + len(self.initialplayerinfos) * 1.0
player.respawn_timer = bs.Timer(
respawn_time, bs.Call(self.spawn_player_if_exists, player)
)
player.respawn_icon = RespawnIcon(player, respawn_time)
else:
# Default handler.
return super().handlemessage(msg)
return None
def _update_scoreboard(self) -> None:
for team in self.teams:
self._scoreboard.set_team_value(team, team.score)
def end_game(self) -> None:
results = bs.GameResults()
for team in self.teams:
results.set_team_score(team, team.score)
self.end(results)
class Egg(bs.Actor):
"""A lovely egg that can be picked up for points."""
def __init__(self, position: tuple[float, float, float] = (0.0, 1.0, 0.0)):
super().__init__()
activity = self.activity
assert isinstance(activity, EggHuntInTheSkyGame)
shared = SharedObjects.get()
# Spawn just above the provided point.
self._spawn_pos = (position[0], position[1] + 1.0, position[2])
ctex = (activity.egg_tex_1, activity.egg_tex_2, activity.egg_tex_3)[
random.randrange(3)
]
mats = [shared.object_material, activity.egg_material]
self.node = bs.newnode(
'prop',
delegate=self,
attrs={
'mesh': activity.egg_mesh,
'color_texture': ctex,
'body': 'capsule',
'reflection': 'soft',
'mesh_scale': 0.5,
'body_scale': 0.6,
'density': 4.0,
'reflection_scale': [0.15],
'shadow_size': 0.6,
'position': self._spawn_pos,
'materials': mats,
'is_area_of_interest': True,
},
)
def exists(self) -> bool:
return bool(self.node)
def handlemessage(self, msg: Any) -> Any:
if isinstance(msg, bs.DieMessage):
if self.node:
self.node.delete()
elif isinstance(msg, bs.HitMessage):
if 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],
)
else:
super().handlemessage(msg)
# ba_meta export plugin
class AddToCoopPracticeLevels(bs.Plugin):
def on_app_running(self) -> None:
bs.app.classic.add_coop_practice_level(
bs.Level(
name='Egg Hunt in the Sky',
gametype=EggHuntInTheSkyGame,
settings={},
preview_texture_name='alwaysLandPreview',
),
)
bs.app.classic.add_coop_practice_level(
bs.Level(
name='Pro Egg Hunt in the Sky',
gametype=EggHuntInTheSkyGame,
settings={'Pro Mode': True},
preview_texture_name='alwaysLandPreview',
),
)

595
dist/ba_root/mods/games/jaggernaut.py vendored Normal file
View file

@ -0,0 +1,595 @@
"""Made by Sebaman2009"""
# ba_meta require api 8
# (see https://ballistica.net/wiki/meta-tag-system)
from __future__ import annotations
from typing import TYPE_CHECKING
from typing_extensions import override
import bascenev1 as bs
import random
import _bascenev1
from bascenev1lib.actor.playerspaz import PlayerSpazHurtMessage
from bascenev1lib.actor.playerspaz import PlayerSpaz
from bascenev1lib.actor.scoreboard import Scoreboard
from bascenev1lib.actor.powerupbox import PowerupBox
from bascenev1lib.actor import powerupbox
from bascenev1lib.game.elimination import Icon
import babase
import bascenev1lib
if TYPE_CHECKING:
from typing import Any, Sequence
session = ""
class LivesRemaining(bs.Actor):
def __init__(self,team):
super().__init__()
self.team = team
self.teamcolor = team.color
self.bar_posx = -100 - 120 if isinstance(session,bs.DualTeamSession) == True else 85 - 120
self._height = 35
self._width = 70
self._bar_tex = self._backing_tex = bs.gettexture('bar')
self._cover_tex = bs.gettexture('uiAtlas')
self._mesh = bs.getmesh('meterTransparent')
self._backing = bs.NodeActor(
bs.newnode(
'image',
attrs={
'position': (self.bar_posx + self._width / 2, -35) if self.team.id == 0 or isinstance(session,bs.DualTeamSession) == False else (-self.bar_posx + -self._width / 2, -35),
'scale': (self._width, self._height),
'opacity': 0.7,
'color': (
self.teamcolor[0] * 0.2,
self.teamcolor[1] * 0.2,
self.teamcolor[2] * 0.2,
),
'vr_depth': -3,
'attach': 'topCenter',
'texture': self._backing_tex
}))
self._cover = bs.NodeActor(
bs.newnode(
'image',
attrs={
'position': (self.bar_posx + 35, -35) if self.team.id == 0 or isinstance(session,bs.DualTeamSession) == False else (-self.bar_posx - 35, -35),
'scale': (self._width * 1.15, self._height * 1.6),
'opacity': 1.0,
'color': (
self.teamcolor[0] * 1.1,
self.teamcolor[1] * 1.1,
self.teamcolor[2] * 1.1,
),
'vr_depth': 2,
'attach': 'topCenter',
'texture': self._cover_tex,
'mesh_transparent': self._mesh}))
self._score_text = bs.NodeActor(
bs.newnode(
'text',
attrs={
'position': (self.bar_posx +35 , -35) if self.team.id == 0 or isinstance(session,bs.DualTeamSession) == False else (-self.bar_posx - 35, -35),
'h_attach': 'center',
'v_attach': 'top',
'h_align': 'center',
'v_align': 'center',
'maxwidth': 130,
'scale': 0.9,
'text': '',
'shadow': 0.5,
'flatness': 1.0,
'color': (1.00,1.00,1.00,0.8)
}))
def update_text(self,num,color = (1,1,1,0.8) ):
text = bs.NodeActor(bs.newnode('text',attrs={'position': (self.bar_posx + 35 , -35) if self.team.id == 0 or isinstance(session,bs.DualTeamSession) == False else (-self.bar_posx - 35 , -35) ,'h_attach': 'center','v_attach': 'top','h_align': 'center','v_align': 'center','maxwidth': 130,'scale': 0.9,'text': str(num),'shadow': 0.5,'flatness': 1.0,'color': color}))
return text
def flick(self):
bs.animate(
self._score_text.node,
'opacity',
{
0.00: 1.0,
0.05: 0.0,
0.10: 1.0,
0.15: 0.2,
0.20: 1.0,
},
)
def flick_two(self):
bs.animate(
self._score_text.node,
'opacity',
{
0.00: 1.0,
0.05: 0.0,
0.10: 1.0,
},
)
class Player(bs.Player['Team']):
"""Our player type for this game."""
def __init__(self) -> None:
self.jagg_light: bs.NodeActor | None = None
self.lives = 1
self.icon = None
class Team(bs.Team[Player]):
"""Our team type for this game."""
def __init__(self) -> None:
self.score = 0
self.survival_seconds = int()
lista = []
# ba_meta export bascenev1.GameActivity
class Jaggernaut(bs.TeamGameActivity[Player, Team]):
name = 'Jaggernaut'
description = 'Kill the jagger!.'
scoreconfig = bs.ScoreConfig(
label='Survived', scoretype=bs.ScoreType.SECONDS
)
# Print messages when players die since it matters here.
announce_player_deaths = True
allow_mid_activity_joins = False
@classmethod
def get_available_settings(
cls, sessiontype: Type[bs.Session]) -> List[babase.Setting]:
settings = [
bs.IntChoiceSetting(
"Jaggers's Health",
choices=[
('Normal (1x)', 1000),
('Stronger (1.5x)',1500),
('Much Stronger (2x)',2000),
],
default=1000,),
bs.IntChoiceSetting(
"Jaggers's Bombs",
choices=[
('Normal', 1),
('Double',2),
('Triple',3),
],
default=3,
),
bs.BoolSetting('Jagger has boxing gloves', default = False),
bs.BoolSetting('Spawn powerups', default = True),
bs.BoolSetting('Epic Mode', default=False)]
return settings
@classmethod
def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool:
return issubclass(sessiontype, bs.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._dingsound = bs.getsound('dingSmall')
self._epic_mode = bool(settings['Epic Mode'])
self.boxing = bool(settings['Jagger has boxing gloves'])
self.health = int(settings["Jaggers's Health"])
self.bombs = int(settings["Jaggers's Bombs"])
self.powerups = bool(settings["Spawn powerups"])
# 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.player_count = len(bs.getactivity().players)
def get_instance_description(self) -> Union[str, Sequence]:
return 'Kill the titan!' if isinstance(self.session, bs.DualTeamSession) == False else "Kill the oposing titan!"
def get_instance_description_short(self) -> Union[str, Sequence]:
return f"Kill {self.jagg.team.name}!" if isinstance(self.session, bs.DualTeamSession) == False else "Kill the oposing titan!"
def tick(self) -> None:
if self.powerups:
factory = powerupbox.PowerupBoxFactory()
powerup = factory.get_random_powerup_type(excludetypes = ["ice_bombs","curse","health"])
lugar = random.choice(self.map.powerup_spawn_points)
PowerupBox((lugar[0],lugar[1],lugar[2]),powerup).autoretain()
def dissapear(self):
if isinstance(self.session, bs.DualTeamSession) == True:
bs.animate(
self.jagg.icon.node,
'opacity',
{
0.00: 1.0,
0.05: 0.0,
0.10: 1.0,
0.15: 0.0,
0.20: 1.0,
0.25: 0.0,
0.30: 1.0,
0.35: 0.0,
0.40: 1.0,
0.45: 0.0,
0.50: 0.2,
0.55: 1.0,
0.60: 0.0,
0.65: 0.2,
0.70: 1.0,
0.75: 0.0,
0.80: 0.2,
0.85: 1.0,
0.90: 0.0,
0.95: 0.2,
1.00: 0,
},
)
bs.animate(
self.jagg.icon._name_text,
'opacity',
{
0.00: 1.0,
0.05: 0.0,
0.10: 1.0,
0.15: 0.0,
0.20: 1.0,
0.25: 0.0,
0.30: 1.0,
0.35: 0.0,
0.40: 1.0,
0.45: 0.0,
0.50: 0.2,
0.55: 1.0,
0.60: 0.0,
0.65: 0.2,
0.70: 1.0,
0.75: 0.0,
0.80: 0.2,
0.85: 1.0,
0.90: 0.0,
0.95: 0.2,
1.00: 0,
},
)
bs.animate(
self.jag.icon.node,
'opacity',
{
0.00: 1.0,
0.05: 0.0,
0.10: 1.0,
0.15: 0.0,
0.20: 1.0,
0.25: 0.0,
0.30: 1.0,
0.35: 0.0,
0.40: 1.0,
0.45: 0.0,
0.50: 0.2,
0.55: 1.0,
0.60: 0.0,
0.65: 0.2,
0.70: 1.0,
0.75: 0.0,
0.80: 0.2,
0.85: 1.0,
0.90: 0.0,
0.95: 0.2,
1.00: 0,
},
)
bs.animate(
self.jag.icon._name_text,
'opacity',
{
0.00: 1.0,
0.05: 0.0,
0.10: 1.0,
0.15: 0.0,
0.20: 1.0,
0.25: 0.0,
0.30: 1.0,
0.35: 0.0,
0.40: 1.0,
0.45: 0.0,
0.50: 0.2,
0.55: 1.0,
0.60: 0.0,
0.65: 0.2,
0.70: 1.0,
0.75: 0.0,
0.80: 0.2,
0.85: 1.0,
0.90: 0.0,
0.95: 0.2,
1.00: 0,
},
)
else:
bs.animate(
self.jagg.icon.node,
'opacity',
{
0.00: 1.0,
0.05: 0.0,
0.10: 1.0,
0.15: 0.0,
0.20: 1.0,
0.25: 0.0,
0.30: 1.0,
0.35: 0.0,
0.40: 1.0,
0.45: 0.0,
0.50: 0.2,
0.55: 1.0,
0.60: 0.0,
0.65: 0.2,
0.70: 1.0,
0.75: 0.0,
0.80: 0.2,
0.85: 1.0,
0.90: 0.0,
0.95: 0.2,
1.00: 0,
},
)
bs.animate(
self.jagg.icon._name_text,
'opacity',
{
0.00: 1.0,
0.05: 0.0,
0.10: 1.0,
0.15: 0.0,
0.20: 1.0,
0.25: 0.0,
0.30: 1.0,
0.35: 0.0,
0.40: 1.0,
0.45: 0.0,
0.50: 0.2,
0.55: 1.0,
0.60: 0.0,
0.65: 0.2,
0.70: 1.0,
0.75: 0.0,
0.80: 0.2,
0.85: 1.0,
0.90: 0.0,
0.95: 0.2,
1.00: 0,
},
)
def on_begin(self):
super().on_begin()
global session
session = self.session
if isinstance(self.session, bs.DualTeamSession) == False:
powerupbox.DEFAULT_POWERUP_INTERVAL = 12.0
self._start_time = bs.time()
jagg = random.choice(bs.getactivity().players)
self.player_count = len(bs.getactivity().players)
jaggy = jagg.actor
jaggy.hitpoints = self.health*len(bs.getactivity().players)
jaggy.hitpoints_max = self.health*len(bs.getactivity().players)
if self.boxing:
jaggy.equip_boxing_gloves()
jaggy.set_score_text("Jaggernaut")
jaggy.bomb_count = 3
bs.timer(12.0,self.tick,True)
color = [
0.3 + c * 0.7
for c in bs.normalized_color(jagg.team.color)
]
light = jaggy.jagg_light = bs.NodeActor(
bs.newnode(
'light',
attrs={
'intensity': 0.6,
'height_attenuated': False,
'volume_intensity_scale': 0.1,
'radius': 0.13,
'color': color},
)
)
assert isinstance(jaggy, PlayerSpaz)
jaggy.node.connectattr(
'position', light.node, 'position'
)
self.jagg = jagg
self.jaggy = jaggy
self.jagg.icon = Icon(player = self.jagg,position = (0 ,550),scale = 1.0, show_lives = False)
self.text_jagg = LivesRemaining(self.jagg.team)
self.text_jagg.position = 0 - 120
self.text_jagg._score_text = self.text_jagg.update_text(round(self.jaggy.hitpoints//10))
bs.timer(8.0,self.dissapear)
return jaggy
else:
powerupbox.DEFAULT_POWERUP_INTERVAL = 12.0
self._start_time = bs.time()
alive = self._get_living_teams()
print(alive)
self.jagg = random.choice(alive[0].players)
self.jag = random.choice(alive[1].players)
self.jaggy = self.jagg.actor
self.jagy = self.jag.actor
self.jaggy.hitpoints = self.health*len(bs.getactivity().players)
self.jaggy.hitpoints_max = self.health*len(bs.getactivity().players)
self.jagy.hitpoints = self.health*len(bs.getactivity().players)
self.jagy.hitpoints_max = self.health*len(bs.getactivity().players)
if self.boxing:
self.jaggy.equip_boxing_gloves()
self.jagy.equip_boxing_gloves()
self.jaggy.set_score_text("Jaggernaut",self.jagg.color)
self.jagy.set_score_text("Jaggernaut",self.jag.color)
self.jaggy.bomb_count = 3
self.jagy.bomb_count = 3
bs.timer(12.0,self.tick,True)
color1 = [
0.3 + c * 0.7
for c in bs.normalized_color(self.jagg.team.color)
]
light1 = self.jaggy.jagg_light = bs.NodeActor(
bs.newnode(
'light',
attrs={
'intensity': 0.6,
'height_attenuated': False,
'volume_intensity_scale': 0.1,
'radius': 0.13,
'color': color1},
)
)
assert isinstance(self.jaggy, PlayerSpaz)
self.jaggy.node.connectattr(
'position', light1.node, 'position'
)
color2 = [
0.3 + c * 0.7
for c in bs.normalized_color(self.jag.team.color)
]
light2 = self.jagy.jagg_light = bs.NodeActor(
bs.newnode(
'light',
attrs={
'intensity': 0.6,
'height_attenuated': False,
'volume_intensity_scale': 0.1,
'radius': 0.13,
'color': color2},
)
)
assert isinstance(self.jagy, PlayerSpaz)
self.jagy.node.connectattr(
'position', light2.node, 'position'
)
self.jagg.icon = Icon(player = self.jagg,position = ( -185 ,550),scale = 1.0, show_lives = False)
self.jag.icon = Icon(player = self.jag,position = ( 185 ,550),scale = 1.0, show_lives = False)
self.text_jagg = LivesRemaining(self.jagg.team)
self.text_jag = LivesRemaining(self.jag.team)
self.text_jagg._score_text = self.text_jagg.update_text(round(self.jaggy.hitpoints//10))
self.text_jag._score_text = self.text_jag.update_text(round(self.jagy.hitpoints//10))
bs.timer(8.0,self.dissapear)
def on_player_join(self, player):
self.spawn_player(player)
def on_player_leave(self,player):
self.player_count -= 1
if player == self.jagg:
self.end_game()
alive_teams = self._get_living_teams()
if len(alive_teams) == 1:
for team in alive_teams:
team.survival_seconds += int(bs.time() - self._start_time)
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 check_win(self):
alive_teams = self._get_living_teams()
if self.player_count == 0:
self.end_game()
elif self.msg.getkillerplayer(Player) == self.jagg and self.msg.getplayer(Player) == self.jagg:
self.msg.getkillerplayer(Player).team.survival_seconds = 0
for team in alive_teams:
team.survival_seconds += int(bs.time() - self._start_time)
self.end_game()
elif self.msg.getplayer(Player) == self.jagg:
self.msg.getkillerplayer(Player).team.survival_seconds += 1
self.jagg.team.survival_seconds = 0
for team in alive_teams:
team.survival_seconds += int(bs.time() - self._start_time)
self.end_game()
elif self.player_count == 1:
self.jagg.team.survival_seconds += int(bs.time() - self._start_time)
self.end_game()
def check_win_teams(self):
if self.player_count == 0:
self.end_game()
elif self.jagy.is_alive() == False and self.jaggy.is_alive() == False:
self.end_game()
elif self.msg.getplayer(Player) == self.jagg:
self.msg.getplayer(Player).team.score -= 1
self.end_game()
elif self.msg.getplayer(Player) == self.jag:
self.msg.getplayer(Player).team.score -= 1
self.end_game()
def handlemessage(self, msg: Any) -> Any:
if isinstance(msg, bs.PlayerDiedMessage):
super().handlemessage(msg)
msg.getplayer(Player).team.survival_seconds += int(bs.time() - self._start_time)
msg.getplayer(Player).lives -= 1
self.player_count -= 1
self.msg = msg
if msg.getplayer(Player).actor == self.jaggy:
self.jaggy.jagg_light = None
self.text_jagg._score_text = self.text_jagg.update_text(0,(1.00, 0.15, 0.15))
if isinstance(self.session, bs.DualTeamSession) == True:
if msg.getplayer(Player).actor == self.jagy:
self.jagy.jagg_light = None
self.text_jag._score_text = self.text_jag.update_text(0,(1.00, 0.15, 0.15))
if isinstance(self.session, bs.DualTeamSession) == False:
bs.timer(1.0,self.check_win)
else:
bs.timer(1.0,self.check_win_teams)
if isinstance(msg, PlayerSpazHurtMessage):
if isinstance(self.session, bs.DualTeamSession) == True:
if msg.spaz == self.jaggy:
self.text_jagg._score_text = self.text_jagg.update_text(round(self.jaggy.hitpoints//10))
self.text_jagg.flick()
if self.jaggy.hitpoints == 0:
self.text_jagg._score_text = self.text_jagg.update_text(round(self.jaggy.hitpoints//10),(1.00, 0.15, 0.15))
self.timertwo = None
elif self.jaggy.hitpoints <= (self.jaggy.hitpoints_max//4):
self.text_jagg._score_text = self.text_jagg.update_text(round(self.jaggy.hitpoints//10),(1.00, 0.15, 0.15))
self.timertwo = None
self.timertwo = bs.Timer(0.1,self.text_jagg.flick_two,True)
elif self.jaggy.hitpoints <= (self.jaggy.hitpoints_max//2):
self.text_jagg._score_text = self.text_jagg.update_text(round(self.jaggy.hitpoints//10),(1.00, 0.50, 0.00))
self.text_jagg.flick()
elif msg.spaz == self.jagy:
self.text_jag._score_text = self.text_jag.update_text(round(self.jagy.hitpoints//10))
self.text_jag.flick()
if self.jagy.hitpoints == 0:
self.text_jag._score_text = self.text_jag.update_text(round(self.jagy.hitpoints//10),(1.00, 0.15, 0.15))
self.timer = None
elif self.jagy.hitpoints <= (self.jagy.hitpoints_max//4):
self.text_jag._score_text = self.text_jag.update_text(round(self.jagy.hitpoints//10),(1.00, 0.15, 0.15))
self.timer = None
self.timer = bs.Timer(0.1,self.text_jag.flick_two,True)
elif self.jagy.hitpoints <= (self.jagy.hitpoints_max//2):
self.text_jag._score_text = self.text_jag.update_text(round(self.jagy.hitpoints//10),(1.00, 0.50, 0.00))
self.text_jag.flick()
elif msg.spaz == self.jaggy:
self.text_jagg._score_text = self.text_jagg.update_text(round(self.jaggy.hitpoints//10))
self.text_jagg.flick()
if self.jaggy.hitpoints == 0:
self.text_jagg._score_text = self.text_jagg.update_text(round(self.jaggy.hitpoints//10),(1.00, 0.15, 0.15))
self.timer = None
elif self.jaggy.hitpoints <= (self.jaggy.hitpoints_max//4):
self.text_jagg._score_text = self.text_jagg.update_text(round(self.jaggy.hitpoints//10),(1.00, 0.15, 0.15))
self.timer = None
self.timer = bs.Timer(0.1,self.text_jagg.flick_two,True)
elif self.jaggy.hitpoints <= (self.jaggy.hitpoints_max//2):
self.text_jagg._score_text = self.text_jagg.update_text(round(self.jaggy.hitpoints//10),(1.00, 0.50, 0.00))
self.text_jagg.flick()
def end_game(self) -> None:
results = bs.GameResults()
for team in self.teams:
if isinstance(self.session, bs.DualTeamSession) == False:
results.set_team_score(team, team.survival_seconds)
else:
results.set_team_score(team, team.score)
self.end(results=results)

625
dist/ba_root/mods/games/kill_or_die.py vendored Normal file
View file

@ -0,0 +1,625 @@
# ba_meta require api 8
from __future__ import annotations
# Made by Vishal (Discord id : 𝑽𝑰𝑺𝑯𝑼𝑼𝑼#2921)
from typing import TYPE_CHECKING
import logging
import bascenev1 as bs
from bascenev1lib.actor.spazfactory import SpazFactory
from bascenev1lib.actor.scoreboard import Scoreboard
from bascenev1lib.gameutils import SharedObjects
if TYPE_CHECKING:
from typing import Any, Sequence, Optional, Union
class Icon(bs.Actor):
"""Creates in in-game icon on screen."""
def __init__(self,
player: Player,
position: tuple[float, float],
scale: float,
show_lives: bool = True,
show_death: bool = True,
name_scale: float = 1.0,
name_maxwidth: float = 115.0,
flatness: float = 1.0,
shadow: float = 1.0):
super().__init__()
self._player = player
self._show_lives = show_lives
self._show_death = show_death
self._name_scale = name_scale
self._outline_tex = bs.gettexture('characterIconMask')
icon = player.get_icon()
self.node = bs.newnode('image',
delegate=self,
attrs={
'texture': icon['texture'],
'tint_texture': icon['tint_texture'],
'tint_color': icon['tint_color'],
'vr_depth': 400,
'tint2_color': icon['tint2_color'],
'mask_texture': self._outline_tex,
'opacity': 1.0,
'absolute_scale': True,
'attach': 'bottomCenter'
})
self._name_text = bs.newnode(
'text',
owner=self.node,
attrs={
'text': bs.Lstr(value=player.getname()),
'color': bs.safecolor(player.team.color),
'h_align': 'center',
'v_align': 'center',
'vr_depth': 410,
'maxwidth': name_maxwidth,
'shadow': shadow,
'flatness': flatness,
'h_attach': 'center',
'v_attach': 'bottom'
})
if self._show_lives:
self._lives_text = bs.newnode('text',
owner=self.node,
attrs={
'text': 'x0',
'color': (1, 1, 0.5),
'h_align': 'left',
'vr_depth': 430,
'shadow': 1.0,
'flatness': 1.0,
'h_attach': 'center',
'v_attach': 'bottom'
})
self.set_position_and_scale(position, scale)
def set_position_and_scale(self, position: tuple[float, float],
scale: float) -> None:
"""(Re)position the icon."""
assert self.node
self.node.position = position
self.node.scale = [70.0 * scale]
self._name_text.position = (position[0], position[1] + scale * 52.0)
self._name_text.scale = 1.0 * scale * self._name_scale
if self._show_lives:
self._lives_text.position = (position[0] + scale * 10.0,
position[1] - scale * 43.0)
self._lives_text.scale = 1.0 * scale
def update_for_lives(self) -> None:
"""Update for the target player's current lives."""
if self._player:
lives = self._player.lives
else:
lives = 0
if self._show_lives:
if lives > 0:
self._lives_text.text = 'x' + str(lives - 1)
else:
self._lives_text.text = ''
if lives == 0:
self._name_text.opacity = 0.2
assert self.node
self.node.color = (0.7, 0.3, 0.3)
self.node.opacity = 0.2
def handle_player_spawned(self) -> None:
"""Our player spawned; hooray!"""
if not self.node:
return
self.node.opacity = 1.0
self.update_for_lives()
def handle_player_died(self) -> None:
"""Well poo; our player died."""
if not self.node:
return
if self._show_death:
bs.animate(
self.node, 'opacity', {
0.00: 1.0,
0.05: 0.0,
0.10: 1.0,
0.15: 0.0,
0.20: 1.0,
0.25: 0.0,
0.30: 1.0,
0.35: 0.0,
0.40: 1.0,
0.45: 0.0,
0.50: 1.0,
0.55: 0.2
})
lives = self._player.lives
if lives == 0:
bs.timer(0.6, self.update_for_lives)
def handlemessage(self, msg: Any) -> Any:
if isinstance(msg, bs.DieMessage):
self.node.delete()
return None
return super().handlemessage(msg)
class Player(bs.Player['Team']):
"""Our player type for this game."""
def __init__(self) -> None:
self.lives = 0
self.icons: list[Icon] = []
class Team(bs.Team[Player]):
"""Our team type for this game."""
def __init__(self) -> None:
self.survival_seconds: Optional[int] = None
self.spawn_order: list[Player] = []
# ba_meta export bascenev1.GameActivity
class KillOrDieGame(bs.TeamGameActivity[Player, Team]):
"""Game type where last player(s) left alive win."""
name = 'Kill Or Die'
description = 'Kill the opponent or You Die.'
scoreconfig = bs.ScoreConfig(label='Survived',
scoretype=bs.ScoreType.SECONDS,
none_is_winner=True)
# Show messages when players die since it's meaningful here.
announce_player_deaths = True
allow_mid_activity_joins = False
@classmethod
def get_available_settings(
cls, sessiontype: type[bs.Session]) -> list[bs.Setting]:
settings = [
bs.IntSetting(
'Lives Per Player',
default=1,
min_value=1,
max_value=10,
increment=1,
),
bs.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('Epic Mode', default=False),
]
if issubclass(sessiontype, bs.DualTeamSession):
settings.append(
bs.BoolSetting('Balance Total Lives', default=False))
return settings
@classmethod
def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool:
return (issubclass(sessiontype, bs.DualTeamSession))
@classmethod
def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]:
return ['The Pad']
def __init__(self, settings: dict):
super().__init__(settings)
shared = SharedObjects.get()
self._scoreboard = Scoreboard()
self._start_time: Optional[float] = None
self._vs_text: Optional[bs.Actor] = None
self._round_end_timer: Optional[bs.Timer] = None
self._epic_mode = bool(settings['Epic Mode'])
self._lives_per_player = int(settings['Lives Per Player'])
self._time_limit = float(settings['Time Limit'])
self._balance_total_lives = bool(
settings.get('Balance Total Lives', False))
self._solo_mode = True
self._collide_with_player = bs.Material()
self._collide_with_player.add_actions(conditions=('we_are_older_than', 1), actions=(('modify_part_collision', 'collide', True)))
self.left_region = bs.newnode('region',attrs={
'position': (-6.35,5,-2.7),
'scale': (2.1,5,14),
'type': 'box',
'materials': (self._collide_with_player, shared.footing_material)})
self.right_region = bs.newnode('region',attrs={
'position': (6.9,5,-2.7),
'scale': (2.1,5,14),
'type': 'box',
'materials': (self._collide_with_player, shared.footing_material)})
self.bottom_region = bs.newnode('region',attrs={
'position': ((0.36072, 4.62957, 2.8769)),
'scale': (14,5,2.1),
'type': 'box',
'materials': (self._collide_with_player, shared.footing_material)})
self.front_region = bs.newnode('region',attrs={
'position': ((0.36072, 4.62957, -8.5)),
'scale': (14,5,2.1),
'type': 'box',
'materials': (self._collide_with_player, shared.footing_material)})
self.test = bs.newnode('locator',attrs={
'shape':'circleOutline',
'position':(0.3, 3.5, -2.58),
'color':(1,1,1),
'opacity':1,
'draw_beauty':True,
'additive':False,
'size':[100, 0.001, 100]
})
self.size = (5.45*2, 0.001, 5.45*2)
self.rad = 5.30
# Base class overrides:
self.slow_motion = self._epic_mode
self.default_music = (bs.MusicType.EPIC
if self._epic_mode else bs.MusicType.SURVIVAL)
self.tint = (1,1,1)
def get_instance_description(self) -> Union[str, Sequence]:
return 'Last team standing wins.' if isinstance(
self.session, bs.DualTeamSession) else 'Last one standing wins.'
def get_instance_description_short(self) -> Union[str, Sequence]:
return 'last team standing wins' if isinstance(
self.session, bs.DualTeamSession) else 'last one standing wins'
def on_player_join(self, player: Player) -> None:
player.lives = self._lives_per_player
if self._solo_mode:
player.team.spawn_order.append(player)
self._update_solo_mode()
else:
# Create our icon and spawn.
player.icons = [Icon(player, position=(0, 50), scale=0.8)]
if player.lives > 0:
self.spawn_player(player)
# Don't waste time doing this until begin.
if self.has_begun():
self._update_icons()
def on_begin(self) -> None:
super().on_begin()
self._start_time = bs.time()
self.setup_standard_time_limit(self._time_limit)
if self._solo_mode:
self._vs_text = bs.NodeActor(
bs.newnode('text',
attrs={
'position': (0, 105),
'h_attach': 'center',
'h_align': 'center',
'maxwidth': 200,
'shadow': 0.5,
'vr_depth': 390,
'scale': 0.6,
'v_attach': 'bottom',
'color': (0.8, 0.8, 0.3, 1.0),
'text': bs.Lstr(resource='vsText')
}))
# If balance-team-lives is on, add lives to the smaller team until
# total lives match.
if (isinstance(self.session, bs.DualTeamSession)
and self._balance_total_lives and self.teams[0].players
and self.teams[1].players):
if self._get_total_team_lives(
self.teams[0]) < self._get_total_team_lives(self.teams[1]):
lesser_team = self.teams[0]
greater_team = self.teams[1]
else:
lesser_team = self.teams[1]
greater_team = self.teams[0]
add_index = 0
while (self._get_total_team_lives(lesser_team) <
self._get_total_team_lives(greater_team)):
lesser_team.players[add_index].lives += 1
add_index = (add_index + 1) % len(lesser_team.players)
self.tint = bs.get_foreground_host_activity().globalsnode.tint
bs.get_foreground_host_activity().globalsnode.tint = (0.4, 0.4, 0.4)
self._update_icons()
# We could check game-over conditions at explicit trigger points,
# but lets just do the simple thing and poll it.
bs.timer(1.0, self._update, repeat=True)
bs.timer(0.2,self.red_zone,repeat=True)
def red_zone(self) -> None:
try:
bs.animate_array(
self.test,
"size",
3,
{
0: self.size,
0.2: (
self.size[0] - (0.2 if self._epic_mode else 0.1),
self.size[1],
self.size[2] - (0.2 if self._epic_mode else 0.1)
)
},
loop=False
)
self.size = (
self.size[0] - (0.2 if self._epic_mode else 0.1),
self.size[1],
self.size[2] - (0.2 if self._epic_mode else 0.1)
)
self.rad = self.rad - (0.1 if self._epic_mode else 0.05)
for player in self.players:
if not player.actor is None:
if player.actor.is_alive():
p1 = player.actor.node.position
p2 = (0.3, 3.5, -2.58)
diff = (bs.Vec3(p1[0]-p2[0], 0.0, p1[2]-p2[2]))
dist = (diff.length())
if dist > self.rad:
player.actor.handlemessage(bs.DieMessage())
except Exception:
return
def _update_solo_mode(self) -> None:
# For both teams, find the first player on the spawn order list with
# lives remaining and spawn them if they're not alive.
for team in self.teams:
# Prune dead players from the spawn order.
team.spawn_order = [p for p in team.spawn_order if p]
for player in team.spawn_order:
assert isinstance(player, Player)
if player.lives > 0:
if not player.is_alive():
self.spawn_player(player)
break
def _update_icons(self) -> None:
# pylint: disable=too-many-branches
# In free-for-all mode, everyone is just lined up along the bottom.
if isinstance(self.session, bs.FreeForAllSession):
count = len(self.teams)
x_offs = 85
xval = x_offs * (count - 1) * -0.5
for team in self.teams:
if len(team.players) == 1:
player = team.players[0]
for icon in player.icons:
icon.set_position_and_scale((xval, 30), 0.7)
icon.update_for_lives()
xval += x_offs
# In teams mode we split up teams.
else:
if self._solo_mode:
# First off, clear out all icons.
for player in self.players:
player.icons = []
# Now for each team, cycle through our available players
# adding icons.
for team in self.teams:
if team.id == 0:
xval = -60
x_offs = -78
else:
xval = 60
x_offs = 78
is_first = True
test_lives = 1
while True:
players_with_lives = [
p for p in team.spawn_order
if p and p.lives >= test_lives
]
if not players_with_lives:
break
for player in players_with_lives:
player.icons.append(
Icon(player,
position=(xval, (40 if is_first else 25)),
scale=1.0 if is_first else 0.5,
name_maxwidth=130 if is_first else 75,
name_scale=0.8 if is_first else 1.0,
flatness=0.0 if is_first else 1.0,
shadow=0.5 if is_first else 1.0,
show_death=is_first,
show_lives=False))
xval += x_offs * (0.8 if is_first else 0.56)
is_first = False
test_lives += 1
# Non-solo mode.
else:
for team in self.teams:
if team.id == 0:
xval = -50
x_offs = -85
else:
xval = 50
x_offs = 85
for player in team.players:
for icon in player.icons:
icon.set_position_and_scale((xval, 30), 0.7)
icon.update_for_lives()
xval += x_offs
def _get_spawn_point(self, player: Player) -> Optional[bs.Vec3]:
del player # Unused.
# In solo-mode, if there's an existing live player on the map, spawn at
# whichever spot is farthest from them (keeps the action spread out).
if self._solo_mode:
living_player = None
living_player_pos = None
for team in self.teams:
for tplayer in team.players:
if tplayer.is_alive():
assert tplayer.node
ppos = tplayer.node.position
living_player = tplayer
living_player_pos = ppos
break
if living_player:
assert living_player_pos is not None
player_pos = bs.Vec3(living_player_pos)
points: list[tuple[float, bs.Vec3]] = []
for team in self.teams:
start_pos = bs.Vec3(self.map.get_start_position(team.id))
points.append(
((start_pos - player_pos).length(), start_pos))
# Hmm.. we need to sort vectors too?
points.sort(key=lambda x: x[0])
return points[-1][1]
return None
def spawn_player(self, player: Player) -> bs.Actor:
if player.team.id == 0:
spaz = self.spawn_player_spaz(player, position=(-3.02237, 3.52416, -2.81289))
return spaz
elif player.team.id == 1:
spaz = self.spawn_player_spaz(player, position=(3.67858, 3.52384, -2.77144))
return spaz
actor = self.spawn_player_spaz(player, self._get_spawn_point(player))
if not self._solo_mode:
bs.timer(0.3, bs.Call(self._print_lives, player))
# If we have any icons, update their state.
for icon in player.icons:
icon.handle_player_spawned()
def _print_lives(self, player: Player) -> None:
from bascenev1lib.actor import popuptext
# We get called in a timer so it's possible our player has left/etc.
if not player or not player.is_alive() or not player.node:
return
popuptext.PopupText('x' + str(player.lives - 1),
color=(1, 1, 0, 1),
offset=(0, -0.8, 0),
random_offset=0.0,
scale=1.8,
position=player.node.position).autoretain()
def on_player_leave(self, player: Player) -> None:
super().on_player_leave(player)
player.icons = []
# Remove us from spawn-order.
if self._solo_mode:
if player in player.team.spawn_order:
player.team.spawn_order.remove(player)
# Update icons in a moment since our team will be gone from the
# list then.
bs.timer(0, self._update_icons)
# If the player to leave was the last in spawn order and had
# their final turn currently in-progress, mark the survival time
# for their team.
if self._get_total_team_lives(player.team) == 0:
assert self._start_time is not None
player.team.survival_seconds = int(bs.time() - self._start_time)
def _get_total_team_lives(self, team: Team) -> int:
return sum(player.lives for player in team.players)
def handlemessage(self, msg: Any) -> Any:
if isinstance(msg, bs.PlayerDiedMessage):
# Augment standard behavior.
super().handlemessage(msg)
player = msg.getplayer(Player)
player.lives -= 1
if player.lives < 0:
logging.error(
"Got lives < 0 in Elim; this shouldn't happen. solo:" +
str(self._solo_mode))
player.lives = 0
# If we have any icons, update their state.
for icon in player.icons:
icon.handle_player_died()
# Play big death sound on our last death
# or for every one in solo mode.
if self._solo_mode or player.lives == 0:
SpazFactory.get().single_player_death_sound.play()
# If we hit zero lives, we're dead (and our team might be too).
if player.lives == 0:
# If the whole team is now dead, mark their survival time.
if self._get_total_team_lives(player.team) == 0:
assert self._start_time is not None
player.team.survival_seconds = int(bs.time() -
self._start_time)
else:
# Otherwise, in regular mode, respawn.
if not self._solo_mode:
self.respawn_player(player)
# In solo, put ourself at the back of the spawn order.
if self._solo_mode:
player.team.spawn_order.remove(player)
player.team.spawn_order.append(player)
def _update(self) -> None:
if self._solo_mode:
# For both teams, find the first player on the spawn order
# list with lives remaining and spawn them if they're not alive.
for team in self.teams:
# Prune dead players from the spawn order.
team.spawn_order = [p for p in team.spawn_order if p]
for player in team.spawn_order:
assert isinstance(player, Player)
if player.lives > 0:
if not player.is_alive():
self.size = (5.45*2, 0.001, 5.45*2)
self.rad = 5.30
self.spawn_player(player)
self._update_icons()
break
# If we're down to 1 or fewer living teams, start a timer to end
# the game (allows the dust to settle and draws to occur if deaths
# are close enough).
if len(self._get_living_teams()) < 2:
self._round_end_timer = bs.Timer(0.5, self.end_game)
def _get_living_teams(self) -> list[Team]:
return [
team for team in self.teams
if len(team.players) > 0 and any(player.lives > 0
for player in team.players)
]
def end_game(self) -> None:
if self.has_ended():
return
results = bs.GameResults()
self._vs_text = None # Kill our 'vs' if its there.
for team in self.teams:
results.set_team_score(team, team.survival_seconds)
bs.get_foreground_host_activity().globalsnode.tint = self.tint
self.end(results=results)

View file

@ -0,0 +1,416 @@
# ba_meta require api 8
from typing import Sequence
import random
import bascenev1, babase, baclassic, baplus, bauiv1
from bascenev1lib.actor.spaz import Spaz
from bascenev1lib.actor.scoreboard import Scoreboard
from bascenev1lib.gameutils import SharedObjects
from bascenev1lib.actor.powerupbox import PowerupBoxFactory
class Player(bascenev1.Player['Team']):
"""Our player type for this game."""
class Team(bascenev1.Team[Player]):
"""Our team type for this game."""
def __init__(self) -> None:
super().__init__()
self.score = 1
class ChoosingThingHitMessage:
def __init__(self, hitter:Player) -> None:
self.hitter = hitter
class ChoosingThingDieMessage:
def __init__(self, how:bascenev1.DeathType) -> None:
self.how = how
class ChoosingThing():
def __init__(self, pos, color) -> None:
pass
def recolor(self, color:list[int | float], highlight:list[int, float] = (1,1,1)):
raise NotImplementedError()
def is_dead(self):
raise NotImplementedError()
def _is_dead(self):
return self.is_dead()
def create_locator(self, node:bascenev1.Node, pos, color):
loc = bascenev1.newnode(
'locator',
attrs={
'shape': 'circleOutline',
'position': pos,
'color': color,
'opacity': 1,
'draw_beauty': False,
'additive': True,
},
)
node.connectattr("position", loc, "position")
bascenev1.animate_array(loc, "size", 1, keys={0:[0.5,], 1:[2,], 1.5:[0.5]}, loop=True)
return loc
dead = property(_is_dead)
class ChoosingSpaz(Spaz, ChoosingThing):
def __init__(
self,
pos:Sequence[float],
color: Sequence[float] = (1.0, 1.0, 1.0),
highlight: Sequence[float] = (0.5, 0.5, 0.5),
):
super().__init__(color, highlight, "Spaz", None, True, True, False, False)
self.stand(pos)
self.loc = self.create_locator(self.node, pos, color)
def handlemessage(self, msg):
if isinstance(msg, bascenev1.FreezeMessage):
return
if isinstance(msg, bascenev1.PowerupMessage):
if not(msg.poweruptype == "health"):
return
super().handlemessage(msg)
if isinstance(msg, bascenev1.HitMessage):
self.handlemessage(bascenev1.PowerupMessage("health"))
player = msg.get_source_player(Player)
if self.is_alive():
self.activity.handlemessage(ChoosingThingHitMessage(player))
elif isinstance(msg, bascenev1.DieMessage):
self._dead = True
self.activity.handlemessage(ChoosingThingDieMessage(msg.how))
self.loc.delete()
def stand(self, pos = (0,0,0), angle = 0):
self.handlemessage(bascenev1.StandMessage(pos,angle))
def recolor(self, color, highlight = (1,1,1)):
self.node.color = color
self.node.highlight = highlight
self.loc.color = color
def is_dead(self):
return self._dead
class ChoosingBall(bascenev1.Actor, ChoosingThing):
def __init__(self, pos, color = (0.5,0.5,0.5)) -> None:
super().__init__()
shared = SharedObjects.get()
pos = (pos[0], pos[1] + 2, pos[2])
# We want the puck to kill powerups; not get stopped by them
self.puck_material = bascenev1.Material()
self.puck_material.add_actions(
conditions=('they_have_material',
PowerupBoxFactory.get().powerup_material),
actions=(('modify_part_collision', 'physical', False),
('message', 'their_node', 'at_connect', bascenev1.DieMessage())))
#fontSmall0 jumpsuitColor menuBG operaSingerColor rgbStripes zoeColor
self.node = bascenev1.newnode('prop',
delegate=self,
attrs={
'mesh': bascenev1.getmesh('frostyPelvis'),
'color_texture':
bascenev1.gettexture('gameCenterIcon'),
'body': 'sphere',
'reflection': 'soft',
'reflection_scale': [0.2],
'shadow_size': 0.5,
'is_area_of_interest': True,
'position': pos,
"materials": [shared.object_material, self.puck_material]
})
#seince this ball allways jumps a specefic direction when it spawned, we just jump it randomly
self.node.handlemessage(
'impulse',
random.uniform(-10, 10),
random.uniform(-10, 10),
random.uniform(-10, 10),
random.uniform(-10, 10),
random.uniform(-10, 10),
random.uniform(-10, 10),
random.uniform(-10, 10),
random.uniform(-10, 10),
0,
random.uniform(-10, 10),
random.uniform(-10, 10),
random.uniform(-10, 10),
random.uniform(-10, 10),
)
self.loc = self.create_locator(self.node, pos, color)
self._died = False
def handlemessage(self, msg):
if isinstance(msg, bascenev1.HitMessage):
player = msg.get_source_player(Player)
self.activity.handlemessage(ChoosingThingHitMessage(player))
mag = msg.magnitude
velocity_mag = msg.velocity_magnitude
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],
)
elif isinstance(msg, bascenev1.DieMessage):
if self.node.exists():
self.node.delete()
self.loc.delete()
self._died = True
self.activity.handlemessage(ChoosingThingDieMessage(msg.how))
return super().handlemessage(msg)
def exists(self) -> bool:
return not self.dead
def is_alive(self) -> bool:
return not self.dead
def recolor(self, color: list[int | float], highlight: list[int] = (1, 1, 1)):
self.loc.color = color
def is_dead(self):
return self._died
class ChooseBilbord(bascenev1.Actor):
def __init__(self, player:Player, delay = 0.1) -> None:
super().__init__()
icon = player.get_icon()
self.scale = 100
self.node = bascenev1.newnode(
'image',
delegate=self,
attrs={
"position":(60,-125),
'texture': icon['texture'],
'tint_texture': icon['tint_texture'],
'tint_color': icon['tint_color'],
'tint2_color': icon['tint2_color'],
'opacity': 1.0,
'absolute_scale': True,
'attach': "topLeft"
},
)
self.name_node = bascenev1.newnode(
'text',
owner=self.node,
attrs={
'position': (60,-185),
'text': bascenev1.Lstr(value=player.getname()),
'color': bascenev1.safecolor(player.team.color),
'h_align': 'center',
'v_align': 'center',
'vr_depth': 410,
'flatness': 1.0,
'h_attach': 'left',
'v_attach': 'top',
'maxwidth':self.scale
},
)
bascenev1.animate_array(self.node, "scale", keys={0 + delay:[0,0], 0.05 + delay:[self.scale, self.scale]}, size=1)
bascenev1.animate(self.name_node, "scale", {0 + delay:0, 0.07 + delay:1})
def handlemessage(self, msg):
super().handlemessage(msg)
if isinstance(msg, bascenev1.DieMessage):
bascenev1.animate_array(self.node, "scale", keys={0:self.node.scale, 0.05:[0,0]}, size=1)
bascenev1.animate(self.name_node, "scale", {0:self.name_node.scale, 0.07:0})
def __delete():
self.node.delete()
self.name_node.delete()
bascenev1.timer(0.2, __delete)
# ba_meta export bascenev1.GameActivity
class LastPunchStand(bascenev1.TeamGameActivity[Player, Team]):
name = "Last Punch Stand"
description = "Last one punchs the choosing thing wins"
tips = [
'keep punching the choosing thing to be last punched player at times up!',
'you can not frezz the choosing spaz',
"evry time you punch the choosing thing, you will get one point",
]
default_music = bascenev1.MusicType.TO_THE_DEATH
def get_instance_display_string(self) -> bascenev1.Lstr:
name = self.name
if self.settings_raw["Ball Mode"]:
name += " Ball Mode"
return name
def get_instance_description_short(self) -> str | Sequence:
if self.settings_raw["Ball Mode"]:
return "Punch the Ball"
else:
return "Punch the Spaz"
available_settings = [
bascenev1.BoolSetting("Ball Mode", False),
bascenev1.FloatSetting("min time limit (in seconds)", 50.0, min_value=30.0),
bascenev1.FloatSetting("max time limit (in seconds)", 160.0, 60),
]
def __init__(self, settings: dict):
super().__init__(settings)
self._min_timelimit = settings["min time limit (in seconds)"]
self._max_timelimit = settings["max time limit (in seconds)"]
self.ball_mod:bool = settings["Ball Mode"]
if (self._min_timelimit > self._max_timelimit):
self._max_timelimit = self._min_timelimit
self._choosing_thing_defcolor = (0.5,0.5,0.5)
self.choosing_thing:ChoosingThing = None
self.choosed_player = None
self.times_uped = False
self.scoreboard = Scoreboard()
@classmethod
def get_supported_maps(cls, sessiontype: type[bascenev1.Session]) -> list[str]:
assert bascenev1.app.classic is not None
return bascenev1.app.classic.getmaps('team_flag')
def times_up(self):
self.times_uped = True
self.end_game()
for player in self.players:
try:
if self.choosed_player and player and (player.team.id != self.choosed_player.team.id):
player.actor._cursed = True
player.actor.curse_explode()
except AttributeError:
pass
def __get_thing_spawn_point(self):
if len(self.map.flag_points_default) > 0:
return self.map.get_flag_position(None)
elif len(self.map.tnt_points) > 0:
return self.map.tnt_points[random.randint(0, len(self.map.tnt_points)-1)]
else:
return (0, 6, 0)
def spaw_bot(self):
"spawns a choosing bot"
if self.ball_mod:
self.choosing_thing = ChoosingBall(self.__get_thing_spawn_point())
else:
self.choosing_thing = ChoosingSpaz(self.__get_thing_spawn_point())
self.choose_bilbord = None
def on_begin(self) -> None:
super().on_begin()
time_limit = random.randint(self._min_timelimit, self._max_timelimit)
self.spaw_bot()
bascenev1.timer(time_limit, self.times_up)
self.setup_standard_powerup_drops(False)
def end_game(self) -> None:
results = bascenev1.GameResults()
total = 0
for team in self.teams:
total = team.score
for team in self.teams:
if self.choosed_player and (team.id == self.choosed_player.team.id): team.score += total
results.set_team_score(team, team.score)
self.end(results=results)
def change_choosed_player(self, hitter:Player):
if hitter == self.choosed_player:
return
if hitter:
self.choosing_thing.recolor(hitter.color, hitter.highlight)
self.choosed_player = hitter
hitter.team.score += 1
self.choose_bilbord = ChooseBilbord(hitter)
self.hide_score_board()
else:
self.choosing_thing.recolor(self._choosing_thing_defcolor)
self.choosed_player = None
self.choose_bilbord = None
self.show_score_board()
def show_score_board(self):
self.scoreboard = Scoreboard()
for team in self.teams:
self.scoreboard.set_team_value(team, team.score)
def hide_score_board(self):
self.scoreboard = None
def _watch_dog_(self):
"checks if choosing spaz exists"
#choosing spaz wont respawn if death type if generic
#this becuse we dont want to keep respawn him when he dies because of losing referce
#but sometimes "choosing spaz" dies naturaly and his death type is generic! so it wont respawn back again
#thats why we have this function; to check if spaz exits in the case that he didnt respawned
if self.choosing_thing:
if self.choosing_thing.dead:
self.spaw_bot()
else:
self.spaw_bot()
def handlemessage(self, msg):
super().handlemessage(msg)
if isinstance(msg, ChoosingThingHitMessage):
hitter = msg.hitter
if hitter:
self.change_choosed_player(hitter)
elif isinstance(msg, ChoosingThingDieMessage):
if msg.how.value != bascenev1.DeathType.GENERIC.value:
self.spaw_bot()
self.change_choosed_player(None)
elif isinstance(msg, bascenev1.PlayerDiedMessage):
player = msg.getplayer(Player)
if not (self.has_ended() or self.times_uped):
self.respawn_player(player, 0)
if self.choosed_player and (player.getname(True) == self.choosed_player.getname(True)):
self.change_choosed_player(None)
self._watch_dog_()

410
dist/ba_root/mods/games/tag.py vendored Normal file
View file

@ -0,0 +1,410 @@
"""Made by: Sebaman2009"""
# ba_meta require api 8
# (see https://ballistica.net/wiki/meta-tag-system)
from __future__ import annotations
from typing import TYPE_CHECKING
from typing_extensions import override
import bascenev1 as bs
import random
from bascenev1lib.actor.playerspaz import PlayerSpazHurtMessage
from bascenev1lib.actor.playerspaz import PlayerSpaz
from bascenev1lib.actor.scoreboard import Scoreboard
import bascenev1lib
import babase
import _bascenev1
from bascenev1lib.game.elimination import Icon
if TYPE_CHECKING:
from typing import Any, Sequence
class LivesRemaining(bs.Actor):
def __init__(self,team):
super().__init__()
self.team = team
self.teamcolor = team.color
self.bar_posx = -100 - 120
self._height = 35
self._width = 70
self._bar_tex = self._backing_tex = bs.gettexture('bar')
self._cover_tex = bs.gettexture('uiAtlas')
self._mesh = bs.getmesh('meterTransparent')
self._backing = bs.NodeActor(
bs.newnode(
'image',
attrs={
'position': (self.bar_posx + self._width / 2, -35) if team.id == 0 else (-self.bar_posx + -self._width / 2, -35),
'scale': (self._width, self._height),
'opacity': 0.7,
'color': (
self.teamcolor[0] * 0.2,
self.teamcolor[1] * 0.2,
self.teamcolor[2] * 0.2,
),
'vr_depth': -3,
'attach': 'topCenter',
'texture': self._backing_tex
}))
self._cover = bs.NodeActor(
bs.newnode(
'image',
attrs={
'position': (self.bar_posx + 35, -35) if team.id == 0 else (-self.bar_posx - 35, -35),
'scale': (self._width * 1.15, self._height * 1.6),
'opacity': 1.0,
'color': (
self.teamcolor[0] * 1.1,
self.teamcolor[1] * 1.1,
self.teamcolor[2] * 1.1,
),
'vr_depth': 2,
'attach': 'topCenter',
'texture': self._cover_tex,
'mesh_transparent': self._mesh}))
self._score_text = bs.NodeActor(
bs.newnode(
'text',
attrs={
'position': (self.bar_posx +35 , -35) if team.id == 0 else (-self.bar_posx - 35, -35),
'h_attach': 'center',
'v_attach': 'top',
'h_align': 'center',
'v_align': 'center',
'maxwidth': 130,
'scale': 0.9,
'text': str(len(self.team.players)),
'shadow': 0.5,
'flatness': 1.0,
'color': (1,1,1,0.8)
}))
def update_text(self,num):
text = bs.NodeActor(bs.newnode('text',attrs={'position': (self.bar_posx + 35 , -35) if self.team.id == 0 else (-self.bar_posx - 35 , -35) ,'h_attach': 'center','v_attach': 'top','h_align': 'center','v_align': 'center','maxwidth': 130,'scale': 0.9,'text': str(num),'shadow': 0.5,'flatness': 1.0,'color': (1,1,1,0.8)}))
return text
def flick(self):
_bascenev1.Sound.play(bs.getsound("shieldDown"))
bs.animate(
self._score_text.node,
'opacity',
{
0.00: 1.0,
0.05: 0.0,
0.10: 1.0,
0.15: 0.0,
0.20: 1.0,
0.25: 0.0,
0.30: 1.0,
0.35: 0.0,
0.40: 1.0,
0.45: 0.0,
0.50: 0.2,
0.55: 1.0,
0.60: 0.0,
0.65: 0.2,
0.70: 1.0,
0.75: 0.0,
0.80: 0.2,
0.85: 1.0,
0.90: 0.0,
0.95: 0.2,
1.00: 1.0,
},
)
class Player(bs.Player['Team']):
"""Our player type for this game."""
def __init__(self) -> None:
self.tag_light: bs.NodeActor | None = None
self.lives = 1
self.time = 0
class Team(bs.Team[Player]):
"""Our team type for this game."""
def __init__(self) -> None:
self.score = 0
self.survival_seconds = int()
lista = []
# ba_meta export bascenev1.GameActivity
class Tag(bs.TeamGameActivity[Player, Team]):
"""A game type based on acquiring kills."""
name = 'Tag'
description = "Don't get caught!"
scoreconfig = bs.ScoreConfig(
label='Survived', scoretype=bs.ScoreType.SECONDS
)
# Print messages when players die since it matters here.
allow_mid_activity_joins = False
announce_player_deaths = True
@classmethod
def get_available_settings(
cls, sessiontype: Type[bs.Session]) -> List[babase.Setting]:
settings = [
bs.IntChoiceSetting(
"Tag time",
choices=[
('Shorter',15),
('Normal', 20),
('Longer',25),
],
default=20,),
bs.BoolSetting('Epic Mode', default=False),
bs.BoolSetting('Disable Bombs', default=False),
bs.BoolSetting('Disable Pickup', default=False),
bs.BoolSetting('Tag explodes when time ends', default=True)]
return settings
@classmethod
def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool:
return (issubclass(sessiontype, bs.DualTeamSession)
or issubclass(sessiontype, bs.FreeForAllSession))
@classmethod
def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]:
return bs.app.classic.getmaps('melee')
def __init__(self, settings: dict):
super().__init__(settings)
self._dingsound = bs.getsound('dingSmall')
self.tag_length = int(settings["Tag time"])
self._epic_mode = bool(settings['Epic Mode'])
self.bombs = bool(settings['Disable Bombs'])
self.grab = bool(settings['Disable Pickup'])
self.explode = bool(settings['Tag explodes when time ends'])
self.alive_teams = [team for team in self.teams if len(team.players) > 0 and any(player.lives > 0 for player in team.players)]
self.ended = False
# Base class overrides.
self.default_music = (bs.MusicType.EPIC if self._epic_mode else
bs.MusicType.RACE)
self.tag = ""
self.tag_act = ""
self.time = self.tag_length
self._countdownsounds: dict[int, bs.Sound] = {
10: bs.getsound('announceTen'),
9: bs.getsound('announceNine'),
8: bs.getsound('announceEight'),
7: bs.getsound('announceSeven'),
6: bs.getsound('announceSix'),
5: bs.getsound('announceFive'),
4: bs.getsound('announceFour'),
3: bs.getsound('announceThree'),
2: bs.getsound('announceTwo'),
1: bs.getsound('announceOne'),
}
self.slow_motion = self._epic_mode
def get_instance_description(self) -> Union[str, Sequence]:
return "Don't get tagged!"
def get_instance_description_short(self) -> Union[str, Sequence]:
return "Don't get tagged!"
def tick(self):
self.time -= 1
if self.time == 0:
if self.explode == True:
self.tag_act.curse_time = 0.000000000000000000001
self.tag_act.curse()
else:
self.tag_act.handlemessage(bs.DieMessage())
if self.time in self._countdownsounds:
self._countdownsounds[self.time].play()
self.tag_act.set_score_text(f"{self.time}",self.color,True)
else:
self.tag_act.set_score_text(f"{self.time}",self.color)
def select_tag(self):
alive = self._get_living_teams()
print(alive)
self.tag = random.choice(alive) if alive else self.end_game()
self.player_count = len(bs.getactivity().players)
self.tag_act = self.tag.actor
self.tag_act.invincible = True
self.tag_act.set_score_text("Tag")
self.color = [
0.3 + c * 0.7
for c in bs.normalized_color(self.tag.team.color)
]
light = self.tag_act.tag_light = bs.NodeActor(
bs.newnode(
'light',
attrs={
'intensity': 0.6,
'height_attenuated': False,
'volume_intensity_scale': 0.1,
'radius': 0.13,
'color': self.color},
)
)
assert isinstance(self.tag_act, PlayerSpaz)
self.tag_act.node.connectattr(
'position', light.node, 'position'
)
self.cuenta = bs.Timer(1.0,call= self.tick,repeat = True)
def flick(self):
bs.animate(
self.icon.node,
'opacity',
{
0.00: 1.0,
0.05: 0.0,
0.10: 1.0,
0.15: 0.2,
0.20: 1.0,
0.25: 0.0,
0.30: 1.0,
},
)
bs.animate(
self.icon._name_text,
'opacity',
{
0.00: 1.0,
0.05: 0.0,
0.10: 1.0,
0.15: 0.2,
0.20: 1.0,
0.25: 0.0,
0.30: 1.0,
},
)
def on_begin(self):
super().on_begin()
if len(bs.getactivity().players) == 1:
self.end_game()
if isinstance(self.session, bs.DualTeamSession) == True:
self.team_one_bar = LivesRemaining(self.teams[0])
self.team_two_bar = LivesRemaining(self.teams[1])
self._start_time = bs.time()
self.select_tag()
self.icon = Icon(player = self.tag,position = (0 ,600),scale = 1.0, show_lives = False)
players = self._get_living_teams()
for player in players:
actor = player.actor
actor.hitpoints = 20000000000000000000000000000000000
actor.hitpoints_max = 20000000000000000000000000000000000
if self.bombs == True and self.grab == True:
actor.disconnect_controls_from_player()
actor.connect_controls_to_player(enable_bomb = False,enable_pickup = False)
elif self.bombs == True and self.grab == False:
actor.disconnect_controls_from_player()
actor.connect_controls_to_player(enable_bomb = False)
elif self.bombs == False and self.grab == True:
actor.disconnect_controls_from_player()
actor.connect_controls_to_player(enable_grab = False)
else:
pass
def on_player_join(self, player):
self.spawn_player(player)
def on_player_leave(self,player):
self.player_count -= 1
if player == self.tag:
self.select_tag()
if self.check_win() != None:
alive = self.check_win()
print(alive)
alive.survival_seconds += int(bs.time() - self._start_time)
self.end_game()
def _get_living_teams(self) -> list[Team]:
alive = []
for team in self.teams:
for player in team.players:
if player.lives > 0:
alive.append(player)
return alive
def check_win(self):
alive_teams = [
team for team in self.teams if len(team.players) > 0 and any(player.lives > 0 for player in team.players)
]
print(alive_teams)
if len(alive_teams) == 1:
alive_teams[0].survival_seconds += int(bs.time() - self._start_time)
for player in alive_teams[0].players:
player.team.score += 1
self.end_game()
def reselect_tag(self):
if self.ended == False:
self.select_tag()
self.icon.node.delete()
self.icon = Icon(player = self.tag,position = (0 ,600),scale = 1.0, show_lives = False)
self.flick()
def handlemessage(self, msg: Any) -> Any:
super().handlemessage(msg)
if isinstance(msg, bs.PlayerDiedMessage):
self.player_count -= 1
msg.getplayer(Player).lives -= 1
alive_teams = [team for team in self.teams if len(team.players) > 0 and any(player.lives > 0 for player in team.players)]
if msg.getplayer(Player).team not in alive_teams:
msg.getplayer(Player).team.survival_seconds += int(bs.time() - self._start_time)
if isinstance(self.session, bs.DualTeamSession):
if msg.getplayer(Player).team == self.teams[0]:
self.team_one_bar._score_text = self.team_one_bar.update_text(int(self.team_one_bar._score_text.node.text)-1)
self.team_one_bar.flick()
else:
self.team_two_bar._score_text = self.team_two_bar.update_text(int(self.team_two_bar._score_text.node.text)-1)
self.team_two_bar.flick()
bs.timer(1.0,self.check_win)
if msg.getplayer(Player).node == self.tag.node:
self.cuenta = None
if self.tag_act:
self.tag_act.tag_light = None
self.time = self.tag_length
bs.animate(
self.icon.node,
'opacity',
{0.00: 1.0,0.05: 0.5,0.10: 0.3,0.15: 0.2,})
bs.animate(
self.icon._name_text,
'opacity',
{0.00: 1.0,0.05: 0.5,0.10: 0.3,0.15: 0.2,})
self.tag_act = None
bs.timer(2.0,self.reselect_tag)
elif isinstance(msg, PlayerSpazHurtMessage):
player = msg.spaz
player_act = player.getplayer(playertype = Player)
if player.last_player_attacked_by == self.tag:
player.last_player_attacked_by = None
if self.tag_act:
self.tag_act.tag_light = None
self.tag_act = player
self.tag = self.tag_act.getplayer(playertype = Player)
self.color = [
0.3 + c * 0.7
for c in bs.normalized_color(self.tag_act.getplayer(playertype = Player).color)
]
light = self.tag_act.tag_light = bs.NodeActor(
bs.newnode(
'light',
attrs={
'intensity': 0.6,
'height_attenuated': False,
'volume_intensity_scale': 0.1,
'radius': 0.13,
'color': self.color},
)
)
assert isinstance(self.tag_act, PlayerSpaz)
self.tag_act.node.connectattr(
'position', light.node, 'position'
)
self.icon.node.delete()
self.icon = Icon(player = self.tag,position = (0 ,600),scale = 1.0, show_lives = False)
self.flick()
def end_game(self) -> None:
self.ended = True
results = bs.GameResults()
for team in self.teams:
results.set_team_score(team, team.survival_seconds)
self.end(results=results)