mirror of
https://github.com/imayushsaini/Bombsquad-Ballistica-Modded-Server.git
synced 2025-10-20 00:00:39 +00:00
maps and games
This commit is contained in:
parent
f83e0008e4
commit
e1f9eafae1
24 changed files with 5152 additions and 11 deletions
4
dist/ba_root/mods/changelogs.json
vendored
4
dist/ba_root/mods/changelogs.json
vendored
|
|
@ -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"
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
6
dist/ba_root/mods/custom_hooks.py
vendored
6
dist/ba_root/mods/custom_hooks.py
vendored
|
|
@ -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={
|
||||
|
|
|
|||
12
dist/ba_root/mods/features/announcement.py
vendored
Normal file
12
dist/ba_root/mods/features/announcement.py
vendored
Normal 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)
|
||||
4
dist/ba_root/mods/features/text_on_map.py
vendored
4
dist/ba_root/mods/features/text_on_map.py
vendored
|
|
@ -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
482
dist/ba_root/mods/games/BlockDash.py
vendored
Normal 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))
|
||||
|
||||
|
||||
BIN
dist/ba_root/mods/games/BlockDash.so
vendored
BIN
dist/ba_root/mods/games/BlockDash.so
vendored
Binary file not shown.
13
dist/ba_root/mods/games/BroElimination.py
vendored
Normal file
13
dist/ba_root/mods/games/BroElimination.py
vendored
Normal 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
642
dist/ba_root/mods/games/Collector.py
vendored
Normal 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
610
dist/ba_root/mods/games/FlagDay.py
vendored
Normal 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
528
dist/ba_root/mods/games/air_soccer.py
vendored
Normal 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
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
230
dist/ba_root/mods/maps/BridgitPlus.py
vendored
Normal 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)
|
||||
BIN
dist/ba_root/mods/maps/CreativeThoughts.so
vendored
BIN
dist/ba_root/mods/maps/CreativeThoughts.so
vendored
Binary file not shown.
161
dist/ba_root/mods/maps/DesertMap.py
vendored
Normal file
161
dist/ba_root/mods/maps/DesertMap.py
vendored
Normal 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
217
dist/ba_root/mods/maps/LakeOfDeath.py
vendored
Normal 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)
|
||||
93
dist/ba_root/mods/maps/WoodenFloor.py
vendored
93
dist/ba_root/mods/maps/WoodenFloor.py
vendored
|
|
@ -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(
|
||||
|
|
|
|||
191
dist/ba_root/mods/maps/creative_thoughts.py
vendored
Normal file
191
dist/ba_root/mods/maps/creative_thoughts.py
vendored
Normal 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)
|
||||
222
dist/ba_root/mods/maps/soccerStadiumPro.py
vendored
Normal file
222
dist/ba_root/mods/maps/soccerStadiumPro.py
vendored
Normal 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)
|
||||
BIN
dist/ba_root/mods/maps/soccerStadiumPro.so
vendored
BIN
dist/ba_root/mods/maps/soccerStadiumPro.so
vendored
Binary file not shown.
157
dist/ba_root/mods/maps/zigZagStubbed.py
vendored
Normal file
157
dist/ba_root/mods/maps/zigZagStubbed.py
vendored
Normal 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
536
dist/ba_root/mods/plugins/auto_stunt.py
vendored
Normal 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
|
||||
14
dist/ba_root/mods/setting.json
vendored
14
dist/ba_root/mods/setting.json
vendored
|
|
@ -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,
|
||||
|
|
|
|||
2
dist/ba_root/mods/tools/ServerUpdate.py
vendored
2
dist/ba_root/mods/tools/ServerUpdate.py
vendored
|
|
@ -6,7 +6,7 @@ from efro.terminal import Clr
|
|||
import json
|
||||
import requests
|
||||
import _ba
|
||||
VERSION=71
|
||||
VERSION=75
|
||||
|
||||
def check():
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue