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

764 lines
28 KiB
Python
Raw Permalink Normal View History

2023-08-03 20:12:51 +05:30
# Released under the MIT License. See LICENSE for details.
2025-01-22 00:21:44 +05:30
# ba_meta require api 9
2023-08-03 20:12:51 +05:30
'''
Character Builder/Maker by Mr.Smoothy
Plugin helps to mix character models and textures in interactive way.
Watch tutorial : https://youtu.be/q0KxY1hfMPQ
Join discord: https://discord.gg/ucyaesh for help
https://bombsquad-community.web.app/home
> create team playlist and add character maker mini game
> Use export command to save character
> Character will be saved in CustomCharacter folder inside Bombsquad Mods folder
Characters can be used offline or online
for online you need to share character file with server owners.
*For server owners:_
You might know what to do with that file,
Still ,
refer code after line 455 in this file , add it as a plugin to import characters from json file.
*For modders:-
You can add more models and texture , check line near 400 and add asset names , you can also modify sounds and icon in json file (optional) .
To share your character with friends ,
send them character .json file and tell them to put file in same location i.e mods/CustomCharacter or for PC appdata/Local/Bombsquad/Mods/CustomCharacter
this plugin should be installed on their device too.
Dont forget to share your creativity with me ,
send your character screenshot discord: mr.smoothy#5824 https://discord.gg/ucyaesh
Register your character in above discord server , so other server owners can add your characters.
Released on 28 May 2021
Update 2 june : use import <character-name>
Update 29 July 2023: updated to API 8 , multiplayer support
'''
from typing import Sequence
import _babase
import babase
import bauiv1 as bui
from bascenev1lib.actor.spazappearance import *
from bascenev1lib.actor.text import Text
from bascenev1lib.actor.image import Image
2023-12-09 00:54:50 +05:30
import bauiv1lib.mainmenu
2023-08-03 20:12:51 +05:30
import os
import copy
import json
GAME_USER_DIRECTORY = _babase.env()["python_directory_user"]
CUSTOM_CHARACTERS = os.path.join(GAME_USER_DIRECTORY, "CustomCharacters")
os.makedirs(CUSTOM_CHARACTERS, exist_ok=True)
SPAZ_PRESET = {
2023-08-03 15:21:30 +00:00
"color_mask": "neoSpazColorMask",
"color_texture": "neoSpazColor",
"head": "neoSpazHead",
"hand": "neoSpazHand",
"torso": "neoSpazTorso",
"pelvis": "neoSpazTorso",
"upper_arm": "neoSpazUpperArm",
"forearm": "neoSpazForeArm",
"upper_leg": "neoSpazUpperLeg",
"lower_leg": "neoSpazLowerLeg",
"toes_mesh": "neoSpazToes",
"jump_sounds": ['spazJump01', 'spazJump02', 'spazJump03', 'spazJump04'],
"attack_sounds": ['spazAttack01', 'spazAttack02', 'spazAttack03', 'spazAttack04'],
"impact_sounds": ['spazImpact01', 'spazImpact02', 'spazImpact03', 'spazImpact04'],
"death_sounds": ['spazDeath01'],
"pickup_sounds": ['spazPickup01'],
"fall_sounds": ['spazFall01'],
"icon_texture": "neoSpazIcon",
2023-08-03 20:12:51 +05:30
"icon_mask_texture": "neoSpazIconColorMask",
2023-08-03 15:21:30 +00:00
"style": "spaz"
2023-08-03 20:12:51 +05:30
}
2023-08-03 15:21:30 +00:00
2023-08-03 20:12:51 +05:30
class Player(bs.Player['Team']):
"""Our player type for this game."""
class Team(bs.Team[Player]):
"""Our team type for this game."""
def __init__(self):
self.score = 0
# ba_meta export bascenev1.GameActivity
class CharacterBuilder(bs.TeamGameActivity[Player, Team]):
"""A game type based on acquiring kills."""
name = 'Character Maker'
description = 'Create your own custom Characters'
# Print messages when players die since it matters here.
announce_player_deaths = True
@classmethod
def get_available_settings(cls, sessiontype):
settings = [
bs.IntSetting(
'Kills to Win Per Player',
min_value=1,
default=5,
increment=1,
),
bs.IntChoiceSetting(
'Time Limit',
choices=[
('None', 0),
('1 Minute', 60),
('2 Minutes', 120),
('5 Minutes', 300),
('10 Minutes', 600),
('20 Minutes', 1200),
],
default=0,
2023-08-03 15:21:30 +00:00
),
2023-08-03 20:12:51 +05:30
bs.FloatChoiceSetting(
'Respawn Times',
choices=[
('Shorter', 0.25),
('Short', 0.5),
('Normal', 1.0),
('Long', 2.0),
('Longer', 4.0),
],
default=1.0,
),
bs.BoolSetting('Epic Mode', default=False),
]
if issubclass(sessiontype, bs.FreeForAllSession):
settings.append(
bs.BoolSetting('Allow Negative Scores', default=False))
return settings
@classmethod
def supports_session_type(cls, sessiontype):
return (issubclass(sessiontype, bs.DualTeamSession)
or issubclass(sessiontype, bs.FreeForAllSession))
@classmethod
def get_supported_maps(cls, sessiontype):
return ['Rampage']
def __init__(self, settings):
super().__init__(settings)
self.initialize_meshs()
self._score_to_win = None
self._dingsound = bs.getsound('dingSmall')
self._epic_mode = bool(settings['Epic Mode'])
self._kills_to_win_per_player = int(
settings['Kills to Win Per Player'])
self._time_limit = float(settings['Time Limit'])
self._allow_negative_scores = bool(
settings.get('Allow Negative Scores', False))
self._punch_image = Image(
bs.gettexture('buttonPunch'),
2023-08-03 15:21:30 +00:00
position=(345, 200),
scale=(50, 50),
color=(0.9, 0.9, 0, 0.9)
2023-08-03 20:12:51 +05:30
)
self._punch_text = Text(
"Model+",
scale=0.7,
shadow=0.5,
flatness=0.5,
color=(0.9, 0.9, 0, 0.9),
2023-08-03 15:21:30 +00:00
position=(263, 190))
2023-08-03 20:12:51 +05:30
self._grab_image = Image(
bs.gettexture('buttonPickUp'),
2023-08-03 15:21:30 +00:00
position=(385, 240),
scale=(50, 50),
color=(0, 0.7, 0.9)
2023-08-03 20:12:51 +05:30
)
self._grab_text = Text(
"Component-",
scale=0.7,
shadow=0.5,
flatness=0.5,
color=(0, 0.7, 1, 0.9),
2023-08-03 15:21:30 +00:00
position=(340, 265))
2023-08-03 20:12:51 +05:30
self._jump_image = Image(
bs.gettexture('buttonJump'),
2023-08-03 15:21:30 +00:00
position=(385, 160),
scale=(50, 50),
color=(0.2, 0.9, 0.2, 0.9)
2023-08-03 20:12:51 +05:30
)
self._jump_text = Text(
"Component+",
scale=0.7,
shadow=0.5,
flatness=0.5,
color=(0.2, 0.9, 0.2, 0.9),
2023-08-03 15:21:30 +00:00
position=(340, 113))
2023-08-03 20:12:51 +05:30
self._bomb_image = Image(
bs.gettexture('buttonBomb'),
2023-08-03 15:21:30 +00:00
position=(425, 200),
scale=(50, 50),
color=(0.9, 0.2, 0.2, 0.9)
2023-08-03 20:12:51 +05:30
)
self._bomb_text = Text(
"Model-",
scale=0.7,
shadow=0.5,
flatness=0.5,
color=(0.9, 0.2, 0.2, 0.9),
2023-08-03 15:21:30 +00:00
position=(452, 190))
2023-08-03 20:12:51 +05:30
self._host = Text(
"Originally created by \ue020HeySmoothy\nhttps://youtu.be/q0KxY1hfMPQ\nhttps://youtu.be/3l2dxWEhrzE\n\nModified for multiplayer by \ue047Nyaa! :3",
flash=False,
maxwidth=0,
scale=0.65,
shadow=0.5,
flatness=0.5,
h_align=Text.HAlign.RIGHT,
v_attach=Text.VAttach.BOTTOM,
h_attach=Text.HAttach.RIGHT,
color=(1.0, 0.4, 0.95, 0.8),
position=(-2, 82))
self._discord = Text(
"Join discord.gg/ucyaesh to provide feedback or to use this Character Maker offline!",
flash=False,
maxwidth=0,
scale=0.85,
shadow=0.5,
flatness=0.5,
h_align=Text.HAlign.CENTER,
v_attach=Text.VAttach.BOTTOM,
h_attach=Text.HAttach.CENTER,
color=(1.0, 0.4, 0, 1),
position=(0, 110))
self._website = Text(
"check mods folder to get JSON character file ever exported from here!",
flash=False,
maxwidth=0,
scale=0.85,
shadow=0.5,
flatness=0.5,
h_align=Text.HAlign.CENTER,
v_attach=Text.VAttach.BOTTOM,
h_attach=Text.HAttach.CENTER,
color=(0.2, 0.9, 1.0, 1),
position=(0, 150))
self._commands = Text(
"Commands:\n\n\t1. /info\n\t2. /export <character-name>\n\t3. /import <character-name>\n\t",
flash=False,
maxwidth=0,
scale=0.8,
shadow=0.5,
flatness=0.5,
h_align=Text.HAlign.LEFT,
v_attach=Text.VAttach.TOP,
h_attach=Text.HAttach.LEFT,
color=(0.3, 0.9, 0.3, 0.8),
position=(30, -112))
# Base class overrides.
self.slow_motion = self._epic_mode
self.default_music = bs.MusicType.MARCHING
def get_instance_description(self):
return ''
def get_instance_description_short(self):
return ''
def on_team_join(self, team: Team):
if self.has_begun():
pass
def on_begin(self):
super().on_begin()
def nextBodyPart(self, spaz):
2023-08-03 15:21:30 +00:00
spaz.bodyindex = (spaz.bodyindex+1) % len(self.cache.keys())
2023-08-03 20:12:51 +05:30
try:
spaz.bodypart.delete()
except AttributeError:
pass
part = list(self.cache.keys())[spaz.bodyindex]
spaz.bodypart = bs.newnode(
2023-08-03 15:21:30 +00:00
'text',
2023-08-03 20:12:51 +05:30
owner=spaz.node,
attrs={
2023-08-03 15:21:30 +00:00
'text': str(part),
'in_world': True,
'color': (1, 1, 1),
'scale': 0.011,
'shadow': 0.5,
'flatness': 0.5,
'h_align': 'center', })
math = bs.newnode('math',
owner=spaz.node,
attrs={
'input1': (0, 1.7, 0.5),
'operation': 'add',
})
2023-08-03 20:12:51 +05:30
spaz.node.connectattr('position', math, 'input2')
math.connectattr('output', spaz.bodypart, 'position')
bs.getsound('deek').play()
def prevBodyPart(self, spaz):
2023-08-03 15:21:30 +00:00
spaz.bodyindex = (spaz.bodyindex-1) % len(self.cache.keys())
2023-08-03 20:12:51 +05:30
try:
spaz.bodypart.delete()
except AttributeError:
pass
2023-08-03 15:21:30 +00:00
part = list(self.cache.keys())[spaz.bodyindex]
spaz.bodypart = bs.newnode(
'text',
2023-08-03 20:12:51 +05:30
owner=spaz.node,
attrs={
2023-08-03 15:21:30 +00:00
'text': str(part),
'in_world': True,
'color': (1, 1, 1),
'scale': 0.011,
'shadow': 0.5,
'flatness': 0.5,
'h_align': 'center', })
math = bs.newnode('math',
owner=spaz.node,
attrs={
'input1': (0, 1.7, 0.5),
'operation': 'add',
})
2023-08-03 20:12:51 +05:30
spaz.node.connectattr('position', math, 'input2')
math.connectattr('output', spaz.bodypart, 'position')
bs.getsound('deek').play()
def nextModel(self, spaz):
try:
spaz.newmesh.delete()
except AttributeError:
pass
part = list(self.cache.keys())[spaz.bodyindex]
2023-08-03 15:21:30 +00:00
spaz.meshindex = (spaz.meshindex+1) % len(self.cache[part])
2023-08-03 20:12:51 +05:30
mesh = self.cache[part][spaz.meshindex]
spaz.newmesh = bs.newnode(
'text',
owner=spaz.node,
attrs={
'text': str(mesh),
'in_world': True,
2023-08-03 15:21:30 +00:00
'color': (1, 1, 1),
2023-08-03 20:12:51 +05:30
'scale': 0.011,
'shadow': 0.5,
'flatness': 0.5,
'h_align': 'center'
})
math = bs.newnode('math',
2023-08-03 15:21:30 +00:00
owner=spaz.node,
attrs={
'input1': (0, -0.6, 0.5),
'operation': 'add',
})
2023-08-03 20:12:51 +05:30
spaz.node.connectattr('position', math, 'input2')
math.connectattr('output', spaz.newmesh, 'position')
if part == "main_color":
2023-08-03 15:21:30 +00:00
self.setColor(spaz, mesh)
2023-08-03 20:12:51 +05:30
elif part == "highlight_color":
2023-08-03 15:21:30 +00:00
self.setHighlight(spaz, mesh)
2023-08-03 20:12:51 +05:30
else:
2023-08-03 15:21:30 +00:00
self.setModel(spaz, part, mesh)
2023-08-03 20:12:51 +05:30
bs.getsound('click01').play()
def prevModel(self, spaz):
try:
spaz.newmesh.delete()
except AttributeError:
pass
part = list(self.cache.keys())[spaz.bodyindex]
2023-08-03 15:21:30 +00:00
spaz.meshindex = (spaz.meshindex-1) % len(self.cache[part])
2023-08-03 20:12:51 +05:30
mesh = self.cache[part][spaz.meshindex]
spaz.newmesh = bs.newnode(
'text',
owner=spaz.node,
attrs={
'text': str(mesh),
'in_world': True,
2023-08-03 15:21:30 +00:00
'color': (1, 1, 1),
2023-08-03 20:12:51 +05:30
'scale': 0.011,
'shadow': 0.5,
'flatness': 0.5,
'h_align': 'center'
})
math = bs.newnode('math',
2023-08-03 15:21:30 +00:00
owner=spaz.node,
attrs={
'input1': (0, -0.6, 0.5),
'operation': 'add',
})
2023-08-03 20:12:51 +05:30
spaz.node.connectattr('position', math, 'input2')
math.connectattr('output', spaz.newmesh, 'position')
if part == "main_color":
2023-08-03 15:21:30 +00:00
self.setColor(spaz, mesh)
2023-08-03 20:12:51 +05:30
elif part == "highlight_color":
2023-08-03 15:21:30 +00:00
self.setHighlight(spaz, mesh)
2023-08-03 20:12:51 +05:30
else:
2023-08-03 15:21:30 +00:00
self.setModel(spaz, part, mesh)
2023-08-03 20:12:51 +05:30
bs.getsound('click01').play()
def setColor(self, spaz, color):
spaz.node.color = color
def setHighlight(self, spaz, highlight):
spaz.node.highlight = highlight
def setModel(self, spaz, bodypart, meshname):
2023-08-03 15:21:30 +00:00
if bodypart == 'head':
2023-08-03 20:12:51 +05:30
spaz.node.head_mesh = bs.getmesh(meshname)
2023-08-03 15:21:30 +00:00
elif bodypart == 'torso':
2023-08-03 20:12:51 +05:30
spaz.node.torso_mesh = bs.getmesh(meshname)
2023-08-03 15:21:30 +00:00
elif bodypart == 'pelvis':
2023-08-03 20:12:51 +05:30
spaz.node.pelvis_mesh = bs.getmesh(meshname)
2023-08-03 15:21:30 +00:00
elif bodypart == 'upper_arm':
2023-08-03 20:12:51 +05:30
spaz.node.upper_arm_mesh = bs.getmesh(meshname)
2023-08-03 15:21:30 +00:00
elif bodypart == 'forearm':
2023-08-03 20:12:51 +05:30
spaz.node.forearm_mesh = bs.getmesh(meshname)
2023-08-03 15:21:30 +00:00
elif bodypart == 'hand':
2023-08-03 20:12:51 +05:30
spaz.node.hand_mesh = bs.getmesh(meshname)
2023-08-03 15:21:30 +00:00
elif bodypart == 'upper_leg':
2023-08-03 20:12:51 +05:30
spaz.node.upper_leg_mesh = bs.getmesh(meshname)
2023-08-03 15:21:30 +00:00
elif bodypart == 'lower_leg':
2023-08-03 20:12:51 +05:30
spaz.node.lower_leg_mesh = bs.getmesh(meshname)
2023-08-03 15:21:30 +00:00
elif bodypart == 'toes_mesh':
2023-08-03 20:12:51 +05:30
spaz.node.toes_mesh = bs.getmesh(meshname)
2023-08-03 15:21:30 +00:00
elif bodypart == 'style':
2023-08-03 20:12:51 +05:30
spaz.node.style = meshname
2023-08-03 15:21:30 +00:00
elif bodypart == 'color_texture':
2023-08-03 20:12:51 +05:30
spaz.node.color_texture = bs.gettexture(meshname)
2023-08-03 15:21:30 +00:00
elif bodypart == 'color_mask':
2023-08-03 20:12:51 +05:30
spaz.node.color_mask_texture = bs.gettexture(meshname)
def spawn_player(self, player):
spaz = self.spawn_player_spaz(player)
2023-08-03 15:21:30 +00:00
spaz.bodyindex = 0
spaz.meshindex = 0
spaz.bodypart = bs.newnode(
'text',
2023-08-03 20:12:51 +05:30
owner=spaz.node,
attrs={
2023-08-03 15:21:30 +00:00
'text': "<Choose Component>",
'in_world': True,
'scale': 0.011,
'color': (1, 0.4, 0.9, 1),
'h_align': 'center',
'shadow': 0.7,
'flatness': 0.5,
2023-08-03 20:12:51 +05:30
})
2023-08-03 15:21:30 +00:00
math = bs.newnode('math',
owner=spaz.node,
attrs={
'input1': (0, 1.7, 0.5),
'operation': 'add',
})
2023-08-03 20:12:51 +05:30
spaz.node.connectattr('position', math, 'input2')
math.connectattr('output', spaz.bodypart, 'position')
spaz.newmesh = bs.newnode(
2023-08-03 15:21:30 +00:00
'text',
2023-08-03 20:12:51 +05:30
owner=spaz.node,
attrs={
2023-08-03 15:21:30 +00:00
'text': "<Choose Model/Tex>",
'in_world': True,
'scale': 0.011,
'color': (1, 0.4, 0.9, 1),
'h_align': 'center',
'shadow': 0.7,
'flatness': 0.5,
2023-08-03 20:12:51 +05:30
})
2023-08-03 15:21:30 +00:00
math = bs.newnode('math',
owner=spaz.node,
attrs={
'input1': (0, -0.6, 0.5),
'operation': 'add',
})
2023-08-03 20:12:51 +05:30
spaz.node.connectattr('position', math, 'input2')
math.connectattr('output', spaz.newmesh, 'position')
# 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_jump=False,
# enable_bomb=False,
# enable_pickup=False)
intp = babase.InputType
player.assigninput(intp.JUMP_PRESS, lambda: self.nextBodyPart(spaz))
player.assigninput(intp.PICK_UP_PRESS, lambda: self.prevBodyPart(spaz))
player.assigninput(intp.PUNCH_PRESS, lambda: self.nextModel(spaz))
player.assigninput(intp.BOMB_PRESS, lambda: self.prevModel(spaz))
# Also lets have them make some noise when they die.
spaz.play_big_death_sound = True
return spaz
def handlemessage(self, msg):
if isinstance(msg, bs.PlayerDiedMessage):
# Augment standard behavior.
super().handlemessage(msg)
player = msg.getplayer(Player)
self.respawn_player(player)
else:
return super().handlemessage(msg)
return None
def _update_scoreboard(self):
for team in self.teams:
self._scoreboard.set_team_value(team, team.score,
self._score_to_win)
def end_game(self):
results = bs.GameResults()
for team in self.teams:
results.set_team_score(team, team.score)
self.end(results=results)
def initialize_meshs(self):
self.cache = {
2023-08-03 15:21:30 +00:00
"head": ["bomb", "landMine", "wing", "eyeLid", "impactBomb"],
"hand": ["hairTuft3", "bomb", "powerup"],
"torso": ["bomb", "landMine", "bomb"],
"pelvis": ["hairTuft4", "bomb"],
"upper_arm": ["wing", "locator", "bomb"],
"forearm": ["flagPole", "bomb"],
"upper_leg": ["bomb"],
"lower_leg": ["bomb"],
"toes_mesh": ["bomb"],
"style": ["spaz", "female", "ninja", "kronk", "mel", "pirate", "santa", "frosty", "bones", "bear", "penguin", "ali", "cyborg", "agent", "pixie", "bunny"],
"color_texture": ["kronk", "egg1", "egg2", "egg3", "achievementGotTheMoves", "bombColor", "crossOut", "explosion", "rgbStripes", "powerupCurse", "powerupHealth", "impactBombColorLit"],
"color_mask": ["egg1", "egg2", "egg3", "bombColor", "crossOutMask", "fontExtras3"],
"main_color": [(0, 0, 0), (1, 0, 0), (0, 1, 0), (0, 0, 1), (1, 1, 0), (1, 0, 1), (0, 1, 1), (1, 1, 1)],
"highlight_color": [(0, 0, 0), (1, 0, 0), (0, 1, 0), (0, 0, 1), (1, 1, 0), (1, 0, 1), (0, 1, 1), (1, 1, 1)],
2023-08-03 20:12:51 +05:30
}
2023-08-03 15:21:30 +00:00
chars = ["neoSpaz", "zoe", "ninja", "kronk", "mel", "jack", "santa", "frosty",
"bones", "bear", "penguin", "ali", "cyborg", "agent", "wizard", "pixie", "bunny"]
2023-08-03 20:12:51 +05:30
for char in chars:
self.cache["head"].append(char + "Head")
self.cache["hand"].append(char + "Hand")
self.cache["torso"].append(char + "Torso")
2023-08-03 15:21:30 +00:00
if char not in ['mel', "jack", "santa"]:
2023-08-03 20:12:51 +05:30
self.cache["pelvis"].append(char + "Pelvis")
self.cache["upper_arm"].append(char + "UpperArm")
self.cache["forearm"].append(char + "ForeArm")
self.cache["upper_leg"].append(char + "UpperLeg")
self.cache["lower_leg"].append(char + "LowerLeg")
self.cache["toes_mesh"].append(char + "Toes")
self.cache["color_mask"].append(char + "ColorMask")
2023-08-03 15:21:30 +00:00
if char != "kronk":
2023-08-03 20:12:51 +05:30
self.cache["color_texture"].append(char + "Color")
def mesh_to_string(mesh):
return str(mesh)[17:-2]
def texture_to_string(texture):
return str(texture)[20:-2]
def spaz_to_json(spaz):
spaz_json = copy.deepcopy(SPAZ_PRESET)
2023-08-03 15:21:30 +00:00
spaz_json['head'] = mesh_to_string(spaz.node.head_mesh)
spaz_json['hand'] = mesh_to_string(spaz.node.hand_mesh)
spaz_json['torso'] = mesh_to_string(spaz.node.torso_mesh)
spaz_json['pelvis'] = mesh_to_string(spaz.node.pelvis_mesh)
spaz_json['upper_arm'] = mesh_to_string(spaz.node.upper_arm_mesh)
spaz_json['forearm'] = mesh_to_string(spaz.node.forearm_mesh)
spaz_json['upper_leg'] = mesh_to_string(spaz.node.upper_leg_mesh)
spaz_json['lower_leg'] = mesh_to_string(spaz.node.lower_leg_mesh)
spaz_json['toes_mesh'] = mesh_to_string(spaz.node.toes_mesh)
spaz_json['style'] = spaz.node.style
spaz_json['color_mask'] = texture_to_string(spaz.node.color_mask_texture)
2023-08-03 20:12:51 +05:30
spaz_json['color_texture'] = texture_to_string(spaz.node.color_texture)
return spaz_json
def import_character(name, spaz):
if not name:
bs.screenmessage("Inavlid character name")
return
character = None
for appearance_name, appearance_character in bs.app.classic.spaz_appearances.items():
if name.lower() == appearance_name.lower():
character = appearance_character
break
if not character:
return (False, name)
activity = bs.get_foreground_host_activity()
with activity.context:
2023-08-03 15:21:30 +00:00
spaz.node.head_mesh = bs.getmesh(character.head_mesh)
spaz.node.hand_mesh = bs.getmesh(character.hand_mesh)
spaz.node.torso_mesh = bs.getmesh(character.torso_mesh)
spaz.node.pelvis_mesh = bs.getmesh(character.pelvis_mesh)
spaz.node.upper_arm_mesh = bs.getmesh(character.upper_arm_mesh)
spaz.node.forearm_mesh = bs.getmesh(character.forearm_mesh)
spaz.node.upper_leg_mesh = bs.getmesh(character.upper_leg_mesh)
spaz.node.lower_leg_mesh = bs.getmesh(character.lower_leg_mesh)
spaz.node.toes_mesh = bs.getmesh(character.toes_mesh)
spaz.node.style = character.style
spaz.node.color_mask_texture = bs.gettexture(character.color_mask_texture)
spaz.node.color_texture = bs.gettexture(character.color_texture)
2023-08-03 20:12:51 +05:30
return (True, appearance_name)
def export_character(name, spaz):
default_characters = tuple(bs.app.classic.spaz_appearances.keys())[:30]
os.makedirs(CUSTOM_CHARACTERS, exist_ok=True)
character_file = name + ".json"
for saved_character_file in os.listdir(CUSTOM_CHARACTERS):
if character_file.lower() == saved_character_file.lower():
return (False, os.path.splitext(saved_character_file)[0])
for default_character in default_characters:
if name.lower() == default_character.lower():
return (False, default_character)
spaz_json = spaz_to_json(spaz)
with open(os.path.join(CUSTOM_CHARACTERS, character_file), "w") as fout:
json.dump(spaz_json, fout, indent=4)
register_character_json(name, spaz_json)
return (True, name)
def register_character_json(name, character):
2023-08-03 15:21:30 +00:00
appearance = Appearance(name)
appearance.color_texture = character['color_texture']
2023-08-03 20:12:51 +05:30
appearance.color_mask_texture = character['color_mask']
2023-08-03 15:21:30 +00:00
appearance.default_color = (0.6, 0.6, 0.6)
appearance.default_highlight = (0, 1, 0)
appearance.icon_texture = character['icon_texture']
appearance.icon_mask_texture = character['icon_mask_texture']
appearance.head_mesh = character['head']
appearance.torso_mesh = character['torso']
appearance.pelvis_mesh = character['pelvis']
appearance.upper_arm_mesh = character['upper_arm']
appearance.forearm_mesh = character['forearm']
appearance.hand_mesh = character['hand']
appearance.upper_leg_mesh = character['upper_leg']
appearance.lower_leg_mesh = character['lower_leg']
appearance.toes_mesh = character['toes_mesh']
appearance.jump_sounds = character['jump_sounds']
appearance.attack_sounds = character['attack_sounds']
appearance.impact_sounds = character['impact_sounds']
appearance.death_sounds = character['death_sounds']
appearance.pickup_sounds = character['pickup_sounds']
appearance.fall_sounds = character['fall_sounds']
appearance.style = character['style']
2023-08-03 20:12:51 +05:30
cm = bs.chatmessage
2023-08-03 15:21:30 +00:00
2023-08-03 20:12:51 +05:30
def _new_chatmessage(msg: str | babase.Lstr, *args, **kwargs):
activity = bs.get_foreground_host_activity()
if not activity:
cm(msg, *args, **kwargs)
return
is_a_command = any(msg.startswith(command) for command in ("/export", "/import", "/info"))
if not is_a_command:
cm(msg, *args, **kwargs)
return
player = get_player(msg, activity)
if not player:
cm("no player exists in game, try adding client id at last of command", *args, **kwargs)
cm(msg, *args, **kwargs)
return
if msg.startswith("/export"):
if len(msg.split(" ")) > 1:
2023-08-03 15:21:30 +00:00
success, character_name = export_character(" ".join(msg.split(" ")[1:]), player.actor)
2023-08-03 20:12:51 +05:30
if success:
bs.screenmessage(
'Exported character "{}"'.format(character_name),
2023-08-03 15:21:30 +00:00
color=(0, 1, 0)
2023-08-03 20:12:51 +05:30
)
bui.getsound("gunCocking").play()
else:
bs.screenmessage(
'Character "{}" already exists'.format(character_name),
2023-08-03 15:21:30 +00:00
color=(1, 0, 0)
2023-08-03 20:12:51 +05:30
)
bui.getsound("error").play()
else:
cm("Enter name of character, Usage: /export <character_name>", *args, **kwargs)
elif msg.startswith("/import"):
if len(msg.split(" ")) > 1:
2023-08-03 15:21:30 +00:00
success, character_name = import_character(" ".join(msg.split(" ")[1:]), player.actor)
2023-08-03 20:12:51 +05:30
if success:
bs.screenmessage(
'Imported character "{}"'.format(character_name),
2023-08-03 15:21:30 +00:00
color=(0, 1, 0)
2023-08-03 20:12:51 +05:30
)
bui.getsound("gunCocking").play()
else:
bs.screenmessage(
'Character "{}" doesn\'t exist'.format(character_name),
2023-08-03 15:21:30 +00:00
color=(1, 0, 0)
2023-08-03 20:12:51 +05:30
)
bui.getsound("error").play()
else:
cm("Usage: /import <character_name>", *args, **kwargs)
elif msg.startswith("/info"):
spaz_json = spaz_to_json(player.actor)
del spaz_json["jump_sounds"]
del spaz_json["attack_sounds"]
del spaz_json["impact_sounds"]
del spaz_json["death_sounds"]
del spaz_json["pickup_sounds"]
del spaz_json["fall_sounds"]
spaz_str = ""
for key, value in spaz_json.items():
spaz_str += "{}: {}\n".format(key, value)
2023-08-03 15:21:30 +00:00
bs.screenmessage(spaz_str, color=(1, 1, 1))
2023-08-03 20:12:51 +05:30
cm(msg, *args, **kwargs)
2023-08-03 15:21:30 +00:00
2023-08-03 20:12:51 +05:30
bs.chatmessage = _new_chatmessage
2023-08-03 15:21:30 +00:00
2023-08-03 20:12:51 +05:30
def get_player(msg, activity):
client_id = -1
words = msg.split(" ")
last_word = words[-1]
if last_word.isdigit():
client_id = int(last_word)
for player in activity.players:
2023-08-03 15:21:30 +00:00
player_client_id = player.sessionplayer.inputdevice.client_id
if client_id == player_client_id:
return player
2023-08-03 20:12:51 +05:30
2023-12-09 00:54:50 +05:30
2025-06-24 00:55:09 +05:30
# ba_meta export babase.Plugin
2023-08-03 20:12:51 +05:30
class bySmoothy(babase.Plugin):
def __init__(self):
_babase.import_character = import_character
_babase.export_character = export_character
_babase.spaz_to_json = spaz_to_json
character_files = os.listdir(CUSTOM_CHARACTERS)
for character_file in character_files:
if character_file.lower().endswith(".json"):
name, _ = os.path.splitext(character_file)
with open(os.path.join(CUSTOM_CHARACTERS, character_file), "r") as fin:
character = json.load(fin)
register_character_json(name, character)