2025-08-03 13:53:51 +03:00
|
|
|
# Copyright 2025 - Solely by BrotherBoard
|
|
|
|
|
# Bug? Feedback? Telegram >> @GalaxyA14user
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
Camera v1.0 - Say cheese.
|
|
|
|
|
|
|
|
|
|
Adds a button to pause menu. Camera is advanced
|
|
|
|
|
Camera allows you to change camera position and
|
|
|
|
|
target with a very easy graphical visualization
|
|
|
|
|
of how it would look like.
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
from _babase import (
|
|
|
|
|
get_display_resolution as GDR,
|
|
|
|
|
clipboard_is_supported as CIS,
|
|
|
|
|
set_camera_position as SCP,
|
|
|
|
|
clipboard_set_text as COPY,
|
|
|
|
|
set_camera_manual as SSCM,
|
|
|
|
|
set_camera_target as SCT
|
|
|
|
|
)
|
|
|
|
|
from bascenev1 import (
|
|
|
|
|
get_foreground_host_activity as ga,
|
|
|
|
|
OutOfBoundsMessage,
|
|
|
|
|
gettexture as gbt,
|
|
|
|
|
getsound as gbs,
|
|
|
|
|
timer as tick,
|
|
|
|
|
Material,
|
|
|
|
|
getmesh,
|
|
|
|
|
newnode,
|
|
|
|
|
animate,
|
|
|
|
|
emitfx
|
|
|
|
|
)
|
|
|
|
|
from bauiv1 import (
|
|
|
|
|
get_special_widget as gsw,
|
|
|
|
|
containerwidget as cw,
|
|
|
|
|
screenmessage as push,
|
|
|
|
|
buttonwidget as bw,
|
|
|
|
|
imagewidget as iw,
|
|
|
|
|
textwidget as tw,
|
|
|
|
|
gettexture as gt,
|
|
|
|
|
apptimer as teck,
|
|
|
|
|
getsound as gs,
|
|
|
|
|
app as APP
|
|
|
|
|
)
|
|
|
|
|
from bauiv1lib.ingamemenu import InGameMenuWindow as igm
|
|
|
|
|
from babase import Plugin, InputType as IT
|
|
|
|
|
from math import sqrt, dist
|
|
|
|
|
|
2025-08-10 13:02:22 +00:00
|
|
|
|
2025-08-03 13:53:51 +03:00
|
|
|
class Camera:
|
|
|
|
|
__doc__ = 'A simple camera.'
|
|
|
|
|
__ins__ = None
|
|
|
|
|
__lst__ = None
|
|
|
|
|
__yes__ = False
|
2025-08-10 13:02:22 +00:00
|
|
|
|
2025-08-03 13:53:51 +03:00
|
|
|
def __init__(s) -> None:
|
|
|
|
|
c = s.__class__
|
|
|
|
|
if c.__yes__:
|
2025-08-10 13:02:22 +00:00
|
|
|
note('Stopped camera!', True)
|
2025-08-03 13:53:51 +03:00
|
|
|
c.__ins__.done(talk=False)
|
|
|
|
|
return
|
|
|
|
|
c.__ins__ = s
|
|
|
|
|
c.__yes__ = True
|
2025-08-10 13:02:22 +00:00
|
|
|
if c.__lst__:
|
|
|
|
|
SCM(False)
|
2025-08-03 13:53:51 +03:00
|
|
|
s.stage = 0
|
2025-08-10 13:02:22 +00:00
|
|
|
p = (0, 1, 0)
|
2025-08-03 13:53:51 +03:00
|
|
|
s.tex = 'achievementCrossHair'
|
|
|
|
|
s.kids = []
|
|
|
|
|
s.okay = []
|
|
|
|
|
with ga().context:
|
|
|
|
|
s.M = Material()
|
|
|
|
|
s.M.add_actions(
|
|
|
|
|
conditions=(('they_are_older_than', 0)),
|
|
|
|
|
actions=(
|
|
|
|
|
('modify_part_collision', 'collide', False),
|
|
|
|
|
('modify_part_collision', 'physical', False),
|
|
|
|
|
('modify_part_collision', 'friction', 0),
|
|
|
|
|
('modify_part_collision', 'stiffness', 0),
|
|
|
|
|
('modify_part_collision', 'damping', 0)
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
n = newnode(
|
|
|
|
|
'prop',
|
|
|
|
|
delegate=s,
|
|
|
|
|
attrs={
|
|
|
|
|
'mesh': getmesh('tnt'),
|
|
|
|
|
'color_texture': gbt(s.tex),
|
|
|
|
|
'body': 'crate',
|
|
|
|
|
'reflection': 'soft',
|
|
|
|
|
'density': 4.0,
|
|
|
|
|
'reflection_scale': [1.5],
|
|
|
|
|
'shadow_size': 0.6,
|
|
|
|
|
'position': p,
|
|
|
|
|
'gravity_scale': 0,
|
|
|
|
|
'materials': [s.M],
|
|
|
|
|
'is_area_of_interest': True
|
|
|
|
|
}
|
|
|
|
|
)
|
2025-08-10 13:02:22 +00:00
|
|
|
tick(0.15, animate(n, 'mesh_scale', {0: 2, 0.1: 0.5}).delete)
|
2025-08-03 13:53:51 +03:00
|
|
|
gbs('powerup01').play(position=p)
|
|
|
|
|
s.step = 0.01
|
|
|
|
|
s.node = n
|
|
|
|
|
s.wait = 0.001
|
|
|
|
|
s.mode = 4
|
|
|
|
|
s.llr = s.lud = 0.0
|
|
|
|
|
s.overlay = Overlay()
|
|
|
|
|
LN({
|
|
|
|
|
'UP_DOWN': lambda a: s.manage(a),
|
2025-08-10 13:02:22 +00:00
|
|
|
'LEFT_RIGHT': lambda a: s.manage(a, 1),
|
2025-08-03 13:53:51 +03:00
|
|
|
'PICK_UP_PRESS': lambda: s.start(2),
|
|
|
|
|
'JUMP_PRESS': lambda: s.start(0),
|
|
|
|
|
'PICK_UP_RELEASE': lambda: s.stop(2),
|
|
|
|
|
'JUMP_RELEASE': lambda: s.stop(0),
|
|
|
|
|
'BOMB_PRESS': s.done,
|
|
|
|
|
'BOMB_RELEASE': lambda: s.overlay.release(1),
|
|
|
|
|
'PUNCH_PRESS': s.mark,
|
|
|
|
|
'PUNCH_RELEASE': lambda: s.overlay.release(3),
|
|
|
|
|
})
|
|
|
|
|
s.move()
|
|
|
|
|
"""Write a tip"""
|
2025-08-10 13:02:22 +00:00
|
|
|
def tip(s, t, p, h='left', b=True):
|
2025-08-03 13:53:51 +03:00
|
|
|
n = newnode(
|
|
|
|
|
'text',
|
|
|
|
|
attrs={
|
|
|
|
|
'in_world': True,
|
|
|
|
|
'scale': 0.01,
|
|
|
|
|
'flatness': 1,
|
2025-08-10 13:02:22 +00:00
|
|
|
'color': (1, 1, 1),
|
2025-08-03 13:53:51 +03:00
|
|
|
'shadow': 1.0,
|
|
|
|
|
'position': p,
|
|
|
|
|
'text': t,
|
|
|
|
|
'h_align': h
|
|
|
|
|
}
|
|
|
|
|
)
|
2025-08-10 13:02:22 +00:00
|
|
|
if b:
|
|
|
|
|
s.kids.append(n)
|
2025-08-03 13:53:51 +03:00
|
|
|
return n
|
|
|
|
|
"""Create a dot"""
|
2025-08-10 13:02:22 +00:00
|
|
|
def dot(s, p, b=True, tex='black'):
|
2025-08-03 13:53:51 +03:00
|
|
|
n = newnode(
|
|
|
|
|
'prop',
|
|
|
|
|
delegate=s,
|
2025-08-10 13:02:22 +00:00
|
|
|
attrs={
|
|
|
|
|
'mesh': getmesh('tnt'),
|
|
|
|
|
'color_texture': gbt(tex),
|
|
|
|
|
'body': 'crate',
|
|
|
|
|
'mesh_scale': 0.1,
|
|
|
|
|
'position': p,
|
|
|
|
|
'gravity_scale': 0,
|
|
|
|
|
'materials': [s.M],
|
|
|
|
|
}
|
2025-08-03 13:53:51 +03:00
|
|
|
)
|
2025-08-10 13:02:22 +00:00
|
|
|
if b:
|
|
|
|
|
s.kids.append(n)
|
2025-08-03 13:53:51 +03:00
|
|
|
return n
|
|
|
|
|
"""Draw a line"""
|
2025-08-10 13:02:22 +00:00
|
|
|
def line(s, p1, p2, i=2, tex='black'):
|
|
|
|
|
x1, y1, z1 = p1
|
|
|
|
|
x2, y2, z2 = p2
|
|
|
|
|
n = dist(p1, p2)*i
|
|
|
|
|
for i in range(1, int(n+1)):
|
2025-08-03 13:53:51 +03:00
|
|
|
t = i/n
|
|
|
|
|
x = x1+t*(x2-x1)
|
|
|
|
|
y = y1+t*(y2-y1)
|
|
|
|
|
z = z1+t*(z2-z1)
|
2025-08-10 13:02:22 +00:00
|
|
|
s.kids.append(s.dot((x, y, z), tex=tex))
|
2025-08-03 13:53:51 +03:00
|
|
|
"""Mark"""
|
|
|
|
|
def mark(s):
|
|
|
|
|
if not s.stage:
|
|
|
|
|
s.stage = 1
|
|
|
|
|
p = s.getpos()
|
2025-08-10 13:02:22 +00:00
|
|
|
s.p1 = (p[0]-0.01, p[1], p[2])
|
|
|
|
|
s.okay.append(s.dot(s.p1, b=False))
|
|
|
|
|
s.okay.append(
|
|
|
|
|
s.tip(f'Camera position\n{tuple([round(i, 2) for i in s.p1])}', s.p1, b=False))
|
2025-08-03 13:53:51 +03:00
|
|
|
else:
|
|
|
|
|
[i.delete() for i in s.kids]
|
|
|
|
|
s.kids.clear()
|
|
|
|
|
p2 = s.p2 = s.getpos()
|
|
|
|
|
|
|
|
|
|
r = GDR()
|
|
|
|
|
w = r[0]/r[1]
|
|
|
|
|
h = 1
|
|
|
|
|
|
|
|
|
|
vd = sub(p2, s.p1)
|
|
|
|
|
vd_n = norm(vd)
|
|
|
|
|
|
|
|
|
|
t_up = (0, 1, 0)
|
|
|
|
|
r_v = cross(vd_n, t_up)
|
|
|
|
|
r_v_n = norm(r_v)
|
|
|
|
|
|
|
|
|
|
up_v = cross(r_v_n, vd_n)
|
|
|
|
|
up_v_n = norm(up_v)
|
|
|
|
|
|
|
|
|
|
hw = w / 2.0
|
|
|
|
|
hh = h / 2.0
|
|
|
|
|
|
|
|
|
|
tr = add(p2, add(scale(r_v_n, hw), scale(up_v_n, hh)))
|
|
|
|
|
tl = add(p2, add(scale(r_v_n, -hw), scale(up_v_n, hh)))
|
|
|
|
|
br = add(p2, add(scale(r_v_n, hw), scale(up_v_n, -hh)))
|
|
|
|
|
bl = add(p2, add(scale(r_v_n, -hw), scale(up_v_n, -hh)))
|
|
|
|
|
|
|
|
|
|
s.line(s.p1, tr)
|
|
|
|
|
s.line(s.p1, tl)
|
|
|
|
|
s.line(s.p1, br)
|
|
|
|
|
s.line(s.p1, bl)
|
|
|
|
|
|
|
|
|
|
m = 4
|
2025-08-10 13:02:22 +00:00
|
|
|
j = {'tex': 'crossOutMask'}
|
2025-08-03 13:53:51 +03:00
|
|
|
s.line(tr, tl, m, **j)
|
|
|
|
|
s.line(tl, bl, m, **j)
|
|
|
|
|
s.line(bl, br, m, **j)
|
|
|
|
|
s.line(br, tr, m, **j)
|
|
|
|
|
|
2025-08-10 13:02:22 +00:00
|
|
|
s.tip(
|
|
|
|
|
f'Your display\n{r[0]}x{r[1]} px\n{tuple([round(i, 2) for i in p2])}', tr, 'right')
|
2025-08-03 13:53:51 +03:00
|
|
|
s.stage = 2
|
|
|
|
|
s.overlay.press(3)
|
2025-08-10 13:02:22 +00:00
|
|
|
tick(0.25, animate(s.node, 'mesh_scale', {0: 0.5, 0.1: 0.2, 0.2: 0.5}).delete)
|
2025-08-03 13:53:51 +03:00
|
|
|
gbs('gunCocking').play(position=s.node.position)
|
|
|
|
|
"""Handle events"""
|
|
|
|
|
def handlemessage(s, m):
|
|
|
|
|
if isinstance(m, OutOfBoundsMessage):
|
|
|
|
|
p = s.getpos()
|
|
|
|
|
gbs('shatter').play(position=p)
|
|
|
|
|
emitfx(
|
|
|
|
|
scale=1,
|
|
|
|
|
count=30,
|
|
|
|
|
spread=0.1,
|
|
|
|
|
position=p,
|
|
|
|
|
chunk_type='ice'
|
|
|
|
|
)
|
|
|
|
|
s.destroy()
|
|
|
|
|
note('Out of bounds!')
|
|
|
|
|
"""Destroy"""
|
|
|
|
|
def destroy(s):
|
|
|
|
|
with ga().context:
|
|
|
|
|
n = s.node
|
|
|
|
|
s.mode = 2
|
|
|
|
|
n.delete()
|
|
|
|
|
s.reset()
|
|
|
|
|
"""Reset input"""
|
|
|
|
|
def reset(s):
|
|
|
|
|
s.__class__.__yes__ = False
|
|
|
|
|
me = getme()
|
2025-08-10 13:02:22 +00:00
|
|
|
if not me:
|
|
|
|
|
return
|
2025-08-03 13:53:51 +03:00
|
|
|
me.resetinput()
|
2025-08-10 13:02:22 +00:00
|
|
|
with ga().context:
|
|
|
|
|
me.actor.connect_controls_to_player()
|
2025-08-03 13:53:51 +03:00
|
|
|
[i.delete() for i in (s.kids+s.okay)]
|
|
|
|
|
"""Manage movement"""
|
2025-08-10 13:02:22 +00:00
|
|
|
def manage(s, a, lr=0):
|
|
|
|
|
if lr:
|
|
|
|
|
s.llr = a
|
|
|
|
|
return
|
2025-08-03 13:53:51 +03:00
|
|
|
s.lud = a
|
|
|
|
|
"""Move"""
|
|
|
|
|
def move(s):
|
|
|
|
|
m = getme(1)
|
2025-08-10 13:02:22 +00:00
|
|
|
if (not m) or m._dead:
|
|
|
|
|
s.destroy()
|
|
|
|
|
try:
|
|
|
|
|
p = s.getpos()
|
2025-08-03 13:53:51 +03:00
|
|
|
except:
|
|
|
|
|
s.overlay.destroy()
|
|
|
|
|
return
|
2025-08-10 13:02:22 +00:00
|
|
|
s.setpos((p[0]+s.llr*s.step, p[1], p[2]-s.lud*s.step))
|
|
|
|
|
s.overlay.up(*p, s.llr, s.lud)
|
2025-08-03 13:53:51 +03:00
|
|
|
SCT(*p)
|
2025-08-10 13:02:22 +00:00
|
|
|
teck(s.wait, s.move)
|
2025-08-03 13:53:51 +03:00
|
|
|
"""Start elevating"""
|
2025-08-10 13:02:22 +00:00
|
|
|
def start(s, i):
|
2025-08-03 13:53:51 +03:00
|
|
|
s.overlay.press(i)
|
|
|
|
|
s.mode = i
|
|
|
|
|
s.loop(i)
|
|
|
|
|
"""Keep elevating"""
|
2025-08-10 13:02:22 +00:00
|
|
|
def loop(s, i):
|
|
|
|
|
if s.mode != i:
|
|
|
|
|
return
|
|
|
|
|
try:
|
|
|
|
|
p = list(s.node.position)
|
|
|
|
|
except:
|
|
|
|
|
return
|
2025-08-03 13:53:51 +03:00
|
|
|
p[1] += s.step if i else -s.step
|
|
|
|
|
s.node.position = tuple(p)
|
|
|
|
|
teck(s.wait, lambda: s.loop(i))
|
|
|
|
|
"""Stop elevating"""
|
2025-08-10 13:02:22 +00:00
|
|
|
def stop(s, i):
|
2025-08-03 13:53:51 +03:00
|
|
|
s.overlay.release(i)
|
|
|
|
|
s.mode = 4
|
|
|
|
|
"""Get position"""
|
|
|
|
|
def getpos(s):
|
|
|
|
|
return s.node.position
|
|
|
|
|
"""Set position"""
|
2025-08-10 13:02:22 +00:00
|
|
|
def setpos(s, p):
|
2025-08-03 13:53:51 +03:00
|
|
|
s.node.position = p
|
|
|
|
|
"""Done"""
|
2025-08-10 13:02:22 +00:00
|
|
|
def done(s, talk=True):
|
2025-08-03 13:53:51 +03:00
|
|
|
s.overlay.press(1)
|
|
|
|
|
s.overlay.destroy()
|
2025-08-10 13:02:22 +00:00
|
|
|
try:
|
|
|
|
|
p = s.node.position
|
|
|
|
|
except:
|
|
|
|
|
return
|
2025-08-03 13:53:51 +03:00
|
|
|
with ga().context:
|
|
|
|
|
gbs('laser').play(position=p)
|
2025-08-10 13:02:22 +00:00
|
|
|
tick(0.2, animate(s.node, 'mesh_scale', {0: 0.5, 0.08: 1, 0.2: 0}).delete)
|
|
|
|
|
tick(0.2, s.node.delete)
|
2025-08-03 13:53:51 +03:00
|
|
|
s.reset()
|
|
|
|
|
if s.stage > 1 and talk:
|
|
|
|
|
SCM(True)
|
|
|
|
|
SCP(*s.p1)
|
|
|
|
|
SCT(*s.p2)
|
2025-08-10 13:02:22 +00:00
|
|
|
var('lp1', s.p1)
|
|
|
|
|
var('lp2', s.p2)
|
2025-08-03 13:53:51 +03:00
|
|
|
nice('Applied!')
|
|
|
|
|
elif talk:
|
|
|
|
|
note('Incomplete camera setup\nNo changes applied.')
|
2025-08-10 13:02:22 +00:00
|
|
|
if s.__class__.__ins__ == s:
|
|
|
|
|
s.__class__.__ins__ = None
|
|
|
|
|
|
2025-08-03 13:53:51 +03:00
|
|
|
|
|
|
|
|
"""Controls overlay"""
|
2025-08-10 13:02:22 +00:00
|
|
|
|
|
|
|
|
|
2025-08-03 13:53:51 +03:00
|
|
|
class Overlay:
|
|
|
|
|
__lst__ = None
|
|
|
|
|
"""Place nodes"""
|
|
|
|
|
def __init__(s):
|
|
|
|
|
s.__class__.__lst__ = str(ga())
|
|
|
|
|
s.colors = [
|
2025-08-10 13:02:22 +00:00
|
|
|
[(0.2, 0.6, 0.2), (0.4, 1, 0.4)],
|
|
|
|
|
[(0.6, 0, 0), (1, 0, 0)],
|
|
|
|
|
[(0.2, 0.6, 0.6), (0.4, 1, 1)],
|
|
|
|
|
[(0.6, 0.6, 0.2), (1, 1, 0.4)],
|
|
|
|
|
[(0.3, 0.23, 0.5), (0.2, 0.13, 0.3)]
|
2025-08-03 13:53:51 +03:00
|
|
|
]
|
|
|
|
|
s.pics = []
|
|
|
|
|
s.texts = []
|
|
|
|
|
s.pos = []
|
|
|
|
|
s.nub = []
|
2025-08-10 13:02:22 +00:00
|
|
|
s.old = [0, 0, 0]
|
2025-08-03 13:53:51 +03:00
|
|
|
s.dead = False
|
|
|
|
|
with ga().context:
|
|
|
|
|
for i in range(4):
|
2025-08-10 13:02:22 +00:00
|
|
|
j = ['Jump', 'Bomb', 'PickUp', 'Punch'][i]
|
|
|
|
|
k = [600, 650, 600, 550][i]
|
|
|
|
|
l = [170, 220, 270, 220][i]
|
2025-08-03 13:53:51 +03:00
|
|
|
c = s.colors[i][0]
|
|
|
|
|
n = newnode(
|
|
|
|
|
'image',
|
|
|
|
|
attrs={
|
|
|
|
|
'texture': gbt('button'+j),
|
|
|
|
|
'absolute_scale': True,
|
2025-08-10 13:02:22 +00:00
|
|
|
'position': (k, l),
|
|
|
|
|
'scale': (60, 60),
|
2025-08-03 13:53:51 +03:00
|
|
|
'color': c
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
s.pics.append(n)
|
2025-08-10 13:02:22 +00:00
|
|
|
j = ['Down', 'Done', 'Up', 'Mark'][i]
|
|
|
|
|
k = [600, 680, 600, 515][i]
|
|
|
|
|
l = [115, 220, 325, 220][i]
|
|
|
|
|
h = ['center', 'left', 'center', 'right'][i]
|
|
|
|
|
v = ['bottom', 'center', 'top', 'center'][i]
|
2025-08-03 13:53:51 +03:00
|
|
|
n = newnode(
|
|
|
|
|
'text',
|
|
|
|
|
attrs={
|
|
|
|
|
'text': j,
|
2025-08-10 13:02:22 +00:00
|
|
|
'position': (k, l),
|
2025-08-03 13:53:51 +03:00
|
|
|
'color': c,
|
|
|
|
|
'h_align': h,
|
|
|
|
|
'v_align': v
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
s.texts.append(n)
|
|
|
|
|
for i in range(3):
|
2025-08-10 13:02:22 +00:00
|
|
|
c = s.colors[[1, 0, 2][i]][0]
|
2025-08-03 13:53:51 +03:00
|
|
|
n = newnode(
|
|
|
|
|
'text',
|
|
|
|
|
attrs={
|
|
|
|
|
'text': '0',
|
2025-08-10 13:02:22 +00:00
|
|
|
'position': (640, 155-30*i),
|
2025-08-03 13:53:51 +03:00
|
|
|
'color': c,
|
|
|
|
|
'h_align': 'left'
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
s.pos.append(n)
|
2025-08-10 13:02:22 +00:00
|
|
|
s.np = (790, 140)
|
|
|
|
|
for i in [0, 1]:
|
|
|
|
|
j = [110, 60][i]
|
2025-08-03 13:53:51 +03:00
|
|
|
n = newnode(
|
|
|
|
|
'image',
|
|
|
|
|
attrs={
|
|
|
|
|
'texture': gbt('nub'),
|
|
|
|
|
'absolute_scale': True,
|
|
|
|
|
'position': s.np,
|
2025-08-10 13:02:22 +00:00
|
|
|
'scale': (j, j),
|
2025-08-03 13:53:51 +03:00
|
|
|
'color': s.colors[4][i]
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
s.nub.append(n)
|
|
|
|
|
s.fade()
|
|
|
|
|
"""Color overlays"""
|
2025-08-10 13:02:22 +00:00
|
|
|
def set(s, i, c):
|
2025-08-03 13:53:51 +03:00
|
|
|
s.pics[i].color = s.texts[i].color = c
|
|
|
|
|
"""Color position"""
|
2025-08-10 13:02:22 +00:00
|
|
|
def pset(s, i, c):
|
2025-08-03 13:53:51 +03:00
|
|
|
s.pos[i].color = c
|
|
|
|
|
"""Simulate pressed"""
|
2025-08-10 13:02:22 +00:00
|
|
|
def press(s, i):
|
|
|
|
|
s.set(i, s.colors[i][1])
|
2025-08-03 13:53:51 +03:00
|
|
|
s.pics[i].opacity = 1.0
|
|
|
|
|
"""Simulate released"""
|
2025-08-10 13:02:22 +00:00
|
|
|
def release(s, i):
|
|
|
|
|
s.set(i, s.colors[i][0])
|
2025-08-03 13:53:51 +03:00
|
|
|
s.pics[i].opacity = 0.7
|
|
|
|
|
"""Get all nodes"""
|
|
|
|
|
def nodes(s):
|
|
|
|
|
return s.pics+s.texts+s.pos+s.nub
|
|
|
|
|
"""Update position"""
|
2025-08-10 13:02:22 +00:00
|
|
|
def up(s, x, y, z, lr, ud):
|
|
|
|
|
new = [x, y, z]
|
2025-08-03 13:53:51 +03:00
|
|
|
for i in range(3):
|
2025-08-10 13:02:22 +00:00
|
|
|
c = s.colors[[1, 0, 2][i]]
|
|
|
|
|
if s.old[i] == new[i]:
|
|
|
|
|
s.pset(i, c[0])
|
|
|
|
|
continue
|
2025-08-03 13:53:51 +03:00
|
|
|
t = s.pos[i]
|
2025-08-10 13:02:22 +00:00
|
|
|
t.text = str(round(new[i], 5))
|
|
|
|
|
s.pset(i, c[1])
|
2025-08-03 13:53:51 +03:00
|
|
|
s.old = new
|
2025-08-10 13:02:22 +00:00
|
|
|
[setattr(s.nub[i], 'opacity', [[0.5, 0.2], [0.7, 0.3]][bool(lr or ud)][i]) for i in [0, 1]]
|
2025-08-03 13:53:51 +03:00
|
|
|
p = s.np
|
|
|
|
|
m = sqrt(lr**2+ud**2) or 1
|
2025-08-10 13:02:22 +00:00
|
|
|
d = 25*min(sqrt(lr**2+ud**2), 1)
|
2025-08-03 13:53:51 +03:00
|
|
|
lr /= m
|
|
|
|
|
ud /= m
|
2025-08-10 13:02:22 +00:00
|
|
|
s.nub[1].position = (p[0]+lr*d, p[1]+ud*d)
|
2025-08-03 13:53:51 +03:00
|
|
|
"""Fade"""
|
2025-08-10 13:02:22 +00:00
|
|
|
def fade(s, i=0):
|
|
|
|
|
if str(ga()) != s.__class__.__lst__:
|
|
|
|
|
return
|
2025-08-03 13:53:51 +03:00
|
|
|
mem = s.nodes()
|
2025-08-10 13:02:22 +00:00
|
|
|
[tick(1, animate(n, 'opacity', {0: i, 0.5: abs(i-0.7)}).delete) for n in mem]
|
2025-08-03 13:53:51 +03:00
|
|
|
"""Destroy overlay"""
|
|
|
|
|
def destroy(s):
|
2025-08-10 13:02:22 +00:00
|
|
|
if s.dead:
|
|
|
|
|
return
|
2025-08-03 13:53:51 +03:00
|
|
|
s.dead = True
|
|
|
|
|
with ga().context:
|
2025-08-10 13:02:22 +00:00
|
|
|
tick(0.2, lambda: s.fade(0.7))
|
|
|
|
|
tick(2, lambda: [n.delete() for n in s.nodes()])
|
|
|
|
|
|
2025-08-03 13:53:51 +03:00
|
|
|
|
|
|
|
|
# Mini tools
|
2025-08-10 13:02:22 +00:00
|
|
|
def note(t, b=False): return (push(t, color=(1, 1, 0)), gs('block').play() if b else None)
|
|
|
|
|
def nice(t): return (push(t, color=(0, 1, 0)), gs('dingSmallHigh').play())
|
|
|
|
|
def SCM(b): return (setattr(Camera, '__lst__', b), SSCM(b))
|
|
|
|
|
def scale(v, s): return (v[0]*s, v[1]*s, v[2]*s)
|
|
|
|
|
def cross(a, b): return (a[1]*b[2]-a[2]*b[1], a[2]*b[0]-a[0]*b[2], a[0]*b[1]-a[1]*b[0])
|
|
|
|
|
def sub(a, b): return (a[0]-b[0], a[1]-b[1], a[2]-b[2])
|
|
|
|
|
def add(a, b): return (a[0]+b[0], a[1]+b[1], a[2]+b[2])
|
|
|
|
|
|
|
|
|
|
|
2025-08-03 13:53:51 +03:00
|
|
|
def getme(actor=0):
|
|
|
|
|
for p in ga().players:
|
|
|
|
|
if p.sessionplayer.inputdevice.client_id == -1:
|
|
|
|
|
return p.actor if actor else p
|
2025-08-10 13:02:22 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def LN(d): me = getme(); [me.assigninput(getattr(IT, k), d[k]) for k in d]
|
|
|
|
|
|
|
|
|
|
|
2025-08-03 13:53:51 +03:00
|
|
|
def RESUME():
|
|
|
|
|
u = APP.ui_v1
|
|
|
|
|
c = APP.classic
|
|
|
|
|
c.resume()
|
|
|
|
|
u.clear_main_window()
|
|
|
|
|
[z() for z in c.main_menu_resume_callbacks]
|
|
|
|
|
c.main_menu_resume_callbacks.clear()
|
2025-08-10 13:02:22 +00:00
|
|
|
|
|
|
|
|
|
2025-08-03 13:53:51 +03:00
|
|
|
def norm(v):
|
2025-08-10 13:02:22 +00:00
|
|
|
a, b, c = v
|
2025-08-03 13:53:51 +03:00
|
|
|
l = sqrt(a**2+b**2+c**2)
|
2025-08-10 13:02:22 +00:00
|
|
|
return (0, 0, 0) if l == 0 else (a/l, b/l, c/l)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def var(s, v=None):
|
2025-08-03 13:53:51 +03:00
|
|
|
c = APP.config
|
|
|
|
|
s = 'cam_'+s
|
2025-08-10 13:02:22 +00:00
|
|
|
if v is None:
|
|
|
|
|
return c.get(s, v)
|
2025-08-03 13:53:51 +03:00
|
|
|
c[s] = v
|
|
|
|
|
c.commit()
|
|
|
|
|
|
|
|
|
|
# brobord collide grass
|
|
|
|
|
# ba_meta require api 9
|
|
|
|
|
# ba_meta export babase.Plugin
|
2025-08-10 13:02:22 +00:00
|
|
|
|
|
|
|
|
|
2025-08-03 13:53:51 +03:00
|
|
|
class byBordd(Plugin):
|
2025-08-10 13:02:22 +00:00
|
|
|
def has_settings_ui(s): return True
|
|
|
|
|
def show_settings_ui(s, src): return s.ui(source=src)
|
|
|
|
|
col = (0.18, 0.18, 0.18)
|
|
|
|
|
|
2025-08-03 13:53:51 +03:00
|
|
|
def __init__(s):
|
|
|
|
|
o = igm._refresh_in_game
|
2025-08-10 13:02:22 +00:00
|
|
|
|
|
|
|
|
def e(f, *a, **k):
|
|
|
|
|
r = o(f, *a, **k)
|
2025-08-03 13:53:51 +03:00
|
|
|
b = bw(
|
|
|
|
|
label='',
|
2025-08-10 13:02:22 +00:00
|
|
|
size=(90, 40),
|
2025-08-03 13:53:51 +03:00
|
|
|
button_type='square',
|
|
|
|
|
parent=f._root_widget,
|
2025-08-10 13:02:22 +00:00
|
|
|
color=(0.18, 0.18, 0.18),
|
|
|
|
|
position=(f._width-20, 0),
|
2025-08-03 13:53:51 +03:00
|
|
|
)
|
2025-08-10 13:02:22 +00:00
|
|
|
bw(b, on_activate_call=lambda: s.ui(source=b, main=True))
|
2025-08-03 13:53:51 +03:00
|
|
|
iw(
|
2025-08-10 13:02:22 +00:00
|
|
|
size=(40, 40),
|
2025-08-03 13:53:51 +03:00
|
|
|
texture=gt('tv'),
|
|
|
|
|
parent=f._root_widget,
|
2025-08-10 13:02:22 +00:00
|
|
|
position=(f._width-20, 5)
|
2025-08-03 13:53:51 +03:00
|
|
|
)
|
|
|
|
|
tw(
|
|
|
|
|
maxwidth=50,
|
|
|
|
|
text='Camera',
|
|
|
|
|
h_align='left',
|
|
|
|
|
parent=f._root_widget,
|
2025-08-10 13:02:22 +00:00
|
|
|
position=(f._width+15, 0)
|
2025-08-03 13:53:51 +03:00
|
|
|
)
|
|
|
|
|
return r
|
|
|
|
|
igm._refresh_in_game = e
|
|
|
|
|
"""The UI"""
|
2025-08-10 13:02:22 +00:00
|
|
|
def ui(s, source=None, main=False):
|
2025-08-03 13:53:51 +03:00
|
|
|
s.main = main
|
2025-08-10 13:02:22 +00:00
|
|
|
off = source.get_screen_space_center() if source else (0, 0)
|
2025-08-03 13:53:51 +03:00
|
|
|
w = cw(
|
|
|
|
|
color=s.col,
|
2025-08-10 13:02:22 +00:00
|
|
|
size=(350, 305),
|
2025-08-03 13:53:51 +03:00
|
|
|
stack_offset=off,
|
|
|
|
|
transition='in_scale',
|
|
|
|
|
parent=gsw('overlay_stack'),
|
|
|
|
|
scale_origin_stack_offset=off
|
|
|
|
|
)
|
2025-08-10 13:02:22 +00:00
|
|
|
s.back = lambda b=True: (
|
|
|
|
|
cw(w, transition=['out_right', 'out_scale'][bool(source) and b]), gs('swish').play() if b else None)
|
|
|
|
|
cw(w, on_outside_click_call=s.back)
|
2025-08-03 13:53:51 +03:00
|
|
|
b = Camera.__yes__
|
|
|
|
|
t = [
|
2025-08-10 13:02:22 +00:00
|
|
|
('Camera is ready!', (0, 1, 1)),
|
|
|
|
|
('Camera is running!', (0, 1, 0)),
|
2025-08-03 13:53:51 +03:00
|
|
|
][b]
|
|
|
|
|
tw(
|
|
|
|
|
parent=w,
|
|
|
|
|
text=t[0],
|
|
|
|
|
scale=1.5,
|
|
|
|
|
color=t[1],
|
|
|
|
|
h_align='center',
|
2025-08-10 13:02:22 +00:00
|
|
|
position=(155, 250)
|
2025-08-03 13:53:51 +03:00
|
|
|
)
|
|
|
|
|
for i in range(4):
|
|
|
|
|
j = [
|
2025-08-10 13:02:22 +00:00
|
|
|
('3D Camera mapper', s.start),
|
|
|
|
|
('Last mapped config', s.load),
|
|
|
|
|
('Last dev command', s.copy),
|
|
|
|
|
('Reset all settings', s.reset)
|
2025-08-03 13:53:51 +03:00
|
|
|
][i]
|
|
|
|
|
tw(
|
|
|
|
|
parent=w,
|
|
|
|
|
text=j[0],
|
|
|
|
|
maxwidth=195,
|
2025-08-10 13:02:22 +00:00
|
|
|
position=(20, 30+55*i)
|
2025-08-03 13:53:51 +03:00
|
|
|
)
|
|
|
|
|
k = [
|
2025-08-10 13:02:22 +00:00
|
|
|
(['Start', 'Stop'][b], 'cursor'),
|
|
|
|
|
('Load', 'achievementOutline'),
|
|
|
|
|
('Copy', 'file'),
|
|
|
|
|
('Reset', 'replayIcon')
|
2025-08-03 13:53:51 +03:00
|
|
|
][i]
|
|
|
|
|
bw(
|
|
|
|
|
parent=w,
|
|
|
|
|
label=k[0],
|
|
|
|
|
color=s.col,
|
2025-08-10 13:02:22 +00:00
|
|
|
size=(120, 50),
|
2025-08-03 13:53:51 +03:00
|
|
|
icon=gt(k[1]),
|
|
|
|
|
enable_sound=not i,
|
2025-08-10 13:02:22 +00:00
|
|
|
textcolor=(1, 1, 1),
|
2025-08-03 13:53:51 +03:00
|
|
|
button_type='square',
|
|
|
|
|
on_activate_call=j[1],
|
2025-08-10 13:02:22 +00:00
|
|
|
position=(220, 20+55*i)
|
2025-08-03 13:53:51 +03:00
|
|
|
)
|
|
|
|
|
"""Gather last"""
|
|
|
|
|
def gather(s):
|
2025-08-10 13:02:22 +00:00
|
|
|
return var('lp1'), var('lp2')
|
2025-08-03 13:53:51 +03:00
|
|
|
"""Reset"""
|
|
|
|
|
def reset(s):
|
|
|
|
|
SCM(False)
|
|
|
|
|
nice('Resetored original settings!')
|
|
|
|
|
"""Copy last"""
|
|
|
|
|
def copy(s):
|
2025-08-10 13:02:22 +00:00
|
|
|
if not CIS():
|
|
|
|
|
note('Unsupported!', True)
|
|
|
|
|
return
|
2025-08-03 13:53:51 +03:00
|
|
|
g = s.gather()
|
2025-08-10 13:02:22 +00:00
|
|
|
if not g[1]:
|
|
|
|
|
note('Apply something first!', True)
|
|
|
|
|
return
|
|
|
|
|
g = [tuple([round(i, 2) for i in j]) for j in g]
|
|
|
|
|
COPY(
|
|
|
|
|
f'from _babase import set_camera_manual as SCM, set_camera_target as SCT, set_camera_position as SCP; SCM(True); SCP(*{g[0]}); SCT(*{g[1]})')
|
2025-08-03 13:53:51 +03:00
|
|
|
nice('Copied command!\nPaste it in dev console anytime to load config!')
|
|
|
|
|
"""Load last"""
|
|
|
|
|
def load(s):
|
|
|
|
|
g = s.gather()
|
2025-08-10 13:02:22 +00:00
|
|
|
if not g[1]:
|
|
|
|
|
note('Apply something first!', True)
|
|
|
|
|
return
|
|
|
|
|
if Camera.__yes__:
|
|
|
|
|
note('Stop camera first!', True)
|
|
|
|
|
return
|
2025-08-03 13:53:51 +03:00
|
|
|
SCM(True)
|
|
|
|
|
SCP(*g[0])
|
|
|
|
|
SCT(*g[1])
|
|
|
|
|
nice('Loaded last config!')
|
|
|
|
|
"""Start camera"""
|
|
|
|
|
def start(s):
|
|
|
|
|
a = ga()
|
2025-08-10 13:02:22 +00:00
|
|
|
if not a:
|
|
|
|
|
note('Only mapping requires you to be the host!\nYou still can load previous config though', True)
|
|
|
|
|
return
|
|
|
|
|
if not getme():
|
|
|
|
|
note('Join the game first!', True)
|
|
|
|
|
return
|
2025-08-03 13:53:51 +03:00
|
|
|
s.back(False)
|
|
|
|
|
RESUME() if s.main else None
|
2025-08-10 13:02:22 +00:00
|
|
|
with a.context:
|
|
|
|
|
Camera()
|