bombsquad-plugin-manager/plugins/utilities/auto_stunt.py

551 lines
20 KiB
Python
Raw Normal View History

# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport)
# ba_meta require api 8
2022-11-26 12:33:00 +00:00
# AutoStunt mod by - Mr.Smoothy x Rikko
2022-11-26 18:01:28 +05:30
# https://discord.gg/ucyaesh
# https://bombsquad-community.web.app/home
2022-11-26 18:01:28 +05:30
# 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 babase
import bauiv1 as bui
import bascenev1 as bs
import _babase
import bascenev1lib
from bascenev1lib.actor.text import Text
from bascenev1lib.actor.image import Image
from bascenev1lib.actor import spaz
from bascenev1lib.actor import playerspaz
from bascenev1lib.gameutils import SharedObjects
from bascenev1lib.actor.powerupbox import PowerupBoxFactory
from bascenev1lib.actor.spazfactory import SpazFactory
from bascenev1lib.game.elimination import EliminationGame
2022-11-26 18:01:28 +05:30
import math
import json
import os
from typing import Optional
CONTROLS_CENTER = (0, 0)
CONTROLS_SCALE = 1
BASE_STUNTS_DIRECTORY = os.path.join(_babase.env()["python_directory_user"], "CustomStunts")
2022-11-26 18:01:28 +05:30
PLAYERS_STUNT_INFO = {}
STUNT_CACHE = {}
original_on_begin = bs._activity.Activity.on_begin
original_chatmessage = bs.chatmessage
2022-11-26 18:01:28 +05:30
class ControlsUI:
2022-11-26 12:36:30 +00:00
2022-11-26 18:01:28 +05:30
def on_jump_press(activity):
2022-11-26 12:36:30 +00:00
activity._jump_image.node.color = list(
channel * 2 for channel in activity._jump_image.node.color[:3]) + [1]
2022-11-26 18:01:28 +05:30
def on_jump_release(activity):
2022-11-26 12:33:00 +00:00
activity._jump_image.node.color = list(
channel * 0.5 for channel in activity._jump_image.node.color[:3]) + [1]
2022-11-26 18:01:28 +05:30
def on_pickup_press(activity):
2022-11-26 12:33:00 +00:00
activity._pickup_image.node.color = list(
channel * 2 for channel in activity._pickup_image.node.color[:3]) + [1]
2022-11-26 18:01:28 +05:30
def on_pickup_release(activity):
2022-11-26 12:33:00 +00:00
activity._pickup_image.node.color = list(
channel * 0.5 for channel in activity._pickup_image.node.color[:3]) + [1]
2022-11-26 18:01:28 +05:30
def on_punch_press(activity):
2022-11-26 12:33:00 +00:00
activity._punch_image.node.color = list(
channel * 2 for channel in activity._punch_image.node.color[:3]) + [1]
2022-11-26 18:01:28 +05:30
def on_punch_release(activity):
2022-11-26 12:33:00 +00:00
activity._punch_image.node.color = list(
channel * 0.5 for channel in activity._punch_image.node.color[:3]) + [1]
2022-11-26 18:01:28 +05:30
def on_bomb_press(activity):
2022-11-26 12:33:00 +00:00
activity._bomb_image.node.color = list(
channel * 2 for channel in activity._bomb_image.node.color[:3]) + [1]
2022-11-26 18:01:28 +05:30
def on_bomb_release(activity):
2022-11-26 12:33:00 +00:00
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)
2022-11-26 18:01:28 +05:30
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
}
2022-11-26 12:33:00 +00:00
class NewSpaz(bascenev1lib.actor.spaz.Spaz):
2022-11-26 18:01:28 +05:30
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,
}
2022-11-26 12:33:00 +00:00
class NewPlayerSpaz(bascenev1lib.actor.playerspaz.PlayerSpaz):
2022-11-26 18:01:28 +05:30
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": bs.time() - self.source_player.recording_start_time,
2022-11-26 18:01:28 +05:30
"move": {
"action": action,
"value": value,
}
})
elif self.source_player.in_replay:
ui_activation = CONTROLS_UI_MAP.get(action)
if ui_activation:
2022-11-26 12:33:00 +00:00
if action in ["UP_DOWN", "LEFT_RIGHT"]:
ui_activation(self.source_player.actor._activity(), value)
2022-11-26 18:01:28 +05:30
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():
2022-11-26 12:33:00 +00:00
if action in ["UP_DOWN", "LEFT_RIGHT", "RUN"]:
2022-11-26 18:01:28 +05:30
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 bs.get_foreground_host_activity()
2022-11-26 18:01:28 +05:30
for player in activity.players:
if player.sessionplayer.inputdevice.client_id == client_id:
return player
raise bs.SessionPlayerNotFound()
2022-11-26 18:01:28 +05:30
2022-11-26 12:33:00 +00:00
2022-11-26 18:01:28 +05:30
def mirror(clieid):
player = get_player_from_client_id(clieid)
spawn_mirror_spaz(player)
2022-11-26 12:33:00 +00:00
2022-11-26 18:01:28 +05:30
def capture(player):
with babase.ContextRef(player.actor._activity()):
player.recording_start_time = bs.time()
2022-11-26 18:01:28 +05:30
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:
bui.screenmessage(f"{stunt_name} doesn't exists")
2022-11-26 18:01:28 +05:30
return
player.in_replay = True
with babase.ContextRef(player.actor._activity()):
2022-11-26 18:01:28 +05:30
ControlsUI.display(player.actor._activity())
for move in stunt:
value = move["move"]["value"]
if value is None:
bs.timer(
2022-11-26 18:01:28 +05:30
move["time"],
babase.Call(player.actor.move_map[move["move"]["action"]])
2022-11-26 18:01:28 +05:30
)
else:
bs.timer(
2022-11-26 18:01:28 +05:30
move["time"],
babase.Call(player.actor.move_map[move["move"]["action"]], move["move"]["value"])
2022-11-26 18:01:28 +05:30
)
last_move_time = move["time"]
time_to_hide_controls = last_move_time + 1
bs.timer(time_to_hide_controls, babase.Call(handle_player_replay_end, player))
2022-11-26 18:01:28 +05:30
2022-11-26 12:33:00 +00:00
2022-11-26 18:01:28 +05:30
def spawn_mirror_spaz(player):
player.mirror_mode = True
with babase.ContextRef(player.actor._activity()):
2022-11-26 12:33:00 +00:00
bot = spaz.Spaz(player.color, player.highlight, character=player.character).autoretain()
bot.handlemessage(bs.StandMessage(
2022-11-26 12:33:00 +00:00
(player.actor.node.position[0], player.actor.node.position[1], player.actor.node.position[2]+1), 93))
2022-11-26 18:01:28 +05:30
bot.node.name = player.actor.node.name
bot.node.name_color = player.actor.node.name_color
player.actor.mirror_spaz.append(bot)
2022-11-26 12:33:00 +00:00
2022-11-26 18:01:28 +05:30
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:
bui.screenmessage(f"{stunt_name} doesn't exists")
2022-11-26 18:01:28 +05:30
return
player.in_replay = True
with babase.ContextRef(player.actor._activity()):
2022-11-26 12:33:00 +00:00
bot = spaz.Spaz((1, 0, 0), character="Spaz").autoretain()
bot.handlemessage(bs.StandMessage(player.actor.node.position, 93))
2022-11-26 18:01:28 +05:30
give_ghost_power(bot)
ControlsUI.display(player.actor._activity())
for move in stunt:
value = move["move"]["value"]
if value is None:
bs.timer(
2022-11-26 18:01:28 +05:30
move["time"],
babase.Call(bot.move_map[move["move"]["action"]])
2022-11-26 18:01:28 +05:30
)
ui_activation = CONTROLS_UI_MAP.get(move["move"]["action"])
if ui_activation:
bs.timer(
2022-11-26 18:01:28 +05:30
move["time"],
babase.Call(ui_activation, player.actor._activity())
2022-11-26 18:01:28 +05:30
)
else:
bs.timer(
2022-11-26 18:01:28 +05:30
move["time"],
babase.Call(bot.move_map[move["move"]["action"]], move["move"]["value"])
2022-11-26 18:01:28 +05:30
)
ui_activation = CONTROLS_UI_MAP.get(move["move"]["action"])
if ui_activation:
bs.timer(
2022-11-26 18:01:28 +05:30
move["time"],
babase.Call(ui_activation, player.actor._activity(), move["move"]["value"])
2022-11-26 18:01:28 +05:30
)
last_move_time = move["time"]
time_to_hide_controls = last_move_time + 1
bs.timer(time_to_hide_controls, babase.Call(handle_player_replay_end, player))
bs.timer(time_to_hide_controls, babase.Call(bot.node.delete))
2022-11-26 18:01:28 +05:30
2022-11-26 12:33:00 +00:00
2022-11-26 18:01:28 +05:30
def give_ghost_power(spaz):
spaz.node.invincible = True
shared = SharedObjects.get()
factory = SpazFactory.get()
ghost = bs.Material()
2022-11-26 18:01:28 +05:30
# smoothy hecks
ghost.add_actions(
2022-11-26 12:33:00 +00:00
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=(
2022-11-26 18:01:28 +05:30
('modify_part_collision', 'collide', False),
('modify_part_collision', 'physical', False)
2022-11-26 12:33:00 +00:00
))
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)
2022-11-26 18:01:28 +05:30
mats.append(ghost)
roller.append(ghost)
ext.append(ghost)
pick.append(ghost)
punch.append(ghost)
2022-11-26 12:33:00 +00:00
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)
2022-11-26 18:01:28 +05:30
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)
bs.chatmessage("Recording started for {}.".format(
2022-11-26 18:01:28 +05:30
player.getname(),
))
return original_chatmessage(msg)
stunt_name = " ".join(msg_splits[1:])
if command == "save":
if len(msg_splits) < 2:
bui.screenmessage("Enter name of stunt eg : *save bombjump")
2022-11-26 18:01:28 +05:30
return original_chatmessage(msg)
save(player, stunt_name)
bs.chatmessage('Recording "{}" by {} saved.'.format(
2022-11-26 18:01:28 +05:30
stunt_name,
player.getname(),
))
elif command == "stunt":
if len(msg_splits) < 2:
bui.screenmessage("Enter name of stunt eg : *stunt bombjump")
2022-11-26 18:01:28 +05:30
return original_chatmessage(msg)
replay(player, stunt_name)
bs.chatmessage('Replaying "{}" on {}.'.format(
2022-11-26 18:01:28 +05:30
stunt_name,
player.getname(),
))
elif command == "learn":
if len(msg_splits) < 2:
bui.screenmessage("Enter name of stunt eg : *learn bombjump")
2022-11-26 18:01:28 +05:30
return original_chatmessage(msg)
ghost(player, stunt_name)
bs.chatmessage('Replaying "{}" on {}.'.format(
2022-11-26 18:01:28 +05:30
stunt_name,
player.getname(),
))
elif command == "mirror":
spawn_mirror_spaz(player)
return original_chatmessage(msg)
2022-11-26 12:33:00 +00:00
2022-11-26 18:01:28 +05:30
def set_stick_image_position(self, x: float, y: float) -> None:
2022-11-26 12:33:00 +00:00
# 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
2022-11-26 18:01:28 +05:30
def on_begin(self, *args, **kwargs) -> None:
self._jump_image = Image(
bui.gettexture('buttonJump'),
2022-11-26 12:33:00 +00:00
position=(385, 160),
scale=(50, 50),
color=[0.1, 0.45, 0.1, 0]
2022-11-26 18:01:28 +05:30
)
self._pickup_image = Image(
bui.gettexture('buttonPickUp'),
2022-11-26 12:33:00 +00:00
position=(385, 240),
scale=(50, 50),
color=[0, 0.35, 0, 0]
2022-11-26 18:01:28 +05:30
)
self._punch_image = Image(
bui.gettexture('buttonPunch'),
2022-11-26 12:33:00 +00:00
position=(345, 200),
scale=(50, 50),
color=[0.45, 0.45, 0, 0]
2022-11-26 18:01:28 +05:30
)
self._bomb_image = Image(
bui.gettexture('buttonBomb'),
2022-11-26 12:33:00 +00:00
position=(425, 200),
scale=(50, 50),
color=[0.45, 0.1, 0.1, 0]
2022-11-26 18:01:28 +05:30
)
self.stick_image_position_x = self.stick_image_position_y = 0.0
2022-11-26 12:33:00 +00:00
self._stick_base_position = p = (-328, 200)
2022-11-26 18:01:28 +05:30
self._stick_base_image_color = c2 = (0.25, 0.25, 0.25, 1.0)
self._stick_base_image = bs.newnode(
2022-11-26 12:33:00 +00:00
'image',
attrs={
'texture': bui.gettexture('nub'),
2022-11-26 12:33:00 +00:00
'absolute_scale': True,
'vr_depth': -40,
'position': p,
'scale': (220.0*0.6, 220.0*0.6),
'color': c2
})
2022-11-26 18:01:28 +05:30
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 = bs.newnode('image',
2022-11-26 12:33:00 +00:00
attrs={
'texture': bui.gettexture('nub'),
2022-11-26 12:33:00 +00:00
'absolute_scale': True,
'position': p,
'scale': (110*0.6, 110*0.66),
'color': c3
})
2022-11-26 18:01:28 +05:30
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_meta export plugin
class byHeySmoothy(babase.Plugin):
2022-11-26 18:01:28 +05:30
def on_app_running(self):
bui.set_party_icon_always_visible(True)
bs._activity.Activity.on_begin = on_begin
bs.chatmessage = new_chatmessage
bascenev1lib.actor.playerspaz.PlayerSpaz = NewPlayerSpaz
bascenev1lib.actor.spaz.Spaz = NewSpaz
2022-11-26 18:01:28 +05:30
# lets define a sample elimination game that can use super power of this plugin
# ba_meta export bascenev1.GameActivity
2022-11-26 18:01:28 +05:30
class BroEliminaition(EliminationGame):
name = 'BroElimination'
description = 'Elimination Game with dual character control'
def spawn_player(self, player) -> bs.Actor:
2022-11-26 18:01:28 +05:30
super().spawn_player(player)
2022-11-26 12:33:00 +00:00
spawn_mirror_spaz(player)