# Released under the MIT License. See LICENSE for details.
#
"""Provides a window to display game credits."""
from __future__ import annotations
import os
import logging
from typing import TYPE_CHECKING, override
import bauiv1 as bui
if TYPE_CHECKING:
from typing import Sequence
[docs]
class CreditsWindow(bui.MainWindow):
"""Window for displaying game credits."""
def __init__(
self,
transition: str | None = 'in_right',
origin_widget: bui.Widget | None = None,
):
# pylint: disable=too-many-locals
# pylint: disable=too-many-statements
import json
bui.set_analytics_screen('Credits Window')
assert bui.app.classic is not None
uiscale = bui.app.ui_v1.uiscale
width = 990 if uiscale is bui.UIScale.SMALL else 670
x_inset = 100 if uiscale is bui.UIScale.SMALL else 0
height = 450 if uiscale is bui.UIScale.SMALL else 500
self._r = 'creditsWindow'
super().__init__(
root_widget=bui.containerwidget(
size=(width, height),
toolbar_visibility=(
'menu_minimal'
if uiscale is bui.UIScale.SMALL
else 'menu_full'
),
scale=(
1.8
if uiscale is bui.UIScale.SMALL
else 1.2 if uiscale is bui.UIScale.MEDIUM else 1.0
),
stack_offset=(
(0, 0) if uiscale is bui.UIScale.SMALL else (0, 0)
),
),
transition=transition,
origin_widget=origin_widget,
)
if uiscale is bui.UIScale.SMALL:
bui.containerwidget(
edit=self._root_widget, on_cancel_call=self.main_window_back
)
else:
btn = bui.buttonwidget(
parent=self._root_widget,
position=(40 + x_inset, height - 62),
size=(140, 60),
scale=0.8,
label=bui.Lstr(resource='backText'),
button_type='back',
on_activate_call=self.main_window_back,
autoselect=True,
)
bui.containerwidget(edit=self._root_widget, cancel_button=btn)
bui.buttonwidget(
edit=btn,
button_type='backSmall',
position=(
40 + x_inset,
height - 62 + 5,
),
size=(60, 48),
label=bui.charstr(bui.SpecialChar.BACK),
)
bui.textwidget(
parent=self._root_widget,
position=(0, height - (93 if uiscale is bui.UIScale.SMALL else 54)),
size=(width, 30),
scale=0.8 if uiscale is bui.UIScale.SMALL else 1.0,
text=bui.Lstr(
resource=f'{self._r}.titleText',
subs=[('${APP_NAME}', bui.Lstr(resource='titleText'))],
),
h_align='center',
color=bui.app.ui_v1.title_color,
maxwidth=330,
v_align='center',
)
scroll = bui.scrollwidget(
parent=self._root_widget,
position=(40 + x_inset, 62 if uiscale is bui.UIScale.SMALL else 35),
size=(
width - (80 + 2 * x_inset),
height - (160 if uiscale is bui.UIScale.SMALL else 100),
),
capture_arrows=True,
)
bui.widget(
edit=scroll,
right_widget=bui.get_special_widget('squad_button'),
)
if uiscale is bui.UIScale.SMALL:
bui.widget(
edit=scroll,
left_widget=bui.get_special_widget('back_button'),
)
def _format_names(names2: Sequence[str], inset: float) -> str:
sval = ''
# measure a series since there's overlaps and stuff..
space_width = (
bui.get_string_width(' ' * 10, suppress_warning=True) / 10.0
)
spacing = 330.0
col1 = inset
col2 = col1 + spacing
col3 = col2 + spacing
line_width = 0.0
nline = ''
for name in names2:
# move to the next column (or row) and print
if line_width > col3:
sval += nline + '\n'
nline = ''
line_width = 0
if line_width > col2:
target = col3
elif line_width > col1:
target = col2
else:
target = col1
spacingstr = ' ' * int((target - line_width) / space_width)
nline += spacingstr
nline += name
line_width = bui.get_string_width(nline, suppress_warning=True)
if nline != '':
sval += nline + '\n'
return sval
sound_and_music = bui.Lstr(
resource=f'{self._r}.songCreditText'
).evaluate()
sound_and_music = sound_and_music.replace(
'${TITLE}', "'William Tell (Trumpet Entry)'"
)
sound_and_music = sound_and_music.replace(
'${PERFORMER}', 'The Apollo Symphony Orchestra'
)
sound_and_music = sound_and_music.replace(
'${PERFORMER}', 'The Apollo Symphony Orchestra'
)
sound_and_music = sound_and_music.replace(
'${COMPOSER}', 'Gioacchino Rossini'
)
sound_and_music = sound_and_music.replace('${ARRANGER}', 'Chris Worth')
sound_and_music = sound_and_music.replace('${PUBLISHER}', 'BMI')
sound_and_music = sound_and_music.replace(
'${SOURCE}', 'www.AudioSparx.com'
)
spc = ' '
sound_and_music = spc + sound_and_music.replace('\n', '\n' + spc)
names = [
'HubOfTheUniverseProd',
'Jovica',
'LG',
'Leady',
'Percy Duke',
'PhreaKsAccount',
'Pogotron',
'Rock Savage',
'anamorphosis',
'benboncan',
'cdrk',
'chipfork',
'guitarguy1985',
'jascha',
'joedeshon',
'loofa',
'm_O_m',
'mich3d',
'sandyrb',
'shakaharu',
'sirplus',
'stickman',
'thanvannispen',
'virotic',
'zimbot',
]
names.sort(key=lambda x: x.lower())
freesound_names = _format_names(names, 90)
try:
with open(
os.path.join(
bui.app.env.data_directory,
'ba_data',
'data',
'langdata.json',
),
encoding='utf-8',
) as infile:
translation_contributors = json.loads(infile.read())[
'translation_contributors'
]
except Exception:
logging.exception('Error reading translation contributors.')
translation_contributors = []
translation_names = _format_names(translation_contributors, 60)
# Need to bake this out and chop it up since we're passing our
# 65535 vertex limit for meshes..
# We can remove that limit once we drop support for GL ES2.. :-/
# (or add mesh splitting under the hood)
credits_text = (
' '
+ bui.Lstr(resource=f'{self._r}.codingGraphicsAudioText')
.evaluate()
.replace('${NAME}', 'Eric Froemling')
+ '\n'
'\n'
' '
+ bui.Lstr(resource=f'{self._r}.additionalAudioArtIdeasText')
.evaluate()
.replace('${NAME}', 'Raphael Suter')
+ '\n'
'\n'
' '
+ bui.Lstr(resource=f'{self._r}.soundAndMusicText').evaluate()
+ '\n'
'\n' + sound_and_music + '\n'
'\n'
' '
+ bui.Lstr(resource=f'{self._r}.publicDomainMusicViaText')
.evaluate()
.replace('${NAME}', 'Musopen.com')
+ '\n'
' '
+ bui.Lstr(resource=f'{self._r}.thanksEspeciallyToText')
.evaluate()
.replace('${NAME}', 'the US Army, Navy, and Marine Bands')
+ '\n'
'\n'
' '
+ bui.Lstr(resource=f'{self._r}.additionalMusicFromText')
.evaluate()
.replace('${NAME}', 'The YouTube Audio Library')
+ '\n'
'\n'
' '
+ bui.Lstr(resource=f'{self._r}.soundsText')
.evaluate()
.replace('${SOURCE}', 'Freesound.org')
+ '\n'
'\n' + freesound_names + '\n'
'\n'
' '
+ bui.Lstr(
resource=f'{self._r}.languageTranslationsText'
).evaluate()
+ '\n'
'\n'
+ '\n'.join(translation_names.splitlines()[:146])
+ '\n'.join(translation_names.splitlines()[146:])
+ '\n'
'\n'
' Shout Out to Awesome Mods / Modders / Contributors:\n\n'
' BombDash ModPack\n'
' TheMikirog & SoK - BombSquad Joyride Modpack\n'
' Mrmaxmeier - BombSquad-Community-Mod-Manager\n'
' Ritiek Malhotra \n'
' Dliwk\n'
' vishal332008\n'
' itsre3\n'
' Drooopyyy\n'
'\n'
' Holiday theme vector art designed by Freepik\n'
'\n'
' '
+ bui.Lstr(resource=f'{self._r}.specialThanksText').evaluate()
+ '\n'
'\n'
' Todd, Laura, and Robert Froemling\n'
' '
+ bui.Lstr(resource=f'{self._r}.allMyFamilyText')
.evaluate()
.replace('\n', '\n ')
+ '\n'
' '
+ bui.Lstr(
resource=f'{self._r}.whoeverInventedCoffeeText'
).evaluate()
+ '\n'
'\n'
' ' + bui.Lstr(resource=f'{self._r}.legalText').evaluate() + '\n'
'\n'
' '
+ bui.Lstr(resource=f'{self._r}.softwareBasedOnText')
.evaluate()
.replace('${NAME}', 'the Khronos Group')
+ '\n'
'\n'
' '
' www.ballistica.net\n'
)
txt = credits_text
lines = txt.splitlines()
line_height = 20
scale = 0.55
self._sub_width = width - 80
self._sub_height = line_height * len(lines) + 40
container = self._subcontainer = bui.containerwidget(
parent=scroll,
size=(self._sub_width, self._sub_height),
background=False,
claims_left_right=False,
claims_tab=False,
)
voffs = 0
for line in lines:
bui.textwidget(
parent=container,
padding=4,
color=(0.7, 0.9, 0.7, 1.0),
scale=scale,
flatness=1.0,
size=(0, 0),
position=(0, self._sub_height - 20 + voffs),
h_align='left',
v_align='top',
text=bui.Lstr(value=line),
)
voffs -= line_height
[docs]
@override
def get_main_window_state(self) -> bui.MainWindowState:
# Support recreating our window for back/refresh purposes.
cls = type(self)
return bui.BasicMainWindowState(
create_call=lambda transition, origin_widget: cls(
transition=transition, origin_widget=origin_widget
)
)