1 from logging
import info
, debug
2 from sys
import platform
, exit
3 from os
import environ
, system
5 from importlib
import import_module
6 from inspect
import isclass
7 from webbrowser
import open_new_tab
8 from panda3d
.core
import Texture
, TextNode
, WindowProperties
, LVector2i
, \
9 TextProperties
, TextPropertiesManager
10 from direct
.gui
.DirectGui
import DirectButton
, DirectCheckButton
, \
11 DirectOptionMenu
, DirectSlider
, DirectCheckButton
12 from direct
.gui
.DirectGuiGlobals
import FLAT
13 from direct
.gui
.OnscreenText
import OnscreenText
14 from lib
.engine
.gui
.cursor
import MouseCursor
15 from game
.scene
import Scene
16 from panda3d
.bullet
import BulletWorld
21 def __init__(self
, fsm
, lang_mgr
, opt_file
, music
, pipeline
, scenes
):
23 self
._lang
_mgr
= lang_mgr
24 self
._opt
_file
= opt_file
26 self
._pipeline
= pipeline
28 self
._cursor
= MouseCursor(
29 'assets/images/buttons/arrowUpLeft.dds', (.04, 1, .04), (.5, .5, .5, 1),
31 self
._font
= base
.loader
.load_font('assets/fonts/Hanken-Book.ttf')
33 self
._font
.set_pixels_per_unit(60)
34 self
._font
.set_minfilter(Texture
.FTLinearMipmapLinear
)
35 self
._font
.set_outline((0, 0, 0, 1), .8, .2)
39 'text_font': self
._font
,
40 'text_fg': (.9, .9, .9, 1),
42 'frameColor': (.4, .4, .4, .14),
43 'rolloverSound': loader
.load_sfx('assets/audio/sfx/rollover.ogg'),
44 'clickSound': loader
.load_sfx('assets/audio/sfx/click.ogg')}
45 self
._common
_btn
= {'frameSize': (-4.8, 4.8, -.6, 1.2)} | self
._common
46 hlc
= self
._common
_btn
['frameColor']
47 hlc
= (hlc
[0] + .2, hlc
[1] + .2, hlc
[2] + .2, hlc
[3] + .2)
49 'item_frameColor': self
._common
_btn
['frameColor'],
50 'popupMarker_frameColor': self
._common
_btn
['frameColor'],
51 'item_relief': self
._common
_btn
['relief'],
52 'item_text_font': self
._common
_btn
['text_font'],
53 'item_text_fg': self
._common
_btn
['text_fg'],
55 'highlightColor': hlc
,
56 'text_align': TextNode
.A_center
,
58 f_s
= self
._common
_opt
['frameSize']
59 self
._common
_opt
['frameSize'] = f_s
[0], f_s
[1] - .56, f_s
[2], f_s
[3]
60 self
._common
_slider
= self
._common |
{
62 'thumb_frameColor': (.4, .4, .4, .4),
65 del self
._common
_slider
['rolloverSound']
66 del self
._common
_slider
['clickSound']
71 self
._widgets
+= [DirectButton(
72 text
=_('Play'), pos
=(0, 1, .6), command
=self
.on_play
,
74 self
._widgets
+= [DirectButton(
75 text
=_('Options'), pos
=(0, 1, .2), command
=self
.on_options
,
77 self
._widgets
+= [DirectButton(
78 text
=_('Credits'), pos
=(0, 1, -.2), command
=self
.on_credits
,
80 self
._widgets
+= [DirectButton(
81 text
=_('Exit'), pos
=(0, 1, -.6), command
=lambda: exit(),
83 self
._rearrange
_width
()
85 def _set_options(self
):
87 self
._lang
_funcs
= [lambda: _('English'), lambda: _('Italian')]
88 items
= [fnc() for fnc
in self
._lang
_funcs
]
92 }[self
._opt
_file
['settings']['language']]
93 btn
= DirectOptionMenu(
94 text
=_('Language'), items
=items
, initialitem
=inititem
,
95 pos
=(0, 1, .8), command
=self
.on_language
, **self
._common
_opt
)
96 btn
.popupMenu
['frameColor'] = self
._common
_btn
['frameColor']
97 btn
.popupMenu
['relief'] = self
._common
_btn
['relief']
98 self
._widgets
+= [btn
]
99 self
._widgets
+= [OnscreenText(
100 _('Volume'), pos
=(-.1, .55), font
=self
._common
['text_font'],
101 scale
=self
._common
['scale'], fg
=self
._common
['text_fg'],
102 align
=TextNode
.A_right
)]
103 self
._widgets
+= [DirectSlider(
105 value
=self
._opt
_file
['settings']['volume'],
106 command
=self
.on_volume
,
107 **self
._common
_slider
)]
108 self
._slider
= self
._widgets
[-1]
109 self
._widgets
+= [DirectCheckButton(
110 text
=_('Fullscreen'), pos
=(0, 1, .3), command
=self
.on_fullscreen
,
111 indicator_frameColor
=self
._common
_opt
['highlightColor'],
112 indicator_relief
=self
._common
_btn
['relief'],
113 indicatorValue
=self
._opt
_file
['settings']['fullscreen'],
115 res
= self
._opt
_file
['settings']['resolution']
116 d_i
= base
.pipe
.get_display_information()
118 return d_i
.get_display_mode_width(idx
), \
119 d_i
.get_display_mode_height(idx
)
121 _res(idx
) for idx
in range(d_i
.get_total_display_modes())]
122 resolutions
= list(set(resolutions
))
123 resolutions
= sorted(resolutions
)
124 resolutions
= [(str(_res
[0]), str(_res
[1])) for _res
in resolutions
]
125 resolutions
= ['x'.join(_res
) for _res
in resolutions
]
127 res
= resolutions
[-1]
128 btn
= DirectOptionMenu(
129 text
=_('Resolution'), items
=resolutions
, initialitem
=res
,
130 pos
=(0, 1, .05), command
=self
.on_resolution
, **self
._common
_opt
)
131 btn
.popupMenu
['frameColor'] = self
._common
_btn
['frameColor']
132 btn
.popupMenu
['relief'] = self
._common
_btn
['relief']
133 self
._widgets
+= [btn
]
134 self
._widgets
+= [DirectCheckButton(
135 text
=_('Antialiasing'), pos
=(0, 1, -.2), command
=self
.on_aa
,
136 indicator_frameColor
=self
._common
_opt
['highlightColor'],
137 indicator_relief
=self
._common
_btn
['relief'],
138 indicatorValue
=self
._opt
_file
['settings']['antialiasing'],
140 self
._widgets
+= [DirectCheckButton(
141 text
=_('Shadows'), pos
=(0, 1, -.45), command
=self
.on_shadows
,
142 indicator_frameColor
=self
._common
_opt
['highlightColor'],
143 indicator_relief
=self
._common
_btn
['relief'],
144 indicatorValue
=self
._opt
_file
['settings']['shadows'],
146 self
._widgets
+= [DirectButton(
147 text
=_('Back'), pos
=(0, 1, -.8), command
=self
.on_back
,
150 def _set_credits(self
):
152 tp_scale
= TextProperties()
153 tp_scale
.set_text_scale(.64)
154 TextPropertiesManager
.getGlobalPtr().setProperties('scale', tp_scale
)
155 self
._widgets
+= [OnscreenText(
156 _('Code and gfx\n \1scale\1Flavio Calva\2\n\n\nMusic\n \1scale\1Stefan Grossmann\2'),
157 pos
=(-.9, .55), font
=self
._common
['text_font'],
158 scale
=self
._common
['scale'], fg
=self
._common
['text_fg'],
159 align
=TextNode
.A_left
)]
160 self
._widgets
+= [DirectButton(
161 text
=_('Website'), pos
=(-.6, 1, .29), command
=self
.on_website
,
162 **self
._common
_btn |
{'scale': .08})]
163 self
._widgets
+= [OnscreenText(
164 _('Special thanks to:\n \1scale\1rdb\2\n \1scale\1Luisa Tenuta\2\n \1scale\1Damiana Ercolani\2'),
165 pos
=(.1, .55), font
=self
._common
['text_font'],
166 scale
=self
._common
['scale'], fg
=self
._common
['text_fg'],
167 align
=TextNode
.A_left
)]
168 self
._widgets
+= [DirectButton(
169 text
=_('Back'), pos
=(0, 1, -.8), command
=self
.on_back
,
174 self
._cursor
= MouseCursor(
175 'assets/images/buttons/arrowUpLeft.dds', (.04, 1, .04), (.5, .5, .5, 1),
178 cmn
= self
._common
_btn
.copy() |
{
179 'frameSize': (-2.4, 2.4, -2.4, 2.4),
180 'frameColor': (1, 1, 1, .8),
182 left
= - (dx
:= .8) * (min(4, len(self
._scenes
)) - 1) / 2
183 for i
, cls
in enumerate(self
._scenes
):
184 top
= .1 if len(self
._scenes
) < 5 else .6
185 row
= 0 if i
< 4 else 1
186 self
._widgets
+= [DirectButton(
187 text
=cls
.name(), pos
=(left
+ dx
* (i
% 4), 1, top
- dx
* row
),
188 command
=self
.start
, extraArgs
=[cls
], text_wordwrap
=6,
189 frameTexture
='assets/images/scenes/%s.dds' % cls
.__name
__,
192 tnode
= self
._widgets
[-1].component('text%s' % j
).textNode
193 height
= - tnode
.getLineHeight() / 2
194 height
+= (tnode
.get_height() - tnode
.get_line_height()) / 2
195 self
._widgets
[-1].component('text%s' % j
).set_pos(0, 0, height
)
196 self
._widgets
+= [DirectButton(
197 text
=_('Back'), pos
=(0, 1, -.8), command
=self
.on_back
,
200 def start(self
, cls
):
201 self
._fsm
.demand('Scene', cls
)
203 def on_options(self
):
205 self
._cursor
= MouseCursor(
206 'assets/images/buttons/arrowUpLeft.dds', (.04, 1, .04), (.5, .5, .5, 1),
210 def on_credits(self
):
212 self
._cursor
= MouseCursor(
213 'assets/images/buttons/arrowUpLeft.dds', (.04, 1, .04), (.5, .5, .5, 1),
217 def _rearrange_width(self
):
219 for wdg
in self
._widgets
:
220 t_n
= wdg
.component('text0')
221 u_l
= t_n
.textNode
.get_upper_left_3d()
222 l_r
= t_n
.textNode
.get_lower_right_3d()
223 max_width
= max(l_r
[0] - u_l
[0], max_width
)
224 for wdg
in self
._widgets
:
225 m_w
= max_width
/ 2 + .8
226 wdg
['frameSize'] = -m_w
, m_w
, wdg
['frameSize'][2], wdg
['frameSize'][3]
228 def on_language(self
, arg
):
230 _('English'): 'en_EN',
231 _('Italian'): 'it_IT'}[arg
]
232 self
._lang
_mgr
.set_lang(lang_code
)
233 self
._opt
_file
['settings']['language'] = lang_code
[:2]
234 self
._opt
_file
.store()
238 self
._opt
_file
['settings']['volume'] = self
._slider
['value']
239 self
._music
.set_volume(self
._slider
['value'])
241 def on_fullscreen(self
, arg
):
242 props
= WindowProperties()
243 props
.set_fullscreen(arg
)
244 base
.win
.request_properties(props
)
245 self
._opt
_file
['settings']['fullscreen'] = int(arg
)
246 self
._opt
_file
.store()
248 def on_resolution(self
, arg
):
249 props
= WindowProperties()
250 props
.set_size(LVector2i(*[int(_res
) for _res
in arg
.split('x')]))
251 base
.win
.request_properties(props
)
252 self
._opt
_file
['settings']['resolution'] = arg
253 self
._opt
_file
.store()
255 def on_aa(self
, arg
):
256 self
._pipeline
.msaa_samples
= 4 if arg
else 1
257 debug(f
'msaa: {self._pipeline.msaa_samples}')
258 self
._opt
_file
['settings']['antialiasing'] = int(arg
)
259 self
._opt
_file
.store()
261 def on_shadows(self
, arg
):
262 self
._pipeline
.enable_shadows
= int(arg
)
263 debug(f
'shadows: {self._pipeline.enable_shadows}')
264 self
._opt
_file
['settings']['shadows'] = int(arg
)
265 self
._opt
_file
.store()
267 def on_website(self
):
268 if platform
.startswith('linux'):
269 environ
['LD_LIBRARY_PATH'] = ''
270 system('xdg-open https://www.ya2.it')
272 open_new_tab('https://www.ya2.it')
275 self
._opt
_file
.store()
277 self
._cursor
= MouseCursor(
278 'assets/images/buttons/arrowUpLeft.dds', (.04, 1, .04), (.5, .5, .5, 1),
283 [wdg
.destroy() for wdg
in self
._widgets
]
284 self
._cursor
.destroy()