maps and games

This commit is contained in:
Ayush Saini 2023-03-05 01:04:38 +05:30
parent f83e0008e4
commit e1f9eafae1
24 changed files with 5152 additions and 11 deletions

View file

@ -34,6 +34,10 @@
"71":{
"log":"BS 1.7.10 update , bug fix , V2 account support, prop rotation",
"time":"2 Oct 2022"
},
"75": {
"log": "bug fixes, BS 1.7.19 , season end notfication, server restart notification, more maps and games",
"time": "4 March 2023"
}
}

View file

@ -31,7 +31,7 @@ from spazmod import modifyspaz
from tools import servercheck, ServerUpdate, logger, playlist
from playersData import pdata
from features import EndVote
from features import text_on_map
from features import text_on_map, announcement
from features import map_fun
from spazmod import modifyspaz
if TYPE_CHECKING:
@ -194,9 +194,8 @@ def new_end(self, results: Any = None, delay: float = 0.0, force: bool = False):
_ba.prop_axis(1, 0, 0)
if isinstance(activity, CoopScoreScreen):
team_balancer.checkToExitCoop()
announcement.showScoreScreenAnnouncement()
org_end(self, results, delay, force)
ba._activity.Activity.end = new_end
org_player_join = ba._activity.Activity.on_player_join
@ -257,6 +256,7 @@ def shutdown(func) -> None:
"""Set the app to quit either now or at the next clean opportunity."""
def wrapper(*args, **kwargs):
# add screen text and tell players we are going to restart soon.
ba.internal.chatmessage("Server will restart on next opportunity. (series end)")
_ba.restart_scheduled = True
_ba.get_foreground_host_activity().restart_msg = _ba.newnode('text',
attrs={

View file

@ -0,0 +1,12 @@
import ba
import ba.internal
import setting
import random
setti=setting.get_settings_data()
def showScoreScreenAnnouncement():
if setti["ScoreScreenAnnouncement"]["enable"]:
color=((0+random.random()*1.0),(0+random.random()*1.0),(0+random.random()*1.0))
msgs = setti["ScoreScreenAnnouncement"]["msg"]
ba.screenmessage(random.choice(msgs), color = color)

View file

@ -8,8 +8,6 @@ import ba.internal
import setting
from stats import mystats
from datetime import datetime
import random
setti=setting.get_settings_data()
class textonmap:
@ -30,7 +28,7 @@ class textonmap:
self.nextGame(nextMap)
self.restart_msg()
if hasattr(_ba, "season_ends_in_days"):
if _ba.season_ends_in_days < 8:
if _ba.season_ends_in_days < 9:
self.season_reset(_ba.season_ends_in_days)
if setti["leaderboard"]["enable"]:
self.leaderBoard()

482
dist/ba_root/mods/games/BlockDash.py vendored Normal file
View file

@ -0,0 +1,482 @@
# Released under the MIT License. See LICENSE for details.
#
"""Elimination mini-game."""
# ba_meta require api 7
# (see https://ballistica.net/wiki/meta-tag-system)
from __future__ import annotations
from typing import TYPE_CHECKING
import ba,_ba
from bastd.actor.spazfactory import SpazFactory
from bastd.actor.scoreboard import Scoreboard
from bastd.gameutils import SharedObjects
if TYPE_CHECKING:
from typing import Any, Sequence, Optional, Union
import random
from games.lib import Player,Team,Icon,eli
from bastd.game.elimination import EliminationGame
# ba_meta export game
class BlockDashGame(EliminationGame):
"""Game type where last player(s) left alive win."""
name = 'Block Dash'
description = 'Last remaining alive wins.'
scoreconfig = ba.ScoreConfig(label='Survived',
scoretype=ba.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_supported_maps(cls, sessiontype: type[ba.Session]) -> list[str]:
return ["Wooden Floor"]
def __init__(self, settings: dict):
super().__init__(settings)
shared=SharedObjects.get()
self._scoreboard = Scoreboard()
self._start_time: Optional[float] = None
self._vs_text: Optional[ba.Actor] = None
self._round_end_timer: Optional[ba.Timer] = None
self._epic_mode = bool(settings['Epic Mode'])
self._lives_per_player =1
self._time_limit = float(settings['Time Limit'])
self._balance_total_lives = bool(
settings.get('Balance Total Lives', False))
self._solo_mode = bool(settings.get('Solo Mode', False))
# Base class overrides:
self.slow_motion = self._epic_mode
self.default_music = (ba.MusicType.EPIC
if self._epic_mode else ba.MusicType.SURVIVAL)
self.laser_material=ba.Material()
self.laser_material.add_actions(
conditions=('they_have_material',
shared.player_material),
actions=(('modify_part_collision', 'collide',True),
('message','their_node','at_connect',ba.DieMessage()))
)
def get_instance_description(self) -> Union[str, Sequence]:
return 'Last team standing wins.' if isinstance(
self.session, ba.DualTeamSession) else 'Last one standing wins.'
def get_instance_description_short(self) -> Union[str, Sequence]:
return 'last team standing wins' if isinstance(
self.session, ba.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 = ba.time()
self.setup_standard_time_limit(self._time_limit)
# self.setup_standard_powerup_drops()
self.add_wall()
if self._solo_mode:
self._vs_text = ba.NodeActor(
ba.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': ba.Lstr(resource='vsText')
}))
# If balance-team-lives is on, add lives to the smaller team until
# total lives match.
if (isinstance(self.session, ba.DualTeamSession)
and self._balance_total_lives and self.teams[0].players
and self.teams[1].players):
if self._get_total_team_lives(
self.teams[0]) < self._get_total_team_lives(self.teams[1]):
lesser_team = self.teams[0]
greater_team = self.teams[1]
else:
lesser_team = self.teams[1]
greater_team = self.teams[0]
add_index = 0
while (self._get_total_team_lives(lesser_team) <
self._get_total_team_lives(greater_team)):
lesser_team.players[add_index].lives += 1
add_index = (add_index + 1) % len(lesser_team.players)
self._update_icons()
# We could check game-over conditions at explicit trigger points,
# but lets just do the simple thing and poll it.
ba.timer(1.0, self._update, repeat=True)
def _update_solo_mode(self) -> None:
# For both teams, find the first player on the spawn order list with
# lives remaining and spawn them if they're not alive.
for team in self.teams:
# Prune dead players from the spawn order.
team.spawn_order = [p for p in team.spawn_order if p]
for player in team.spawn_order:
assert isinstance(player, Player)
if player.lives > 0:
if not player.is_alive():
self.spawn_player(player)
break
def _update_icons(self) -> None:
return
# lets do nothing ;Eat 5 Star
def _get_spawn_point(self, player: Player) -> Optional[ba.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 = ba.Vec3(living_player_pos)
points: list[tuple[float, ba.Vec3]] = []
for team in self.teams:
start_pos = ba.Vec3(self.map.get_start_position(team.id))
points.append(
((start_pos - player_pos).length(), start_pos))
# Hmm.. we need to sorting vectors too?
points.sort(key=lambda x: x[0])
return points[-1][1]
return None
def spawn_player(self, player: Player) -> ba.Actor:
p=[-6,-4.3,-2.6,-0.9,0.8,2.5,4.2,5.9]
q=[-4,-2.3,-0.6,1.1,2.8,4.5]
x=random.randrange(0,len(p))
y=random.randrange(0,len(q))
actor = self.spawn_player_spaz(player, position=(0,1.8,0))
actor.connect_controls_to_player(enable_punch=False,
enable_bomb=False,
enable_pickup=False)
if not self._solo_mode:
ba.timer(0.3, ba.Call(self._print_lives, player))
# If we have any icons, update their state.
for icon in player.icons:
icon.handle_player_spawned()
return actor
def _print_lives(self, player: Player) -> None:
from bastd.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.
ba.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(ba.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, ba.PlayerDiedMessage):
# Augment standard behavior.
super().handlemessage(msg)
player: Player = msg.getplayer(Player)
player.lives -= 1
if player.lives < 0:
ba.print_error(
"Got lives < 0 in Elim; this shouldn't happen. solo:" +
str(self._solo_mode))
player.lives = 0
# If we have any icons, update their state.
for icon in player.icons:
icon.handle_player_died()
# Play big death sound on our last death
# or for every one in solo mode.
if self._solo_mode or player.lives == 0:
ba.playsound(SpazFactory.get().single_player_death_sound)
# 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(ba.time() -
self._start_time)
else:
# Otherwise, in regular mode, respawn.
if not self._solo_mode:
self.respawn_player(player)
# In solo, put ourself at the back of the spawn order.
if self._solo_mode:
player.team.spawn_order.remove(player)
player.team.spawn_order.append(player)
def _update(self) -> None:
if self._solo_mode:
# For both teams, find the first player on the spawn order
# list with lives remaining and spawn them if they're not alive.
for team in self.teams:
# Prune dead players from the spawn order.
team.spawn_order = [p for p in team.spawn_order if p]
for player in team.spawn_order:
assert isinstance(player, Player)
if player.lives > 0:
if not player.is_alive():
self.spawn_player(player)
self._update_icons()
break
# If we're down to 1 or fewer living teams, start a timer to end
# the game (allows the dust to settle and draws to occur if deaths
# are close enough).
if len(self._get_living_teams()) < 2:
self._round_end_timer = ba.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 = ba.GameResults()
self._vs_text = None # Kill our 'vs' if its there.
for team in self.teams:
results.set_team_score(team, team.survival_seconds)
self.end(results=results)
def add_wall(self):
# FIXME: Chop this into vr and non-vr chunks.
shared = SharedObjects.get()
pwm=ba.Material()
cwwm=ba.Material()
# pwm.add_actions(
# actions=('modify_part_collision', 'friction', 0.0))
# anything that needs to hit the wall should apply this.
pwm.add_actions(
actions=(
('modify_part_collision', 'collide', True),
('modify_part_collision', 'physical', True)
))
self.mat = ba.Material()
self.mat.add_actions(
actions=( ('modify_part_collision','physical',False),
('modify_part_collision','collide',False))
)
ud_1_r=ba.newnode('region',attrs={'position': (-2,0,-4),'scale': (14.5,1,14.5),'type': 'box','materials': [shared.footing_material,pwm ]})
node = ba.newnode('prop',
owner=ud_1_r,
attrs={
'model':ba.getmodel('image1x1'),
'light_model':ba.getmodel('powerupSimple'),
'position':(2,7,2),
'body':'puck',
'shadow_size':0.0,
'velocity':(0,0,0),
'color_texture':ba.gettexture('flagColor'),
'model_scale':14.5,
'reflection_scale':[1.5],
'materials':[self.mat, shared.object_material,shared.footing_material],
})
mnode = ba.newnode('math',
owner=ud_1_r,
attrs={
'input1': (0, 0.7, 0),
'operation': 'add'
})
node.changerotation(1,0,0)
ud_1_r.connectattr('position', mnode, 'input2')
mnode.connectattr('output', node, 'position')
ba.timer(8,ba.Call(self.create_block_wall_easy))
self.gate_count=4
self.wall_count=0
def create_wall(self):
x=-9
for i in range(0,17):
self.create_block(x,0.5)
self.create_block(x,1.2)
x=x+0.85
def create_block_wall_hardest(self):
x=-3
for i in range(0,7):
self.create_block(x,0.4)
x=x+0.85
ba.timer(1.5,ba.Call(self.create_wall))
ba.timer(15,ba.Call(self.create_block_wall_hardest))
def create_block_wall_hard(self):
x=-9
self.wall_count+=1
for i in range(0,17):
self.create_block(x,0.4)
x=x+0.85
if self.wall_count <4:
ba.timer(12,ba.Call(self.create_block_wall_hard))
else:
ba.timer(7,ba.Call(self.create_block_wall_hard)) #hardest too heavy to play
def create_block_wall_easy(self):
x=-9
c=0
for i in range(0,17):
if random.randrange(0,2) and c<self.gate_count:
pass
else:
self.create_block(x,0.5)
c+=1
x=x+0.85
self.wall_count+=1
if self.wall_count < 5:
ba.timer(11,ba.Call(self.create_block_wall_easy))
else:
self.wall_count=0
ba.timer(15,ba.Call(self.create_block_wall_hard))
def create_block(self,x,y):
shared = SharedObjects.get()
pwm=ba.Material()
cwwm=ba.Material()
# pwm.add_actions(
# actions=('modify_part_collision', 'friction', 0.0))
# anything that needs to hit the wall should apply this.
pwm.add_actions(
actions=(
('modify_part_collision', 'collide', True),
('modify_part_collision', 'physical', True)
))
self.mat = ba.Material()
self.mat.add_actions(
actions=( ('modify_part_collision','physical',False),
('modify_part_collision','collide',False))
)
cmodel = ba.getcollidemodel('courtyardPlayerWall')
ud_1_r=ba.newnode('region',attrs={'position': (x,y,-13),'scale': (1,1.5,1),'type': 'box','materials': [shared.footing_material,pwm ]})
node = ba.newnode('prop',
owner=ud_1_r,
attrs={
'model':ba.getmodel('tnt'),
'light_model':ba.getmodel('powerupSimple'),
'position':(2,7,2),
'body':'puck',
'shadow_size':0.0,
'velocity':(0,0,0),
'color_texture':ba.gettexture('tnt'),
'model_scale':1.2,
'reflection_scale':[1.5],
'materials':[self.mat, shared.object_material,shared.footing_material],
'density':9000000000
})
mnode = ba.newnode('math',
owner=ud_1_r,
attrs={
'input1': (0, 0.5, 0),
'operation': 'add'
})
node.changerotation(1,0,0)
ud_1_r.connectattr('position', mnode, 'input2')
mnode.connectattr('output', node, 'position')
_rcombine=ba.newnode('combine',
owner=ud_1_r,
attrs={
'input0':x,
'input1':y,
'size':3
})
ba.animate(_rcombine,'input2',{
0:-12,
11:4
})
_rcombine.connectattr('output',ud_1_r,'position')
ba.timer(11,ba.Call(ud_1_r.delete))

Binary file not shown.

View file

@ -0,0 +1,13 @@
# ba_meta require api 7
from plugins import auto_stunt
from bastd.game.elimination import EliminationGame
import ba
# ba_meta export game
class BroEliminaition(EliminationGame):
name = 'BroElimination'
description = 'Elimination Game with dual character control'
def spawn_player(self, player) -> ba.Actor:
super().spawn_player(player)
auto_stunt.spawn_mirror_spaz(player)

642
dist/ba_root/mods/games/Collector.py vendored Normal file
View file

@ -0,0 +1,642 @@
# ba_meta require api 7
# (see https://ballistica.net/wiki/meta-tag-system)
'''
Gamemode: Collector
Creator: TheMikirog
Website: https://bombsquadjoyride.blogspot.com/
This is a gamemode purely made by me just to spite unchallenged modders
out there that put out crap to the market.
We don't want gamemodes that are just the existing ones
with some novelties! Gamers deserve more!
In this gamemode you have to kill others in order to get their Capsules.
Capsules can be collected and staked in your inventory,
how many as you please.
After you kill an enemy that carries some of them,
they drop a respective amount of Capsules they carried + two more.
Your task is to collect these Capsules,
get to the flag and score them KOTH style.
You can't score if you don't have any Capsules with you.
The first player or team to get to the required ammount wins.
This is a gamemode all about trying to stay alive
and picking your battles in order to win.
A rare skill in BombSquad, where everyone is overly aggressive.
'''
from __future__ import annotations
import weakref
from enum import Enum
from typing import TYPE_CHECKING
import ba
import random
from bastd.actor.flag import Flag
from bastd.actor.popuptext import PopupText
from bastd.actor.playerspaz import PlayerSpaz
from bastd.actor.scoreboard import Scoreboard
from bastd.gameutils import SharedObjects
if TYPE_CHECKING:
from typing import Any, Sequence
lang = ba.app.lang.language
if lang == 'Spanish':
name = 'Coleccionista'
description = ('Elimina a tus oponentes para robar sus cápsulas.\n'
'¡Recolecta y anota en el punto de depósito!')
description_ingame = 'Obtén ${ARG1} cápsulas de tus enemigos.'
description_short = 'colecciona ${ARG1} cápsulas'
tips = [(
'¡Si tu oponente cae fuera del mapa, sus cápsulas desapareceran!\n'
'No intestes matar a tus enemigos arrojándolos al vacio.'),
'No te apresures. ¡Puedes perder tus cápsulas rápidamente!',
('¡No dejes que el jugador con más cápsulas anote!\n'
'¡Intenta atraparlo si puedes!'),
('¡Las Capsulas de la Suerte te dan 4 cápsulas en lugar de 2'
'y tienen un 8% de probabilidad de aparecer después de matar'),
('¡No te quedes en un solo lugar! Muevete más rapido que tu enemigo, '
'¡con suerte conseguirás algunas cápsulas!'),
]
capsules_to_win = 'Cápsulas para Ganar'
capsules_death = 'Cápsulas al Morir'
lucky_capsules = 'Cápsulas de la Suerte'
bonus = '¡BONUS!'
full_capacity = '¡Capacidad Completa!'
else:
name = 'Collector'
description = ('Kill your opponents to steal their Capsules.\n'
'Collect them and score at the Deposit point!')
description_ingame = 'Score ${ARG1} capsules from your enemies.'
description_short = 'collect ${ARG1} capsules'
tips = [(
'Making you opponent fall down the pit makes his Capsules wasted!\n'
'Try not to kill enemies by throwing them off the cliff.'),
'Don\'t be too reckless. You can lose your loot quite quickly!',
('Don\'t let the leading player score his Capsules '
'at the Deposit Point!\nTry to catch him if you can!'),
('Lucky Capsules give 4 to your inventory and they have 8% chance '
'of spawning after kill!'),
('Don\'t camp in one place! Make your move first, '
'so hopefully you get some dough!'),
]
capsules_to_win = 'Capsules to Win'
capsules_death = 'Capsules on Death'
lucky_capsules = 'Allow Lucky Capsules'
bonus = 'BONUS!'
full_capacity = 'Full Capacity!'
class FlagState(Enum):
"""States our single flag can be in."""
NEW = 0
UNCONTESTED = 1
CONTESTED = 2
HELD = 3
class Player(ba.Player['Team']):
"""Our player type for this game."""
def __init__(self) -> None:
self.time_at_flag = 0
self.capsules = 0
self.light = None
class Team(ba.Team[Player]):
"""Our team type for this game."""
def __init__(self) -> None:
self.score = 0
# ba_meta export game
class CollectorGame(ba.TeamGameActivity[Player, Team]):
name = name
description = description
tips = tips
# 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(
capsules_to_win,
min_value=1,
default=10,
increment=1,
),
ba.IntSetting(
capsules_death,
min_value=1,
max_value=10,
default=2,
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(lucky_capsules, default=True),
ba.BoolSetting('Epic Mode', default=False),
]
return settings
@classmethod
def supports_session_type(cls, sessiontype: type[ba.Session]) -> bool:
return issubclass(sessiontype, ba.DualTeamSession) or issubclass(
sessiontype, ba.FreeForAllSession
)
@classmethod
def get_supported_maps(cls, sessiontype: type[ba.Session]) -> list[str]:
return ba.getmaps('keep_away')
def __init__(self, settings: dict):
super().__init__(settings)
shared = SharedObjects.get()
self._scoreboard = Scoreboard()
self._score_to_win: int | None = None
self._swipsound = ba.getsound('swip')
self._lucky_sound = ba.getsound('ding')
self._flag_pos: Sequence[float] | None = None
self._flag_state: FlagState | None = None
self._flag: Flag | None = None
self._flag_light: ba.Node | None = None
self._scoring_team: weakref.ref[Team] | None = None
self._time_limit = float(settings['Time Limit'])
self._epic_mode = bool(settings['Epic Mode'])
self._capsules_to_win = int(settings[capsules_to_win])
self._capsules_death = int(settings[capsules_death])
self._lucky_capsules = bool(settings[lucky_capsules])
self._capsules: list[Any] = []
self._capsule_model = ba.getmodel('bomb')
self._capsule_tex = ba.gettexture('bombColor')
self._capsule_lucky_tex = ba.gettexture('bombStickyColor')
self._collect_sound = ba.getsound('powerup01')
self._lucky_collect_sound = ba.getsound('cashRegister2')
self._capsule_material = ba.Material()
self._capsule_material.add_actions(
conditions=('they_have_material', shared.player_material),
actions=('call', 'at_connect', self._on_capsule_player_collide),
)
self._flag_region_material = ba.Material()
self._flag_region_material.add_actions(
conditions=('they_have_material', shared.player_material),
actions=(
('modify_part_collision', 'collide', True),
('modify_part_collision', 'physical', False),
(
'call',
'at_connect',
ba.Call(self._handle_player_flag_region_collide, True),
),
(
'call',
'at_disconnect',
ba.Call(self._handle_player_flag_region_collide, False),
),
),
)
# Base class overrides.
self.slow_motion = self._epic_mode
self.default_music = (
ba.MusicType.EPIC if self._epic_mode else ba.MusicType.SCARY
)
def get_instance_description(self) -> str | Sequence:
return description_ingame, self._score_to_win
def get_instance_description_short(self) -> str | Sequence:
return description_short, self._score_to_win
def create_team(self, sessionteam: ba.SessionTeam) -> Team:
return Team()
def on_team_join(self, team: Team) -> None:
self._update_scoreboard()
def on_begin(self) -> None:
super().on_begin()
shared = SharedObjects.get()
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._capsules_to_win * max(
1, max(len(t.players) for t in self.teams)
)
self._update_scoreboard()
if isinstance(self.session, ba.FreeForAllSession):
self._flag_pos = self.map.get_flag_position(random.randint(0, 1))
else:
self._flag_pos = self.map.get_flag_position(None)
ba.timer(1.0, self._tick, repeat=True)
self._flag_state = FlagState.NEW
Flag.project_stand(self._flag_pos)
self._flag = Flag(
position=self._flag_pos, touchable=False, color=(1, 1, 1)
)
self._flag_light = ba.newnode(
'light',
attrs={
'position': self._flag_pos,
'intensity': 0.2,
'height_attenuated': False,
'radius': 0.4,
'color': (0.2, 0.2, 0.2),
},
)
# Flag region.
flagmats = [self._flag_region_material, shared.region_material]
ba.newnode(
'region',
attrs={
'position': self._flag_pos,
'scale': (1.8, 1.8, 1.8),
'type': 'sphere',
'materials': flagmats,
},
)
self._update_flag_state()
def _tick(self) -> None:
self._update_flag_state()
if self._scoring_team is None:
scoring_team = None
else:
scoring_team = self._scoring_team()
if not scoring_team:
return
if isinstance(self.session, ba.FreeForAllSession):
players = self.players
else:
players = scoring_team.players
for player in players:
if player.time_at_flag > 0:
self.stats.player_scored(
player, 3, screenmessage=False, display=False
)
if player.capsules > 0:
if self._flag_state != FlagState.HELD:
return
if scoring_team.score >= self._score_to_win:
return
player.capsules -= 1
scoring_team.score += 1
self._handle_capsule_storage((
self._flag_pos[0],
self._flag_pos[1]+1,
self._flag_pos[2]
), player)
ba.playsound(
self._collect_sound,
0.8,
position=self._flag_pos)
self._update_scoreboard()
if player.capsules > 0:
assert self._flag is not None
self._flag.set_score_text(
str(self._score_to_win - scoring_team.score))
# winner
if scoring_team.score >= self._score_to_win:
self.end_game()
def end_game(self) -> None:
results = ba.GameResults()
for team in self.teams:
results.set_team_score(team, team.score)
self.end(results=results, announce_delay=0)
def _update_flag_state(self) -> None:
holding_teams = set(
player.team for player in self.players if player.time_at_flag
)
prev_state = self._flag_state
assert self._flag_light
assert self._flag is not None
assert self._flag.node
if len(holding_teams) > 1:
self._flag_state = FlagState.CONTESTED
self._scoring_team = None
self._flag_light.color = (0.6, 0.6, 0.1)
self._flag.node.color = (1.0, 1.0, 0.4)
elif len(holding_teams) == 1:
holding_team = list(holding_teams)[0]
self._flag_state = FlagState.HELD
self._scoring_team = weakref.ref(holding_team)
self._flag_light.color = ba.normalized_color(holding_team.color)
self._flag.node.color = holding_team.color
else:
self._flag_state = FlagState.UNCONTESTED
self._scoring_team = None
self._flag_light.color = (0.2, 0.2, 0.2)
self._flag.node.color = (1, 1, 1)
if self._flag_state != prev_state:
ba.playsound(self._swipsound)
def _handle_player_flag_region_collide(self, colliding: bool) -> None:
try:
spaz = ba.getcollision().opposingnode.getdelegate(PlayerSpaz, True)
except ba.NotFoundError:
return
if not spaz.is_alive():
return
player = spaz.getplayer(Player, True)
# Different parts of us can collide so a single value isn't enough
# also don't count it if we're dead (flying heads shouldn't be able to
# win the game :-)
if colliding and player.is_alive():
player.time_at_flag += 1
else:
player.time_at_flag = max(0, player.time_at_flag - 1)
self._update_flag_state()
def _update_scoreboard(self) -> None:
for team in self.teams:
self._scoreboard.set_team_value(
team, team.score, self._score_to_win
)
def _drop_capsule(self, player: Player) -> None:
pt = player.node.position
# Throw out capsules that the victim has + 2 more to keep the game running
for i in range(player.capsules + self._capsules_death):
# How far from each other these capsules should spawn
w = 0.6
# How much these capsules should fly after spawning
s = 0.005 - (player.capsules * 0.01)
self._capsules.append(
Capsule(
position=(pt[0] + random.uniform(-w, w),
pt[1] + 0.75 + random.uniform(-w, w),
pt[2]),
velocity=(random.uniform(-s, s),
random.uniform(-s, s),
random.uniform(-s, s)),
lucky=False))
if random.randint(1, 12) == 1 and self._lucky_capsules:
# How far from each other these capsules should spawn
w = 0.6
# How much these capsules should fly after spawning
s = 0.005
self._capsules.append(
Capsule(
position=(pt[0] + random.uniform(-w, w),
pt[1] + 0.75 + random.uniform(-w, w),
pt[2]),
velocity=(random.uniform(-s, s),
random.uniform(-s, s),
random.uniform(-s, s)),
lucky=True))
def _on_capsule_player_collide(self) -> None:
if self.has_ended():
return
collision = ba.getcollision()
# Be defensive here; we could be hitting the corpse of a player
# who just left/etc.
try:
capsule = collision.sourcenode.getdelegate(Capsule, True)
player = collision.opposingnode.getdelegate(
PlayerSpaz, True
).getplayer(Player, True)
except ba.NotFoundError:
return
if not player.is_alive():
return
if capsule.node.color_texture == self._capsule_lucky_tex:
player.capsules += 4
PopupText(
bonus,
color=(1, 1, 0),
scale=1.5,
position=capsule.node.position
).autoretain()
ba.playsound(
self._lucky_collect_sound,
1.0,
position=capsule.node.position)
ba.emitfx(
position=capsule.node.position,
velocity=(0, 0, 0),
count=int(6.4+random.random()*24),
scale=1.2,
spread=2.0,
chunk_type='spark');
ba.emitfx(
position=capsule.node.position,
velocity=(0, 0, 0),
count=int(4.0+random.random()*6),
emit_type='tendrils');
else:
player.capsules += 1
ba.playsound(
self._collect_sound,
0.6,
position=capsule.node.position)
# create a flash
light = ba.newnode(
'light',
attrs={
'position': capsule.node.position,
'height_attenuated': False,
'radius': 0.1,
'color': (1, 1, 0)})
# Create a short text informing about your inventory
self._handle_capsule_storage(player.position, player)
ba.animate(light, 'intensity', {
0: 0,
0.1: 0.5,
0.2: 0
}, loop=False)
ba.timer(0.2, light.delete)
capsule.handlemessage(ba.DieMessage())
def _update_player_light(self, player: Player, capsules: int) -> None:
if player.light:
intensity = 0.04 * capsules
ba.animate(player.light, 'intensity', {
0.0: player.light.intensity,
0.1: intensity
})
def newintensity():
player.light.intensity = intensity
ba.timer(0.1, newintensity)
else:
player.light = ba.newnode(
'light',
attrs={
'height_attenuated': False,
'radius': 0.2,
'intensity': 0.0,
'color': (0.2, 1, 0.2)
})
player.node.connectattr('position', player.light, 'position')
def _handle_capsule_storage(self, pos: float, player: Player) -> None:
capsules = player.capsules
text = str(capsules)
scale = 1.75 + (0.02 * capsules)
if capsules > 10:
player.capsules = 10
text = full_capacity
color = (1, 0.85, 0)
elif capsules > 7:
color = (1, 0, 0)
scale = 2.4
elif capsules > 5:
color = (1, 0.4, 0.4)
scale = 2.1
elif capsules > 3:
color = (1, 1, 0.4)
scale = 2.0
else:
color = (1, 1, 1)
scale = 1.9
PopupText(
text,
color=color,
scale=scale,
position=(pos[0], pos[1]-1, pos[2])
).autoretain()
self._update_player_light(player, capsules)
def handlemessage(self, msg: Any) -> Any:
if isinstance(msg, ba.PlayerDiedMessage):
super().handlemessage(msg) # Augment default.
# No longer can count as time_at_flag once dead.
player = msg.getplayer(Player)
player.time_at_flag = 0
self._update_flag_state()
self._drop_capsule(player)
player.capsules = 0
self._update_player_light(player, 0)
self.respawn_player(player)
else:
return super().handlemessage(msg)
class Capsule(ba.Actor):
def __init__(self,
position: Sequence[float] = (0.0, 1.0, 0.0),
velocity: Sequence[float] = (0.0, 0.5, 0.0),
lucky: bool = False):
super().__init__()
shared = SharedObjects.get()
activity = self.getactivity()
# spawn just above the provided point
self._spawn_pos = (position[0], position[1], position[2])
if lucky:
ba.playsound(activity._lucky_sound, 1.0, self._spawn_pos)
self.node = ba.newnode(
'prop',
attrs={
'model': activity._capsule_model,
'color_texture': activity._capsule_lucky_tex if lucky else (
activity._capsule_tex),
'body': 'crate' if lucky else 'capsule',
'reflection': 'powerup' if lucky else 'soft',
'body_scale': 0.65 if lucky else 0.3,
'density':6.0 if lucky else 4.0,
'reflection_scale': [0.15],
'shadow_size': 0.65 if lucky else 0.6,
'position': self._spawn_pos,
'velocity': velocity,
'materials': [
shared.object_material, activity._capsule_material]
},
delegate=self)
ba.animate(self.node, 'model_scale', {
0.0: 0.0,
0.1: 0.9 if lucky else 0.6,
0.16: 0.8 if lucky else 0.5
})
self._light_capsule = ba.newnode(
'light',
attrs={
'position': self._spawn_pos,
'height_attenuated': False,
'radius': 0.5 if lucky else 0.1,
'color': (0.2, 0.2, 0) if lucky else (0.2, 1, 0.2)
})
self.node.connectattr('position', self._light_capsule, 'position')
def handlemessage(self, msg: Any):
if isinstance(msg, ba.DieMessage):
self.node.delete()
ba.animate(self._light_capsule, 'intensity', {
0: 1.0,
0.05: 0.0
}, loop=False)
ba.timer(0.05, self._light_capsule.delete)
elif isinstance(msg, ba.OutOfBoundsMessage):
self.handlemessage(ba.DieMessage())
elif isinstance(msg, ba.HitMessage):
self.node.handlemessage(
'impulse',
msg.pos[0], msg.pos[1], msg.pos[2],
msg.velocity[0]/8, msg.velocity[1]/8, msg.velocity[2]/8,
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:
return super().handlemessage(msg)

610
dist/ba_root/mods/games/FlagDay.py vendored Normal file
View file

@ -0,0 +1,610 @@
# 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 json
import math
import random
from bastd.game.elimination import Icon
from bastd.actor.bomb import Bomb, Blast
from bastd.actor.playerspaz import PlayerSpaz
from bastd.actor.scoreboard import Scoreboard
from bastd.actor.powerupbox import PowerupBox
from bastd.actor.flag import Flag, FlagPickedUpMessage
from bastd.actor.spazbot import SpazBotSet, BrawlerBotLite, SpazBotDiedMessage
if TYPE_CHECKING:
from typing import Any, Sequence
lang = ba.app.lang.language
if lang == 'Spanish':
name = 'Día de la Bandera'
description = ('Recoge las banderas para recibir un premio.\n'
'Pero ten cuidado...')
slow_motion_deaths = 'Muertes en Cámara Lenta'
credits = 'Creado por MattZ45986 en Github | Actualizado por byANG3L'
you_were = 'Estas'
cursed_text = 'MALDITO'
run = 'CORRE'
climb_top = 'Escala a la cima'
bomb_rain = '¡LLUVIA DE BOMBAS!'
lame_guys = 'Chicos Ligeros'
jackpot = '¡PREMIO MAYOR!'
diedtxt = '¡'
diedtxt2 = ' ha sido eliminado!'
else:
name = 'Flag Day'
description = 'Pick up flags to receive a prize.\nBut beware...'
slow_motion_deaths = 'Slow Motion Deaths'
credits = 'Created by MattZ45986 on Github | Updated by byANG3L'
you_were = 'You were'
cursed_text = 'CURSED'
run = 'RUN'
climb_top = 'Climb to the top'
bomb_rain = 'BOMB RAIN!'
lame_guys = 'Lame Guys'
jackpot = '!JACKPOT!'
diedtxt = ''
diedtxt2 = ' died!'
class Icon(Icon):
def __init__(
self,
player: Player,
position: tuple[float, float],
scale: float,
show_lives: bool = True,
show_death: bool = True,
name_scale: float = 1.0,
name_maxwidth: float = 115.0,
flatness: float = 1.0,
shadow: float = 1.0,
dead: bool = False,
):
super().__init__(player,position,scale,show_lives,show_death,
name_scale,name_maxwidth,flatness,shadow)
if dead:
self._name_text.opacity = 0.2
self.node.color = (0.7, 0.3, 0.3)
self.node.opacity = 0.2
class FlagBearer(PlayerSpaz):
def handlemessage(self, msg: Any) -> Any:
super().handlemessage(msg)
if isinstance(msg, ba.PowerupMessage):
activity = self.activity
player = self.getplayer(Player)
if not player.is_alive():
return
if activity.last_prize == 'curse':
player.team.score += 25
activity._update_scoreboard()
elif activity.last_prize == 'land_mines':
player.team.score += 15
activity._update_scoreboard()
self.connect_controls_to_player()
elif activity.last_prize == 'climb':
player.team.score += 50
activity._update_scoreboard()
if msg.poweruptype == 'health':
activity.round_timer = None
ba.timer(0.2, activity.setup_next_round)
class Player(ba.Player['Team']):
"""Our player type for this game."""
def __init__(self) -> None:
self.dead = False
self.icons: list[Icon] = []
class Team(ba.Team[Player]):
"""Our team type for this game."""
def __init__(self) -> None:
self.score = 0
# ba_meta export game
class FlagDayGame(ba.TeamGameActivity[Player, Team]):
"""A game type based on acquiring kills."""
name = name
description = description
# Print messages when players die since it matters here.
announce_player_deaths = True
allow_mid_activity_joins = False
@classmethod
def get_available_settings(
cls, sessiontype: type[ba.Session]
) -> list[ba.Setting]:
settings = [
ba.BoolSetting(slow_motion_deaths, default=True),
ba.BoolSetting('Epic Mode', default=False),
]
return settings
@classmethod
def supports_session_type(cls, sessiontype: type[ba.Session]) -> bool:
return (
issubclass(sessiontype, ba.CoopSession)
or issubclass(sessiontype, ba.DualTeamSession)
or issubclass(sessiontype, ba.FreeForAllSession)
)
@classmethod
def get_supported_maps(cls, sessiontype: type[ba.Session]) -> list[str]:
return ['Courtyard']
def __init__(self, settings: dict):
super().__init__(settings)
self.credits()
self._scoreboard = Scoreboard()
self._dingsound = ba.getsound('dingSmall')
self._epic_mode = bool(settings['Epic Mode'])
self._slow_motion_deaths = bool(settings[slow_motion_deaths])
self.current_player: Player | None = None
self.prize_recipient: Player | None = None
self.bomb_survivor: Player | None = None
self.bad_guy_cost: int = 0
self.player_index: int = 0
self.bombs: list = []
self.queue_line: list = []
self._bots: SpazBotSet | None = None
self.light: ba.Node | None = None
self.last_prize = 'none'
self._flag: Flag | None = None
self._flag2: Flag | None = None
self._flag3: Flag | None = None
self._flag4: Flag | None = None
self._flag5: Flag | None = None
self._flag6: Flag | None = None
self._flag7: Flag | None = None
self._flag8: Flag | None = None
self.set = False
self.round_timer: ba.Timer | None = None
self.give_points_timer: ba.Timer | None = None
self._jackpot_sound = ba.getsound('achievement')
self._round_sound = ba.getsound('powerup01')
self._dingsound = ba.getsound('dingSmall')
# 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 on_team_join(self, team: Team) -> None:
if self.has_begun():
self._update_scoreboard()
def on_player_leave(self, player: Player) -> None:
if player is self.current_player:
self.setup_next_round()
self._check_end_game()
super().on_player_leave(player)
self.queue_line.remove(player)
self._update_icons()
def on_begin(self) -> None:
super().on_begin()
for player in self.players:
if player.actor:
player.actor.handlemessage(ba.DieMessage())
player.actor.node.delete()
self.queue_line.append(player)
self.spawn_player_spaz(
self.queue_line[self.player_index % len(self.queue_line)],
(0.0, 3.0, -2.0))
self.current_player = self.queue_line[0]
# Declare a set of bots (enemies) that we will use later
self._bots = SpazBotSet()
self.reset_flags()
self._update_icons()
self._update_scoreboard()
def credits(self) -> None:
ba.newnode(
'text',
attrs={
'v_attach': 'bottom',
'h_align': 'center',
'vr_depth': 0,
'color': (0, 0.2, 0),
'shadow': 1.0,
'flatness': 1.0,
'position': (0,0),
'scale': 0.8,
'text': credits
})
def _update_icons(self) -> None:
# pylint: disable=too-many-branches
for player in self.queue_line:
player.icons = []
if player == self.current_player:
xval = 0
x_offs = -78
player.icons.append(
Icon(player,
position=(xval, 65),
scale=1.0,
name_maxwidth=130,
name_scale=0.8,
flatness=0.0,
shadow=0.5,
show_death=True,
show_lives=False))
elif player.dead:
xval = 65
x_offs = 78
player.icons.append(
Icon(player,
position=(xval, 50),
scale=0.5,
name_maxwidth=75,
name_scale=1.0,
flatness=1.0,
shadow=1.0,
show_death=False,
show_lives=False,
dead=True))
xval += x_offs * 0.56
else:
xval = -65
x_offs = 78
player.icons.append(
Icon(player,
position=(xval, 50),
scale=0.5,
name_maxwidth=75,
name_scale=1.0,
flatness=1.0,
shadow=1.0,
show_death=False,
show_lives=False))
xval -= x_offs * 0.56
def give_prize(self, prize: int) -> None:
if prize == 1:
# Curse him aka make him blow up in 5 seconds
# give them a nice message
ba.screenmessage(you_were, color=(0.1, 0.1, 0.1))
ba.screenmessage(cursed_text, color=(1.0, 0.0, 0.0))
self.make_health_box((0.0, 0.0, 0.0))
self.last_prize = 'curse'
self.prize_recipient.actor.curse()
# ba.timer(5.5, self.setup_next_round)
if prize == 2:
self.setup_rof()
ba.screenmessage(run, color=(1.0, 0.2, 0.1))
self.last_prize = 'ring_of_fire'
if prize == 3:
self.last_prize = 'climb'
self.light = ba.newnode(
'locator',
attrs={
'shape': 'circle',
'position': (0.0, 3.0, -9.0),
'color': (1.0, 1.0, 1.0),
'opacity': 1.0,
'draw_beauty': True,
'additive': True
})
ba.screenmessage(climb_top, color=(0.5, 0.5, 0.5))
ba.timer(3.0, ba.Call(self.make_health_box, (0.0, 6.0, -9.0)))
self.round_timer = ba.Timer(10.0, self.setup_next_round)
if prize == 4:
self.last_prize = 'land_mines'
self.make_health_box((6.0, 5.0, -2.0))
self.make_land_mines()
self.prize_recipient.actor.connect_controls_to_player(
enable_bomb=False)
self.prize_recipient.actor.node.handlemessage(
ba.StandMessage(position=(-6.0, 3.0, -2.0)))
self.round_timer = ba.Timer(7.0, self.setup_next_round)
if prize == 5:
# Make it rain bombs
self.bomb_survivor = self.prize_recipient
ba.screenmessage(bomb_rain, color=(1.0, 0.5, 0.16))
# Set positions for the bombs to drop
for bzz in range(-5,6):
for azz in range(-5,2):
# for each position make a bomb drop there
self.make_bomb(bzz, azz)
self.give_points_timer = ba.Timer(3.3, self.give_points)
self.last_prize = 'bombrain'
if prize == 6:
self.setup_br()
self.bomb_survivor = self.prize_recipient
self.give_points_timer = ba.Timer(7.0, self.give_points)
self.last_prize = 'bombroad'
if prize == 7:
# makes killing a bad guy worth ten points
self.bad_guy_cost = 2
ba.screenmessage(lame_guys, color=(1.0, 0.5, 0.16))
# makes a set of nine positions
for a in range(-1, 2):
for b in range(-3, 0):
# and spawns one in each position
self._bots.spawn_bot(BrawlerBotLite, pos=(a, 2.5, b))
# and we give our player boxing gloves and a shield
self._player.equip_boxing_gloves()
self._player.equip_shields()
self.last_prize = 'lameguys'
if prize == 8:
ba.playsound(self._jackpot_sound)
ba.screenmessage(jackpot, color=(1.0, 0.0, 0.0))
ba.screenmessage(jackpot, color=(0.0, 1.0, 0.0))
ba.screenmessage(jackpot, color=(0.0, 0.0, 1.0))
team = self.prize_recipient.team
# GIVE THEM A WHOPPING 50 POINTS!!!
team.score += 50
# and update the scores
self._update_scoreboard()
self.last_prize = 'jackpot'
ba.timer(2.0, self.setup_next_round)
def setup_next_round(self) -> None:
if self._slow_motion_deaths:
ba.getactivity().globalsnode.slow_motion = False
if self.set:
return
if self.light:
self.light.delete()
for bomb in self.bombs:
bomb.handlemessage(ba.DieMessage())
self.kill_flags()
self._bots.clear()
self.reset_flags()
self.current_player.actor.handlemessage(
ba.DieMessage(how='game'))
self.current_player.actor.node.delete()
c = 0
self.player_index += 1
self.player_index %= len(self.queue_line)
if len(self.queue_line) > 0:
while self.queue_line[self.player_index].dead:
if c > len(self.queue_line):
return
self.player_index += 1
self.player_index %= len(self.queue_line)
c += 1
self.spawn_player_spaz(
self.queue_line[self.player_index], (0.0, 3.0, -2.0))
self.current_player = self.queue_line[self.player_index]
self.last_prize = 'none'
self._update_icons()
def check_bots(self) -> None:
if not self._bots.have_living_bots():
self.setup_next_round()
def make_land_mines(self) -> None:
self.bombs = []
for i in range(-11, 7):
self.bombs.append(Bomb(
position=(0.0, 6.0, i/2.0),
bomb_type='land_mine',
blast_radius=2.0))
self.bombs[i+10].arm()
def give_points(self) -> None:
if self.bomb_survivor is not None and self.bomb_survivor.is_alive():
self.bomb_survivor.team.score += 20
self._update_scoreboard()
self.round_timer = ba.Timer(1.0, self.setup_next_round)
def make_health_box(self, position: Sequence[float]) -> None:
if position == (0.0, 3.0, 0.0):
position = (random.randint(-6, 6), 6, random.randint(-6, 4))
elif position == (0,0,0):
position = random.choice(
((-7, 6, -5), (7, 6, -5), (-7, 6, 1), (7, 6, 1)))
self.health_box = PowerupBox(
position=position, poweruptype='health').autoretain()
# called in prize #5
def make_bomb(self, xpos: float, zpos: float) -> None:
# makes a bomb at the given position then auto-retains it aka:
# makes sure it doesn't disappear because there is no reference to it
self.bombs.append(Bomb(position=(xpos, 12, zpos)))
def setup_br(self) -> None:
self.make_bomb_row(6)
self.prize_recipient.actor.handlemessage(
ba.StandMessage(position=(6.0, 3.0, -2.0)))
def make_bomb_row(self, num: int) -> None:
if not self.prize_recipient.is_alive():
return
if num == 0:
self.round_timer = ba.Timer(1.0, self.setup_next_round)
return
for i in range(-11, 7):
self.bombs.append(
Bomb(position=(-3, 3, i/2.0),
velocity=(12, 0.0, 0.0),
bomb_type='normal',
blast_radius=1.2))
ba.timer(1.0, ba.Call(self.make_bomb_row, num-1))
def setup_rof(self) -> None:
self.make_blast_ring(10)
self.prize_recipient.actor.handlemessage(
ba.StandMessage(position=(0.0, 3.0, -2.0)))
def make_blast_ring(self, length: float) -> None:
if not self.prize_recipient.is_alive():
return
if length == 0:
self.setup_next_round()
self.prize_recipient.team.score += 50
self._update_scoreboard()
return
for angle in range(0, 360, 45):
angle += random.randint(0, 45)
angle %= 360
x = length * math.cos(math.radians(angle))
z = length * math.sin(math.radians(angle))
blast = Blast(position=(x, 2.2, z-2), blast_radius=3.5)
ba.timer(0.75, ba.Call(self.make_blast_ring, length-1))
# a method to remake the flags
def reset_flags(self) -> None:
# remake the flags
self._flag = Flag(
position=(0.0, 3.0, 1.0), touchable=True, color=(0.0, 0.0, 1.0))
self._flag2 = Flag(
position=(0.0, 3.0, -5.0), touchable=True, color=(1.0, 0.0, 0.0))
self._flag3 = Flag(
position=(3.0, 3.0, -2.0), touchable=True, color=(0.0, 1.0, 0.0))
self._flag4 = Flag(
position=(-3.0, 3.0, -2.0), touchable=True, color=(1.0, 1.0, 1.0))
self._flag5 = Flag(
position=(1.8, 3.0, 0.2), touchable=True, color=(0.0, 1.0, 1.0))
self._flag6 = Flag(
position=(-1.8, 3.0, 0.2), touchable=True, color=(1.0, 0.0, 1.0))
self._flag7 = Flag(
position=(1.8, 3.0, -3.8), touchable=True, color=(1.0, 1.0, 0.0))
self._flag8 = Flag(
position=(-1.8, 3.0, -3.8), touchable=True, color=(0.0, 0.0, 0.0))
# a method to kill the flags
def kill_flags(self) -> None:
# destroy all the flags by erasing all references to them,
# indicated by None similar to null
self._flag.node.delete()
self._flag2.node.delete()
self._flag3.node.delete()
self._flag4.node.delete()
self._flag5.node.delete() # 132, 210 ,12
self._flag6.node.delete()
self._flag7.node.delete()
self._flag8.node.delete()
def _check_end_game(self) -> None:
for player in self.queue_line:
if not player.dead:
return
self.end_game()
def spawn_player_spaz(
self,
player: PlayerType,
position: Sequence[float] = (0, 0, 0),
angle: float | None = None,
) -> PlayerSpaz:
from ba import _math
from ba._gameutils import animate
from ba._coopsession import CoopSession
angle = None
name = player.getname()
color = player.color
highlight = player.highlight
light_color = _math.normalized_color(color)
display_color = ba.safecolor(color, target_intensity=0.75)
spaz = FlagBearer(color=color,
highlight=highlight,
character=player.character,
player=player)
player.actor = spaz
assert spaz.node
spaz.node.name = name
spaz.node.name_color = display_color
spaz.connect_controls_to_player()
# Move to the stand position and add a flash of light.
spaz.handlemessage(
ba.StandMessage(
position,
angle if angle is not None else random.uniform(0, 360)))
ba.playsound(self._spawn_sound, 1, position=spaz.node.position)
light = ba.newnode('light', attrs={'color': light_color})
spaz.node.connectattr('position', light, 'position')
animate(light, 'intensity', {0: 0, 0.25: 1, 0.5: 0})
ba.timer(0.5, light.delete)
return spaz
def handlemessage(self, msg: Any) -> Any:
if isinstance(msg, ba.PlayerDiedMessage):
# give them a nice farewell
if ba.time() < 0.5:
return
if msg.how == 'game':
return
player = msg.getplayer(Player)
ba.screenmessage(
diedtxt + str(player.getname()) + diedtxt2, color=player.color)
player.dead = True
if player is self.current_player:
self.round_timer = None
self.give_points_timer = None
if not msg.how is ba.DeathType.FALL:
if self._slow_motion_deaths:
ba.getactivity().globalsnode.slow_motion = True
time = 0.5
else:
time = 0.01
# check to see if we can end the game
self._check_end_game()
ba.timer(time, self.setup_next_round)
elif isinstance(msg, FlagPickedUpMessage):
msg.flag.last_player_to_hold = msg.node.getdelegate(
FlagBearer, True
).getplayer(Player, True)
self._player = msg.node.getdelegate(
FlagBearer, True
)
self.prize_recipient = msg.node.getdelegate(
FlagBearer, True
).getplayer(Player, True)
self.kill_flags()
self.give_prize(random.randint(1, 8))
ba.playsound(self._round_sound)
self.current_player = self.prize_recipient
elif isinstance(msg, SpazBotDiedMessage):
# find out which team the last person to hold a flag was on
team = self.prize_recipient.team
# give them their points
team.score += self.bad_guy_cost
ba.playsound(self._dingsound, 0.5)
# update the scores
for team in self.teams:
self._scoreboard.set_team_value(team, team.score)
ba.timer(0.3, self.check_bots)
return None
def _update_scoreboard(self) -> None:
for player in self.queue_line:
if not player.dead:
if player.team.score > 0:
ba.playsound(self._dingsound)
self._scoreboard.set_team_value(player.team, player.team.score)
def end_game(self) -> None:
if self.set:
return
self.set = True
results = ba.GameResults()
for team in self.teams:
results.set_team_score(team, team.score)
self.end(results=results)

528
dist/ba_root/mods/games/air_soccer.py vendored Normal file
View file

@ -0,0 +1,528 @@
# Released under the MIT License. See LICENSE for details.
# BY Stary_Agent
"""Hockey 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,_ba
from bastd.actor.playerspaz import PlayerSpaz
from bastd.actor.scoreboard import Scoreboard
from bastd.actor.powerupbox import PowerupBoxFactory
from bastd.gameutils import SharedObjects
if TYPE_CHECKING:
from typing import Any, Sequence, Dict, Type, List, Optional, Union
class PuckDiedMessage:
"""Inform something that a puck has died."""
def __init__(self, puck: Puck):
self.puck = puck
def create_slope(self):
shared = SharedObjects.get()
x=5
y=12
for i in range(0,10):
ba.newnode('region',attrs={'position': (x, y, -5.52),'scale': (0.2,0.1,6),'type': 'box','materials': [shared.footing_material,self._real_wall_material ]})
x= x+0.3
y=y+0.1
class Puck(ba.Actor):
"""A lovely giant hockey puck."""
def __init__(self, position: Sequence[float] = (0.0, 13.0, 0.0)):
super().__init__()
shared = SharedObjects.get()
activity = self.getactivity()
# Spawn just above the provided point.
self._spawn_pos = (position[0], position[1] + 1.0, position[2])
self.last_players_to_touch: Dict[int, Player] = {}
self.scored = False
assert activity is not None
assert isinstance(activity, HockeyGame)
pmats = [shared.object_material, activity.puck_material]
self.node = ba.newnode('prop',
delegate=self,
attrs={
'model': activity.puck_model,
'color_texture': activity.puck_tex,
'body': 'sphere',
'reflection': 'soft',
'reflection_scale': [0.2],
'gravity_scale':0.3,
'shadow_size': 0.5,
'is_area_of_interest': True,
'position': self._spawn_pos,
'materials': pmats
})
ba.animate(self.node, 'model_scale', {0: 0, 0.2: 1.3, 0.26: 1})
def handlemessage(self, msg: Any) -> Any:
if isinstance(msg, ba.DieMessage):
assert self.node
self.node.delete()
activity = self._activity()
if activity and not msg.immediate:
activity.handlemessage(PuckDiedMessage(self))
# If we go out of bounds, move back to where we started.
elif isinstance(msg, ba.OutOfBoundsMessage):
assert self.node
self.node.position = self._spawn_pos
elif isinstance(msg, ba.HitMessage):
assert self.node
assert msg.force_direction is not None
self.node.handlemessage(
'impulse', msg.pos[0], msg.pos[1], msg.pos[2], msg.velocity[0],
msg.velocity[1], msg.velocity[2], 1.0 * msg.magnitude,
1.0 * msg.velocity_magnitude, msg.radius, 0,
msg.force_direction[0], msg.force_direction[1],
msg.force_direction[2])
# If this hit came from a player, log them as the last to touch us.
s_player = msg.get_source_player(Player)
if s_player is not None:
activity = self._activity()
if activity:
if s_player in activity.players:
self.last_players_to_touch[s_player.team.id] = s_player
else:
super().handlemessage(msg)
class Player(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 AirSoccerGame(ba.TeamGameActivity[Player, Team]):
"""Ice hockey game."""
name = 'Epic Air Soccer'
description = 'Score some goals.'
available_settings = [
ba.IntSetting(
'Score to Win',
min_value=1,
default=1,
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.1),
('Short', 0.5),
('Normal', 1.0),
('Long', 2.0),
('Longer', 4.0),
],
default=1.0,
),
]
default_music = ba.MusicType.HOCKEY
@classmethod
def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool:
return issubclass(sessiontype, ba.DualTeamSession)
@classmethod
def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]:
return ['Creative Thoughts']
def __init__(self, settings: dict):
super().__init__(settings)
shared = SharedObjects.get()
self.slow_motion = True
self._scoreboard = Scoreboard()
self._cheer_sound = ba.getsound('cheer')
self._chant_sound = ba.getsound('crowdChant')
self._foghorn_sound = ba.getsound('foghorn')
self._swipsound = ba.getsound('swip')
self._whistle_sound = ba.getsound('refWhistle')
self.puck_model = ba.getmodel('bomb')
self.puck_tex = ba.gettexture('landMine')
self.puck_scored_tex = ba.gettexture('landMineLit')
self._puck_sound = ba.getsound('metalHit')
self.puck_material = ba.Material()
self.puck_material.add_actions(actions=(('modify_part_collision',
'friction', 0.5)))
self.puck_material.add_actions(conditions=('they_have_material',
shared.pickup_material),
actions=('modify_part_collision',
'collide', True))
self.puck_material.add_actions(
conditions=(
('we_are_younger_than', 100),
'and',
('they_have_material', shared.object_material),
),
actions=('modify_node_collision', 'collide', False),
)
self.puck_material.add_actions(conditions=('they_have_material',
shared.footing_material),
actions=('impact_sound',
self._puck_sound, 0.2, 5))
self._real_wall_material=ba.Material()
self._real_wall_material.add_actions(
actions=(
('modify_part_collision', 'collide', True),
('modify_part_collision', 'physical', True)
))
self._real_wall_material.add_actions(
conditions=('they_have_material', shared.player_material),
actions=(
('modify_part_collision', 'collide', True),
('modify_part_collision', 'physical', True)
))
self._goal_post_material=ba.Material()
self._goal_post_material.add_actions(
actions=(
('modify_part_collision', 'collide', True),
('modify_part_collision', 'physical', True)
))
self._goal_post_material.add_actions(
conditions=('they_have_material', shared.player_material),
actions=(
('modify_part_collision', 'collide', False),
('modify_part_collision', 'physical', False)
))
# Keep track of which player last touched the puck
self.puck_material.add_actions(
conditions=('they_have_material', shared.player_material),
actions=(('call', 'at_connect',
self._handle_puck_player_collide), ))
# We want the puck to kill powerups; not get stopped by them
self.puck_material.add_actions(
conditions=('they_have_material',
PowerupBoxFactory.get().powerup_material),
actions=(('modify_part_collision', 'physical', False),
('message', 'their_node', 'at_connect', ba.DieMessage())))
self._score_region_material = ba.Material()
self._score_region_material.add_actions(
conditions=('they_have_material', self.puck_material),
actions=(('modify_part_collision', 'collide',
True), ('modify_part_collision', 'physical', False),
('call', 'at_connect', self._handle_score)))
self._puck_spawn_pos: Optional[Sequence[float]] = None
self._score_regions: Optional[List[ba.NodeActor]] = None
self._puck: Optional[Puck] = None
self._score_to_win = int(settings['Score to Win'])
self._time_limit = float(settings['Time Limit'])
def get_instance_description(self) -> Union[str, Sequence]:
if self._score_to_win == 1:
return 'Score a goal.'
return 'Score ${ARG1} goals.', self._score_to_win
def get_instance_description_short(self) -> Union[str, Sequence]:
if self._score_to_win == 1:
return 'score a goal'
return 'score ${ARG1} goals', self._score_to_win
def on_begin(self) -> None:
super().on_begin()
self.setup_standard_time_limit(self._time_limit)
self.setup_standard_powerup_drops()
self._puck_spawn_pos =(0,16.9,-5.5)
self._spawn_puck()
self.make_map()
# Set up the two score regions.
defs = self.map.defs
self._score_regions = []
self._score_regions.append(
ba.NodeActor(
ba.newnode('region',
attrs={
'position': (17,14.5,-5.52),
'scale': (1,3,1),
'type': 'box',
'materials': [self._score_region_material]
})))
self._score_regions.append(
ba.NodeActor(
ba.newnode('region',
attrs={
'position': (-17,14.5,-5.52),
'scale': (1,3,1),
'type': 'box',
'materials': [self._score_region_material]
})))
self._update_scoreboard()
ba.playsound(self._chant_sound)
def on_team_join(self, team: Team) -> None:
self._update_scoreboard()
def _handle_puck_player_collide(self) -> None:
collision = ba.getcollision()
try:
puck = collision.sourcenode.getdelegate(Puck, True)
player = collision.opposingnode.getdelegate(PlayerSpaz,
True).getplayer(
Player, True)
except ba.NotFoundError:
return
puck.last_players_to_touch[player.team.id] = player
def make_map(self):
shared = SharedObjects.get()
_ba.get_foreground_host_activity()._map.leftwall.materials= [shared.footing_material,self._real_wall_material ]
_ba.get_foreground_host_activity()._map.rightwall.materials=[shared.footing_material,self._real_wall_material ]
_ba.get_foreground_host_activity()._map.topwall.materials=[shared.footing_material,self._real_wall_material ]
floor=""
for i in range(0,90):
floor+="_ "
# self.floorwall=ba.newnode('region',attrs={'position': (-18.65152479, 4.057427485, -5.52),'scale': (72,2,6),'type': 'box','materials': [shared.footing_material,self._real_wall_material ]})
self.floorwall=ba.newnode('region',attrs={'position': (0, 5, -5.52),'scale': (35.4,0.2,2),'type': 'box','materials': [shared.footing_material,self._real_wall_material ]})
ba.newnode('locator', attrs={'shape':'box', 'position':(0, 5, -5.52), 'color':(0,0,0), 'opacity':1,'draw_beauty':True,'additive':False,'size':(35.4,0.2,2)})
# self.floor_text = ba.newnode('text',
# attrs={
# 'text': floor,
# 'in_world': True,
# 'shadow': 1.0,
# 'flatness': 1.0,
# 'scale':0.019,
# 'h_align': 'center',
# 'position':(0,5.2,-5)
# })
self.create_goal_post(-16.65,12.69)
self.create_goal_post(-16.65,16.69)
self.create_goal_post(16.65,12.69)
self.create_goal_post(16.65,16.69)
self.create_static_step(0,16.29)
self.create_static_step(4.35,11.1)
self.create_static_step(-4.35,11.1)
self.create_vertical(10, 15.6)
self.create_vertical(-10, 15.6)
def create_static_step(self,x,y):
floor=""
for i in range(0,7):
floor+="_ "
shared = SharedObjects.get()
step={}
step["r"]=ba.newnode('region',attrs={'position': (x, y, -5.52),'scale': (3,0.1,6),'type': 'box','materials': [shared.footing_material,self._real_wall_material ]})
ba.newnode('locator', attrs={'shape':'box', 'position':( x, y, -5.52), 'color':(1,1,0), 'opacity':1,'draw_beauty':True,'additive':False,'size':(3,0.1,2)})
# step["t"]=ba.newnode('text',
# attrs={
# 'text': floor,
# 'in_world': True,
# 'shadow': 1.0,
# 'flatness': 1.0,
# 'scale':0.019,
# 'h_align': 'left',
# 'position':(x-1.2,y,-5.52)
# })
return step
def create_goal_post(self,x,y):
shared = SharedObjects.get()
if x > 0:
color = (1,0,0) #change to team specific color
else:
color = (0,0,1)
floor=""
for i in range(0,4):
floor+="_ "
ba.newnode('region',attrs={'position': (x-0.2, y, -5.52),'scale': (1.8,0.1,6),'type': 'box','materials': [shared.footing_material,self._goal_post_material]})
ba.newnode('locator', attrs={'shape':'box', 'position':( x-0.2, y, -5.52), 'color': color, 'opacity':1,'draw_beauty':True,'additive':False,'size':(1.8,0.1,2)})
# ba.newnode('text',
# attrs={
# 'text': floor,
# 'in_world': True,
# 'color': color,
# 'shadow': 1.0,
# 'flatness': 1.0,
# 'scale':0.019,
# 'h_align': 'left',
# 'position':(x-1.2,y,-5.52)
# })
def create_vertical(self,x,y):
shared = SharedObjects.get()
floor = ""
for i in range(0,4):
floor +="|\n"
ba.newnode('region',attrs={'position': (x, y, -5.52),'scale': (0.1,2.8,1),'type': 'box','materials': [shared.footing_material,self._real_wall_material ]})
ba.newnode('locator', attrs={'shape':'box', 'position':( x, y, -5.52), 'color':(1,1,0), 'opacity':1,'draw_beauty':True,'additive':False,'size':(0.1,2.8,2)})
# ba.newnode('text',
# attrs={
# 'text': floor,
# 'in_world': True,
# 'shadow': 1.0,
# 'flatness': 1.0,
# 'scale':0.019,
# 'h_align': 'left',
# 'position':(x,y+1,-5.52)
# })
def spawn_player_spaz(self,
player: Player,
position: Sequence[float] = None,
angle: float = None) -> PlayerSpaz:
"""Intercept new spazzes and add our team material for them."""
if player.team.id==0:
position=(-10.75152479, 5.057427485, -5.52)
elif player.team.id==1:
position=(8.75152479, 5.057427485, -5.52)
spaz = super().spawn_player_spaz(player, position, angle)
return spaz
def _kill_puck(self) -> None:
self._puck = None
def _handle_score(self) -> None:
"""A point has been scored."""
assert self._puck is not None
assert self._score_regions is not None
# Our puck might stick around for a second or two
# we don't want it to be able to score again.
if self._puck.scored:
return
region = ba.getcollision().sourcenode
index = 0
for index in range(len(self._score_regions)):
if region == self._score_regions[index].node:
break
for team in self.teams:
if team.id == index:
scoring_team = team
team.score += 1
# Tell all players to celebrate.
for player in team.players:
if player.actor:
player.actor.handlemessage(ba.CelebrateMessage(2.0))
# If we've got the player from the scoring team that last
# touched us, give them points.
if (scoring_team.id in self._puck.last_players_to_touch
and self._puck.last_players_to_touch[scoring_team.id]):
self.stats.player_scored(
self._puck.last_players_to_touch[scoring_team.id],
20,
big_message=True)
# End game if we won.
if team.score >= self._score_to_win:
self.end_game()
ba.playsound(self._foghorn_sound)
ba.playsound(self._cheer_sound)
self._puck.scored = True
# Change puck texture to something cool
self._puck.node.color_texture = self.puck_scored_tex
# Kill the puck (it'll respawn itself shortly).
ba.timer(1.0, self._kill_puck)
light = ba.newnode('light',
attrs={
'position': ba.getcollision().position,
'height_attenuated': False,
'color': (1, 0, 0)
})
ba.animate(light, 'intensity', {0: 0, 0.5: 1, 1.0: 0}, loop=True)
ba.timer(1.0, light.delete)
ba.cameraflash(duration=10.0)
self._update_scoreboard()
def end_game(self) -> None:
results = ba.GameResults()
for team in self.teams:
results.set_team_score(team, team.score)
self.end(results=results)
def _update_scoreboard(self) -> None:
winscore = self._score_to_win
for team in self.teams:
self._scoreboard.set_team_value(team, team.score, winscore)
def handlemessage(self, msg: Any) -> Any:
# Respawn dead players if they're still in the game.
if isinstance(msg, ba.PlayerDiedMessage):
# Augment standard behavior...
super().handlemessage(msg)
self.respawn_player(msg.getplayer(Player))
# Respawn dead pucks.
elif isinstance(msg, PuckDiedMessage):
if not self.has_ended():
ba.timer(3.0, self._spawn_puck)
else:
super().handlemessage(msg)
def _flash_puck_spawn(self) -> None:
light = ba.newnode('light',
attrs={
'position': self._puck_spawn_pos,
'height_attenuated': False,
'color': (1, 0, 0)
})
ba.animate(light, 'intensity', {0.0: 0, 0.25: 1, 0.5: 0}, loop=True)
ba.timer(1.0, light.delete)
def _spawn_puck(self) -> None:
ba.playsound(self._swipsound)
ba.playsound(self._whistle_sound)
self._flash_puck_spawn()
assert self._puck_spawn_pos is not None
self._puck = Puck(position=self._puck_spawn_pos)

1039
dist/ba_root/mods/games/hot_potato.py vendored Normal file

File diff suppressed because it is too large Load diff

230
dist/ba_root/mods/maps/BridgitPlus.py vendored Normal file
View file

@ -0,0 +1,230 @@
from __future__ import annotations
from typing import TYPE_CHECKING
import ba,_ba
from bastd.gameutils import SharedObjects
if TYPE_CHECKING:
from typing import Any, List, Dict
class mapdefs:
points = {}
# noinspection PyDictCreation
boxes = {}
boxes['area_of_interest_bounds'] = (-0.2457963347, 3.828181068,
-1.528362695) + (0.0, 0.0, 0.0) + (
19.14849937, 7.312788846, 13.436232726)
points['ffa_spawn1'] = (-5.869295124, 3.715437928,
-1.617274877) + (0.9410329222, 1.0, 1.818908238)
points['ffa_spawn2'] = (5.160809653, 3.761793434,
-1.443012115) + (0.7729807005, 1.0, 1.818908238)
points['ffa_spawn3'] = (-0.4266381164, 3.761793434,
-1.555562653) + (4.034151421, 1.0, 0.2731725824)
points['flag1'] = (-7.354603923, 3.770769731, -1.617274877)
points['flag2'] = (6.885846926, 3.770685211, -1.443012115)
points['flag_default'] = (-0.2227795102, 3.802429326, -1.562586233)
boxes['map_bounds'] = (-0.1916036665, 7.481446847, -1.311948055) + (
0.0, 0.0, 0.0) + (27.41996888, 18.47258973, 19.52220249)
points['powerup_spawn1'] = (6.82849491, 4.658454461, 0.1938139802)
points['powerup_spawn2'] = (-7.253381358, 4.728692078, 0.252121017)
points['powerup_spawn3'] = (6.82849491, 4.658454461, -3.461765427)
points['powerup_spawn4'] = (-7.253381358, 4.728692078, -3.40345839)
points['shadow_lower_bottom'] = (-0.2227795102, 2.83188898, 2.680075641)
points['shadow_lower_top'] = (-0.2227795102, 3.498267184, 2.680075641)
points['shadow_upper_bottom'] = (-0.2227795102, 6.305086402, 2.680075641)
points['shadow_upper_top'] = (-0.2227795102, 9.470923628, 2.680075641)
points['spawn1'] = (-5.869295124, 3.715437928,
-1.617274877) + (0.9410329222, 1.0, 1.818908238)
points['spawn2'] = (5.160809653, 3.761793434,
-1.443012115) + (0.7729807005, 1.0, 1.818908238)
class BridgitPlus(ba.Map):
"""Map with a narrow bridge in the middle."""
# from bastd.mapdata import bridgit as defs
defs = mapdefs
name = 'Bridgit Plus'
dataname = 'bridgit'
@classmethod
def get_play_types(cls) -> list[str]:
"""Return valid play types for this map."""
# print('getting playtypes', cls._getdata()['play_types'])
return ['melee', 'team_flag', 'keep_away']
@classmethod
def get_preview_texture_name(cls) -> str:
return 'bridgitPreview'
@classmethod
def on_preload(cls) -> Any:
data: dict[str, Any] = {
'model_top': ba.getmodel('bridgitLevelTop'),
'model_bottom': ba.getmodel('bridgitLevelBottom'),
'model_bg': ba.getmodel('natureBackground'),
'bg_vr_fill_model': ba.getmodel('natureBackgroundVRFill'),
'collide_model': ba.getcollidemodel('bridgitLevelCollide'),
'tex': ba.gettexture('bridgitLevelColor'),
'model_bg_tex': ba.gettexture('natureBackgroundColor'),
'collide_bg': ba.getcollidemodel('natureBackgroundCollide'),
'railing_collide_model':
(ba.getcollidemodel('bridgitLevelRailingCollide')),
'bg_material': ba.Material()
}
data['bg_material'].add_actions(actions=('modify_part_collision',
'friction', 10.0))
return data
def __init__(self) -> None:
super().__init__()
shared = SharedObjects.get()
self.node = ba.newnode(
'terrain',
delegate=self,
attrs={
'collide_model': self.preloaddata['collide_model'],
'model': self.preloaddata['model_top'],
'color_texture': self.preloaddata['tex'],
'materials': [shared.footing_material]
})
self.bottom = ba.newnode('terrain',
attrs={
'model': self.preloaddata['model_bottom'],
'lighting': False,
'color_texture': self.preloaddata['tex']
})
self.background = ba.newnode(
'terrain',
attrs={
'model': self.preloaddata['model_bg'],
'lighting': False,
'background': True,
'color_texture': self.preloaddata['model_bg_tex']
})
ba.newnode('terrain',
attrs={
'model': self.preloaddata['bg_vr_fill_model'],
'lighting': False,
'vr_only': True,
'background': True,
'color_texture': self.preloaddata['model_bg_tex']
})
self.bg_collide = ba.newnode('terrain',
attrs={
'collide_model':
self.preloaddata['collide_bg'],
'materials': [
shared.footing_material,
self.preloaddata['bg_material'],
shared.death_material
]
})
gnode = ba.getactivity().globalsnode
gnode.tint = (1.1, 1.2, 1.3)
gnode.ambient_color = (1.1, 1.2, 1.3)
gnode.vignette_outer = (0.65, 0.6, 0.55)
gnode.vignette_inner = (0.9, 0.9, 0.93)
self.map_extend()
def is_point_near_edge(self,
point: ba.Vec3,
running: bool = False) -> bool:
box_position = self.defs.boxes['edge_box'][0:3]
box_scale = self.defs.boxes['edge_box'][6:9]
xpos = (point.x - box_position[0]) / box_scale[0]
zpos = (point.z - box_position[2]) / box_scale[2]
return xpos < -0.5 or xpos > 0.5 or zpos < -0.5 or zpos > 0.5
def map_extend(self):
shared = SharedObjects.get()
self._real_wall_material=ba.Material()
self._real_wall_material.add_actions(
actions=(
('modify_part_collision', 'collide', True),
('modify_part_collision', 'physical', True)
))
self.mat = ba.Material()
self.mat.add_actions(
actions=( ('modify_part_collision','physical',False),
('modify_part_collision','collide',False))
)
spaz_collide_mat=ba.Material()
pos=(-1.8323341846466064, 3.004164695739746, -1.3991328477859497)
self.ud_1_r=ba.newnode('region',attrs={'position': pos,'scale': (2,1,2),'type': 'box','materials': [shared.footing_material,self._real_wall_material,spaz_collide_mat ]})
self.node = ba.newnode('prop',
owner=self.ud_1_r,
attrs={
'model':ba.getmodel('bridgitLevelTop'),
'light_model':ba.getmodel('powerupSimple'),
'position':(2,7,2),
'body':'puck',
'shadow_size':0.0,
'velocity':(0,0,0),
'color_texture':ba.gettexture('bridgitLevelColor'),
'reflection_scale':[1.5],
'materials':[self.mat, shared.object_material,shared.footing_material],
'density':9000000000
})
self.node.changerotation(0,1,0)
mnode = ba.newnode('math',
owner=self.ud_1_r,
attrs={
'input1': (0, -2.9, 0),
'operation': 'add'
})
self.ud_1_r.connectattr('position', mnode, 'input2')
mnode.connectattr('output', self.node, 'position')
# base / bottom ====================================
pos=(-1.8323341846466064, 2.004164695739746, -1.3991328477859497)
self.ud_2_r=ba.newnode('region',attrs={'position': pos,'scale': (2,1,2),'type': 'box','materials': [shared.footing_material,self._real_wall_material,spaz_collide_mat ]})
self.node2 = ba.newnode('prop',
owner=self.ud_2_r,
attrs={
'model':ba.getmodel('bridgitLevelBottom'),
'light_model':ba.getmodel('powerupSimple'),
'position':(2,7,2),
'body':'puck',
'shadow_size':0.0,
'velocity':(0,0,0),
'color_texture':ba.gettexture('bridgitLevelColor'),
'reflection_scale':[1.5],
'materials':[self.mat, shared.object_material,shared.footing_material],
'density':9000000000
})
mnode = ba.newnode('math',
owner=self.ud_2_r,
attrs={
'input1': (0, -1.8, 0),
'operation': 'add'
})
self.node2.changerotation(0,1,0)
self.ud_2_r.connectattr('position', mnode, 'input2')
mnode.connectattr('output', self.node2, 'position')
# /// region to stand long bar ===============
pos=(-0.26, 3.204164695739746, -5.3991328477859497)
self.v_region=ba.newnode('region',attrs={'position': pos,'scale': (1.5,1,21),'type': 'box','materials': [shared.footing_material,self._real_wall_material,spaz_collide_mat ]})
pos=(-0.26, 3.204164695739746, -7.5)
self.h_1_region=ba.newnode('region',attrs={'position': pos,'scale': (4.9,1,3.6),'type': 'box','materials': [shared.footing_material,self._real_wall_material,spaz_collide_mat ]})
pos=(-0.42, 3.204164695739746, 4.1)
self.h_1_region=ba.newnode('region',attrs={'position': pos,'scale': (4.9,1,3.6),'type': 'box','materials': [shared.footing_material,self._real_wall_material,spaz_collide_mat ]})
ba._map.register_map(BridgitPlus)

Binary file not shown.

161
dist/ba_root/mods/maps/DesertMap.py vendored Normal file
View file

@ -0,0 +1,161 @@
from __future__ import annotations
from typing import TYPE_CHECKING
import ba,_ba
from bastd.gameutils import SharedObjects
if TYPE_CHECKING:
from typing import Any, List, Dict
# This file was automatically generated from "big_g.ma"
# pylint: disable=all
class mapdefs:
points = {}
# noinspection PyDictCreation
boxes = {}
boxes['area_of_interest_bounds'] = (-1.4011866709, -1.331310176,
-4.5426286416) + (0.0, 0.0, 0.0) + (
19.11746262, 10.19675564, 25.50119277)
points['ffa_spawn1'] = (3.140826121, -1.16512015,
6.172121491) + (4.739204545, 1-1.0, 1.028864849)
points['ffa_spawn2'] = (5.416289073, -1.180022599, -0.1696495695) + (
2.945888237, -0.621599724, 0.4969830881)
points['ffa_spawn3'] = (-0.3692088357, -1.88984723, -6.909741615) + (
7.575371952, 0.621599724, 0.4969830881)
points['ffa_spawn4'] = (-2.391932409, -1.123690253, -3.417262271) + (
2.933065031, 0.621599724, 0.9796558695)
points['ffa_spawn5'] = (-7.46052038, -1.863807079,
4.936420902) + (0.8707600789, -0.621599724, 2.233577195)
points['flag1'] = (7.557928387, 2.889342613, -7.208799596)
points['flag2'] = (7.696183956, 1.095466627, 6.103380446)
points['flag3'] = (-8.122819332, 2.844893069, 6.103380446)
points['flag4'] = (-8.018537918, 2.844893069, -6.202403896)
points['flag_default'] = (-7.563673017, 2.850652319, 0.08844978098)
boxes['map_bounds'] = (-7.1916036665, -3.764115729, -43.1971423239) + (
0.0, 0.0, 0.0) + (48.41996888, 100.47258973, 150.17335735)
points['powerup_spawn1'] = (7.830495287, -1.115087683, -0.05452287857)
points['powerup_spawn2'] = (-5.190293739, -1.476317443, -3.80237889)
points['powerup_spawn3'] = (-8.540957726, -1.762979519, -7.27710542)
points['powerup_spawn4'] = (7.374052727, -1.762979519, -3.091707631)
points['powerup_spawn5'] = (-8.691423338, -1.692026034, 6.627877455)
points['race_mine1'] = (-0.06161453294, 1.123140909, 4.966104324)
points['race_mine10'] = (-6.870248758, 2.851484105, 2.718992803)
points['race_mine2'] = (-0.06161453294, 1.123140909, 6.99632996)
points['race_mine3'] = (-0.7319278377, 1.123140909, -2.828583367)
points['race_mine4'] = (-3.286508423, 1.123140909, 0.8453899305)
points['race_mine5'] = (5.077545429, 2.850225463, -5.253575631)
points['race_mine6'] = (6.286453838, 2.850225463, -5.253575631)
points['race_mine7'] = (0.969120762, 2.851484105, -7.892038145)
points['race_mine8'] = (-2.976299166, 2.851484105, -6.241064664)
points['race_mine9'] = (-6.962812986, 2.851484105, -2.120262964)
points['race_point1'] = (2.280447713, 1.16512015, 6.015278429) + (
0.7066894139, 4.672784871, 1.322422256)
points['race_point10'] = (-4.196540687, 2.877461266, -7.106874334) + (
0.1057202515, 5.496127671, 1.028552836)
points['race_point11'] = (-7.634488499, 2.877461266, -3.61728743) + (
1.438144134, 5.157457566, 0.06318119808)
points['race_point12'] = (-7.541251512, 2.877461266, 3.290439202) + (
1.668578284, 5.52484043, 0.06318119808)
points['race_point2'] = (4.853459878, 1.16512015,
6.035867283) + (0.3920628436, 4.577066678, 1.34568243)
points['race_point3'] = (6.905234402, 1.16512015, 1.143337503) + (
1.611663691, 3.515259775, 0.1135135003)
points['race_point4'] = (2.681673258, 1.16512015, 0.771967064) + (
0.6475414982, 3.602143342, 0.1135135003)
points['race_point5'] = (-0.3776550727, 1.225615225, 1.920343787) + (
0.1057202515, 4.245024435, 0.5914887576)
points['race_point6'] = (-4.365081958, 1.16512015, -0.3565529313) + (
1.627090525, 4.549428479, 0.1135135003)
points['race_point7'] = (0.4149308672, 1.16512015, -3.394316313) + (
0.1057202515, 4.945367833, 1.310190117)
points['race_point8'] = (4.27031635, 2.19747021, -3.335165617) + (
0.1057202515, 4.389664492, 1.20413595)
points['race_point9'] = (2.552998384, 2.877461266, -7.117366939) + (
0.1057202515, 5.512312989, 0.9986814472)
points['shadow_lower_bottom'] = (-0.2227795102, 0.2903873918, 2.680075641)
points['shadow_lower_top'] = (-0.2227795102, 0.8824975157, 2.680075641)
points['shadow_upper_bottom'] = (-0.2227795102, 6.305086402, 2.680075641)
points['shadow_upper_top'] = (-0.2227795102, 9.470923628, 2.680075641)
points['spawn1'] = (3.180043217, -3.85596295, -1.407134234) + (0.7629937742,
-1.0, 1.818908238)
points['spawn2'] = (-5.880548999, -3.142163379, -2.171168951) + (1.817516622, -1.0,
0.7724344394)
points['spawn_by_flag1'] = (7.180043217, 2.85596295,
-4.407134234) + (0.7629937742, 1.0, 1.818908238)
points['spawn_by_flag2'] = (5.880548999, 1.142163379,
6.171168951) + (1.817516622, 1.0, 0.7724344394)
points['spawn_by_flag3'] = (-6.66642559, 3.554416948,
5.820238985) + (1.097315815, 1.0, 1.285161684)
points['spawn_by_flag4'] = (-6.842951255, 3.554416948,
-6.17429905) + (0.8208434737, 1.0, 1.285161684)
points['tnt1'] = (-3.398312776, 2.067056737, -1.90142919)
class Desert(ba.Map):
"""Large G shaped map for racing"""
defs = mapdefs
name = 'Desert'
@classmethod
def get_play_types(cls) -> List[str]:
"""Return valid play types for this map."""
return [
'race', 'melee', 'keep_away', 'team_flag', 'king_of_the_hill',
'conquest'
]
@classmethod
def get_preview_texture_name(cls) -> str:
return 'bigGPreview'
@classmethod
def on_preload(cls) -> Any:
data: Dict[str, Any] = {
'model_top': ba.getmodel('bigG'),
'model_bottom': ba.getmodel('bigGBottom'),
'model_bg': ba.getmodel('natureBackground'),
'bg_vr_fill_model': ba.getmodel('natureBackgroundVRFill'),
'collide_model': ba.getcollidemodel('bigGCollide'),
'tex': ba.gettexture('bigG'),
'model_bg_tex': ba.gettexture('natureBackgroundColor'),
'collide_bg': ba.getcollidemodel('natureBackgroundCollide'),
'bumper_collide_model': ba.getcollidemodel('bigGBumper'),
'bg_material': ba.Material()
}
data['bg_material'].add_actions(actions=('modify_part_collision',
'friction', 3.0))
return data
def __init__(self) -> None:
super().__init__()
shared = SharedObjects.get()
self.background = ba.newnode(
'terrain',
attrs={
'model': self.preloaddata['model_bg'],
'lighting': False,
'background': True,
'color_texture': self.preloaddata['model_bg_tex']
})
self.bg_collide = ba.newnode('terrain',
attrs={
'collide_model':
self.preloaddata['collide_bg'],
'materials': [
shared.footing_material,
self.preloaddata['bg_material'],
]
})
gnode = ba.getactivity().globalsnode
gnode.tint = (1.1, 1.2, 1.3)
gnode.ambient_color = (1.1, 1.2, 1.3)
gnode.vignette_outer = (0.65, 0.6, 0.55)
gnode.vignette_inner = (0.9, 0.9, 0.93)
ba._map.register_map(Desert)

217
dist/ba_root/mods/maps/LakeOfDeath.py vendored Normal file
View file

@ -0,0 +1,217 @@
from __future__ import annotations
from typing import TYPE_CHECKING
import ba,_ba
from bastd.gameutils import SharedObjects
from bastd.actor.playerspaz import PlayerSpaz
if TYPE_CHECKING:
from typing import Any, List, Dict
class mapdefs:
points = {}
# noinspection PyDictCreation
boxes = {}
boxes['area_of_interest_bounds'] = (0.0, 1.185751251, 0.4326226188) + (
0.0, 0.0, 0.0) + (29.8180273, 11.57249038, 18.89134176)
boxes['edge_box'] = (-0.103873591, 0.4133341891, 0.4294651013) + (
0.0, 0.0, 0.0) + (22.48295719, 1.290242794, 8.990252454)
points['ffa_spawn1'] = (-0.08015551329, 0.02275111462,
-4.373674593) + (8.895057015, 1.0, 0.444350722)
points['ffa_spawn2'] = (-0.08015551329, 0.02275111462,
4.076288941) + (8.895057015, 1.0, 0.444350722)
points['flag1'] = (-10.99027878, 0.05744967453, 0.1095578275)
points['flag2'] = (11.01486398, 0.03986567039, 0.1095578275)
points['flag_default'] = (-0.1001374046, 0.04180340146, 0.1095578275)
boxes['goal1'] = (12.22454533, 1.0,
0.1087926362) + (0.0, 0.0, 0.0) + (2.0, 2.0, 12.97466313)
boxes['goal2'] = (-12.15961605, 1.0,
0.1097860203) + (0.0, 0.0, 0.0) + (2.0, 2.0, 13.11856424)
boxes['map_bounds'] = (0.0, 1.185751251, 0.4326226188) + (0.0, 0.0, 0.0) + (
42.09506485, 22.81173179, 29.76723155)
points['powerup_spawn1'] = (5.414681236, 0.9515026107, -5.037912441)
points['powerup_spawn2'] = (-5.555402285, 0.9515026107, -5.037912441)
points['powerup_spawn3'] = (5.414681236, 0.9515026107, 5.148223181)
points['powerup_spawn4'] = (-5.737266365, 0.9515026107, 5.148223181)
points['spawn1'] = (-10.03866341, 0.02275111462, 0.0) + (0.5, 1.0, 4.0)
points['spawn2'] = (9.823107149, 0.01092306765, 0.0) + (0.5, 1.0, 4.0)
points['tnt1'] = (-0.08421587483, 0.9515026107, -0.7762602271)
class LakeOfDeath(ba.Map):
"""Stadium map for football games."""
defs = mapdefs
defs.points['spawn1'] = (-12.03866341, 0.02275111462, 0.0) + (0.5, 1.0, 4.0)
defs.points['spawn2'] = (12.823107149, 0.01092306765, 0.0) + (0.5, 1.0, 4.0)
name = 'Lake of Death'
@classmethod
def get_play_types(cls) -> list[str]:
"""Return valid play types for this map."""
return ['melee', 'football', 'team_flag', 'keep_away']
@classmethod
def get_preview_texture_name(cls) -> str:
return 'footballStadiumPreview'
@classmethod
def on_preload(cls) -> Any:
data: dict[str, Any] = {
'model': ba.getmodel('footballStadium'),
'vr_fill_model': ba.getmodel('footballStadiumVRFill'),
'collide_model': ba.getcollidemodel('footballStadiumCollide'),
'tex': ba.gettexture('footballStadium')
}
return data
def __init__(self) -> None:
super().__init__()
shared = SharedObjects.get()
self.node = ba.newnode(
'terrain',
delegate=self,
attrs={
'model': self.preloaddata['model'],
'collide_model': self.preloaddata['collide_model'],
'color_texture': self.preloaddata['tex'],
'materials': [shared.footing_material]
})
ba.newnode('terrain',
attrs={
'model': self.preloaddata['vr_fill_model'],
'lighting': False,
'vr_only': True,
'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
self.map_extend()
def is_point_near_edge(self,
point: ba.Vec3,
running: bool = False) -> bool:
box_position = self.defs.boxes['edge_box'][0:3]
box_scale = self.defs.boxes['edge_box'][6:9]
xpos = (point.x - box_position[0]) / box_scale[0]
zpos = (point.z - box_position[2]) / box_scale[2]
return xpos < -0.5 or xpos > 0.5 or zpos < -0.5 or zpos > 0.5
def map_extend(self):
self.create_ramp(0)
self.create_ramp(10.9)
self.ground()
def ground(self):
shared = SharedObjects.get()
self._real_wall_material=ba.Material()
self._real_wall_material.add_actions(
actions=(
('modify_part_collision', 'collide', True),
('modify_part_collision', 'physical', True)
))
self.mat = ba.Material()
self.mat.add_actions(
actions=( ('modify_part_collision','physical',False),
('modify_part_collision','collide',False))
)
spaz_collide_mat=ba.Material()
spaz_collide_mat.add_actions(
conditions=('they_have_material',shared.player_material),
actions=(
('modify_part_collision', 'collide', True),
( 'call','at_connect',ba.Call(self._handle_player_collide )),
),
)
pos=(0,0.1,-5)
self.main_region=ba.newnode('region',attrs={'position': pos,'scale': (21,0.001,23),'type': 'box','materials': [shared.footing_material,self._real_wall_material,spaz_collide_mat]})
def create_ramp(self,loc):
z_marg=0
if loc!=0:
z_marg=0.3
shared = SharedObjects.get()
self._real_wall_material=ba.Material()
self._real_wall_material.add_actions(
actions=(
('modify_part_collision', 'collide', True),
('modify_part_collision', 'physical', True)
))
self.mat = ba.Material()
self.mat.add_actions(
actions=( ('modify_part_collision','physical',False),
('modify_part_collision','collide',False))
)
spaz_collide_mat=ba.Material()
pos=(-5.3 +loc,0.7,1.1+z_marg)
self.ud_1_r=ba.newnode('region',attrs={'position': pos,'scale': (2,1,2),'type': 'box','materials': [shared.footing_material,spaz_collide_mat ]})
self.node = ba.newnode('prop',
owner=self.ud_1_r,
attrs={
'model':ba.getmodel('bridgitLevelTop'),
'light_model':ba.getmodel('powerupSimple'),
'position':(2,7,2),
'body':'puck',
'shadow_size':0.0,
'velocity':(0,0,0),
'color_texture':ba.gettexture('bridgitLevelColor'),
'model_scale':0.72,
'reflection_scale':[1.5],
'materials':[self.mat, shared.object_material,shared.footing_material],
'density':9000000000
})
self.node.changerotation(0,0,0)
mnode = ba.newnode('math',
owner=self.ud_1_r,
attrs={
'input1': (0, -2.9, 0),
'operation': 'add'
})
self.ud_1_r.connectattr('position', mnode, 'input2')
mnode.connectattr('output', self.node, 'position')
pos=(-9.67+loc,0.1,0+z_marg)
self.left_region=ba.newnode('region',attrs={'position': pos,'scale': (2.4,0.4,3.4),'type': 'box','materials': [shared.footing_material,self._real_wall_material,spaz_collide_mat ]})
pos=(-5.67+loc,0.1,0+z_marg)
self.center_region=ba.newnode('region',attrs={'position': pos,'scale': (8,0.4,1),'type': 'box','materials': [shared.footing_material,self._real_wall_material,spaz_collide_mat ]})
pos=(-1.3+loc-0.1,0.1,0+z_marg)
self.right_region=ba.newnode('region',attrs={'position': pos,'scale': (2.6,0.4,3.7),'type': 'box','materials': [shared.footing_material,self._real_wall_material,spaz_collide_mat ]})
def _handle_player_collide(self):
try:
player = ba.getcollision().opposingnode.getdelegate(
PlayerSpaz, True)
except ba.NotFoundError:
return
if player.is_alive():
player.shatter(True)
ba._map.register_map(LakeOfDeath)

View file

@ -108,6 +108,99 @@ class WoodenFloor(ba.Map):
zpos = (point.z - box_position[2]) / box_scale[2]
return xpos < -0.5 or xpos > 0.5 or zpos < -0.5 or zpos > 0.5
def map_extend(self):
pass
# p=[-6,-4.3,-2.6,-0.9,0.8,2.5,4.2,5.9]
# q=[-4,-2.3,-0.6,1.1,2.8,4.5,6.2]
# for i in p:
# for j in q:
# self.create_ramp(i,j)
# self.create_ramp(10.9)
# self.ground()
def ground(self):
shared = SharedObjects.get()
self._real_wall_material=ba.Material()
self._real_wall_material.add_actions(
actions=(
('modify_part_collision', 'collide', True),
('modify_part_collision', 'physical', True)
))
self.mat = ba.Material()
self.mat.add_actions(
actions=( ('modify_part_collision','physical',False),
('modify_part_collision','collide',False))
)
spaz_collide_mat=ba.Material()
spaz_collide_mat.add_actions(
conditions=('they_have_material',shared.player_material),
actions=(
('modify_part_collision', 'collide', True),
( 'call','at_connect',ba.Call(self._handle_player_collide )),
),
)
pos=(0,0.1,-5)
self.main_region=ba.newnode('region',attrs={'position': pos,'scale': (21,0.001,20),'type': 'box','materials': [shared.footing_material,self._real_wall_material,spaz_collide_mat]})
def create_ramp_111(self,x,z):
shared = SharedObjects.get()
self._real_wall_material=ba.Material()
self._real_wall_material.add_actions(
actions=(
('modify_part_collision', 'collide', True),
('modify_part_collision', 'physical', True)
))
self.mat = ba.Material()
self.mat.add_actions(
actions=( ('modify_part_collision','physical',False),
('modify_part_collision','collide',False))
)
spaz_collide_mat=ba.Material()
pos=(x,0,z)
ud_1_r=ba.newnode('region',attrs={'position': pos,'scale': (1.5,1,1.5),'type': 'box','materials': [shared.footing_material,self._real_wall_material ]})
node = ba.newnode('prop',
owner=ud_1_r,
attrs={
'model':ba.getmodel('image1x1'),
'light_model':ba.getmodel('powerupSimple'),
'position':(2,7,2),
'body':'puck',
'shadow_size':0.0,
'velocity':(0,0,0),
'color_texture':ba.gettexture('tnt'),
'model_scale':1.5,
'reflection_scale':[1.5],
'materials':[self.mat, shared.object_material,shared.footing_material],
'density':9000000000
})
mnode = ba.newnode('math',
owner=ud_1_r,
attrs={
'input1': (0, 0.6, 0),
'operation': 'add'
})
node.changerotation(1,0,0)
ud_1_r.connectattr('position', mnode, 'input2')
mnode.connectattr('output', node, 'position')
def _handle_player_collide(self):
try:
player = ba.getcollision().opposingnode.getdelegate(

View file

@ -0,0 +1,191 @@
from __future__ import annotations
from typing import TYPE_CHECKING
import ba
from bastd.gameutils import SharedObjects
if TYPE_CHECKING:
from typing import Any, List, Dict
class mapdefs:
points = {}
# noinspection PyDictCreation
boxes = {}
boxes['area_of_interest_bounds'] = (-1.045859963, 12.67722855,
-5.401537075) + (0.0, 0.0, 0.0) + (
42.46156851, 20.94044653, 0.6931564611)
points['ffa_spawn1'] = (-9.295167711, 8.010664315,
-5.44451005) + (1.555840357, 1.453808816, 0.1165648888)
points['ffa_spawn2'] = (7.484707127, 8.172681752, -5.614479365) + (
1.553861796, 1.453808816, 0.04419853907)
points['ffa_spawn3'] = (9.55724115, 11.30789446, -5.614479365) + (
1.337925849, 1.453808816, 0.04419853907)
points['ffa_spawn4'] = (-11.55747023, 10.99170684, -5.614479365) + (
1.337925849, 1.453808816, 0.04419853907)
points['ffa_spawn5'] = (-1.878892369, 9.46490571, -5.614479365) + (
1.337925849, 1.453808816, 0.04419853907)
points['ffa_spawn6'] = (-0.4912812943, 5.077006397, -5.521672101) + (
1.878332089, 1.453808816, 0.007578097856)
points['flag1'] = (-11.75152479, 8.057427485, -5.52)
points['flag2'] = (9.840909039, 8.188634282, -5.52)
points['flag3'] = (-0.2195258696, 5.010273907, -5.52)
points['flag4'] = (-0.04605809154, 12.73369108, -5.52)
points['flag_default'] = (-0.04201942896, 12.72374492, -5.52)
boxes['map_bounds'] = (-0.8748348681, 9.212941713, -5.729538885) + (
0.0, 0.0, 0.0) + (42.09666006, 26.19950145, 7.89541168)
points['powerup_spawn1'] = (1.160232442, 6.745963662, -5.469115985)
points['powerup_spawn2'] = (-1.899700206, 10.56447241, -5.505721177)
points['powerup_spawn3'] = (10.56098871, 12.25165669, -5.576232453)
points['powerup_spawn4'] = (-12.33530337, 12.25165669, -5.576232453)
points['spawn1'] = (-9.295167711, 8.010664315,
-5.44451005) + (1.555840357, 1.453808816, 0.1165648888)
points['spawn2'] = (7.484707127, 8.172681752,
-5.614479365) + (1.553861796, 1.453808816, 0.04419853907)
points['spawn_by_flag1'] = (-9.295167711, 8.010664315, -5.44451005) + (
1.555840357, 1.453808816, 0.1165648888)
points['spawn_by_flag2'] = (7.484707127, 8.172681752, -5.614479365) + (
1.553861796, 1.453808816, 0.04419853907)
points['spawn_by_flag3'] = (-1.45994593, 5.038762459, -5.535288724) + (
0.9516389866, 0.6666414677, 0.08607244075)
points['spawn_by_flag4'] = (0.4932087091, 12.74493212, -5.598987003) + (
0.5245740665, 0.5245740665, 0.01941146064)
class CreativeThoughts(ba.Map):
"""Freaking map by smoothy."""
defs = mapdefs
name = 'Creative Thoughts'
@classmethod
def get_play_types(cls) -> List[str]:
"""Return valid play types for this map."""
return [
'melee', 'keep_away', 'team_flag'
]
@classmethod
def get_preview_texture_name(cls) -> str:
return 'alwaysLandPreview'
@classmethod
def on_preload(cls) -> Any:
data: Dict[str, Any] = {
'model': ba.getmodel('alwaysLandLevel'),
'bottom_model': ba.getmodel('alwaysLandLevelBottom'),
'bgmodel': ba.getmodel('alwaysLandBG'),
'collide_model': ba.getcollidemodel('alwaysLandLevelCollide'),
'tex': ba.gettexture('alwaysLandLevelColor'),
'bgtex': ba.gettexture('alwaysLandBGColor'),
'vr_fill_mound_model': ba.getmodel('alwaysLandVRFillMound'),
'vr_fill_mound_tex': ba.gettexture('vrFillMound')
}
return data
@classmethod
def get_music_type(cls) -> ba.MusicType:
return ba.MusicType.FLYING
def __init__(self) -> None:
super().__init__(vr_overlay_offset=(0, -3.7, 2.5))
shared = SharedObjects.get()
self._fake_wall_material=ba.Material()
self._real_wall_material=ba.Material()
self._fake_wall_material.add_actions(
conditions=(('they_are_younger_than',9000),'and',('they_have_material', shared.player_material)),
actions=(
('modify_part_collision', 'collide', True),
('modify_part_collision', 'physical', True)
))
self._real_wall_material.add_actions(
conditions=('they_have_material', shared.player_material),
actions=(
('modify_part_collision', 'collide', True),
('modify_part_collision', 'physical', True)
))
self.background = ba.newnode(
'terrain',
attrs={
'model': self.preloaddata['bgmodel'],
'lighting': False,
'background': True,
'color_texture': ba.gettexture("rampageBGColor")
})
self.leftwall=ba.newnode('region',attrs={'position': (-17.75152479, 13, -5.52),'scale': (0.1,15.5,2),'type': 'box','materials': [shared.footing_material,self._real_wall_material ]})
self.rightwall=ba.newnode('region',attrs={'position': (17.75, 13, -5.52),'scale': (0.1,15.5,2),'type': 'box','materials': [shared.footing_material,self._real_wall_material ]})
self.topwall=ba.newnode('region',attrs={'position': (0, 21.0, -5.52),'scale': (35.4,0.2,2),'type': 'box','materials': [shared.footing_material,self._real_wall_material ]})
ba.newnode('locator', attrs={'shape':'box', 'position':(-17.75152479, 13, -5.52), 'color':(0,0,0), 'opacity':1,'draw_beauty':True,'additive':False,'size':(0.1,15.5,2)})
ba.newnode('locator', attrs={'shape':'box', 'position':(17.75, 13, -5.52), 'color':(0,0,0), 'opacity':1,'draw_beauty':True,'additive':False,'size':(0.1,15.5,2)})
ba.newnode('locator', attrs={'shape':'box', 'position':(0, 21.0, -5.52), 'color':(0,0,0), 'opacity':1,'draw_beauty':True,'additive':False,'size':(35.4,0.2,2)})
# self.node_text_left = ba.newnode('text',
# attrs={
# 'text': "|\n|\n|\n|\n|\n\n\n\n|\n|\n|\n|\n End here \n|\n|\n|\n|\n|\n|\n|\n\n\n\n|\n|\n",
# 'in_world': True,
# 'shadow': 1.0,
# 'flatness': 1.0,
# 'scale':0.019,
# 'h_align': 'center',
# 'position':(-18,20,-5)
# })
# self.node_text_right = ba.newnode('text',
# attrs={
# 'text': "|\n|\n|\n|\n|\n\n\n\n|\n|\n|\n|\n End here \n|\n|\n|\n|\n|\n|\n|\n\n\n\n|\n|\n",
# 'in_world': True,
# 'shadow': 1.0,
# 'flatness': 1.0,
# 'scale':0.019,
# 'h_align': 'center',
# 'position':(17,20,-5)
# })
# self.node_text_top = ba.newnode('text',
# attrs={
# 'text': "_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _",
# 'in_world': True,
# 'shadow': 1.0,
# 'flatness': 1.0,
# 'scale':0.019,
# 'h_align': 'center',
# 'position':(0,21,-5)
# })
gnode = ba.getactivity().globalsnode
gnode.happy_thoughts_mode = True
gnode.shadow_offset = (0.0, 8.0, 5.0)
gnode.tint = (1.3, 1.23, 1.0)
gnode.ambient_color = (1.3, 1.23, 1.0)
gnode.vignette_outer = (0.64, 0.59, 0.69)
gnode.vignette_inner = (0.95, 0.95, 0.93)
gnode.vr_near_clip = 1.0
self.is_flying = True
# throw out some tips on flying
txt = ba.newnode('text',
attrs={
'text': ba.Lstr(resource='pressJumpToFlyText'),
'scale': 1.2,
'maxwidth': 800,
'position': (0, 200),
'shadow': 0.5,
'flatness': 0.5,
'h_align': 'center',
'v_attach': 'bottom'
})
cmb = ba.newnode('combine',
owner=txt,
attrs={
'size': 4,
'input0': 0.3,
'input1': 0.9,
'input2': 0.0
})
ba.animate(cmb, 'input3', {3.0: 0, 4.0: 1, 9.0: 1, 10.0: 0})
cmb.connectattr('output', txt, 'color')
ba.timer(10.0, txt.delete)
ba._map.register_map(CreativeThoughts)

View file

@ -0,0 +1,222 @@
from __future__ import annotations
from typing import TYPE_CHECKING
import ba,_ba
from bastd.gameutils import SharedObjects
if TYPE_CHECKING:
from typing import Any, List, Dict
class mapdefs:
points = {}
# noinspection PyDictCreation
boxes = {}
boxes['area_of_interest_bounds'] = (0.0, 1.185751251, 0.4326226188) + (
0.0, 0.0, 0.0) + (45.8180273, 11.57249038, 22.89134176)
boxes['edge_box'] = (-0.103873591, 0.4133341891, 0.4294651013) + (
0.0, 0.0, 0.0) + (22.48295719, 1.290242794, 8.990252454)
points['ffa_spawn1'] = (-0.08015551329, 0.02275111462,
-4.373674593) + (8.895057015, 1.0, 0.444350722)
points['ffa_spawn2'] = (-0.08015551329, 0.02275111462,
4.076288941) + (8.895057015, 1.0, 0.444350722)
points['flag1'] = (-10.99027878, 0.05744967453, 0.1095578275)
points['flag2'] = (11.01486398, 0.03986567039, 0.1095578275)
points['flag_default'] = (-0.1001374046, 0.04180340146, 0.1095578275)
boxes['goal1'] = (16.22454533, 1.0,
-1.6087926362) + (0.0, 0.0, 0.0) + (1.6, 4.0, 6.17466313)
boxes['goal2'] = (-16.25961605, 1.0,
-1.6097860203) + (0.0, 0.0, 0.0) + (1.6, 4.0, 6.11856424)
boxes['map_bounds'] = (0.0, 1.185751251, 0.4326226188) + (0.0, 0.0, 0.0) + (
42.09506485, 22.81173179, 29.76723155)
points['powerup_spawn1'] = (8.414681236, 0.9515026107, -5.037912441)
points['powerup_spawn2'] = (-8.555402285, 0.9515026107, -5.037912441)
points['powerup_spawn3'] = (5.414681236, 0.9515026107, 5.148223181)
points['powerup_spawn4'] = (-5.737266365, 0.9515026107, 5.148223181)
points['spawn1'] = (-10.03866341, 0.02275111462, 0.0) + (0.5, 1.0, 4.0)
points['spawn2'] = (9.823107149, 0.01092306765, 0.0) + (0.5, 1.0, 4.0)
points['tnt1'] = (-0.08421587483, 0.9515026107, -0.7762602271)
class SoccerStadiumPro(ba.Map):
"""Stadium map for football games."""
defs = mapdefs
name = 'Soccer Stadium Pro'
@classmethod
def get_play_types(cls) -> list[str]:
"""Return valid play types for this map."""
return ['melee', 'football', 'team_flag', 'keep_away']
@classmethod
def get_preview_texture_name(cls) -> str:
return 'footballStadiumPreview'
@classmethod
def on_preload(cls) -> Any:
data: dict[str, Any] = {
'model': ba.getmodel('footballStadium'),
'vr_fill_model': ba.getmodel('footballStadiumVRFill'),
'collide_model': ba.getcollidemodel('footballStadiumCollide'),
'tex': ba.gettexture('footballStadium')
}
return data
def __init__(self) -> None:
super().__init__()
shared = SharedObjects.get()
# self.node = ba.newnode(
# 'terrain',
# delegate=self,
# attrs={
# 'model': self.preloaddata['model'],
# 'collide_model': self.preloaddata['collide_model'],
# 'color_texture': self.preloaddata['tex'],
# 'materials': [shared.footing_material]
# })
ba.newnode('terrain',
attrs={
'model': self.preloaddata['vr_fill_model'],
'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
# gnode.area_of_interest_bounds=(-20,-2,-10,54,2,3)
self.extend()
def is_point_near_edge(self,
point: ba.Vec3,
running: bool = False) -> bool:
box_position = self.defs.boxes['edge_box'][0:3]
box_scale = self.defs.boxes['edge_box'][6:9]
xpos = (point.x - box_position[0]) / box_scale[0]
zpos = (point.z - box_position[2]) / box_scale[2]
return xpos < -0.5 or xpos > 0.5 or zpos < -0.5 or zpos > 0.5
def extend(self):
shared = SharedObjects.get()
self.mat = ba.Material()
self._real_wall_material=ba.Material()
self._real_wall_material.add_actions(
actions=(
('modify_part_collision', 'collide', True),
('modify_part_collision', 'physical', True)
))
self.mat.add_actions(
actions=( ('modify_part_collision','physical',False),
('modify_part_collision','collide',False))
)
fakemat=ba.Material()
fakemat.add_actions(
actions=( ('modify_part_collision','physical',False),
('modify_part_collision','collide',False))
)
# map
pos=(0,0.1,-2)
self.main_ground=ba.newnode('region',attrs={'position': pos,'scale': (54,0.001,28),'type': 'box','materials': [self._real_wall_material,shared.footing_material]})
self.node_map = ba.newnode('prop',
owner=self.main_ground,
attrs={
'model':self.preloaddata['model'],
'light_model':ba.getmodel('powerupSimple'),
'position':(0,7,0),
'body':'puck',
'shadow_size':0.0,
'velocity':(0,0,0),
'color_texture':self.preloaddata['tex'],
'reflection_scale':[1.5],
'materials':[self.mat,shared.footing_material],
'model_scale':1.6,
'body_scale':1.7,
'density':9000000000
})
mnode = ba.newnode('math',
owner=self.main_ground,
attrs={
'input1': (0, 0.1, 0),
'operation': 'add'
})
self.node_map.changerotation(0,0,0)
self.main_ground.connectattr('position', mnode, 'input2')
mnode.connectattr('output', self.node_map, 'position')
self.main_wall_top=ba.newnode('region',attrs={'position': (-4.30,0.1,-10.8),'scale': (54,20,0.1),'type': 'box','materials': [self._real_wall_material,shared.footing_material]})
self.main_wall_left=ba.newnode('region',attrs={'position': (-21.30,0.1,-4.8),'scale': (1,20,34),'type': 'box','materials': [self._real_wall_material,shared.footing_material]})
self.main_wall_right=ba.newnode('region',attrs={'position': (21.30,0.1,-4.8),'scale': (1,20,34),'type': 'box','materials': [self._real_wall_material,shared.footing_material]})
self.main_wall_bottom=ba.newnode('region',attrs={'position': (-4.30,0.1,6.8),'scale': (54,20,0.1),'type': 'box','materials': [self._real_wall_material,shared.footing_material]})
# goal posts
pos=(0.0, 3.504164695739746, -1.6)
self.ud_1_r=ba.newnode('region',attrs={'position': pos,'scale': (2,1,2),'type': 'box','materials': [fakemat ]})
self.node = ba.newnode('prop',
owner=self.ud_1_r,
attrs={
'model':ba.getmodel('hockeyStadiumOuter'),
'light_model':ba.getmodel('powerupSimple'),
'position':(2,7,2),
'body':'puck',
'shadow_size':0.0,
'velocity':(0,0,0),
'color_texture':ba.gettexture('hockeyStadium'),
'reflection_scale':[1.5],
'materials':[self.mat,shared.footing_material],
'model_scale':1.9,
'body_scale':1.9,
'density':9000000000
})
mnode = ba.newnode('math',
owner=self.ud_1_r,
attrs={
'input1': (0, -3.4, 0),
'operation': 'add'
})
self.node.changerotation(0,0,0)
self.ud_1_r.connectattr('position', mnode, 'input2')
mnode.connectattr('output', self.node, 'position')
# # // goal post collide model
pos=(16.88630542755127, 0.3009839951992035, -5.2)
self.gp_upper_r=ba.newnode('region',attrs={'position': pos,'scale': (3.5,6.5,0.4),'type': 'box','materials': [shared.footing_material,self._real_wall_material ]})
pos= (16.88630542755127, 0.4209839951992035, 1.83331298828125)
self.gp_lower_r=ba.newnode('region',attrs={'position': pos,'scale': (3.5,6.5,0.4),'type': 'box','materials': [shared.footing_material,self._real_wall_material ]})
# roof
pos=(16.88630542755127, 3.6009839951992035, -1.63331298828125)
self.gp_roof_r=ba.newnode('region',attrs={'position': pos,'scale': (3.2,0.1,7.2),'type': 'box','materials': [shared.footing_material,self._real_wall_material ]})
# back side
pos=(18.4630542755127, 0.5009839951992035, -2.0)
self.gp_back_r=ba.newnode('region',attrs={'position': pos,'scale': (0.2,6,6.7),'type': 'box','materials': [shared.footing_material,self._real_wall_material ]})
# Left =============================================================================
pos=(-16.85874137878418, 0.3002381920814514, -5.2)
self.gp_upper_l=ba.newnode('region',attrs={'position': pos,'scale': (3.5,6.5,0.4),'type': 'box','materials': [shared.footing_material,self._real_wall_material ]})
pos=(-16.8830542755127, 0.4209839951992035, 1.83331298828125)
self.gp_lower_l=ba.newnode('region',attrs={'position': pos,'scale': (3.5,6.5,0.4),'type': 'box','materials': [shared.footing_material,self._real_wall_material ]})
# roof
pos=(-16.88630542755127, 3.6009839951992035, -1.63331298828125)
self.gp_roof_l=ba.newnode('region',attrs={'position': pos,'scale': (3.2,0.1,7.2),'type': 'box','materials': [shared.footing_material,self._real_wall_material ]})
# back side
pos=(-18.4630542755127, 0.5009839951992035, -2.0)
self.gp_back_l=ba.newnode('region',attrs={'position': pos,'scale': (0.2,6,6.7),'type': 'box','materials': [shared.footing_material,self._real_wall_material ]})
ba._map.register_map(SoccerStadiumPro)

Binary file not shown.

157
dist/ba_root/mods/maps/zigZagStubbed.py vendored Normal file
View file

@ -0,0 +1,157 @@
from __future__ import annotations
from typing import TYPE_CHECKING
import ba
from bastd.gameutils import SharedObjects
if TYPE_CHECKING:
from typing import Any, List, Dict
class ZigZagStubbed(ba.Map):
"""A very long zig-zaggy map"""
from bastd.mapdata import zig_zag as defs
name = 'Zigzag Stubbed'
@classmethod
def get_play_types(cls) -> list[str]:
"""Return valid play types for this map."""
return [
'melee', 'keep_away', 'team_flag', 'conquest', 'king_of_the_hill'
]
@classmethod
def get_preview_texture_name(cls) -> str:
return 'zigzagPreview'
@classmethod
def on_preload(cls) -> Any:
data: dict[str, Any] = {
'model': ba.getmodel('zigZagLevel'),
'model_bottom': ba.getmodel('zigZagLevelBottom'),
'model_bg': ba.getmodel('natureBackground'),
'bg_vr_fill_model': ba.getmodel('natureBackgroundVRFill'),
'collide_model': ba.getcollidemodel('zigZagLevelCollide'),
'tex': ba.gettexture('zigZagLevelColor'),
'model_bg_tex': ba.gettexture('natureBackgroundColor'),
'collide_bg': ba.getcollidemodel('natureBackgroundCollide'),
'railing_collide_model': ba.getcollidemodel('zigZagLevelBumper'),
'bg_material': ba.Material()
}
data['bg_material'].add_actions(actions=('modify_part_collision',
'friction', 10.0))
return data
def __init__(self) -> None:
super().__init__()
shared = SharedObjects.get()
self.node = ba.newnode(
'terrain',
delegate=self,
attrs={
'collide_model': self.preloaddata['collide_model'],
'model': self.preloaddata['model'],
'color_texture': self.preloaddata['tex'],
'materials': [shared.footing_material]
})
self.background = ba.newnode(
'terrain',
attrs={
'model': self.preloaddata['model_bg'],
'lighting': False,
'color_texture': self.preloaddata['model_bg_tex']
})
self.bottom = ba.newnode('terrain',
attrs={
'model': self.preloaddata['model_bottom'],
'lighting': False,
'color_texture': self.preloaddata['tex']
})
ba.newnode('terrain',
attrs={
'model': self.preloaddata['bg_vr_fill_model'],
'lighting': False,
'vr_only': True,
'background': True,
'color_texture': self.preloaddata['model_bg_tex']
})
self.bg_collide = ba.newnode('terrain',
attrs={
'collide_model':
self.preloaddata['collide_bg'],
'materials': [
shared.footing_material,
self.preloaddata['bg_material'],
shared.death_material
]
})
self._real_wall_material=ba.Material()
self._real_wall_material.add_actions(
actions=(
('modify_part_collision', 'collide', True),
('modify_part_collision', 'physical', True)
))
self._prop_material=ba.Material()
self._prop_material.add_actions(
actions=(
('modify_part_collision', 'collide', False),
('modify_part_collision', 'physical', False)
))
gnode = ba.getactivity().globalsnode
gnode.tint = (1.0, 1.15, 1.15)
gnode.ambient_color = (1.0, 1.15, 1.15)
gnode.vignette_outer = (0.57, 0.59, 0.63)
gnode.vignette_inner = (0.97, 0.95, 0.93)
gnode.vr_camera_offset = (-1.5, 0, 0)
self.create_ramp(-4.5,-2.4)
self.create_ramp(-4.5,0)
self.create_ramp(-1.4,-4.7)
self.create_ramp(-1.4,-2.3)
self.create_ramp(1.5,-2.4)
self.create_ramp(1.5,0)
def create_ramp(self,x,z):
shared = SharedObjects.get()
self.ud_1_r=ba.newnode('region',attrs={'position': (x,2.45,z),'scale': (2,1,2.5),'type': 'box','materials': [shared.footing_material,self._real_wall_material ]})
self.floor = ba.newnode('prop',
owner=self.ud_1_r,
attrs={
'model':ba.getmodel('image1x1'),
'light_model':ba.getmodel('powerupSimple'),
'position':(2,7,2),
'body':'puck',
'shadow_size':0.0,
'velocity':(0,0,0),
'color_texture':ba.gettexture('tnt'),
'model_scale':2.45,
'reflection_scale':[.5],
'materials':[ self._prop_material],
'density':9000000000
})
mnode = ba.newnode('math',
owner=self.ud_1_r,
attrs={
'input1': (0, 0.6, 0),
'operation': 'add'
})
self.ud_1_r.connectattr('position', mnode, 'input2')
mnode.connectattr('output', self.floor, 'position')
ba._map.register_map(ZigZagStubbed)

536
dist/ba_root/mods/plugins/auto_stunt.py vendored Normal file
View file

@ -0,0 +1,536 @@
# ba_meta require api 7
# AutoStunt mod by - Mr.Smoothy x Rikko
# https://discord.gg/ucyaesh
# https://bombsquad.ga
# Dont modify redistribute this plugin , if want to use features of this plugin in your mod write logic in seprate file
# and import this as module.
# If want to contribute in this original module, raise PR on github https://github.com/bombsquad-community/plugin-manager
import ba
import _ba
import bastd
from bastd.actor.text import Text
from bastd.actor.image import Image
from bastd.actor import spaz
from bastd.actor import playerspaz
from bastd.gameutils import SharedObjects
from bastd.actor.powerupbox import PowerupBoxFactory
from bastd.actor.spazfactory import SpazFactory
from bastd.game.elimination import EliminationGame
import math
import json
import os
from typing import Optional
CONTROLS_CENTER = (0, 0)
CONTROLS_SCALE = 1
BASE_STUNTS_DIRECTORY = os.path.join(_ba.env()["python_directory_user"], "CustomStunts")
PLAYERS_STUNT_INFO = {}
STUNT_CACHE = {}
original_on_begin = ba._activity.Activity.on_begin
original_chatmessage = _ba.chatmessage
class ControlsUI:
def on_jump_press(activity):
activity._jump_image.node.color = list(
channel * 2 for channel in activity._jump_image.node.color[:3]) + [1]
def on_jump_release(activity):
activity._jump_image.node.color = list(
channel * 0.5 for channel in activity._jump_image.node.color[:3]) + [1]
def on_pickup_press(activity):
activity._pickup_image.node.color = list(
channel * 2 for channel in activity._pickup_image.node.color[:3]) + [1]
def on_pickup_release(activity):
activity._pickup_image.node.color = list(
channel * 0.5 for channel in activity._pickup_image.node.color[:3]) + [1]
def on_punch_press(activity):
activity._punch_image.node.color = list(
channel * 2 for channel in activity._punch_image.node.color[:3]) + [1]
def on_punch_release(activity):
activity._punch_image.node.color = list(
channel * 0.5 for channel in activity._punch_image.node.color[:3]) + [1]
def on_bomb_press(activity):
activity._bomb_image.node.color = list(
channel * 2 for channel in activity._bomb_image.node.color[:3]) + [1]
def on_bomb_release(activity):
activity._bomb_image.node.color = list(
channel * 0.5 for channel in activity._bomb_image.node.color[:3]) + [1]
def on_move_ud(activity, value):
activity.set_stick_image_position(activity, x=activity.stick_image_position_x, y=value)
def on_move_lr(activity, value):
activity.set_stick_image_position(activity, x=value, y=activity.stick_image_position_y)
def display(activity):
activity._jump_image.node.color = list(activity._jump_image.node.color[:3]) + [1]
activity._pickup_image.node.color = list(activity._pickup_image.node.color[:3]) + [1]
activity._punch_image.node.color = list(activity._punch_image.node.color[:3]) + [1]
activity._bomb_image.node.color = list(activity._bomb_image.node.color[:3]) + [1]
activity._stick_base_image.opacity = 1.0
activity._stick_nub_image.opacity = 1.0
def hide(activity):
activity._jump_image.node.color = list(activity._jump_image.node.color[:3]) + [0]
activity._pickup_image.node.color = list(activity._pickup_image.node.color[:3]) + [0]
activity._punch_image.node.color = list(activity._punch_image.node.color[:3]) + [0]
activity._bomb_image.node.color = list(activity._bomb_image.node.color[:3]) + [0]
activity._stick_base_image.opacity = 0.0
activity._stick_nub_image.opacity = 0.0
CONTROLS_UI_MAP = {
"JUMP_PRESS": ControlsUI.on_jump_press,
"JUMP_RELEASE": ControlsUI.on_jump_release,
"PICKUP_PRESS": ControlsUI.on_pickup_press,
"PICKUP_RELEASE": ControlsUI.on_pickup_release,
"PUNCH_PRESS": ControlsUI.on_punch_press,
"PUNCH_RELEASE": ControlsUI.on_punch_release,
"BOMB_PRESS": ControlsUI.on_bomb_press,
"BOMB_RELEASE": ControlsUI.on_bomb_release,
"UP_DOWN": ControlsUI.on_move_ud,
"LEFT_RIGHT": ControlsUI.on_move_lr
}
class NewSpaz(bastd.actor.spaz.Spaz):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.move_map = {
"UP_DOWN": self.on_move_up_down,
"LEFT_RIGHT": self.on_move_left_right,
"HOLD_POSITION": self.on_hold_position_press,
"HOLD_RELEASE": self.on_hold_position_release,
"JUMP_PRESS": self.on_jump_press,
"JUMP_RELEASE": self.on_jump_release,
"PICKUP_PRESS": self.on_pickup_press,
"PICKUP_RELEASE": self.on_pickup_release,
"PUNCH_PRESS": self.on_punch_press,
"PUNCH_RELEASE": self.on_punch_release,
"BOMB_PRESS": self.on_bomb_press,
"BOMB_RELEASE": self.on_bomb_release,
"RUN": self.on_run,
}
class NewPlayerSpaz(bastd.actor.playerspaz.PlayerSpaz):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.move_map = {
"UP_DOWN": self.on_move_up_down,
"LEFT_RIGHT": self.on_move_left_right,
"HOLD_POSITION": self.on_hold_position_press,
"HOLD_RELEASE": self.on_hold_position_release,
"JUMP_PRESS": self.on_jump_press,
"JUMP_RELEASE": self.on_jump_release,
"PICKUP_PRESS": self.on_pickup_press,
"PICKUP_RELEASE": self.on_pickup_release,
"PUNCH_PRESS": self.on_punch_press,
"PUNCH_RELEASE": self.on_punch_release,
"BOMB_PRESS": self.on_bomb_press,
"BOMB_RELEASE": self.on_bomb_release,
"RUN": self.on_run,
}
self.mirror_spaz = []
self.source_player.in_replay = False
self.source_player.mirror_mode = False
def _handle_action(self, action, value: Optional[float] = None) -> None:
if self.source_player.sessionplayer in PLAYERS_STUNT_INFO:
PLAYERS_STUNT_INFO[self.source_player.sessionplayer].append({
"time": ba.time() - self.source_player.recording_start_time,
"move": {
"action": action,
"value": value,
}
})
elif self.source_player.in_replay:
ui_activation = CONTROLS_UI_MAP.get(action)
if ui_activation:
if action in ["UP_DOWN", "LEFT_RIGHT"]:
ui_activation(self.source_player.actor._activity(), value)
else:
ui_activation(self.source_player.actor._activity())
elif self.source_player.mirror_mode:
for mspaz in self.mirror_spaz:
if mspaz and mspaz.node.exists():
if action in ["UP_DOWN", "LEFT_RIGHT", "RUN"]:
mspaz.move_map[action](value)
else:
mspaz.move_map[action]()
def on_move_up_down(self, value: float, *args, **kwargs) -> None:
self._handle_action("UP_DOWN", value)
super().on_move_up_down(value, *args, **kwargs)
def on_move_left_right(self, value: float, *args, **kwargs) -> None:
self._handle_action("LEFT_RIGHT", value)
super().on_move_left_right(value, *args, **kwargs)
def on_hold_position_press(self, *args, **kwargs) -> None:
self._handle_action("HOLD_POSITION")
super().on_hold_position_press(*args, **kwargs)
def on_hold_position_release(self, *args, **kwargs) -> None:
self._handle_action("HOLD_RELEASE")
super().on_hold_position_release(*args, **kwargs)
def on_jump_press(self, *args, **kwargs) -> None:
self._handle_action("JUMP_PRESS")
super().on_jump_press(*args, **kwargs)
def on_jump_release(self, *args, **kwargs) -> None:
self._handle_action("JUMP_RELEASE")
super().on_jump_release(*args, **kwargs)
def on_pickup_press(self, *args, **kwargs) -> None:
self._handle_action("PICKUP_PRESS")
super().on_pickup_press(*args, **kwargs)
def on_pickup_release(self, *args, **kwargs) -> None:
self._handle_action("PICKUP_RELEASE")
super().on_pickup_release(*args, **kwargs)
def on_punch_press(self, *args, **kwargs) -> None:
self._handle_action("PUNCH_PRESS")
super().on_punch_press(*args, **kwargs)
def on_punch_release(self, *args, **kwargs) -> None:
self._handle_action("PUNCH_RELEASE")
super().on_punch_release(*args, **kwargs)
def on_bomb_press(self, *args, **kwargs) -> None:
self._handle_action("BOMB_PRESS")
super().on_bomb_press(*args, **kwargs)
def on_bomb_release(self, *args, **kwargs) -> None:
self._handle_action("BOMB_RELEASE")
super().on_bomb_release(*args, **kwargs)
def on_run(self, value: float, *args, **kwargs) -> None:
self._handle_action("RUN", value)
super().on_run(value, *args, **kwargs)
def handle_player_replay_end(player):
player.in_replay = False
ControlsUI.hide(player.actor._activity())
def get_player_from_client_id(client_id, activity=None):
activity = activity or _ba.get_foreground_host_activity()
for player in activity.players:
if player.sessionplayer.inputdevice.client_id == client_id:
return player
raise ba.SessionPlayerNotFound()
def mirror(clieid):
player = get_player_from_client_id(clieid)
spawn_mirror_spaz(player)
def capture(player):
with ba.Context(player.actor._activity()):
player.recording_start_time = ba.time()
PLAYERS_STUNT_INFO[player.sessionplayer] = []
def save(player, stunt_name):
stunt_path = f"{os.path.join(BASE_STUNTS_DIRECTORY, stunt_name)}.json"
os.makedirs(BASE_STUNTS_DIRECTORY, exist_ok=True)
with open(stunt_path, "w") as fout:
json.dump(PLAYERS_STUNT_INFO[player.sessionplayer], fout, indent=2)
del PLAYERS_STUNT_INFO[player.sessionplayer]
def replay(player, stunt_name):
stunt_path = f"{os.path.join(BASE_STUNTS_DIRECTORY, stunt_name)}.json"
if stunt_name in STUNT_CACHE:
stunt = STUNT_CACHE[stunt_name]
else:
try:
with open(stunt_path, "r") as fin:
stunt = json.load(fin)
STUNT_CACHE[stunt_name] = stunt
except:
ba.screenmessage(f"{stunt_name} doesn't exists")
return
player.in_replay = True
with ba.Context(player.actor._activity()):
ControlsUI.display(player.actor._activity())
for move in stunt:
value = move["move"]["value"]
if value is None:
ba.timer(
move["time"],
ba.Call(player.actor.move_map[move["move"]["action"]])
)
else:
ba.timer(
move["time"],
ba.Call(player.actor.move_map[move["move"]["action"]], move["move"]["value"])
)
last_move_time = move["time"]
time_to_hide_controls = last_move_time + 1
ba.timer(time_to_hide_controls, ba.Call(handle_player_replay_end, player))
def spawn_mirror_spaz(player):
player.mirror_mode = True
with ba.Context(player.actor._activity()):
bot = spaz.Spaz(player.color, player.highlight, character=player.character).autoretain()
bot.handlemessage(ba.StandMessage(
(player.actor.node.position[0], player.actor.node.position[1], player.actor.node.position[2]+1), 93))
bot.node.name = player.actor.node.name
bot.node.name_color = player.actor.node.name_color
player.actor.mirror_spaz.append(bot)
def ghost(player, stunt_name):
stunt_path = f"{os.path.join(BASE_STUNTS_DIRECTORY, stunt_name)}.json"
if stunt_name in STUNT_CACHE:
stunt = STUNT_CACHE[stunt_name]
else:
try:
with open(stunt_path, "r") as fin:
stunt = json.load(fin)
STUNT_CACHE[stunt_name] = stunt
except:
ba.screenmessage(f"{stunt_name} doesn't exists")
return
player.in_replay = True
with ba.Context(player.actor._activity()):
bot = spaz.Spaz((1, 0, 0), character="Spaz").autoretain()
bot.handlemessage(ba.StandMessage(player.actor.node.position, 93))
give_ghost_power(bot)
ControlsUI.display(player.actor._activity())
for move in stunt:
value = move["move"]["value"]
if value is None:
ba.timer(
move["time"],
ba.Call(bot.move_map[move["move"]["action"]])
)
ui_activation = CONTROLS_UI_MAP.get(move["move"]["action"])
if ui_activation:
ba.timer(
move["time"],
ba.Call(ui_activation, player.actor._activity())
)
else:
ba.timer(
move["time"],
ba.Call(bot.move_map[move["move"]["action"]], move["move"]["value"])
)
ui_activation = CONTROLS_UI_MAP.get(move["move"]["action"])
if ui_activation:
ba.timer(
move["time"],
ba.Call(ui_activation, player.actor._activity(), move["move"]["value"])
)
last_move_time = move["time"]
time_to_hide_controls = last_move_time + 1
ba.timer(time_to_hide_controls, ba.Call(handle_player_replay_end, player))
ba.timer(time_to_hide_controls, ba.Call(bot.node.delete))
def give_ghost_power(spaz):
spaz.node.invincible = True
shared = SharedObjects.get()
factory = SpazFactory.get()
ghost = ba.Material()
# smoothy hecks
ghost.add_actions(
conditions=(('they_have_material', factory.spaz_material), 'or',
('they_have_material', shared.player_material), 'or',
('they_have_material', shared.attack_material), 'or',
('they_have_material', shared.pickup_material), 'or',
('they_have_material', PowerupBoxFactory.get().powerup_accept_material)),
actions=(
('modify_part_collision', 'collide', False),
('modify_part_collision', 'physical', False)
))
mats = list(spaz.node.materials)
roller = list(spaz.node.roller_materials)
ext = list(spaz.node.extras_material)
pick = list(spaz.node.pickup_materials)
punch = list(spaz.node.punch_materials)
mats.append(ghost)
roller.append(ghost)
ext.append(ghost)
pick.append(ghost)
punch.append(ghost)
spaz.node.materials = tuple(mats)
spaz.node.roller_materials = tuple(roller)
spaz.node.extras_material = tuple(ext)
spaz.node.pickup_materials = tuple(pick)
spaz.node.punch_materials = tuple(pick)
def new_chatmessage(msg):
if not msg.startswith("*"):
return original_chatmessage(msg)
stripped_msg = msg[1:]
msg_splits = stripped_msg.split(maxsplit=3)
command = msg_splits[0]
client_id = -1
player = get_player_from_client_id(client_id)
if command == "start":
capture(player)
_ba.chatmessage("Recording started for {}.".format(
player.getname(),
))
return original_chatmessage(msg)
stunt_name = " ".join(msg_splits[1:])
if command == "save":
if len(msg_splits) < 2:
ba.screenmessage("Enter name of stunt eg : *save bombjump")
return original_chatmessage(msg)
save(player, stunt_name)
_ba.chatmessage('Recording "{}" by {} saved.'.format(
stunt_name,
player.getname(),
))
elif command == "stunt":
if len(msg_splits) < 2:
ba.screenmessage("Enter name of stunt eg : *stunt bombjump")
return original_chatmessage(msg)
replay(player, stunt_name)
_ba.chatmessage('Replaying "{}" on {}.'.format(
stunt_name,
player.getname(),
))
elif command == "learn":
if len(msg_splits) < 2:
ba.screenmessage("Enter name of stunt eg : *learn bombjump")
return original_chatmessage(msg)
ghost(player, stunt_name)
_ba.chatmessage('Replaying "{}" on {}.'.format(
stunt_name,
player.getname(),
))
elif command == "mirror":
spawn_mirror_spaz(player)
return original_chatmessage(msg)
def set_stick_image_position(self, x: float, y: float) -> None:
# Clamp this to a circle.
len_squared = x * x + y * y
if len_squared > 1.0:
length = math.sqrt(len_squared)
mult = 1.0 / length
x *= mult
y *= mult
self.stick_image_position_x = x
self.stick_image_position_y = y
offs = 50.0
assert self._scale is not None
p = [
self._stick_nub_position[0] + x * offs * 0.6,
self._stick_nub_position[1] + y * offs * 0.6
]
c = list(self._stick_nub_image_color)
if abs(x) > 0.1 or abs(y) > 0.1:
c[0] *= 2.0
c[1] *= 4.0
c[2] *= 2.0
assert self._stick_nub_image is not None
self._stick_nub_image.position = p
self._stick_nub_image.color = c
c = list(self._stick_base_image_color)
if abs(x) > 0.1 or abs(y) > 0.1:
c[0] *= 1.5
c[1] *= 1.5
c[2] *= 1.5
assert self._stick_base_image is not None
self._stick_base_image.color = c
def on_begin(self, *args, **kwargs) -> None:
self._jump_image = Image(
ba.gettexture('buttonJump'),
position=(385, 160),
scale=(50, 50),
color=[0.1, 0.45, 0.1, 0]
)
self._pickup_image = Image(
ba.gettexture('buttonPickUp'),
position=(385, 240),
scale=(50, 50),
color=[0, 0.35, 0, 0]
)
self._punch_image = Image(
ba.gettexture('buttonPunch'),
position=(345, 200),
scale=(50, 50),
color=[0.45, 0.45, 0, 0]
)
self._bomb_image = Image(
ba.gettexture('buttonBomb'),
position=(425, 200),
scale=(50, 50),
color=[0.45, 0.1, 0.1, 0]
)
self.stick_image_position_x = self.stick_image_position_y = 0.0
self._stick_base_position = p = (-328, 200)
self._stick_base_image_color = c2 = (0.25, 0.25, 0.25, 1.0)
self._stick_base_image = ba.newnode(
'image',
attrs={
'texture': ba.gettexture('nub'),
'absolute_scale': True,
'vr_depth': -40,
'position': p,
'scale': (220.0*0.6, 220.0*0.6),
'color': c2
})
self._stick_nub_position = p = (-328, 200)
self._stick_nub_image_color = c3 = (0.4, 0.4, 0.4, 1.0)
self._stick_nub_image = ba.newnode('image',
attrs={
'texture': ba.gettexture('nub'),
'absolute_scale': True,
'position': p,
'scale': (110*0.6, 110*0.66),
'color': c3
})
self._stick_base_image.opacity = 0.0
self._stick_nub_image.opacity = 0.0
self.set_stick_image_position = set_stick_image_position
return original_on_begin(self, *args, **kwargs)
ba._activity.Activity.on_begin = on_begin
# _ba.chatmessage = new_chatmessage
bastd.actor.playerspaz.PlayerSpaz = NewPlayerSpaz
bastd.actor.spaz.Spaz = NewSpaz
# lets define a sample elimination game that can use super power of this plugin

View file

@ -19,6 +19,10 @@
]
}
},
"ScoreScreenAnnouncement":{
"enable": true,
"msg": ["click stats button to join discord", "watch hey smoothy youtube channel","downlaod new mods from discord"]
},
"statsResetAfterDays":31,
"leaderboard":{
"enable":true,
@ -33,11 +37,13 @@
},
"colorfullMap":true,
"playlists":{
"default":12345,
"team":12345,
"ffa":22222,
"elim":34343,
"death":23432
"ffa":412175,
"elim":412172,
"soccer":412160,
"smash":412151,
"ffasmash":412179,
"epic":412173
},
"coopModeWithLessPlayers":{
"enable":false,

View file

@ -6,7 +6,7 @@ from efro.terminal import Clr
import json
import requests
import _ba
VERSION=71
VERSION=75
def check():