Journal System for RenPy Games (& Python in Screen Language)

Discuss how to use the Ren'Py engine to create visual novels and story-based games. New releases are announced in this section.
Forum rules
This is the right place for Ren'Py help. Please ask one question per thread, use a descriptive subject like 'NotFound error in option.rpy' , and include all the relevant information - especially any relevant code and traceback messages. Use the code tag to format scripts.
Message
Author
SvenTheViking
Regular
Posts: 65
Joined: Thu Dec 29, 2011 4:19 am
Projects: Chronicles of the Timetraveler's Wars
Organization: ProgMan Productions; Polymorphic Games
Location: Oregon
Contact:

Journal System for RenPy Games (& Python in Screen Language)

#1 Post by SvenTheViking »

As the title says, I need to handle python and text lists in a screen. Not to have python called when the screen is called, but to have python called during the course of working the screen. Why? Many reasons. Right now, I'm attempting to make a journal system in which each entry is on its own page, but I don't want to write a custom screen for each entry, as that's a pain and far more complicated than it should be. A few days ago, it was to do "style.rebuild()" from within a menu, so when you changed an option, it rebuilt the style, allowing you to change the image of the textbox.

This is a critical, vital thing to be able to do for any level of advanced manipulation of the game, and it seems to be missing. I've checked the wiki and searched the forums, and I can't find any way to do it. What I'd REALLY like is to be able to do inline python with the screen's "action" statement. That is to say...

Code: Select all

textbutton _("Previous") action $ current_journal_page -= 1
Logically, when you press the "Previous" button, it would decrement the counter variable "current_journal_page", allowing this code to draw the previous string in the list:

Code: Select all

label (journal_entries[current_journal_page])
Now, when I try that (assuming everything is properly defined, which it is), it gives me errors:

Code: Select all

File "game/screens.rpy", line 673: expected 'simple_expression' not found.
    textbutton _("Previous") action $ current_journal_page -= 1
Has anyone found a work-around to either of these problems? It's all pretty standard stuff to want to do, I'd think, but that may well be because I have a rather advanced background in programming.

Oh, and the reason I'm not putting up all my code is because I don't particularly feel like having someone dissect it and give me something functional. I want answers to my question, not a solution to my problem in the form of an alternate way of doing a journal screen. That will come later if I still can't figure it out.

EDIT: The text list bit was a SNAFU on my part (using parentheses instead of square bracket quotes).

