vh-bombsquad-modded-server-.../dist/ba_root/mods/plugins/baCheatMax.py
2024-03-31 13:34:28 +05:30

1766 lines
66 KiB
Python

# ba_meta require api 7
from __future__ import annotations
from typing import TYPE_CHECKING
import ba, _ba, os, random, json
from ba._activity import Activity
from bastd.actor.bomb import Bomb
from bastd.gameutils import SharedObjects
from bastd.mainmenu import MainMenuActivity
from bastd.actor.playerspaz import PlayerSpaz
from bastd.actor.spazfactory import SpazFactory
import bastd.actor.popuptext as ptext
import bastd.actor.text as text
import bastd.actor.image as image
import bastd.actor.spaz as spaz
if TYPE_CHECKING:
from typing import Sequence, Any, Callable
class Lang:
def __init__(self,
text: str,
subs: str | list[str] = 'none'):
icons = [ba.charstr(ba.SpecialChar.CROWN),
ba.charstr(ba.SpecialChar.LOGO)]
lang = _ba.app.lang.language
setphrases = {
"Installing":
{"Spanish": f"Instalando <{__name__}>",
"English": f"Installing <{__name__}>",
"Portuguese": f"Instalando <{__name__}>"},
"Installed":
{"Spanish": f"¡<{__name__}> Se instaló correctamente!",
"English": f"<{__name__}> Installed successfully!",
"Portuguese": f"<{__name__}> Instalado com sucesso!"},
"Make Sys":
{"Spanish": "Se creó la carpeta sys",
"English": "Sys folder created",
"Portuguese": "Pasta sys criada"},
"Restart Msg":
{"Spanish": "Reiniciando...",
"English": "Rebooting...",
"Portuguese": "Reinício..."},
"EJ":
{"Spanish": f"Datos incompletos \n Ejemplo: {subs}",
"English": f"Incomplete data \n Example: {subs}",
"Portuguese": f"Dados incompletos \n Exemplo: {subs}"},
"EX":
{"Spanish": f"Ejemplo: {subs}",
"English": f"Example: {subs}",
"Portuguese": f"Exemplo: {subs}"},
"Error Entering Client ID":
{"Spanish": f"'{subs[0]}' no es válido. \n Ingresa números \n Ejemplo: {subs[1]}",
"English": f"'{subs[0]}' is invalid. \n Enter numbers \n Example: {subs[1]}",
"Portuguese": f"'{subs[0]}' é inválido. \n Digite os números \n Exemplo: {subs[1]}"},
"Error Entering Player ID":
{"Spanish": f"'{subs}' no es válido. \n Ingresa el ID del jugador. consulta el comando '-i'",
"English": f"'{subs}' no es válido. \n Add the player ID. use the '-i' command for more information.",
"Portuguese": f"'{subs}' no es válido. \n Adicione o ID do jogador. use o comando '-i' para obter mais informações."},
"Happy":
{"Spanish": "¡Estás felíz!",
"English": "Are you happy!",
"Portuguese": "Você está feliz!"},
"Add Admin Msg":
{"Spanish": f"'{subs}' Se agregó a la lista de Admins",
"English": f"'{subs}' Added to Admins list",
"Portuguese": f"'{subs}' Adicionado à lista de administradores"},
"Delete Admin Msg":
{"Spanish": f"Se removió a '{subs}' de la lista de Admins",
"English": f"'{subs}' was removed from the Admins list",
"Portuguese": f"'{subs}' foi removido da lista de administradores"},
"Players Data":
{"Spanish": "Nombre | Jugador ID | Cliente ID",
"English": "Name | Player ID | Client ID",
"Portuguese": "Nome | Jogador ID | ID do Cliente"},
"Party Info":
{"Spanish": f"{icons[0]}|Host: {subs[0]}\n{icons[1]}|Descripción: {subs[1]}\n{icons[1]}|Versión: {ba.app.version}",
"English": f"{icons[0]}|Host: {subs[0]}\n{icons[1]}|Description: {subs[1]}\n{icons[1]}|Version: {ba.app.version}",
"Portuguese": f"{icons[0]}|Host: {subs[0]}\n{icons[1]}|Descrição: {subs[1]}|\n{icons[1]}|Versão: {ba.app.version}"},
"Same Player":
{"Spanish": "No puedes expulsarte a tí mismo",
"English": "You cannot expel yourself",
"Portuguese": "Você não pode se expulsar"},
"Kick Msg":
{"Spanish": f"Sin rodeos, {subs[0]} ha expulsado a {subs[1]}",
"English": f"{subs[0]} kicked {subs[1]} Goodbye!",
"Portuguese": f"{subs[0]} expulsou {subs[1]}"},
"User Invalid":
{"Spanish": f"'{subs}' No le pertenece a ningún jugador.",
"English": f"'{subs}' Does not belong to any player.",
"Portuguese": f"'{subs}' Não pertence a nenhum jogador."},
"Chat Live":
{"Spanish": f"{icons[0]} CHAT EN VIVO {icons[0]}",
"English": f"{icons[0]} CHAT LIVE {icons[0]}",
"Portuguese": f"{icons[0]} BATE-PAPO AO VIVO {icons[0]}"},
"Not Exists Node":
{"Spanish": "No estás en el juego",
"English": "You're not in the game",
"Portuguese": "Você não está no jogo"},
"Show Spaz Messages":
{"Spanish": "Mostrar mensajes arriba de los jugadores.",
"English": "Show messages above players.",
"Portuguese": "Mostrar mensagens acima dos jogadores."},
"Mute Message":
{"Spanish": f"Se silenció a {subs}",
"English": f"{subs} was muted",
"Portuguese": f"{subs} foi silenciado"},
"Unmute Message":
{"Spanish": f"Se quitó el muteo a {subs}",
"English": f"{subs} can chat again",
"Portuguese": f"{subs} pode conversar novamente"},
"Not In Admins":
{"Spanish": f"No se puede silenciar a [{subs}] porque es administrador.",
"English": f"[{subs}] cannot be muted because he is an administrator.",
"Portuguese": f"[{subs}] não pode ser silenciado porque é um administrador."},
"Module Not Found":
{"Spanish": "No se encontraron los módulos. usa el comando '!dw' para descargarlos.",
"English": "Modules not found. use the '!dw' command to download them.",
"Portuguese": "Módulos não encontrados. use o comando '!dw' para baixá-los."},
"Clima Error Message":
{"Spanish": "Selecciona un clima,\n Usa el comando '-climas' para más información.",
"English": "Select a weather,\n Use the command '-climas' for more information.",
"Portuguese": "Selecione um clima,\n Use o comando '-climas' para mais informações."},
"Clima Message":
{"Spanish": f"Se cambió el clima a '{subs}'",
"English": f"The weather is now '{subs}'",
"Portuguese": f"O tempo está agora '{subs}'"},
"None Account":
{"Spanish": "Información del jugador no válida.",
"English": "Informações do jogador inválidas.",
"Portuguese": "Informações do jogador inválidas."},
"Error ID User":
{"Spanish": f"Se produjo un error al ingresar el ID del jugador. \n '{subs}' no es válido.",
"English": f"An error occurred while entering the player ID. \n '{subs}' is not valid.",
"Portuguese": f"Ocorreu um erro ao inserir o ID do jogador. \n '{subs}' não é válido."},
"Effect Invalid":
{"Spanish": f"'{subs}' es inválido. ingresa el comando '-effects' para más información.",
"English": f"'{subs}' is invalid. enter the command '-effects' for more information.",
"Portuguese": f"'{subs}' é inválido. digite o comando '-effects' para mais informações."},
"Use -i Command":
{"Spanish": "Le sugerimos usar el comando '-i'",
"English": "We suggest you use the '-i' command",
"Portuguese": "Sugerimos que você use o comando '-i'"},
"Add Effect Message":
{"Spanish": f"Se agregó el efecto '{subs[0]}' a {subs[1]}",
"English": f"Added '{subs[0]}' effect to {subs[1]}",
"Portuguese": f"Adicionado efeito '{subs[0]}' para {subs[1]}"},
"You Are Amazing":
{"Spanish": "¡¡Eres ASOMBROSO!!",
"English": "You Are Amazing!!",
"Portuguese": "Desculpe, o anfitrião é a autoridade máxima."},
"Exe":
{"Spanish": "Comando Ejecutado",
"English": "Command Executed",
"Portuguese": "Comando Executado"
},
# ES
"Agrega un texto":
{"Spanish": "Añade un texto",
"English": "Add text",
"Portuguese": "Adicione texto"},
"Cambios Guardados":
{"Spanish": "Información guardada correctamente",
"English": "Information saved successfully",
"Portuguese": "Informações salvas com sucesso"},
"Info Color":
{"Spanish": "Argumento no válido, \n te sugerimos usar el comando '-colors'",
"English": "Invalid argument, \n we suggest you use the '-colors' command",
"Portuguese": "Argumento inválido, \n sugerimos que você use o comando '-colors'"},
"ID Cliente Msj":
{"Spanish": "Agrega el ID del cliente. \n utilice el comando '-i' para más información.",
"English": "Add the client ID. \n use the '-i' command for more information.",
"Portuguese": "Adicione o ID do cliente. \n use o comando '-i' para mais informações."},
"Guardando Informacion":
{"Spanish": "Estamos guardando sus datos...",
"English": "Saving user data...",
"Portuguese": "Estamos salvando seus dados..."},
"Ban A Admin Mensaje":
{"Spanish": f"No puedes expulsar a [{subs}] porque es administrador",
"English": f"You can't kick [{subs}] because he's an admin",
"Portuguese": f"Você não pode chutar [{subs}] porque ele é um administrador"},
"No Info Activa":
{"Spanish": "Necesitas tener activa la información.\n Usa el comando '-info' para activarle.",
"English": "You need to have info active.\n Use the '-info' command to activate it",
"Portuguese": "Você precisa ter as informações ativas.\n Use o comando '-info' para ativá-las"},
}
language = ["Spanish", "English", "Portuguese"]
if lang not in language:
lang = "English"
if text not in setphrases:
self.text = text
else:
self.text = setphrases[text][lang]
def get(self):
return self.text
def getlanguage(*args, **kwargs) -> str:
subs = kwargs.get('subs', 'none')
if type(subs) is not list:
subs = str(subs)
else:
subs = [str(s) for s in subs]
try:
text = Lang(*args, subs=subs).get()
except (IndexError, Exception):
text = Lang(*args).get()
text = text.replace('none', str(subs))
finally:
return text
calls: dict[str, Any] = {}
Chats: list[str] = []
roster = _ba.get_game_roster
act = _ba.get_foreground_host_activity
mutelist = list()
cfg = dict()
class PopupText(ptext.PopupText):
"""New PopupText.
category: **Messages In Game**
"""
def __init__(self, *args, **kwargs) -> None:
super().__init__(*args, **kwargs)
self.node.shadow = 10.0
self.node.color = (1.5, 1.5, 1.5, 1.0)
ba.animate(self._combine, 'input3', {0: 0, 0.1: 1.0})
def handlemessage(self, msg: Any) -> Any | None:
pass
class Commands:
"""Usa los distintos comandos dependiendo tu rango (All, Admins).
Category: **Command Class**
"""
fct: CommandFunctions
"Llama los distintos comandos"
util: Uts
"Llama a las distintas utilidades"
@property
def get(self) -> str | None:
return self.value
def __init__(self,
msg: str,
client_id: int,
arguments: list[str] = []) -> None:
self.message = msg
self.msg = msg.strip()
self.client_id = client_id
self.arguments = arguments
self.value = None
self.util = Uts
self.fct = CommandFunctions
self.filter_chat()
def clientmessage(self, msg: str,
color: Sequence[float] | None = None):
self.util.sm(msg, color=color,
transient=True,
clients=[self.client_id])
def filter_chat(self) -> None:
ms = self.arguments
self.util.update_usernames()
if self.client_id in self.util.accounts:
if self.util.accounts[self.client_id]['Mute']:
return setattr(self, 'value', '@')
if cfg['Commands'].get('ShowMessages'):
cls_node = self.fct.get_actor(self.client_id)
if cls_node is not None:
ActorMessage(self.msg, cls_node)
if 'info' in ms[0].lower():
with ba.Context(act()):
ba.timer(0.01, ba.Call(self.util.create_data_text, act()))
with ba.Context(act()):
ba.timer(0.01, ba.Call(self.util.create_live_chat, act(),
chat=[self.client_id, self.message],
admin=self.fct.user_is_admin(self.client_id)))
self.command_all()
if self.fct.user_is_admin(self.client_id):
self.admin_commands()
def command_all(self) -> None:
msg = self.msg.strip()
ms = self.arguments
cmd = self.fct.all_cmd()
cls_node = self.fct.get_actor(self.client_id)
ClientMessage = self.clientmessage
if msg.lower() == cmd[0]: # -i
self.fct.get_user_list(self.client_id)
elif msg.lower() == cmd[1]: # -pan
self.util.cm("¡Haz recibido pan de \ue061Sr.Palomo!")
#return setattr(self, 'value', '@')
elif msg.lower() == cmd[2]: # -ceb
with ba.Context(act()):
cls_node.handlemessage(
ba.CelebrateMessage(duration=3.0))
ClientMessage(getlanguage('Happy'), color=(1.0, 1.0, 0.0))
elif msg.lower() == cmd[3]: # -colors
cols = str()
cols_list = self.util.sort_list(self.util.colors())
for c in cols_list:
cols += (' | '.join(c) + '\n')
ClientMessage(cols)
elif msg.lower() == cmd[4]: # -mp (max players)
mp = _ba.get_public_party_max_size()
ClientMessage(ba.Lstr(value='${LSTR}: ${COUNT}',
subs=[('${LSTR}', ba.Lstr(resource='maxPartySizeText')),
('${COUNT}', str(mp))]))
elif msg.lower() == cmd[5]: # -pb
self.fct.get_my_pb(self.client_id)
elif msg.lower() == cmd[6]: # -effects
cols = str()
for e in self.fct.effects():
cols += (' | ' + e)
ClientMessage(cols)
def admin_commands(self) -> None:
msg = self.msg.strip()
ms = self.arguments
cls_node = self.fct.get_actor(self.client_id)
ClientMessage = self.clientmessage
ms[0] = ms[0].lower()
cmd = [cd.lower() for cd in self.fct.admins_cmd()]
if ms[0] == cmd[0]: # /name 0 La Pulga
try: name = ms[2]
except:
color = self.util.colors()['orange']
ClientMessage(getlanguage('EJ',
subs=ms[0] + ' 0 La Pulga | ' + ms[0] + ' all La Pulga'), color=color)
else:
self.fct.actor_command(ms=ms,
call=ba.Call(self.fct.actor_name, ' '.join(ms[2:])),
attrs={'Actor': cls_node,
'ClientMessage': ClientMessage})
elif ms[0] == cmd[1]: # /imp
self.fct.actor_command(ms=ms,
call=self.fct.impulse,
attrs={'Actor': cls_node,
'ClientMessage': ClientMessage})
elif ms[0] == cmd[2]: # /box
self.fct.actor_command(ms=ms,
call=self.fct.spaz_box,
attrs={'Actor': cls_node,
'ClientMessage': ClientMessage})
elif ms[0] == cmd[3] or ms[0] == cmd[4]: # /addAdmin
if len(ms) == 1:
ClientMessage(getlanguage('ID Cliente Msj'))
else:
try:
c_id = int(ms[1])
except ValueError:
ClientMessage(
getlanguage('Error Entering Client ID',
subs=[ms[1], '/addAdmin 113']))
else:
if c_id not in self.util.usernames:
ClientMessage(getlanguage('User Invalid', subs=c_id))
else:
if ms[0] == cmd[3]:
self.util.add_or_del_user(c_id, add=True)
else:
self.util.add_or_del_user(c_id, add=False)
elif ms[0] == cmd[5]: # /kill
self.fct.actor_command(ms=ms,
call=self.fct.kill_spaz,
attrs={'Actor': cls_node,
'ClientMessage': ClientMessage})
elif ms[0] == cmd[6]: # -pause
self.fct.pause()
elif ms[0] == cmd[7]: # /infoHost
if not cfg['Commands'].get('ShowInfo'):
ClientMessage(getlanguage('No Info Activa'))
else:
if len(ms) == 1:
ClientMessage(getlanguage('Agrega un texto'))
else:
cfg['Commands']['HostName'] = ' '.join(ms[1:])
self.util.save_settings()
ClientMessage(getlanguage('Informacion guardada'), color=(0.0, 1.0, 0.0))
elif ms[0] == cmd[8]: # /infoDes
if not cfg['Commands'].get('ShowInfo'):
ClientMessage(getlanguage('No Info Activa'))
else:
if len(ms) == 1:
ClientMessage(getlanguage('Agrega un texto'))
else:
cfg['Commands']['Description'] = ' '.join(ms[1:])
self.util.save_settings()
ClientMessage(getlanguage('Informacion guardada'), color=(0.0, 1.0, 0.0))
elif ms[0] == cmd[9]: # -info
if cfg['Commands'].get('ShowInfo'):
cfg['Commands']['ShowInfo'] = False
color = self.util.colors()['red']
else:
cfg['Commands']['ShowInfo'] = True
color = self.util.colors()['green']
self.util.save_settings()
ClientMessage(getlanguage('Cambios Guardados'), color=color)
elif ms[0] == cmd[10]: # /infoColor
if not cfg['Commands'].get('ShowInfo'):
ClientMessage(getlanguage('No Info Activa'))
else:
if len(ms) == 1:
ClientMessage(getlanguage('Info Color'))
else:
if ms[1] not in self.util.colors():
ClientMessage(getlanguage('Info Color'), color=(1, 0.5, 0))
else:
cfg['Commands']['InfoColor'] = self.util.colors()[ms[1]]
self.util.save_settings()
ClientMessage(getlanguage('Cambios Guardados'), color=(1, 1, 0))
elif ms[0] == cmd[11]: # -end
with ba.Context(act()):
act().end_game()
elif ms[0] == cmd[12]: # /kick
if len(ms) == 1:
ClientMessage(getlanguage('ID Cliente Msj'))
else:
try:
c_id = int(ms[1])
except Exception as exc:
type_error = type(exc)
if type_error is ValueError:
ClientMessage(
getlanguage('Error Entering Client ID',
subs=[ms[1], ms[0] + ' 113']))
else:
ClientMessage(f'{type(e).__name__}: {e}')
else:
if self.client_id == c_id:
ClientMessage(getlanguage('Same Player'))
else:
if c_id not in self.util.usernames:
ClientMessage(getlanguage('User Invalid', subs=c_id))
else:
user1 = self.util.usernames[self.client_id]
user2 = self.util.usernames[c_id]
if self.fct.user_is_admin(c_id):
ClientMessage(getlanguage('Ban A Admin Mensaje', subs=user2))
else:
self.util.cm(getlanguage('Kick Msg', subs=[user1, user2]))
_ba.disconnect_client(c_id)
elif ms[0] == cmd[13]: # /-chatLive
if cfg['Commands'].get('ChatLive'):
cfg['Commands']['ChatLive'] = False
color = self.util.colors()['red']
else:
cfg['Commands']['ChatLive'] = True
color = self.util.colors()['green']
self.util.save_settings()
ClientMessage(getlanguage('Cambios Guardados'), color=color)
elif ms[0] == cmd[14]: # /freeze
self.fct.actor_command(ms=ms,
call=self.fct.freeze_spaz,
attrs={'Actor': cls_node,
'ClientMessage': ClientMessage})
elif ms[0] == cmd[15]: # /playerColor
try: color = ms[2]
except IndexError:
ClientMessage(getlanguage('Info Color'))
ClientMessage(getlanguage('EJ',
subs=ms[0] + ' 0 yellow | ' + ms[0] + ' all green'))
else:
self.fct.actor_command(ms=ms,
call=ba.Call(self.fct.player_color, color),
attrs={'Actor': cls_node,
'ClientMessage': ClientMessage})
elif ms[0] == cmd[16]: # /maxPlayers
try:
val = int(ms[1])
except:
ClientMessage(getlanguage('EJ', subs=ms[0] + ' 5'))
else:
_ba.set_public_party_max_size(val)
ClientMessage(
ba.Lstr(value='${LSTR}: ${COUNT}',
subs=[('${LSTR}', ba.Lstr(resource='maxPartySizeText')),
('${COUNT}', ms[1])]))
elif ms[0] == cmd[17]: # -showMessages
if cfg['Commands'].get('ShowMessages'):
cfg['Commands']['ShowMessages'] = False
color = self.util.colors()['red']
else:
cfg['Commands']['ShowMessages'] = True
color = self.util.colors()['green']
self.util.save_settings()
ClientMessage(getlanguage('Show Spaz Messages'), color=color)
elif ms[0] == cmd[18]: # /sleep
self.fct.actor_command(ms=ms,
call=self.fct.spaz_sleep,
attrs={'Actor': cls_node,
'ClientMessage': ClientMessage})
elif ms[0] == cmd[19] or ms[0] == cmd[20]: # /mute /unmute
if len(ms) == 1:
ClientMessage(getlanguage('ID Cliente Msj'))
else:
try:
c_id = int(ms[1])
except Exception as e:
ClientMessage(
getlanguage('Error Entering Client ID',
subs=[ms[1], ms[0] + ' 113']))
else:
if c_id not in self.util.accounts:
ClientMessage(getlanguage('User Invalid', subs=c_id))
else:
user = self.util.usernames[c_id]
if ms[0] == cmd[19]:
if self.fct.user_is_admin(c_id):
self.util.cm(getlanguage('Not In Admins', subs=Uts.usernames[c_id]))
return
if not self.util.accounts[c_id]['Mute']:
self.util.accounts[c_id]['Mute'] = True
self.util.cm(getlanguage('Mute Message', subs=user))
elif ms[0] == cmd[20]:
if self.util.accounts[c_id]['Mute']:
self.util.accounts[c_id]['Mute'] = False
self.util.cm(getlanguage('Unmute Message', subs=user))
Uts.save_players_data()
elif ms[0] == cmd[21]: # /gm
self.fct.actor_command(ms=ms,
call=self.fct.spaz_gm,
attrs={'Actor': cls_node,
'ClientMessage': ClientMessage})
elif ms[0] == cmd[22]: # -slow
self.fct.slow()
elif ms[0] == cmd[23]: # /speed
self.fct.actor_command(ms=ms,
call=self.fct.spaz_speed,
attrs={'Actor': cls_node,
'ClientMessage': ClientMessage})
elif ms[0] == cmd[24]: # /effect
try:
c_id = int(ms[1])
eff = ms[2]
except ValueError:
ClientMessage(getlanguage('Error ID User', subs=ms[1]), color=(1, 0, 0))
except IndexError:
ClientMessage(getlanguage('ID Cliente Msj'), color=(1, 0.5, 0))
ClientMessage(getlanguage('EJ', subs=ms[0] + ' 113 fire'), color=(1, 0.5, 0))
else:
if c_id not in self.util.accounts:
ClientMessage(getlanguage('User Invalid', subs=c_id), color=(1, 0.5, 0))
ClientMessage(getlanguage('Use -i Command'), color=(1, 0.5, 0))
else:
if eff not in self.fct.effects():
ClientMessage(getlanguage('Effect Invalid', subs=eff), color=(1, 0.5, 0))
else:
self.util.accounts[c_id]['Effect'] = eff
self.util.save_players_data()
user = self.util.usernames[c_id]
ClientMessage(getlanguage('Add Effect Message',
subs=[eff, user]), color=(0, 0.5, 1))
elif ms[0] == cmd[25]: # /punch
self.fct.actor_command(ms=ms,
call=self.fct.spaz_punch,
attrs={'Actor': cls_node,
'ClientMessage': ClientMessage})
elif ms[0] == cmd[26]: # /mbox
self.fct.actor_command(ms=ms,
call=self.fct.spaz_mgb,
attrs={'Actor': cls_node,
'ClientMessage': ClientMessage})
elif ms[0] == cmd[27]: # /drop
self.fct.actor_command(ms=ms,
call=self.fct.spaz_drop,
attrs={'Actor': cls_node,
'ClientMessage': ClientMessage})
elif ms[0] == cmd[28]: # /gift
self.fct.actor_command(ms=ms,
call=self.fct.spaz_gift,
attrs={'Actor': cls_node,
'ClientMessage': ClientMessage})
elif ms[0] == cmd[29]: # /curse
self.fct.actor_command(ms=ms,
call=self.fct.spaz_curse,
attrs={'Actor': cls_node,
'ClientMessage': ClientMessage})
elif ms[0] == cmd[30]: # /superjump
self.fct.actor_command(ms=ms,
call=self.fct.spaz_sjump,
attrs={'Actor': cls_node,
'ClientMessage': ClientMessage})
class CommandFunctions:
def all_cmd() -> list[str]:
return [
'-i', '-pan', '-ceb', '-colors',
'-mp', '-pb', '-effects',
]
def admins_cmd() -> list[str]:
return [
'-name', '-imp', '-box', '-addAdmin',
'-delAdmin', '-kill', '-pause', '-infoHost',
'-infoDes', '-info', '-infoColor', '-end',
'-kick', '-chatLive', '-freeze', '-playerColor',
'-maxPlayers', '-showMessages', '-sleep',
'-mute', '-unmute', '-gm', '-slow', '-speed',
'-effect', '-punch', '-mbox', '-drop', '-gift',
'-curse', '-superjump',
]
def effects() -> list[str]:
return ['none', 'footprint', 'fire', 'darkmagic',
'spark', 'stars', 'aure', 'chispitas', 'rainbow']
def get_my_pb(client_id: int) -> None:
print(Uts.userpbs)
if Uts.userpbs.get(client_id):
pb = Uts.userpbs[client_id]
Uts.sm(pb, transient=True, clients=[client_id])
def spaz_sjump(node: ba.Node) -> None:
actor = node.source_player.actor
del node # Unused by default.
with ba.Context(act()):
if getattr(actor, 'cm_superjump', None):
actor.cm_superjump = False
else:
actor.cm_superjump = True
def spaz_curse(node: ba.Node) -> None:
with ba.Context(act()):
node.handlemessage(ba.PowerupMessage('curse', node))
def spaz_gift(node: ba.Node) -> None:
with ba.Context(act()):
ExplosiveGift(owner=node)
def spaz_mgb(node: ba.Node) -> None:
with ba.Context(act()):
MagicBox(pos=node.position).autoretain()
def spaz_punch(node: ba.Node) -> None:
actor = node.source_player.actor
del node # Unused by default.
with ba.Context(act()):
actor._punch_power_scale = 8.0
def spaz_speed(node: ba.Node) -> None:
with ba.Context(act()):
if node.hockey:
node.hockey = False
else:
node.hockey = True
def slow() -> None:
with ba.Context(act()):
gnode = act().globalsnode
if gnode.slow_motion:
gnode.slow_motion = False
else:
gnode.slow_motion = True
def spaz_gm(node: ba.Node) -> None:
with ba.Context(act()):
if node.invincible:
node.invincible = False
else:
node.invincible = True
def spaz_sleep(node: ba.Node) -> None:
with ba.Context(act()):
for x in range(5):
ba.timer(x, ba.Call(node.handlemessage, 'knockout', 5000.0))
def player_color(color: str, node: ba.Node) -> None:
with ba.Context(act()):
node.color = Uts.colors()[color]
def freeze_spaz(node: ba.Node) -> None:
actor = node.source_player.actor
del node # Unused by default.
with ba.Context(act()):
if actor.shield:
actor.shield.delete()
actor.handlemessage(ba.FreezeMessage())
def pause() -> None:
with ba.Context(act()):
globs = act().globalsnode
if globs.paused:
globs.paused = False
else:
globs.paused = True
def kill_spaz(node: ba.Node) -> None:
with ba.Context(act()):
node.handlemessage(
ba.DieMessage())
def spaz_box(node: ba.Node) -> None:
with ba.Context(act()):
node.torso_model = ba.getmodel('tnt')
node.head_model = None
node.pelvis_model = None
node.forearm_model = None
node.color_texture = node.color_mask_texture = ba.gettexture('tnt')
node.color = node.highlight = (1,1,1)
node.style = 'cyborg'
def impulse(node: ba.Node) -> None:
msg = ba.HitMessage(pos=node.position,
velocity=node.velocity,
magnitude=500 * 4,
hit_type='imp',
radius=7840)
if isinstance(msg, ba.HitMessage):
for i in range(2):
with ba.Context(act()):
node.handlemessage(
'impulse', msg.pos[0], msg.pos[1], msg.pos[2],
msg.velocity[0], msg.velocity[1]+2.0, msg.velocity[2], msg.magnitude,
msg.velocity_magnitude, msg.radius, 0, msg.force_direction[0],
msg.force_direction[1], msg.force_direction[2])
def actor_name(name: str, node: ba.Node) -> None:
with ba.Context(act()):
node.name = name
def actor_command(
ms: list[str],
call: Callable,
attrs: dict[str, Any]) -> None:
ClientMessage = attrs['ClientMessage']
def new_call(node: ba.Node):
ClientMessage(getlanguage('Exe'), color=(0, 1, 0))
call(node)
if len(ms) == 1:
if attrs['Actor'] is None:
ClientMessage(getlanguage('Not Exists Node'))
else:
actor = attrs['Actor']
new_call(actor.node)
else:
if ms[1] == 'all':
for p in act().players:
node = p.actor.node
new_call(node)
else:
try:
p_id = int(ms[1])
node = act().players[p_id].actor.node
except Exception as exc:
color = Uts.colors()['orange']
type_error = type(exc)
if type_error is ValueError:
ClientMessage(getlanguage('Error Entering Player ID', subs=ms[1]), color=color)
elif type_error is IndexError:
ClientMessage(getlanguage('User Invalid', subs=p_id), color=color)
else:
ClientMessage(f'{type(e).__name__}: {e}')
ClientMessage(getlanguage('EX', subs=ms[0] + ' 0 | ' + ms[0] + ' all'))
else:
new_call(node)
def spaz_drop(node: ba.Node) -> None:
self = node.source_player.actor
del node # Unused by default.
def drop():
pos = self.node.position
psts = [
(pos[0]-1,pos[1]+4,pos[2]+1),
(pos[0]+1,pos[1]+4,pos[2]+1),
(pos[0],pos[1]+4,pos[2]-1),
(pos[0]-2,pos[1]+4,pos[2]),
(pos[0]+2,pos[1]+4,pos[2]),
(pos[0]+2,pos[1]+4,pos[2]-1),
(pos[0]-2,pos[1]+4,pos[2]-1),
(pos[0],pos[1]+4,pos[2]+2)]
for p in psts:
with ba.Context(act()):
bomb = Bomb(
position=p,
bomb_scale=1.3,
bomb_type='sticky').autoretain()
bomb.node.gravity_scale = 4.0
bomb.node.color_texture = ba.gettexture('bombStickyColor')
for x in range(2):
ba.timer(x * 0.308, ba.Call(drop))
def get_user_list(c_id: int) -> None:
def delete_text(t_id: int):
if t_id == id(act()._ids.node):
act()._ids.node.opacity = 0.0
def gText(txt: str):
act()._ids = text.Text(txt, position=(-0.0, 270.0),
h_align=text.Text.HAlign.CENTER, scale=1.1,
transition=text.Text.Transition.FADE_IN).autoretain()
act()._ids.node.opacity = 0.5
t_id = id(act()._ids.node)
ba.timer(8.0, ba.Call(delete_text, t_id))
txt = str()
txts = [getlanguage('Players Data'),
"______________________"]
try:
players = act().players
except Exception:
players = []
else:
for idx, p in enumerate(players):
if p.is_alive():
s = p.sessionplayer
txts.append(f"{s.getname(False)} | {idx} | {s.inputdevice.client_id}")
txt = '\n'.join(txts)
with ba.Context(act()):
try:
if act()._ids.node.exists():
act()._ids.node.delete()
gText(txt)
except AttributeError:
gText(txt)
ba.screenmessage(txt, clients=[c_id], transient=True)
def get_characters() -> list[str]:
return ba.app.spaz_appearances
def user_is_admin(c_id: int) -> bool:
if c_id == -1:
return True
if c_id in Uts.accounts:
return Uts.accounts[c_id]['Admin']
else:
return False
def get_actor(c_id: int) -> spaz.Spaz | None:
act = _ba.get_foreground_host_activity()
for player in act.players:
if c_id == player.sessionplayer.inputdevice.client_id:
return player.actor
def ActorMessage(msg: str, actor: spaz.Spaz):
def die(node: ba.Node):
if node.exists():
ba.animate(popup.node, 'opacity', {0: 1.0, 0.1: 0.0})
ba.timer(0.1, popup.node.delete)
with ba.Context(act()):
if getattr(actor, 'my_message', None):
actor.my_message.node.delete()
c = (1.0, 1.0, 1.0)
position = (-0.0, 0.5, 0.0)
m = ba.newnode('math', owner=actor.node, attrs={'input1':
(position[0], position[1], position[2]), 'operation': 'add'})
actor.node.connectattr('position_center', m, 'input2')
actor.my_message = popup = PopupText(
text=msg, color=c, scale=1.5).autoretain()
m.connectattr('output', popup.node, 'position')
ba.timer(5.0, ba.Call(die, popup.node))
# Effects
def _fire(self) -> None:
if not self.node.exists():
self._cm_effect_timer = None
else:
ba.emitfx(position=self.node.position,
scale=3,count=50*2,spread=0.3,
chunk_type='sweat')
def _spark(self) -> None:
if not self.node.exists():
self._cm_effect_timer = None
else:
ba.emitfx(position=self.node.position,
scale=0.7,count=50*2,spread=0.3,
chunk_type='spark')
def footprint(self) -> None:
if not self.node.exists():
self._cm_effect_timer = None
else:
loc = ba.newnode('locator', owner=self.node,
attrs={
'position': self.node.position,
'shape': 'circle',
'color': self.node.color,
'size': [0.2],
'draw_beauty': False,
'additive': False})
ba.animate(loc, 'opacity', {0: 1.0, 1.9: 0.0})
ba.timer(2.0, loc.delete)
def aure(self) -> None:
def anim(node: ba.Node) -> None:
ba.animate_array(node, 'color', 3,
{0: (1,1,0), 0.1: (0,1,0),
0.2: (1,0,0), 0.3: (0,0.5,1),
0.4: (1,0,1)}, loop=True)
ba.animate_array(node, 'size', 1,
{0: [1.0], 0.2: [1.5], 0.3: [1.0]}, loop=True)
attrs = ['torso_position', 'position_center', 'position']
for i, pos in enumerate(attrs):
loc = ba.newnode('locator', owner=self.node,
attrs={'shape': 'circleOutline',
'color': self.node.color,
'opacity': 1.0,
'draw_beauty': True,
'additive': False})
self.node.connectattr(pos, loc, 'position')
ba.timer(0.1 * i, ba.Call(anim, loc))
def stars(self) -> None:
def die(node: ba.Node) -> None:
if node:
m = node.model_scale
ba.animate(node, 'model_scale', {0: m, 0.1: 0})
ba.timer(0.1, node.delete)
if not self.node.exists() or self._dead:
self._cm_effect_timer = None
else:
c = 0.3
pos_list = [
(c, 0, 0), (0, 0, c),
(-c, 0, 0), (0, 0, -c)]
for p in pos_list:
m = 1.5
np = self.node.position
pos = (np[0]+p[0], np[1]+p[1]+0.0, np[2]+p[2])
vel = (random.uniform(-m, m), random.uniform(2, 7), random.uniform(-m, m))
texs = ['bombStickyColor', 'aliColor', 'aliColorMask', 'eggTex3']
tex = ba.gettexture(random.choice(texs))
model = ba.getmodel('flash')
factory = SpazFactory.get()
mat = ba.Material()
mat.add_actions(
conditions=('they_have_material', factory.punch_material),
actions=(
('modify_part_collision', 'collide', False),
('modify_part_collision', 'physical', False),
))
node = ba.newnode('prop',
owner=self.node,
attrs={'body': 'sphere',
'position': pos,
'velocity': vel,
'model': model,
'model_scale': 0.1,
'body_scale': 0.0,
'shadow_size': 0.0,
'gravity_scale': 0.5,
'color_texture': tex,
'reflection': 'soft',
'reflection_scale': [1.5],
'materials': [mat]})
light = ba.newnode('light',
owner=node,
attrs={
'intensity': 0.3,
'volume_intensity_scale': 0.5,
'color': (random.uniform(0.5, 1.5),
random.uniform(0.5, 1.5),
random.uniform(0.5, 1.5)),
'radius': 0.035})
node.connectattr('position', light, 'position')
ba.timer(0.25, ba.Call(die, node))
def chispitas(self) -> None:
def die(node: ba.Node) -> None:
if node:
m = node.model_scale
ba.animate(node, 'model_scale', {0: m, 0.1: 0})
ba.timer(0.1, node.delete)
if not self.node.exists() or self._dead:
self._cm_effect_timer = None
else:
c = 0.3
pos_list = [
(c, 0, 0), (0, 0, c),
(-c, 0, 0), (0, 0, -c)]
for p in pos_list:
m = 1.5
np = self.node.position
pos = (np[0]+p[0], np[1]+p[1]+0.0, np[2]+p[2])
vel = (random.uniform(-m, m), random.uniform(2, 7), random.uniform(-m, m))
tex = ba.gettexture('null')
model = None
factory = SpazFactory.get()
mat = ba.Material()
mat.add_actions(
conditions=('they_have_material', factory.punch_material),
actions=(
('modify_part_collision', 'collide', False),
('modify_part_collision', 'physical', False),
))
node = ba.newnode('bomb',
owner=self.node,
attrs={'body': 'sphere',
'position': pos,
'velocity': vel,
'model': model,
'model_scale': 0.1,
'body_scale': 0.0,
'color_texture': tex,
'fuse_length': 0.1,
'materials': [mat]})
light = ba.newnode('light',
owner=node,
attrs={
'intensity': 0.3,
'volume_intensity_scale': 0.5,
'color': (random.uniform(0.5, 1.5),
random.uniform(0.5, 1.5),
random.uniform(0.5, 1.5)),
'radius': 0.035})
node.connectattr('position', light, 'position')
ba.timer(0.25, ba.Call(die, node))
def darkmagic(self) -> None:
def die(node: ba.Node) -> None:
if node:
m = node.model_scale
ba.animate(node, 'model_scale', {0: m, 0.1: 0})
ba.timer(0.1, node.delete)
if not self.node.exists() or self._dead:
self._cm_effect_timer = None
else:
c = 0.3
pos_list = [
(c, 0, 0), (0, 0, c),
(-c, 0, 0), (0, 0, -c)]
for p in pos_list:
m = 1.5
np = self.node.position
pos = (np[0]+p[0], np[1]+p[1]+0.0, np[2]+p[2])
vel = (random.uniform(-m, m), 30.0, random.uniform(-m, m))
tex = ba.gettexture('impactBombColor')
model = ba.getmodel('impactBomb')
factory = SpazFactory.get()
mat = ba.Material()
mat.add_actions(
conditions=('they_have_material', factory.punch_material),
actions=(
('modify_part_collision', 'collide', False),
('modify_part_collision', 'physical', False),
))
node = ba.newnode('prop',
owner=self.node,
attrs={'body': 'sphere',
'position': pos,
'velocity': vel,
'model': model,
'model_scale': 0.4,
'body_scale': 0.0,
'shadow_size': 0.0,
'gravity_scale': 0.5,
'color_texture': tex,
'reflection': 'soft',
'reflection_scale': [0.0],
'materials': [mat]})
light = ba.newnode('light',
owner=node,
attrs={'intensity': 1.0,
'volume_intensity_scale': 0.5,
'color': (0.5, 0.0, 1.0),
'radius': 0.035})
node.connectattr('position', light, 'position')
ba.timer(0.25, ba.Call(die, node))
def _rainbow(self) -> None:
keys = {
0.0: (2.0, 0.0, 0.0),
0.2: (2.0, 1.5, 0.5),
0.4: (2.0, 2.0, 0.0),
0.6: (0.0, 2.0, 0.0),
0.8: (0.0, 2.0, 2.0),
1.0: (0.0, 0.0, 2.0),
}.items()
def _changecolor(color: Sequence[float]) -> None:
if self.node.exists():
self.node.color = color
for time, color in keys:
ba.timer(time, ba.Call(_changecolor, color))
def apply_effect(self, eff: str | None) -> None:
if eff == 'fire':
call = ba.Call(_fire, self)
self._cm_effect_timer = ba.Timer(0.1, call, repeat=True)
elif eff == 'spark':
call = ba.Call(_spark, self)
self._cm_effect_timer = ba.Timer(0.1, call, repeat=True)
elif eff == 'footprint':
call = ba.Call(footprint, self)
self._cm_effect_timer = ba.Timer(0.15, call, repeat=True)
elif eff == 'stars':
call = ba.Call(stars, self)
self._cm_effect_timer = ba.Timer(0.1, call, repeat=True)
elif eff == 'chispitas':
call = ba.Call(chispitas, self)
self._cm_effect_timer = ba.Timer(0.1, call, repeat=True)
elif eff == 'darkmagic':
call = ba.Call(darkmagic, self)
self._cm_effect_timer = ba.Timer(0.1, call, repeat=True)
elif eff == 'rainbow':
call = ba.Call(_rainbow, self)
self._cm_effect_timer = ba.Timer(1.2, call, repeat=True)
elif eff == 'aure':
aure(self)
# -----------
def filter_chat_message(msg: str, client_id: int) -> None:
command = Commands(msg, client_id, msg.split(' '))
return command.get
def new_ga_on_transition_in(self) -> None:
calls['GA_OnTransitionIn'](self)
_ba.set_party_icon_always_visible(True)
Uts.create_data_text(self)
Uts.create_live_chat(self, live=False)
def new_on_player_join(self, player: ba.Player) -> None:
calls['OnPlayerJoin'](self, player)
Uts.player_join(player)
def new_playerspaz_init_(self, *args, **kwargs) -> None:
calls['PlayerSpazInit'](self, *args, **kwargs)
Uts.update_usernames()
user = self._player.sessionplayer.get_v1_account_id()
if user in Uts.pdata:
eff = Uts.pdata[user]['Effect']
apply_effect(self, eff)
def new_playerspaz_on_jump_press(self) -> None:
calls['OnJumpPress'](self)
if not getattr(self, 'cm_superjump', False):
return
if (not self.node or not self.node.jump_pressed):
return
msg = ba.HitMessage(pos=self.node.position,
velocity=self.node.velocity,
magnitude=160*2,
hit_type='imp',
radius=460*2)
if isinstance(msg, ba.HitMessage):
for i in range(2):
with ba.Context(act()):
self.node.handlemessage(
'impulse', msg.pos[0], msg.pos[1], msg.pos[2],
msg.velocity[0], msg.velocity[1]+2.0, msg.velocity[2], msg.magnitude,
msg.velocity_magnitude, msg.radius, 0, msg.force_direction[0],
msg.force_direction[1], msg.force_direction[2])
# -----------
class ExplosiveGift(ba.Actor):
def __init__(self,
time: float = 3.0,
owner: ba.Node = None):
super().__init__()
self.time = time
self.owner = owner
self.scale = 0.8
self.touch = False
pos = list(owner.position)
velocity = (0.0, 60, 0.0)
position = (pos[0], pos[1]+1.47, pos[2])
tex = ba.gettexture('crossOutMask')
model = ba.getmodel('tnt')
self.node = ba.newnode('bomb',
delegate=self,
attrs={'body': 'sphere',
'position': position,
'velocity': velocity,
'model': model,
'body_scale': self.scale,
'shadow_size': 0.3,
'color_texture': tex,
'sticky': True,
'owner': owner,
'reflection': 'soft',
'reflection_scale': [0.22]})
ba.animate(self.node, 'model_scale',
{0: 0,
0.2: self.scale * 1.3,
0.26: self.scale})
ba.animate(self.node, 'fuse_length', {0.0: 1.0, time: 0.0})
ba.timer(time, self._xplosion)
def _xplosion(self):
radius = 3.0
shared = SharedObjects.get()
mat = ba.Material()
mat.add_actions(
conditions=(
('they_have_material', shared.player_material), 'or',
('they_have_material', shared.object_material)
),
actions=(
('modify_part_collision', 'collide', True),
('modify_part_collision', 'physical', False),
('call', 'at_connect', self.call)
))
rmats = [mat, shared.attack_material]
region = ba.newnode('region',
delegate=self,
owner=self.node,
attrs={'scale': tuple(radius*0.7 for s in range(3)),
'type': 'sphere',
'materials': rmats})
self.node.connectattr('position', region, 'position')
shield = ba.newnode('shield',
owner=region,
attrs={'color': (2.0, 1.0, 0.0),
'radius': radius})
region.connectattr('position', shield, 'position')
ba.playsound(ba.getsound('explosion03'), 1, self.node.position)
ba.timer(0.1, ba.Call(
self.handlemessage, ba.DieMessage()))
def call(self) -> None:
node = ba.getcollision().opposingnode
def action():
#if node != self.owner or node != self.node:
msg = ba.HitMessage(
pos=self.node.position,
velocity=node.velocity,
magnitude=1200 * 5,
radius=800 * 5)
node.handlemessage(
'impulse', msg.pos[0], msg.pos[1], msg.pos[2],
msg.velocity[0], msg.velocity[1]+2.0, msg.velocity[2], msg.magnitude,
msg.velocity_magnitude, msg.radius, 0, msg.force_direction[0],
msg.force_direction[1], msg.force_direction[2])
if not self.touch:
self.touch = True
else:
action()
self.touch = False
def handlemessage(self, msg: Any) -> Any:
if isinstance(msg, ba.DieMessage):
if self.node:
self.node.delete()
else:
return super().handlemessage(msg)
class MagicBox(ba.Actor):
def __init__(self, pos: Sequence[float] = (0.0, 1.0, 0.0)) -> None:
super().__init__()
shared = SharedObjects.get()
tex = ba.gettexture('rgbStripes')
model = ba.getmodel('powerup')
position = (pos[0], pos[1] + 1.5, pos[2])
self.node = ba.newnode('prop',
delegate=self,
attrs={'body': 'box',
'position': position,
'model': model,
'shadow_size': 0.5,
'color_texture': tex,
'reflection': 'powerup',
'reflection_scale': [1.0],
'materials': [shared.object_material]})
def handlemessage(self, msg: Any) -> Any:
if isinstance(msg, ba.PickedUpMessage):
self.node.gravity_scale = -1.0
elif isinstance(msg, ba.DroppedMessage):
self.node.gravity_scale = 1.0
elif isinstance(msg, ba.DieMessage):
if self.node:
self.node.delete()
else:
return super().handlemessage(msg)
class Uts:
directory_user: str = ba.app.python_directory_user
directory_sys: str = directory_user + '/sys/' + ba.app.version
sm: Callable = _ba.screenmessage
cm: Callable = _ba.chatmessage
key: str = '#CheatMax'
mod: Any | None
accounts: dict[int, Any] = {}
usernames: dict[int, str] = {}
shortnames: dict[int, str] = {}
useraccounts: dict[int, str] = {}
userpbs: dict[int, str] = {}
players: dict[int, ba.SessionPlayer] = {}
def get_user_name(c_id: int) -> str:
for r in roster():
if r['client_id'] == c_id:
if r['players'] == []:
return r['display_string']
else:
return r['players'][0]['name_full']
break
return 'UNNAMED'
def sort_list(vals: list, count: int = 3) -> list:
vals_dict = dict(r=[])
for n in range(len(vals)):
vals_dict[n] = list()
for c in vals:
if len(vals_dict[n]) == count:
break
else:
if c not in vals_dict['r']:
vals_dict['r'].append(c)
vals_dict[n].append(c)
if len(vals_dict['r']) == len(vals):
vals_dict.pop('r')
break
return list(vals_dict.values())
def colors() -> dict[str, Sequence[float]]:
return dict(
yellow=(1.0, 1.0, 0.0),
red=(1.0, 0.0, 0.0),
green=(0.0, 1.0, 0.0),
blue=(0.2, 1.0, 1.0),
pink=(1, 0.3, 0.5),
orange=(1.0, 0.5, 0.0),
violet=(0.5, 0.25, 1.0),
white=(1.0, 1.0, 1.0),
black=(0.25, 0.25, 0.25))
def get_admins() -> list[str]:
admins = []
if len(Uts.pdata) > 0:
for p, d in Uts.pdata.items():
if d['Admin']:
admins.append(p)
return admins
def add_or_del_user(c_id: int, add: bool = True) -> None:
if c_id == -1:
return Uts.sm(getlanguage('You Are Amazing', subs=c_id), color=(0.5, 0, 1), clients=[c_id], transient=True)
if c_id not in Uts.userpbs:
Uts.sm(getlanguage('User Invalid', subs=c_id), clients=[c_id], transient=True)
else:
user = Uts.userpbs[c_id]
if add:
if user in Uts.pdata:
if not Uts.pdata[user]['Admin']:
Uts.pdata[user]['Admin'] = add
Uts.cm(getlanguage('Add Admin Msg', subs=Uts.usernames[c_id]))
else:
if user in Uts.pdata:
if Uts.pdata[user]['Admin']:
Uts.pdata[user]['Admin'] = add
Uts.cm(getlanguage('Delete Admin Msg', subs=Uts.usernames[c_id]))
Uts.save_players_data()
def create_players_data() -> None:
folder = Uts.directory_user + '/Configs'
file = folder + '/CheatMaxPlayersData.json'
if not os.path.exists(folder):
os.mkdir(folder)
if not os.path.exists(file):
with open(file, 'w') as f:
f.write('{}')
with open(file) as f:
r = f.read()
Uts.pdata = json.loads(r)
def save_players_data() -> None:
folder = Uts.directory_user + '/Configs'
file = folder + '/CheatMaxPlayersData.json'
with open(file, 'w') as f:
w = json.dumps(Uts.pdata, indent=4)
f.write(w)
def player_join(player: ba.Player) -> None:
try:
sessionplayer = player.sessionplayer
account_id = sessionplayer.get_v1_account_id()
client_id = sessionplayer.inputdevice.client_id
account_name = sessionplayer.inputdevice.get_v1_account_name(True)
except Exception:
account_id = None
else:
if type(account_id) is str and account_id.startswith('pb'):
if account_id not in Uts.pdata:
Uts.add_player_data(account_id)
Uts.sm(getlanguage('Guardando Informacion'), color=(0.35, 0.7, 0.1), transient=True, clients=[client_id])
accounts = Uts.pdata[account_id]['Accounts']
if account_name not in accounts:
accounts.append(account_name)
Uts.save_players_data()
Uts.accounts[client_id] = Uts.pdata[account_id]
Uts.usernames[client_id] = account_name
Uts.useraccounts[client_id] = account_name
Uts.players[client_id] = sessionplayer
def update_usernames() -> None:
for r in roster():
c_id = r['client_id']
if c_id not in Uts.accounts:
if r['account_id'] in Uts.pdata:
Uts.accounts[c_id] = Uts.pdata[r['account_id']]
if c_id not in Uts.usernames:
Uts.usernames[c_id] = r['display_string']
acc = r['display_string']
for acc_id, dt in Uts.pdata.items():
for ac in dt['Accounts']:
if ac == acc:
Uts.accounts[c_id] = Uts.pdata[acc_id]
Uts.userpbs[c_id] = acc_id
for c_id, p in Uts.players.items():
if p.exists():
Uts.usernames[c_id] = p.getname(full=True)
Uts.shortnames[c_id] = p.getname(full=False)
if p.get_v1_account_id() is not None:
Uts.userpbs[c_id] = p.get_v1_account_id()
def add_player_data(account_id: str) -> None:
if account_id not in Uts.pdata:
Uts.pdata[account_id] = {
'Mute': False,
'Effect': 'none',
'Admin': False,
'Accounts': []}
Uts.save_players_data()
def save_settings() -> None:
global cfg
folder = Uts.directory_user + '/Configs'
file = folder + '/CheatMaxSettings.json'
with open(file, 'w') as f:
w = json.dumps(cfg, indent=4)
f.write(w)
def create_settings() -> None:
global cfg
folder = Uts.directory_user + '/Configs'
file = folder + '/CheatMaxSettings.json'
if not os.path.exists(folder):
os.mkdir(folder)
if not os.path.exists(file):
with open(file, 'w') as f:
f.write('{}')
with open(file) as f:
r = f.read()
cfg = json.loads(r)
def create_user_system_scripts() -> None:
"""Set up a copy of Ballistica system scripts under your user scripts dir.
(for editing and experiment with)
"""
import shutil
app = _ba.app
path = (app.python_directory_user + '/sys/' + app.version)
pathtmp = path
if os.path.exists(path):
shutil.rmtree(path)
if os.path.exists(pathtmp):
shutil.rmtree(pathtmp)
def _ignore_filter(src: str, names: Sequence[str]) -> Sequence[str]:
del src, names # Unused
# We simply skip all __pycache__ directories. (the user would have
# to blow them away anyway to make changes;
# See https://github.com/efroemling/ballistica/wiki
# /Knowledge-Nuggets#python-cache-files-gotcha
return ('__pycache__', )
print(f'COPYING "{app.python_directory_app}" -> "{pathtmp}".')
shutil.copytree(app.python_directory_app, pathtmp, ignore=_ignore_filter)
print(f'MOVING "{pathtmp}" -> "{path}".')
shutil.move(pathtmp, path)
print(f"Created system scripts at :'{path}"
f"'\nRestart {_ba.appname()} to use them."
f' (use ba.quit() to exit the game)')
if app.platform == 'android':
print('Note: the new files may not be visible via '
'android-file-transfer until you restart your device.')
def create_data_text(self) -> None:
if isinstance(act(), MainMenuActivity):
return
if getattr(self, '_text_data', None):
self._text_data.node.delete()
if cfg['Commands'].get('ShowInfo'):
info = getlanguage('Party Info', subs=[
cfg['Commands'].get('HostName', '???'),
cfg['Commands'].get('Description', '???')])
color = tuple(list(cfg['Commands'].get('InfoColor', Uts.colors()['white'])) + [1])
self._text_data = text.Text(info,
position=(-730.0, -200.0), scale=0.7, color=color)
def create_live_chat(self,
live: bool = True,
chat: list[int, str] | None = None,
admin: bool = False) -> None:
if isinstance(act(), MainMenuActivity):
return
if getattr(self, '_live_chat', None):
self._live_chat.node.delete()
if cfg['Commands'].get('ChatLive'):
max = 6
chats = list()
txt = str()
icon = ba.charstr(ba.SpecialChar.STEAM_LOGO) if admin else ''
if any(_ba.get_chat_messages()):
if len(Chats) == max:
Chats.pop(0)
if live:
name = Uts.shortnames.get(chat[0], chat[0])
msg = chat[1]
Chats.append(f'{icon}{name}: {msg}')
for msg in Chats:
if len(chats) != max:
chats.append(msg)
else: break
txt = '\n'.join(chats)
livetext = getlanguage('Chat Live')
txt = (livetext + '\n' + ''.join(['=' for s
in range(len(livetext))]) + '\n') + txt
self._live_chat = text.Text(txt, position=(-734.0, 150.0),
color=(1, 1, 1, 1), scale=0.7, h_align=text.Text.HAlign.LEFT)
def funtion() -> str:
return """ %s
try:
cm = _ba.app.cheatmax_filter_chat(msg, client_id)
if cm == '@':
return None
except Exception:
pass
""" % Uts.key
def _install() -> None:
from ba import modutils, _hooks, _app
_file = Uts.directory_sys + '/ba/_hooks.py'
ba.app.cheatmax_filter_chat = filter_chat_message
def seq():
Uts.sm(getlanguage('Installing'))
ba.timer(2.0, ba.Call(
Uts.sm, getlanguage('Installed'), (0.0, 1.0, 0.0)))
ba.timer(4.0, ba.Call(
Uts.sm, getlanguage('Restart Msg')))
ba.timer(6.0, _ba.quit)
if not os.path.exists(Uts.directory_sys):
Uts.create_user_system_scripts()
ba.timer(1.0, ba.Call(
Uts.sm, getlanguage('Make Sys'), (0.0, 1.0, 0.0)))
seq()
del seq
with open(_file) as s:
read = s.read()
read_l = read.split('\n')
if Uts.key not in read:
f_list = Uts.funtion().split('\n')
ix = read_l.index('def filter_chat_message(msg: str, client_id: int) -> str | None:')
for i, lt in enumerate(f_list):
read_l.insert(i+(ix+1), lt)
read = '\n'.join(read_l)
with open(_file, 'w') as s:
s.write(read)
seq()
Uts.create_players_data()
#Uts.add_admin('pb-IF4XLRUN')
Uts.save_players_data()
def settings():
global cfg
Uts.create_settings()
if cfg.get('Commands') is None:
cfg['Commands'] = dict()
Uts.save_settings()
def plugin():
calls['GA_OnTransitionIn'] = ba.GameActivity.on_transition_in
calls['OnJumpPress'] = PlayerSpaz.on_jump_press
calls['OnPlayerJoin'] = Activity.on_player_join
calls['PlayerSpazInit'] = PlayerSpaz.__init__
ba.GameActivity.on_transition_in = new_ga_on_transition_in
PlayerSpaz.on_jump_press = new_playerspaz_on_jump_press
Activity.on_player_join = new_on_player_join
PlayerSpaz.__init__ = new_playerspaz_init_
# ba_meta export plugin
class Install(ba.Plugin):
def __init__(self):
plugin()
settings()
ba.timer(1.3, _install)