*sigh* I provided the link for a reason... Following it and reading what is said would have answered your question:
"
_update_screens
When true, the interaction restarts and the screens are updated after the function returns."
Because a screen action do way more than just performing an action. Once again something that you would have been able to understand by yourself by just following the link I provided.
Why the hell would they all be a function?
There's variables, like
renpy.version_name, modules, like
renpy.display, namespace, like
renpy.sound, as well as classes, like
renpy.Render().
your code:
Python:
$track = renpy.music.get_playing(channel='music')
#write the full songname + artist:
if track == None:
$trackname = "No song"
elif track == "audio/abc.mp3":
$trackname = "ABC by XYZ"
[...]
else:
$trackname = "Unknown"
a basic code:
Python:
define audioTracks = { "None": "No song", "audio/abc.mp3": "ABC by Jackson Five", [...] }
screen phone():
[...]
# Since you only use /track/ for this it's not even needed.
$ trackname = audioTracks.get( renpy.music.get_playing(channel='music'), "Unknown" )
More precisely because PyTom is familiar with Python and used Python to build the engine. This permit to standardise the syntax and therefore to be easier to use as a whole.
Funnily it's not even necessary to call it when there's another function (and therefore
Function()) in the chain of actions. When put at the end of the chain, the "_uptade_screens" argument would replace it in a secure way.
Funny not funny that Ren'Py strength is also its flaw; it's to lenient with the syntax.
It's correct.
More globally, as said by the bit of doc that you quoted, it's not a good idea to use actual function in screens, whatever if it's as screen action or as inline python in the screen definition. And the same apply for computations that do not rely on purely local variables (declared throught the
default screen statement).
There's case where it can't be avoided, but there's always a possible side effect since the screen will be proceessed
(and therefore the function called) many time before the screen is shown
(due to the prediction feature), then more or less 5 times by seconds once the screen will be displayed.
So, to stay basic, something like
$ myVar += 1 would increase the value around ten times before the screen is displayed, then around 5 times every second as long as the screen will be displayed.
/!\ It's wrote on the fly and not tested, but this should works, or at least lead to the right direction. /!\
Python:
init python:
def getQueued( channel="music" ):
q = []
for atom in renpy.audio.audio.channels[channel].queue:
q.append( atom.filename )
return q
def shiftQueue( q, marker, before=True ):
while q[0] != marker:
q.append( q.pop( 0 ) )
if before:
q.insert( 0, q.pop() )
else:
q.append( q.pop( 0 ) )
return q
def prevSong( q, marker ):
renpy.music.queue( shiftQueue( q, marker, True ), clear_queue=True, loop=True )
def nextSong( q, marker ):
renpy.music.queue( shiftQueue( q, marker, False ), clear_queue=True, loop=True )
define audioTracks = { "None": "No song", "audio/abc.mp3": "ABC by Jackson Five", [...] }
#phone code reduced to the important bits
screen phone():
tag menu
modal True
$ trackname = audioTracks.get( renpy.music.get_playing(channel='music'), "Unknown" )
add "gui/phone.jpg"
imagebutton auto "gui/phone/return_%s.png":
xalign 0.5
yalign 0.8
focus_mask True
action [Return()]
text "Song: [trackname]":
xalign 0.5
yalign 0.9
$activesong = renpy.music.get_playing()
$ entirelist = getQueued()
imagebutton auto "gui/phone/previousmusic_%s.png":
xalign posbuttonprevious
yalign yposaudiobuttons
focus_mask True
# Only sensitive if not the first song of the queue
sensitive entirelist.index[activesong] != 0
action Function( prevSong, entirelist, activesong, _update_screens=True )
imagebutton auto "gui/phone/nextmusic_%s.png":
xalign posbuttonnext
yalign yposaudiobuttons
focus_mask True
# Only sensitive if not the last song of the queue
sensitive entirelist.index[activesong] != len( entirelist ) - 1
action Function( nextSong, entirelist, activesong, _update_screens=True )
Alright, I still don't fully grasp screens, functions and renpy but it's a good start, I believe.
I also understood what your code is trying to do and why it executes more elegantly.
It just doesn't work correctly when it comes to shiftQueue. The rest seems to be working nicely.
Taking your original code, I was able to open the phone screen. Clicking on the button however resulted in the game freezing. And no. Not the Ren'Py error screen. I'm talking about the game being stuck indefinetely and requiring a forced shutdown.
On further examination, I exchanged
Python:
action Function( nextSong, entirelist, activesong, _update_screens=True )
with
action Function( nextSong(entirelist, activesong), _update_screens=True )
it looked like the more correct syntax to me, is that right?
Either way, doing it this way ensures the game being frozen while trying to open the phone menu which would make sense if we consider Ren'Py's prediction trying to run every code on screen load-up.
The freeze indicated to me that the culprit is most likely the while clause in the shiftQueue function to rearrange the queue to start with the active song before shifting.
if I remove the while clause the game doesn't freeze anymore, just as expected, but this time returning a classic error-screen with "None-type" object is not callable which ultimately lets me believe that I still struggle to grasp how Ren'Py handles variables in screens, which is why I tried to further narrow it down and instead just run this phone screen without any buttons:
Python:
$activesong = renpy.music.get_playing()
$entirelist = getQueued()
$test = shiftQueue(entirelooplist, activesong, True)
text "Active: [activesong]":
xalign 0.5
yalign 0.1
text "entire list: [entirelist]":
xalign 0.5
yalign 0.4
text "test: [test]":
xalign 0.5
yalign 0.8
which put me into full confusion when i used a playlist with multiple songs and:
$renpy.random.shuffle(tracks1)
$renpy.music.queue(tracks1, loop = True)
in the script-file to play the list with 4 songs.
This screen shows on its labels:
active: audio/a.mp3
entirelist: ['audio/b.mp3', 'audio/c.mp3', 'audio/d.mp3']
test: ['audio/b.mp3', 'audio/c.mp3', 'audio/d.mp3']
with not only the actual active song missing but entirelist and test even being identical.
I assume the culprit for this is the fact that the while command was deleted by me...?
Then again: Why would entirelist be identical to test, though? Since entire list copies the filename with the getQueued command, it should also contain audio/a.mp3 right? I literally hear the song in the background.
Which lead me all to the conclusion that I still don't know shit about the way renpy handles variables in screens. There must be something fundamental that I'm misunderstanding, right?
Thank you all in advance for possible suggestions what I'm doing wrong.
EDIT: Oh wait. Could it be that the shiftQueue function edits entirelist? In that case the only mystery that remains is why the while clause doesn't work, right?
I'll look into it tomorrow.