EDIT2: Go here (it's one of the subsequent posts in this thread) for the code to make the journal work.
Last edited by SvenTheViking on Fri Mar 16, 2012 8:25 pm, edited 1 time in total.
"Be not afraid of greatness: some men are born great, some achieve greatness, and some have greatness thrust upon them."
William Shakespeare, "Twelfth Night"

Anima
Veteran
Posts: 448
Joined: Wed Nov 18, 2009 11:17 am
Completed: Loren
Projects: PS2
Location: Germany
Contact:

Re: Python and Text Lists in Screen Language

#2 Post by Anima »

Code: Select all

textbutton _("Previous") action $ current_journal_page -= 1
This does not work. The action keyword needs a callable object, it does not process a Ren'Py line.
So you need to wrap this up in a function and supply it without arguments to the buttons action keyword.

Or you could use the predefined: SetVariable(variable, value) action
Avatar created with this deviation by Crysa
Currently working on:
  • Winterwolves "Planet Stronghold 2" - RPG Framework: Phase III

SvenTheViking
Regular
Posts: 65
Joined: Thu Dec 29, 2011 4:19 am
Projects: Chronicles of the Timetraveler's Wars
Organization: ProgMan Productions; Polymorphic Games
Location: Oregon
Contact:

Re: Python and Text Lists in Screen Language

#3 Post by SvenTheViking »

Anima wrote:

Code: Select all

textbutton _("Previous") action $ current_journal_page -= 1
This does not work. The action keyword needs a callable object, it does not process a Ren'Py line.
So you need to wrap this up in a function and supply it without arguments to the buttons action keyword.
I've tried wrapping code within functions, but it seemed as though to disable the button. Upon later testing, I now realize, the same result can be obtained by using "action False", so perhaps I need my function to return a value which can be recognized as true (as in, not "return 0", which is standard in most languages).
Anima wrote:Or you could use the predefined: SetVariable(variable, value) action
I may well go with this, as somehow I managed to forget overnight that this existed (I was working with it last night for the textbox scenario I talked about), if I can't get python functions to work the way I expect they should.

Thanks for the help, Anima.

EDIT:
I have found an important piece of information! When you use "action Start()", it calls this code (taken from the "renpy-(version)/common/00screen.rpy" file):

Code: Select all

class Start(Action):
        """
         :doc: menu_action
         
         Causes Ren'Py to jump out of the menu context to the named
         label. The main use of this is to start a new game from the
         main menu. Common uses are:

         * Start() - Start at the start label.
         * Start("foo") - Start at the "foo" label.
         """
        
        def __init__(self, label="start"):
            self.label = label

        def __call__(self):
            renpy.jump_out_of_context(self.label)
With this as a base, I wrote this code:

Code: Select all

    class decrementJournal():
        def __call__(self):
            global current_journal_page
            current_journal_page -= 1
            style.rebuild()
Which does work as intended. Now I'm hit with the problem of having to be able to reload the screen. Back to work.
"Be not afraid of greatness: some men are born great, some achieve greatness, and some have greatness thrust upon them."
William Shakespeare, "Twelfth Night"

User avatar
PyTom
Ren'Py Creator
Posts: 16088
Joined: Mon Feb 02, 2004 10:58 am
Completed: Moonlight Walks
Projects: Ren'Py
IRC Nick: renpytom
Github: renpytom
itch: renpytom
Location: Kings Park, NY
Contact:

Re: Python and Text Lists in Screen Language

#4 Post by PyTom »

Reload the screen? Do you want renpy.restart_interaction() ?
Supporting creators since 2004
(When was the last time you backed up your game?)
"Do good work." - Virgil Ivan "Gus" Grissom
Software > Drama • https://www.patreon.com/renpytom

SvenTheViking
Regular
Posts: 65
Joined: Thu Dec 29, 2011 4:19 am
Projects: Chronicles of the Timetraveler's Wars
Organization: ProgMan Productions; Polymorphic Games
Location: Oregon
Contact:

Re: Python and Text Lists in Screen Language

#5 Post by SvenTheViking »

PyTom wrote:Reload the screen? Do you want renpy.restart_interaction() ?
Actually, that does exactly what I want it to do. And now everything works. Thanks again, Tom and Anima.

Here's the full code that I've been working on for the past few days, for future reference (in the event that you are doing your due diligence and find this by way of either the forum search or Google and it proves helpful, you're welcome; I hate it when people say they find a solution but don't tell what it was). You're welcome to use it and modify it and do whatever you want with it, but I'd appreciate a thank-you or some such note (no need to put me in the credits or anything, but you can if you like; I certainly won't stop you). Let me know if there are any problems and I'll fix them (I might have missed a variable somewhere).

First, put this in your navigation menu so you can access the Status screen:

Code: Select all

textbutton _("Information") action ShowMenu("stats")
Next, put this into journal.rpy (which has to be in your game's game directory, of course):

Code: Select all

##############################################################################
## Variables and Functions
##
## This block of code contains all of the variables and functions required to
## get the screens to work.

init -2 python:
    #### Sofie(my MC)'s health
    ## Change this to whatever your character is named.
    sofie_health = 90
    #### Her sanity
    sofie_sanity = 100
    #### The date in the game
    ## Made an empty string at the beginning because you
    ## haven't yet started the game, and so you're not anywhere.
    date_ref = ""
    #### The time reference in the game
    ## For this, I usually use 3-hour chunks, unless I need
    ## something a bit more specific for a certain part.
    time_ref = ""
    #### Your current location in the game
    loc_ref = ""
    #### The curent page of the journal
    current_journal_page = 0
    #### The number of journal pages which can be accessed
    ## You'll want to increment this variable as you go, every time
    ## you hit a point where the player should have access to the next
    ## journal entry, which are pre-defined below.  As this is set to 3,
    ## you can access all the pages I have put into the list below.
    ######## WARNING! ########
    ## If you make this higher than the number of journal pages defined
    ## in the list below, it'll spit you out an error when you try to
    ## access a part of the list which doesn't exist.  If it's giving you
    ## a problem of it being outside the bounds of the array, that's what
    ## you did wrong.
    unlocked_journal_pages = 3
    #### The contents of the journal pages
    ## This is a list of the contents of the journal pages.  The first
    ## item in the list, in this case "X", is in position 0, so your
    ## current journal page, which is set to zero, points to this location.
    ## For the sake of easy programming, define all of your journal pages
    ## before-hand.  Otherwise, you have to deal with inserting them and
    ## nonesense like that, which is sort of painful until you get the
    ## hang of doing it.
    journal_entries = list([
        "X",
        "Y",
        "Z"
        ])
    
    #### The increment function
    ## This is what you put after your "action" keyword
    class incrementJournal():
        ## This defines what happens when the class is called
        ## (as in, when you click the button)
        def __call__(self):
            ## Gotta use the "global" keyword to use any variable
            ## outside your function, as it's a quirk of Python 
            global current_journal_page
            ## Increment the counter variable which keeps track of
            ## which journal page is currently active
            current_journal_page += 1
            ## Restart the interaction to refresh your screen
            renpy.restart_interaction()
        
    #### The decrement function
    ## Exactly the same as above, only you decrement the
    ## counter variable, instead of incrementing it.
    class decrementJournal():
        def __call__(self):
            global current_journal_page
            current_journal_page -= 1
            renpy.restart_interaction()
        
    #### The void function
    ## A void function that I like to use to block out buttons
    def void():
        ## Do something that won't affect the rest of the game
        DummyVariable = 0
        
##############################################################################
# Stats and Info
#
# Displays current statistics and vital information, like the date and time.
    
screen stats:
    ## Replace any other menu that's currently open.
    tag menu
    ## Use the navigation menu (the one you see when you open
    ## the preferences window and such).
    use navigation
    ## This is more or less code I adapted from the preferences
    ## menu, so I'm not 100% certain why it works, I just know that it does.
    hbox:
        xmaximum 250
        vbox:
            ## Creates a box with the label "Vitals", to indicate
            ## that this is the section which shows Sofie's vitals,
            ## which were defined above.
            frame:
                style_group "pref"
                has vbox
                label _("Vitals")
            frame:
                style_group "pref"
                has vbox
                label _("Health")
                ## "bar" creates a bar, "value" sets it current value,
                ## and "range" sets the maximum value, resulting in a
                ## bar which is the ratio between the value and the range.
                bar value sofie_health range 100
            frame:
                style_group "pref"
                has vbox
                label _("Sanity")
                bar value sofie_sanity range 100
    hbox:
        xpos 250
        xmaximum 550
        vbox:
            frame:
                style_group "pref"
                has vbox
                label _("Information")
            ## This is where we use the date, time, and location informatin
            ## we specified earlier (and which we change later on to reflect)
            ## the goings-on of the game.
            frame:
                style_group "pref"
                has vbox
                label _("Date: [date_ref]")
                label _("Reference time: [time_ref]")
                label _("Location: [loc_ref]")
            ## This is the button that brings us to our journal page.
            frame:
                style_group "pref"
                has vbox
                textbutton _("Journal") action ShowMenu("notes_screen")

init -2 python:
    style.pref_frame.xfill = True
    style.pref_frame.xmargin = 5
    style.pref_frame.top_margin = 5

    style.pref_vbox.xfill = True

    style.pref_button.size_group = "pref"
    style.pref_button.xalign = 1.0

    style.pref_slider.xmaximum = 192
    style.pref_slider.xalign = 1.0

    style.soundtest_button.xalign = 1.0


##############################################################################
# Notes
#
# Displays the log of notes.
    
screen notes_screen:
    tag menu
    use navigation
    vbox:
        xminimum 620
        xmaximum 620
        frame:
            yminimum 593
            ymaximum 593
            style_group "pref"
            has vbox
            ## This is where we display the currently-selected page of
            ## the journal, prefaced by the label "Notes:".
            label _("Notes:")
            label (journal_entries[current_journal_page])
    vbox:
        xpos 607
        xmaximum 140
        frame:
            style_group "pref"
            has vbox
            ## This is the control of the journal page.
            label _("Page Nav")
            ## If the currently-selected page is less than the total number
            ## of pages (minus one, as the first item in the list is at
            ## location 0, instead of location 1), make the button increment
            ## the journal page when pressed.
            if current_journal_page < (unlocked_journal_pages - 1):
                textbutton _("Next") action incrementJournal()
            ## Otherwise, disable the button.
            else:
                textbutton _("Next") action void()
            ## Like above, only as long as we're not on the first page
            ## (location 0 in the list), allow the player to move back a page.
            if current_journal_page >= 1:
                textbutton _("Previous") action decrementJournal()
            else:
                textbutton _("Previous") action void()

init -2 python:
    style.pref_frame.xfill = True
    style.pref_frame.xmargin = 5
    style.pref_frame.top_margin = 5

    style.pref_vbox.xfill = True

    style.pref_button.size_group = "pref"
    style.pref_button.xalign = 1.0

    style.pref_slider.xmaximum = 192
    style.pref_slider.xalign = 1.0

    style.soundtest_button.xalign = 1.0
"Be not afraid of greatness: some men are born great, some achieve greatness, and some have greatness thrust upon them."
William Shakespeare, "Twelfth Night"

vociferocity
Regular
Posts: 93
Joined: Sat Jun 12, 2010 11:27 am
Projects: Rogue of Heart, Valkyrie
Contact:

Re: Journal System for RenPy Games (& Python in Screen Langu

#6 Post by vociferocity »

this was a really valuable thread for me to read though! I've definitely learned some really useful tricks today (time to go make my own vn's code cleaner haha)

DerWille
Regular
Posts: 26
Joined: Sun Jul 10, 2011 7:30 pm
Contact:

Re: Journal System for RenPy Games (& Python in Screen Langu

#7 Post by DerWille »

I think I'm stuck on the same sort of issue that you were and I want to double check that we both could use the same solution. I'll throw the problem back at you.

Problem: You were trying to find a way to change what a portion of a screen displays based on whether the player presses "next" or "previous".

Solution: You created separate classes for increment and decrement that have a single function, __call__( self ), that increments or decrements a global variable then restarts then restarts the interaction and rebuilds the screen with renpy.restart_interaction().

If I'm understanding this right, then by creating separate... function classes, I'll call them, to call different lists of effects. For example, this would also be the solution to having a tabbed inventory (what I've been trying to figure out). So if a player were to click on "weapons" it would display weapons, but if they clicked on "armor" it would display armor.

I could do this by having an "armorTab" and "weaponTab" class, with a __call__( self ) that changes a global variable that controls which of my lists display then restart the interaction.

SvenTheViking
Regular
Posts: 65
Joined: Thu Dec 29, 2011 4:19 am
Projects: Chronicles of the Timetraveler's Wars
Organization: ProgMan Productions; Polymorphic Games
Location: Oregon
Contact:

Re: Journal System for RenPy Games (& Python in Screen Langu

#8 Post by SvenTheViking »

@DerWille Sorry about taking so long to reply. If you're just doing text and buttons and such to do your inventory system, then yes, for purposes of selecting which item set to use, it would work. Just replace my function classes (an apt name, as they're classes, but they do the job a normal function would in any other language), which increment and decrement, with ones which give the variable a hard value.

@vociferocity I'm glad you learned something. And remember, everyone, you have two options to make your code clean and to make sure you understand it in the future: Descriptive variable names, and comments. Use both, unless you're like me and can't stand having comments in your code because it makes it so much longer.
"Be not afraid of greatness: some men are born great, some achieve greatness, and some have greatness thrust upon them."
William Shakespeare, "Twelfth Night"

vociferocity
Regular
Posts: 93
Joined: Sat Jun 12, 2010 11:27 am
Projects: Rogue of Heart, Valkyrie
Contact:

Re: Journal System for RenPy Games (& Python in Screen Langu

#9 Post by vociferocity »

oh by cleaner I mostly meant this way is less complicated and roundabout than the way I have it working atm, I'm pretty good at keeping to my own code standard for descriptive variable names and comments.

I do have one question...with this way, is it at all possible for the functions you're calling in screen language to have a parameter? it wouldn't let me pass anything in, when I tried last

DerWille
Regular
Posts: 26
Joined: Sun Jul 10, 2011 7:30 pm
Contact:

Re: Journal System for RenPy Games (& Python in Screen Langu

#10 Post by DerWille »

No worries about the late reply. I've been called into work constantly the last few days so it's been hard to get a good amount of time to sit down and program.

It was able to get a tabbed inventory system up and running with very little effort.

TrickWithAKnife
Eileen-Class Veteran
Posts: 1261
Joined: Fri Mar 16, 2012 11:38 am
Projects: Rika
Organization: Solo (for now)
IRC Nick: Trick
Location: Tokyo, Japan
Contact:

Re: Journal System for RenPy Games (& Python in Screen Langu

#11 Post by TrickWithAKnife »

Awesome topic, and awesome example code.

I do have a question though. Is there any way to use functions or display variables on the journal pages?
I tried playing around with no success. At the moment it seems that each journal page can just display 1 quoted group of text.

What I'm trying to do is set up a journal with a changing number of pages, that shows or hides whatever text I choose, depending on the game progress. For example, Page one might look like this:
ABC
HIJ
QRS
then further in the game the page may look more like this:
ABC
DEF
HIJ
KLM
NOP
QRS
Last edited by TrickWithAKnife on Sat Mar 24, 2012 12:08 pm, edited 1 time in total.
"We must teach them through the tools with which they are comfortable."
The #renpy IRC channel is a great place to chat with other devs. Due to the nature of IRC and timezone differences, people probably won't reply right away.

If you'd like to view or use any code from my VN PM me. All code is freely available without restriction, but also without warranty or (much) support.

User avatar
saguaro
Miko-Class Veteran
Posts: 560
Joined: Sun Feb 12, 2012 9:17 am
Completed: Locked-In, Sunrise, The Censor
Organization: Lucky Special Games
itch: saguarofoo
Location: USA
Contact:

Re: Journal System for RenPy Games (& Python in Screen Langu

#12 Post by saguaro »

I just got a chance to play around with this code (awesome example, by the way) and I'm wondering the same thing.

Anima
Veteran
Posts: 448
Joined: Wed Nov 18, 2009 11:17 am
Completed: Loren
Projects: PS2
Location: Germany
Contact:

Re: Journal System for RenPy Games (& Python in Screen Langu

#13 Post by Anima »

vociferocity wrote:oh by cleaner I mostly meant this way is less complicated and roundabout than the way I have it working atm, I'm pretty good at keeping to my own code standard for descriptive variable names and comments.

I do have one question...with this way, is it at all possible for the functions you're calling in screen language to have a parameter? it wouldn't let me pass anything in, when I tried last
You do it like this:

Code: Select all

class testingAction(Action):
        def __init__(self, pInt):
            self.int = pInt
        
        def __call__(self):
            return self.int
Avatar created with this deviation by Crysa
Currently working on:
  • Winterwolves "Planet Stronghold 2" - RPG Framework: Phase III

User avatar
saguaro
Miko-Class Veteran
Posts: 560
Joined: Sun Feb 12, 2012 9:17 am
Completed: Locked-In, Sunrise, The Censor
Organization: Lucky Special Games
itch: saguarofoo
Location: USA
Contact:

Re: Journal System for RenPy Games (& Python in Screen Langu

#14 Post by saguaro »

TrickWithAKnife wrote:I do have a question though. Is there any way to use functions or display variables on the journal pages?
I just realized you can update the pages by inserting blank variables in the list that can be updated later.

Code: Select all

    journal_entries = list([
        "X [part1] [part2] [part3]",
        "Y",
        "Z"
        ])
Just define part1, part2, etc. as " " in the start label, then update part1 with the text you want to add at the appropriate point in the game. Kinda MacGuyver but it does the trick.

TrickWithAKnife
Eileen-Class Veteran
Posts: 1261
Joined: Fri Mar 16, 2012 11:38 am
Projects: Rika
Organization: Solo (for now)
IRC Nick: Trick
Location: Tokyo, Japan
Contact:

Re: Journal System for RenPy Games (& Python in Screen Langu

#15 Post by TrickWithAKnife »

Thanks, but when I try this I get an error message saying that string indices should be integers, not strings.
This is what I added:

Code: Select all

    global part1
    part1 = "blah"
    global part2
    part2 = "bleh"
    global part3
    part3 = "bleugh"
    
    journal_entries = list([
        "X" [part1] [part2] [part3], 
        "x2", 
        "Y",
        "Z"
        ])
"We must teach them through the tools with which they are comfortable."
The #renpy IRC channel is a great place to chat with other devs. Due to the nature of IRC and timezone differences, people probably won't reply right away.

If you'd like to view or use any code from my VN PM me. All code is freely available without restriction, but also without warranty or (much) support.

Post Reply

Who is online

Users browsing this forum: No registered users