mirror of
https://github.com/bombsquad-community/plugin-manager.git
synced 2025-10-08 14:54:36 +00:00
new mini games
This commit is contained in:
parent
d8de5c4457
commit
25e60eaa8c
5 changed files with 1314 additions and 0 deletions
|
|
@ -293,6 +293,62 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"demolition_war": {
|
||||
"description": "BombFight on wooden floor flying in air.",
|
||||
"external_url": "https://www.youtube.com/channel/UCaQajfKHrTPgiOhuias5iPg",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Mr.Smoothy",
|
||||
"email": "smoothy@bombsquad.ga",
|
||||
"discord": "mr.smoothy#5824"
|
||||
}
|
||||
],
|
||||
"versions": {
|
||||
"1.0.0": null
|
||||
}
|
||||
},
|
||||
"castel_queen": {
|
||||
"description": "Carry the queen for some duration in her room.",
|
||||
"external_url": "https://www.youtube.com/channel/UCaQajfKHrTPgiOhuias5iPg",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Mr.Smoothy",
|
||||
"email": "smoothy@bombsquad.ga",
|
||||
"discord": "mr.smoothy#5824"
|
||||
}
|
||||
],
|
||||
"versions": {
|
||||
"1.0.0": null
|
||||
}
|
||||
},
|
||||
"drone_war": {
|
||||
"description": "Fly with Drone and attack with rocket launcher",
|
||||
"external_url": "https://www.youtube.com/channel/UCaQajfKHrTPgiOhuias5iPg",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Mr.Smoothy",
|
||||
"email": "smoothy@bombsquad.ga",
|
||||
"discord": "mr.smoothy#5824"
|
||||
}
|
||||
],
|
||||
"versions": {
|
||||
"1.0.0": null
|
||||
}
|
||||
},
|
||||
"the_spaz_game": {
|
||||
"description": "Enemy Spaz Amoung us, kill correct person.",
|
||||
"external_url": "https://www.youtube.com/channel/UCaQajfKHrTPgiOhuias5iPg",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Mr.Smoothy",
|
||||
"email": "smoothy@bombsquad.ga",
|
||||
"discord": "mr.smoothy#5824"
|
||||
}
|
||||
],
|
||||
"versions": {
|
||||
"1.0.0": null
|
||||
}
|
||||
},
|
||||
"air_soccer": {
|
||||
"description": "Play soccer while flying in air",
|
||||
"external_url": "https://youtu.be/j6FFk7E6W_U",
|
||||
|
|
|
|||
407
plugins/minigames/castel_queen.py
Normal file
407
plugins/minigames/castel_queen.py
Normal file
|
|
@ -0,0 +1,407 @@
|
|||
# Released under the MIT License. See LICENSE for details.
|
||||
#
|
||||
"""
|
||||
CastelQueen - Carry the Queen alone or with your team.
|
||||
Author: Mr.Smoothy
|
||||
Discord: https://discord.gg/ucyaesh
|
||||
Youtube: https://www.youtube.com/c/HeySmoothy
|
||||
Website: https://bombsquad-community.web.app
|
||||
Github: https://github.com/bombsquad-community
|
||||
"""
|
||||
# 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
|
||||
|
||||
from bastd.gameutils import SharedObjects
|
||||
from bastd.actor.playerspaz import PlayerSpaz
|
||||
from bastd.game.keepaway import KeepAwayGame, FlagState, Player
|
||||
from bastd.actor import spaz
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any, Sequence, Dict, Type, List, Optional, Union
|
||||
|
||||
# ba_meta export game
|
||||
class ChooseQueen(KeepAwayGame):
|
||||
name = 'FCUK The Queen'
|
||||
description = 'Carry the queen for a set length of time'
|
||||
@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 get_instance_description(self) -> str | Sequence:
|
||||
return 'FCUK the queen for ${ARG1} seconds.', self._hold_time
|
||||
|
||||
def get_instance_description_short(self) -> str | Sequence:
|
||||
return 'FCUK the queen for ${ARG1} seconds', self._hold_time
|
||||
|
||||
def __init__(self, settings: dict):
|
||||
super().__init__(settings)
|
||||
shared = SharedObjects.get()
|
||||
self.lifts = {}
|
||||
self._room_wall_material = ba.Material()
|
||||
self._room_wall_material.add_actions(
|
||||
actions=(
|
||||
('modify_part_collision', 'collide', False),
|
||||
('modify_part_collision', 'physical', False)
|
||||
))
|
||||
self._queen_material = ba.Material()
|
||||
self._queen_material.add_actions(
|
||||
conditions=('they_have_material', self._room_wall_material),
|
||||
actions=(
|
||||
('modify_part_collision', 'collide', True),
|
||||
('modify_part_collision', 'physical', True)
|
||||
))
|
||||
self._queen_material.add_actions(
|
||||
actions=(
|
||||
('modify_part_collision', 'collide', True),
|
||||
('modify_part_collision', 'physical', True)
|
||||
))
|
||||
self._room_wall_material.add_actions(
|
||||
conditions=('they_have_material', self._queen_material),
|
||||
actions=(
|
||||
('modify_part_collision', 'collide', True),
|
||||
('modify_part_collision', 'physical', True)
|
||||
))
|
||||
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)
|
||||
|
||||
))
|
||||
|
||||
def on_begin(self):
|
||||
ba.getactivity().globalsnode.happy_thoughts_mode = True
|
||||
super().on_begin()
|
||||
self.make_map()
|
||||
|
||||
def _spawn_flag(self) -> None:
|
||||
ba.playsound(self._swipsound)
|
||||
self._flash_flag_spawn()
|
||||
assert self._flag_spawn_pos is not None
|
||||
shared = SharedObjects.get()
|
||||
self._flag = spaz.Spaz((0, 0, 0), character="Pixel").autoretain()
|
||||
self._flag.handlemessage(ba.StandMessage((0, 14.63, -5.52), 93))
|
||||
self._flag.node.hold_position_pressed = True
|
||||
self._flag.node.materials = (self._queen_material,shared.object_material)
|
||||
# self._flag.node.extras_material= tuple(list(self._flag.node.extras_material).append(self._queen_materia))
|
||||
self._flag.hitpoints = 5000
|
||||
self._flag.hitpoints_max = 5000
|
||||
|
||||
self._flag_state = FlagState.NEW
|
||||
self._flag_light = ba.newnode(
|
||||
'light',
|
||||
owner=self._flag.node,
|
||||
attrs={'intensity': 0.2, 'radius': 0.3, 'color': (0.2, 0.2, 0.2)},
|
||||
)
|
||||
assert self._flag.node
|
||||
self._flag.node.connectattr('position', self._flag_light, 'position')
|
||||
self._update_flag_state()
|
||||
|
||||
def _update_flag_state(self) -> None:
|
||||
if not self._flag.node.exists():
|
||||
self._spawn_flag()
|
||||
for team in self.teams:
|
||||
team.holdingflag = False
|
||||
self._holding_players = []
|
||||
for player in self.players:
|
||||
holdingflag = False
|
||||
try:
|
||||
assert isinstance(player.actor, (PlayerSpaz, type(None)))
|
||||
if (
|
||||
player.actor
|
||||
and player.actor.node
|
||||
and player.actor.node.hold_node
|
||||
):
|
||||
holdingflag = (
|
||||
player.actor.node.hold_node == self._flag.node
|
||||
)
|
||||
except Exception:
|
||||
ba.print_exception('Error checking hold flag.')
|
||||
if holdingflag:
|
||||
self._holding_players.append(player)
|
||||
player.team.holdingflag = True
|
||||
|
||||
holdingteams = set(t for t in self.teams if t.holdingflag)
|
||||
prevstate = self._flag_state
|
||||
assert self._flag is not None
|
||||
assert self._flag_light
|
||||
assert self._flag.node
|
||||
if len(holdingteams) > 1:
|
||||
self._flag_state = FlagState.CONTESTED
|
||||
self._scoring_team = None
|
||||
elif len(holdingteams) == 1:
|
||||
holdingteam = list(holdingteams)[0]
|
||||
self._flag_state = FlagState.HELD
|
||||
self._scoring_team = holdingteam
|
||||
else:
|
||||
self._flag_state = FlagState.UNCONTESTED
|
||||
self._scoring_team = None
|
||||
|
||||
if self._flag_state != prevstate:
|
||||
ba.playsound(self._swipsound)
|
||||
|
||||
def handlemessage(self, msg: Any) -> Any:
|
||||
if isinstance(msg, ba.PlayerDiedMessage):
|
||||
# Augment standard behavior.
|
||||
super().handlemessage(msg)
|
||||
self.respawn_player(msg.getplayer(Player))
|
||||
elif isinstance(msg, (ba.PickedUpMessage, ba.DroppedMessage)):
|
||||
self._update_flag_state()
|
||||
else:
|
||||
super().handlemessage(msg)
|
||||
|
||||
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]
|
||||
|
||||
self.floorwall1 = ba.newnode('region', attrs={'position': (-10, 5, -5.52), 'scale':
|
||||
(15, 0.2, 2), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]})
|
||||
self.floorwall2 = ba.newnode('region', attrs={'position': (10, 5, -5.52), 'scale': (
|
||||
15, 0.2, 2), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]})
|
||||
|
||||
self.wall1 = ba.newnode('region', attrs={'position': (0, 11, -6.90), 'scale': (
|
||||
35.4, 20, 1), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]})
|
||||
self.wall2 = ba.newnode('region', attrs={'position': (0, 11, -4.14), 'scale': (
|
||||
35.4, 20, 1), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]})
|
||||
|
||||
ba.newnode('locator', attrs={'shape': 'box', 'position': (-10, 5, -5.52), 'color': (
|
||||
0, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (15, 0.2, 2)})
|
||||
|
||||
ba.newnode('locator', attrs={'shape': 'box', 'position': (10, 5, -5.52), 'color': (
|
||||
0, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (15, 0.2, 2)})
|
||||
|
||||
self.create_static_step(0, 14.29)
|
||||
# upper right
|
||||
self.create_static_step(11, 16)
|
||||
self.create_slope(8, 16, False)
|
||||
self.create_static_step(3, 18)
|
||||
|
||||
# lower right
|
||||
self.create_static_step(11, 12)
|
||||
self.create_slope(6, 10, True)
|
||||
self.create_static_step(3, 10)
|
||||
|
||||
# upper left
|
||||
self.create_static_step(-11, 16)
|
||||
self.create_slope(-8, 16, True)
|
||||
self.create_static_step(-3, 18)
|
||||
|
||||
# lower left
|
||||
self.create_static_step(-11, 12)
|
||||
self.create_slope(-6, 10, False)
|
||||
self.create_static_step(-3, 10)
|
||||
|
||||
# create queen personal room
|
||||
self.room_wall_left = ba.newnode('region', attrs={'position': (-3.633, 16.63, -5.52), 'scale':
|
||||
(2, 4, 5), 'type': 'box', 'materials': [shared.footing_material, self._room_wall_material]})
|
||||
self.room_wall_right = ba.newnode('region', attrs={'position': (3.533, 16.63, -5.52), 'scale':
|
||||
(2, 4, 5), 'type': 'box', 'materials': [shared.footing_material, self._room_wall_material]})
|
||||
|
||||
def create_static_step(self, x, y):
|
||||
shared = SharedObjects.get()
|
||||
ba.newnode('region', attrs={'position': (x, y, -5.52), 'scale': (5.5, 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': (5.5, 0.1, 2)})
|
||||
|
||||
def create_slope(self, x, y, backslash):
|
||||
shared = SharedObjects.get()
|
||||
|
||||
for _ in range(0, 21):
|
||||
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]})
|
||||
ba.newnode('locator', attrs={'shape': 'box', 'position': (x, y, -5.52), 'color': (
|
||||
1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (0.2, 0.1, 2)})
|
||||
if backslash:
|
||||
x = x + 0.1
|
||||
y = y + 0.1
|
||||
else:
|
||||
x = x - 0.1
|
||||
y = y + 0.1
|
||||
|
||||
|
||||
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)})
|
||||
|
||||
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)
|
||||
|
||||
|
||||
try:
|
||||
ba._map.register_map(CreativeThoughts)
|
||||
except:
|
||||
pass
|
||||
303
plugins/minigames/demolition_war.py
Normal file
303
plugins/minigames/demolition_war.py
Normal file
|
|
@ -0,0 +1,303 @@
|
|||
|
||||
# ba_meta require api 7
|
||||
"""
|
||||
DemolitionWar - BombFight on wooden floor flying in air.
|
||||
Author: Mr.Smoothy
|
||||
Discord: https://discord.gg/ucyaesh
|
||||
Youtube: https://www.youtube.com/c/HeySmoothy
|
||||
Website: https://bombsquad-community.web.app
|
||||
Github: https://github.com/bombsquad-community
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import ba
|
||||
from bastd.game.elimination import EliminationGame, Player
|
||||
from bastd.gameutils import SharedObjects
|
||||
from bastd.actor.bomb import BombFactory
|
||||
import random
|
||||
from bastd.actor.playerspaz import PlayerSpaz
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any, Sequence
|
||||
|
||||
# ba_meta export game
|
||||
class DemolitionWar(EliminationGame):
|
||||
name = 'DemolitionWar'
|
||||
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_available_settings(
|
||||
cls, sessiontype: type[ba.Session]
|
||||
) -> list[ba.Setting]:
|
||||
settings = [
|
||||
ba.IntSetting(
|
||||
'Lives Per Player',
|
||||
default=1,
|
||||
min_value=1,
|
||||
max_value=10,
|
||||
increment=1,
|
||||
),
|
||||
ba.IntChoiceSetting(
|
||||
'Time Limit',
|
||||
choices=[
|
||||
('None', 0),
|
||||
('1 Minute', 60),
|
||||
('2 Minutes', 120),
|
||||
('5 Minutes', 300),
|
||||
('10 Minutes', 600),
|
||||
('20 Minutes', 1200),
|
||||
],
|
||||
default=0,
|
||||
),
|
||||
ba.FloatChoiceSetting(
|
||||
'Respawn Times',
|
||||
choices=[
|
||||
('Shorter', 0.25),
|
||||
('Short', 0.5),
|
||||
('Normal', 1.0),
|
||||
('Long', 2.0),
|
||||
('Longer', 4.0),
|
||||
],
|
||||
default=1.0,
|
||||
),
|
||||
ba.BoolSetting('Epic Mode', default=False),
|
||||
]
|
||||
if issubclass(sessiontype, ba.DualTeamSession):
|
||||
settings.append(ba.BoolSetting('Solo Mode', default=False))
|
||||
settings.append(
|
||||
ba.BoolSetting('Balance Total Lives', 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 ['Wooden Floor']
|
||||
|
||||
def __init__(self, settings: dict):
|
||||
super().__init__(settings)
|
||||
self._lives_per_player = 1
|
||||
self._solo_mode = False
|
||||
self._balance_total_lives = False
|
||||
|
||||
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))
|
||||
spaz = self.spawn_player_spaz(player, position=(p[x], 1.8, q[y]))
|
||||
spaz.bomb_type = 'impact'
|
||||
# Let's reconnect this player's controls to this
|
||||
# spaz but *without* the ability to attack or pick stuff up.
|
||||
spaz.connect_controls_to_player(enable_punch=False,
|
||||
enable_bomb=True,
|
||||
enable_pickup=True)
|
||||
|
||||
# Also lets have them make some noise when they die.
|
||||
spaz.play_big_death_sound = True
|
||||
return spaz
|
||||
|
||||
def on_begin(self) -> None:
|
||||
super().on_begin()
|
||||
self.map_extend()
|
||||
|
||||
def on_blast(self):
|
||||
node = ba.getcollision().sourcenode
|
||||
ba.emitfx((node.position[0], 0.9, node.position[2]),
|
||||
(0, 2, 0), 30, 1, spread=1, chunk_type='splinter')
|
||||
ba.timer(0.1, ba.Call(node.delete))
|
||||
|
||||
def map_extend(self):
|
||||
# TODO need to improve here , so we can increase size of map easily with settings
|
||||
p = [-6, -4.3, -2.6, -0.9, 0.8, 2.5, 4.2, 5.9]
|
||||
q = [-4, -2.3, -0.6, 1.1, 2.8, 4.5]
|
||||
factory = BombFactory.get()
|
||||
self.ramp_bomb = ba.Material()
|
||||
self.ramp_bomb.add_actions(
|
||||
conditions=('they_have_material', factory.bomb_material),
|
||||
actions=(
|
||||
('modify_part_collision', 'collide', True),
|
||||
('modify_part_collision', 'physical', True),
|
||||
('call', 'at_connect', ba.Call(self.on_blast))
|
||||
))
|
||||
self.ramps = []
|
||||
for i in p:
|
||||
for j in q:
|
||||
self.ramps.append(self.create_ramp(i, j))
|
||||
|
||||
def create_ramp(self, x, z):
|
||||
|
||||
shared = SharedObjects.get()
|
||||
self._real_collied_material = ba.Material()
|
||||
|
||||
self._real_collied_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))
|
||||
)
|
||||
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_collied_material, self.ramp_bomb]})
|
||||
|
||||
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
|
||||
})
|
||||
node.changerotation(1, 0, 0)
|
||||
mnode = ba.newnode('math',
|
||||
owner=ud_1_r,
|
||||
attrs={
|
||||
'input1': (0, 0.6, 0),
|
||||
'operation': 'add'
|
||||
})
|
||||
ud_1_r.connectattr('position', mnode, 'input2')
|
||||
mnode.connectattr('output', node, 'position')
|
||||
return ud_1_r
|
||||
|
||||
|
||||
|
||||
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 WoodenFloor(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 = 'Wooden Floor'
|
||||
|
||||
@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_bg': ba.getmodel('doomShroomBG'),
|
||||
'bg_vr_fill_model': ba.getmodel('natureBackgroundVRFill'),
|
||||
'collide_model': ba.getcollidemodel('bridgitLevelCollide'),
|
||||
'tex': ba.gettexture('bridgitLevelColor'),
|
||||
'model_bg_tex': ba.gettexture('doomShroomBGColor'),
|
||||
'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.background = ba.newnode(
|
||||
'terrain',
|
||||
attrs={
|
||||
'model': self.preloaddata['model_bg'],
|
||||
'lighting': False,
|
||||
'background': True,
|
||||
'color_texture': self.preloaddata['model_bg_tex']
|
||||
})
|
||||
self.vr = 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']
|
||||
})
|
||||
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
|
||||
|
||||
|
||||
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 _handle_player_collide(self):
|
||||
try:
|
||||
player = ba.getcollision().opposingnode.getdelegate(
|
||||
PlayerSpaz, True)
|
||||
except ba.NotFoundError:
|
||||
return
|
||||
if player.is_alive():
|
||||
player.shatter(True)
|
||||
|
||||
|
||||
|
||||
try:
|
||||
ba._map.register_map(WoodenFloor)
|
||||
except:
|
||||
pass
|
||||
426
plugins/minigames/drone_war.py
Normal file
426
plugins/minigames/drone_war.py
Normal file
|
|
@ -0,0 +1,426 @@
|
|||
# Released under the MIT License. See LICENSE for details.
|
||||
#
|
||||
"""
|
||||
DroneWar - Attack enemies with drone, Fly with drone and fire rocket launcher.
|
||||
Author: Mr.Smoothy
|
||||
Discord: https://discord.gg/ucyaesh
|
||||
Youtube: https://www.youtube.com/c/HeySmoothy
|
||||
Website: https://bombsquad-community.web.app
|
||||
Github: https://github.com/bombsquad-community
|
||||
"""
|
||||
# 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
|
||||
from ba._generated.enums import InputType
|
||||
from bastd.actor.bomb import Blast
|
||||
|
||||
from bastd.gameutils import SharedObjects
|
||||
from bastd.actor.playerspaz import PlayerSpaz, PlayerType
|
||||
from bastd.game.deathmatch import DeathMatchGame, Player
|
||||
from bastd.actor import spaz
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any, Sequence, Dict, Type, List, Optional, Union
|
||||
|
||||
STORAGE_ATTR_NAME = f'_shared_{__name__}_factory'
|
||||
|
||||
# SMoothy's Drone (fixed version of floater) with rocket launcher
|
||||
# use drone as long as you want , unlike floater which dies after being idle.
|
||||
class Drone(ba.Actor):
|
||||
def __init__(self, spaz):
|
||||
super().__init__()
|
||||
shared = SharedObjects.get()
|
||||
self._drone_material = ba.Material()
|
||||
self.loop_ascend = None
|
||||
self.loop_descend = None
|
||||
self.loop_lr = None
|
||||
self.loop_ud = None
|
||||
self.rocket_launcher = None
|
||||
self.x_direction = 0
|
||||
self.z_direction = 0
|
||||
self.spaz = spaz
|
||||
self._drone_material.add_actions(
|
||||
conditions=('they_have_material',
|
||||
shared.player_material),
|
||||
actions=(('modify_node_collision', 'collide', True),
|
||||
('modify_part_collision', 'physical', True)))
|
||||
self._drone_material.add_actions(
|
||||
conditions=(('they_have_material',
|
||||
shared.object_material), 'or',
|
||||
('they_have_material',
|
||||
shared.footing_material), 'or',
|
||||
('they_have_material',
|
||||
self._drone_material)),
|
||||
actions=('modify_part_collision', 'physical', False))
|
||||
self.node = ba.newnode(
|
||||
'prop',
|
||||
delegate=self,
|
||||
owner = None,
|
||||
attrs={
|
||||
'position': spaz.node.position,
|
||||
'model':ba.getmodel('landMine'),
|
||||
'light_model':ba.getmodel('landMine'),
|
||||
'body':'landMine',
|
||||
'body_scale':1,
|
||||
'model_scale':1,
|
||||
'shadow_size':0.25,
|
||||
'density':999999,
|
||||
'gravity_scale':0.0,
|
||||
'color_texture':ba.gettexture('achievementCrossHair'),
|
||||
'reflection':'soft',
|
||||
'reflection_scale': [0.25],
|
||||
'materials':[shared.footing_material, self._drone_material]
|
||||
})
|
||||
self.grab_node = ba.newnode(
|
||||
'prop',
|
||||
owner=self.node,
|
||||
attrs={
|
||||
'position': (0, 0, 0),
|
||||
'body':'sphere',
|
||||
'model': None,
|
||||
'color_texture':None,
|
||||
'body_scale':0.2,
|
||||
'reflection':'powerup',
|
||||
'density':999999,
|
||||
'reflection_scale': [1.0],
|
||||
'model_scale':0.2,
|
||||
'gravity_scale':0,
|
||||
'shadow_size':0.1,
|
||||
'is_area_of_interest':True,
|
||||
'materials':[shared.object_material, self._drone_material]
|
||||
})
|
||||
self.node.connectattr('position', self.grab_node, 'position')
|
||||
self._rcombine=ba.newnode('combine',
|
||||
owner=self.node,
|
||||
attrs={
|
||||
'input0':self.spaz.node.position[0],
|
||||
'input1':self.spaz.node.position[1]+3,
|
||||
'input2':self.spaz.node.position[2],
|
||||
'size':3
|
||||
})
|
||||
|
||||
self._rcombine.connectattr('output',self.node,'position')
|
||||
def set_rocket_launcher(self, launcher: RocketLauncher):
|
||||
self.rocket_launcher = launcher
|
||||
def fire(self):
|
||||
if hasattr(self.grab_node,"position"):
|
||||
self.rocket_launcher.shot(self.spaz, self.x_direction, self.z_direction , (self.grab_node.position[0], self.grab_node.position[1] -1, self.grab_node.position[2]))
|
||||
def ascend(self):
|
||||
def loop():
|
||||
if self.node.exists():
|
||||
ba.animate( self._rcombine,'input1',{
|
||||
0:self.node.position[1],
|
||||
1:self.node.position[1] + 2
|
||||
})
|
||||
loop()
|
||||
self.loop_ascend = ba.Timer(1, loop , repeat = True)
|
||||
|
||||
def pause_movement(self):
|
||||
self.loop_ascend = None
|
||||
def decend(self):
|
||||
def loop():
|
||||
if self.node.exists():
|
||||
ba.animate( self._rcombine,'input1',{
|
||||
0:self.node.position[1],
|
||||
1:self.node.position[1] - 2
|
||||
})
|
||||
loop()
|
||||
self.loop_ascend = ba.Timer(1, loop , repeat = True )
|
||||
def pause_lr(self):
|
||||
self.loop_lr = None
|
||||
def pause_ud(self):
|
||||
self.loop_ud = None
|
||||
def left_(self, value = -1):
|
||||
def loop():
|
||||
if self.node.exists():
|
||||
ba.animate( self._rcombine,'input0',{
|
||||
0:self.node.position[0],
|
||||
1:self.node.position[0] + 2 * value
|
||||
})
|
||||
if value == 0.0:
|
||||
self.loop_lr = None
|
||||
else:
|
||||
self.x_direction = value
|
||||
self.z_direction = 0
|
||||
loop()
|
||||
self.loop_lr = ba.Timer(1, loop , repeat = True )
|
||||
def right_(self, value = 1):
|
||||
def loop():
|
||||
if self.node.exists():
|
||||
ba.animate( self._rcombine,'input0',{
|
||||
0:self.node.position[0],
|
||||
1:self.node.position[0] + 2 * value
|
||||
})
|
||||
if value == 0.0:
|
||||
self.loop_lr = None
|
||||
else:
|
||||
self.x_direction = value
|
||||
self.z_direction = 0
|
||||
loop()
|
||||
self.loop_lr = ba.Timer(1, loop , repeat = True )
|
||||
def up_(self, value=1):
|
||||
def loop():
|
||||
if self.node.exists():
|
||||
ba.animate( self._rcombine,'input2',{
|
||||
0:self.node.position[2],
|
||||
1:self.node.position[2] - 2 * value
|
||||
})
|
||||
if value == 0.0:
|
||||
self.loop_ud = None
|
||||
else:
|
||||
self.x_direction = 0
|
||||
self.z_direction = - value
|
||||
loop()
|
||||
self.loop_ud = ba.Timer(1, loop , repeat = True )
|
||||
def down_(self, value=-1):
|
||||
def loop():
|
||||
if self.node.exists():
|
||||
ba.animate( self._rcombine,'input2',{
|
||||
0:self.node.position[2],
|
||||
1:self.node.position[2] - 2 * value
|
||||
})
|
||||
if value == 0.0:
|
||||
self.loop_ud = None
|
||||
else:
|
||||
self.x_direction = 0
|
||||
self.z_direction = - value
|
||||
loop()
|
||||
self.loop_ud = ba.Timer(1, loop , repeat = True )
|
||||
def handlemessage(self, msg):
|
||||
if isinstance(msg, ba.DieMessage):
|
||||
self.node.delete()
|
||||
self.grab_node.delete()
|
||||
self.loop_ascend = None
|
||||
self.loop_ud = None
|
||||
self.loop_lr = None
|
||||
elif isinstance(msg, ba.OutOfBoundsMessage):
|
||||
self.handlemessage(ba.DieMessage())
|
||||
else:
|
||||
super().handlemessage(msg)
|
||||
|
||||
# =============================================Copied from Quake Game - Dliwk =====================================================================
|
||||
class RocketFactory:
|
||||
"""Quake Rocket factory"""
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.ball_material = ba.Material()
|
||||
|
||||
self.ball_material.add_actions(
|
||||
conditions=((('we_are_younger_than', 5), 'or',
|
||||
('they_are_younger_than', 5)), 'and',
|
||||
('they_have_material',
|
||||
SharedObjects.get().object_material)),
|
||||
actions=('modify_node_collision', 'collide', False))
|
||||
|
||||
self.ball_material.add_actions(
|
||||
conditions=('they_have_material',
|
||||
SharedObjects.get().pickup_material),
|
||||
actions=('modify_part_collision', 'use_node_collide', False))
|
||||
|
||||
self.ball_material.add_actions(actions=('modify_part_collision',
|
||||
'friction', 0))
|
||||
|
||||
self.ball_material.add_actions(
|
||||
conditions=(('they_have_material',
|
||||
SharedObjects.get().footing_material), 'or',
|
||||
('they_have_material',
|
||||
SharedObjects.get().object_material)),
|
||||
actions=('message', 'our_node', 'at_connect', ImpactMessage()))
|
||||
|
||||
@classmethod
|
||||
def get(cls):
|
||||
"""Get factory if exists else create new"""
|
||||
activity = ba.getactivity()
|
||||
if hasattr(activity, STORAGE_ATTR_NAME):
|
||||
return getattr(activity, STORAGE_ATTR_NAME)
|
||||
factory = cls()
|
||||
setattr(activity, STORAGE_ATTR_NAME, factory)
|
||||
return factory
|
||||
|
||||
|
||||
class RocketLauncher:
|
||||
"""Very dangerous weapon"""
|
||||
|
||||
def __init__(self):
|
||||
self.last_shot = ba.time()
|
||||
|
||||
def give(self, spaz: spaz.Spaz) -> None:
|
||||
"""Give spaz a rocket launcher"""
|
||||
spaz.punch_callback = self.shot
|
||||
self.last_shot = ba.time()
|
||||
|
||||
# FIXME
|
||||
# noinspection PyUnresolvedReferences
|
||||
def shot(self, spaz, x, z, position) -> None:
|
||||
"""Release a rocket"""
|
||||
time = ba.time()
|
||||
if time - self.last_shot > 0.6:
|
||||
self.last_shot = time
|
||||
|
||||
direction = [x, 0, z]
|
||||
direction[1] = 0.0
|
||||
|
||||
mag = 10.0 / 1 if ba.Vec3(*direction).length() == 0 else ba.Vec3(*direction).length()
|
||||
vel = [v * mag for v in direction]
|
||||
Rocket(position=position,
|
||||
velocity=vel,
|
||||
owner=spaz.getplayer(ba.Player),
|
||||
source_player=spaz.getplayer(ba.Player),
|
||||
color=spaz.node.color).autoretain()
|
||||
|
||||
|
||||
class ImpactMessage:
|
||||
"""Rocket touched something"""
|
||||
|
||||
|
||||
class Rocket(ba.Actor):
|
||||
"""Epic rocket from rocket launcher"""
|
||||
|
||||
def __init__(self,
|
||||
position=(0, 5, 0),
|
||||
velocity=(1, 0, 0),
|
||||
source_player=None,
|
||||
owner=None,
|
||||
color=(1.0, 0.2, 0.2)) -> None:
|
||||
super().__init__()
|
||||
self.source_player = source_player
|
||||
self.owner = owner
|
||||
self._color = color
|
||||
factory = RocketFactory.get()
|
||||
|
||||
self.node = ba.newnode('prop',
|
||||
delegate=self,
|
||||
attrs={
|
||||
'position': position,
|
||||
'velocity': velocity,
|
||||
'model': ba.getmodel('impactBomb'),
|
||||
'body': 'sphere',
|
||||
'color_texture': ba.gettexture(
|
||||
'bunnyColor'),
|
||||
'model_scale': 0.2,
|
||||
'is_area_of_interest': True,
|
||||
'body_scale': 0.8,
|
||||
'materials': [
|
||||
SharedObjects.get().object_material,
|
||||
factory.ball_material]
|
||||
}) # yapf: disable
|
||||
self.node.extra_acceleration = (self.node.velocity[0] * 200, 0,
|
||||
self.node.velocity[2] * 200)
|
||||
|
||||
self._life_timer = ba.Timer(
|
||||
5, ba.WeakCall(self.handlemessage, ba.DieMessage()))
|
||||
|
||||
self._emit_timer = ba.Timer(0.001, ba.WeakCall(self.emit), repeat=True)
|
||||
self.base_pos_y = self.node.position[1]
|
||||
|
||||
ba.camerashake(5.0)
|
||||
|
||||
def emit(self) -> None:
|
||||
"""Emit a trace after rocket"""
|
||||
ba.emitfx(position=self.node.position,
|
||||
scale=0.4,
|
||||
spread=0.01,
|
||||
chunk_type='spark')
|
||||
if not self.node:
|
||||
return
|
||||
self.node.position = (self.node.position[0], self.base_pos_y,
|
||||
self.node.position[2]) # ignore y
|
||||
ba.newnode('explosion',
|
||||
owner=self.node,
|
||||
attrs={
|
||||
'position': self.node.position,
|
||||
'radius': 0.2,
|
||||
'color': self._color
|
||||
})
|
||||
|
||||
def handlemessage(self, msg: Any) -> Any:
|
||||
"""Message handling for rocket"""
|
||||
super().handlemessage(msg)
|
||||
if isinstance(msg, ImpactMessage):
|
||||
self.node.handlemessage(ba.DieMessage())
|
||||
|
||||
elif isinstance(msg, ba.DieMessage):
|
||||
if self.node:
|
||||
Blast(position=self.node.position,
|
||||
blast_radius=2,
|
||||
source_player=self.source_player)
|
||||
|
||||
self.node.delete()
|
||||
self._emit_timer = None
|
||||
|
||||
elif isinstance(msg, ba.OutOfBoundsMessage):
|
||||
self.handlemessage(ba.DieMessage())
|
||||
|
||||
|
||||
# ba_meta export game
|
||||
class ChooseQueen(DeathMatchGame):
|
||||
name = 'Drone War'
|
||||
|
||||
@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 ['Football Stadium']
|
||||
|
||||
def spawn_player_spaz(
|
||||
self,
|
||||
player: PlayerType,
|
||||
position: Sequence[float] | None = None,
|
||||
angle: float | None = None,
|
||||
) -> PlayerSpaz:
|
||||
spaz = super().spawn_player_spaz(player, position, angle)
|
||||
self.spawn_drone(spaz)
|
||||
return spaz
|
||||
|
||||
def on_begin(self):
|
||||
super().on_begin()
|
||||
shared = SharedObjects.get()
|
||||
self.ground_material = ba.Material()
|
||||
self.ground_material.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': (30,0.001,23),'type': 'box','materials': [shared.footing_material,self.ground_material]})
|
||||
|
||||
def _handle_player_collide(self):
|
||||
try:
|
||||
player = ba.getcollision().opposingnode.getdelegate(
|
||||
PlayerSpaz, True)
|
||||
except ba.NotFoundError:
|
||||
return
|
||||
if player.is_alive():
|
||||
player.shatter(True)
|
||||
|
||||
def spawn_drone(self, spaz):
|
||||
with ba.Context(_ba.get_foreground_host_activity()):
|
||||
|
||||
drone = Drone(spaz)
|
||||
r_launcher = RocketLauncher()
|
||||
drone.set_rocket_launcher(r_launcher)
|
||||
player = spaz.getplayer(Player, True)
|
||||
spaz.node.hold_node = drone.grab_node
|
||||
player.actor.disconnect_controls_from_player()
|
||||
player.resetinput()
|
||||
player.assigninput(InputType.PICK_UP_PRESS, drone.ascend)
|
||||
player.assigninput(InputType.PICK_UP_RELEASE, drone.pause_movement)
|
||||
player.assigninput(InputType.JUMP_PRESS, drone.decend)
|
||||
player.assigninput(InputType.PUNCH_PRESS, drone.fire)
|
||||
player.assigninput(InputType.LEFT_PRESS, drone.left_)
|
||||
player.assigninput(InputType.RIGHT_PRESS, drone.right_)
|
||||
player.assigninput(InputType.LEFT_RELEASE, drone.pause_lr)
|
||||
player.assigninput(InputType.RIGHT_RELEASE, drone.pause_lr)
|
||||
player.assigninput(InputType.UP_PRESS, drone.up_)
|
||||
player.assigninput(InputType.DOWN_PRESS, drone.down_)
|
||||
player.assigninput(InputType.UP_RELEASE, drone.pause_ud)
|
||||
player.assigninput(InputType.DOWN_RELEASE, drone.pause_ud)
|
||||
122
plugins/minigames/the_spaz_game.py
Normal file
122
plugins/minigames/the_spaz_game.py
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
|
||||
# ba_meta require api 7
|
||||
"""
|
||||
TheSpazGame - Mini game where all characters looks identical , identify enemies and kill them.
|
||||
Author: Mr.Smoothy
|
||||
Discord: https://discord.gg/ucyaesh
|
||||
Youtube: https://www.youtube.com/c/HeySmoothy
|
||||
Website: https://bombsquad-community.web.app
|
||||
Github: https://github.com/bombsquad-community
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import ba
|
||||
from bastd.game.elimination import EliminationGame, Player
|
||||
from bastd.actor.spazfactory import SpazFactory
|
||||
import random
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any, Sequence
|
||||
|
||||
|
||||
CHARACTER = 'Spaz'
|
||||
|
||||
# ba_meta export game
|
||||
class TheSpazGame(EliminationGame):
|
||||
name = 'TheSpazGame'
|
||||
description = 'Enemy Spaz AmongUs. Kill them all'
|
||||
scoreconfig = ba.ScoreConfig(
|
||||
label='Survived', scoretype=ba.ScoreType.SECONDS, none_is_winner=True
|
||||
)
|
||||
|
||||
announce_player_deaths = False
|
||||
|
||||
allow_mid_activity_joins = False
|
||||
|
||||
@classmethod
|
||||
def get_available_settings(
|
||||
cls, sessiontype: type[ba.Session]
|
||||
) -> list[ba.Setting]:
|
||||
settings = [
|
||||
ba.IntSetting(
|
||||
'Lives Per Player',
|
||||
default=1,
|
||||
min_value=1,
|
||||
max_value=10,
|
||||
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.15)
|
||||
],
|
||||
default=1.0,
|
||||
),
|
||||
ba.BoolSetting('Epic Mode', default=False),
|
||||
]
|
||||
if issubclass(sessiontype, ba.DualTeamSession):
|
||||
settings.append(ba.BoolSetting('Solo Mode', default=False))
|
||||
settings.append(
|
||||
ba.BoolSetting('Balance Total Lives', default=False)
|
||||
)
|
||||
return settings
|
||||
|
||||
@classmethod
|
||||
def supports_session_type(cls, sessiontype: type[ba.Session]) -> bool:
|
||||
return issubclass(sessiontype, ba.DualTeamSession) or issubclass(
|
||||
sessiontype, ba.FreeForAllSession
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def get_supported_maps(cls, sessiontype: type[ba.Session]) -> list[str]:
|
||||
return ba.getmaps('melee')
|
||||
|
||||
def get_instance_description(self) -> str | Sequence:
|
||||
return (
|
||||
'Enemy Spaz AmongUs. Kill them all'
|
||||
)
|
||||
|
||||
def get_instance_description_short(self) -> str | Sequence:
|
||||
return (
|
||||
'Enemy Spaz AmongUs. Kill them all'
|
||||
)
|
||||
def __init__(self, settings: dict):
|
||||
super().__init__(settings)
|
||||
self._solo_mode = False
|
||||
|
||||
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))
|
||||
spaz = self.spawn_player_spaz(player, position=(p[x], 1.8, q[y]))
|
||||
spaz.node.color = (1,1,1)
|
||||
spaz.node.highlight = (1,0.4,1)
|
||||
self.update_appearance(spaz, character=CHARACTER)
|
||||
# Also lets have them make some noise when they die.
|
||||
spaz.play_big_death_sound = True
|
||||
return spaz
|
||||
|
||||
def update_appearance(self, spaz, character):
|
||||
factory = SpazFactory.get()
|
||||
media = factory.get_media(character)
|
||||
for field, value in media.items():
|
||||
setattr(spaz.node, field, value)
|
||||
spaz.node.style = factory.get_style(character)
|
||||
spaz.node.name = ''
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue