Is it possible to access the default value of an array after it has changed?

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.
Post Reply
Message
Author
mdqp
Newbie
Posts: 24
Joined: Mon Dec 24, 2018 2:56 pm
Contact:

Is it possible to access the default value of an array after it has changed?

#1 Post by mdqp »

Specifically, I was wondering about updating an array between versions of a game. Let's say the default value for the array is [0,1,2] in version 0.1 and [0,1,2,3,4] in version 0.2. Is it possible to compare the saved array size with the new default one, and if they are different, appending the new values?

User avatar
m_from_space
Eileen-Class Veteran
Posts: 1057
Joined: Sun Feb 21, 2021 3:36 am
Contact:

Re: Is it possible to access the default value of an array after it has changed?

#2 Post by m_from_space »

Is the array constant over a game or does it change when the player progresses? (If it changes, you have to know what it could look like.)

You can always check for the current value of a variable after the player loads a game via the special label "after_load":

Code: Select all

# renpy jumps here after loading a game and before the game resumes
label after_load:
    if array == [0, 1, 2]:
        $ array = [0, 1, 2, 3, 4]
    return

mdqp
Newbie
Posts: 24
Joined: Mon Dec 24, 2018 2:56 pm
Contact:

Re: Is it possible to access the default value of an array after it has changed?

#3 Post by mdqp »

m_from_space wrote: Tue May 31, 2022 6:51 am Is the array constant over a game or does it change when the player progresses? (If it changes, you have to know what it could look like.)

You can always check for the current value of a variable after the player loads a game via the special label "after_load":

Code: Select all

# renpy jumps here after loading a game and before the game resumes
label after_load:
    if array == [0, 1, 2]:
        $ array = [0, 1, 2, 3, 4]
    return
I figured something like that would work, but I was hoping there would be a way to actually check the default value rather than copy the full array below the "after_load" label (I have a class for quests, and I keep them in an array to store info for a questlog, so it's going to become quite large as I add more quests to the game). It's not a big problem though, and if there is no way to directly check the default values, then a variant of this is perfectly fine, Thanks!

User avatar
m_from_space
Eileen-Class Veteran
Posts: 1057
Joined: Sun Feb 21, 2021 3:36 am
Contact:

Re: Is it possible to access the default value of an array after it has changed?

#4 Post by m_from_space »

mdqp wrote: Wed Jun 01, 2022 3:00 amI figured something like that would work, but I was hoping there would be a way to actually check the default value rather than copy the full array below the "after_load" label (I have a class for quests, and I keep them in an array to store info for a questlog, so it's going to become quite large as I add more quests to the game). It's not a big problem though, and if there is no way to directly check the default values, then a variant of this is perfectly fine, Thanks!
Well, you could easily just check for the length of the "array" (in this case actually called a list) or parts of its contents. And you could define a "new_array" and just keep the old default one.

Code: Select all

default array = [1, 2, 3]
default new_array = [1, 2, 3, 4, "newquest"]

label after_load:
    if len(array) == 3:
        $ array = new_array
    # or something like
    if "newquest" not in array:
        $ array = new_array

mdqp
Newbie
Posts: 24
Joined: Mon Dec 24, 2018 2:56 pm
Contact:

Re: Is it possible to access the default value of an array after it has changed?

#5 Post by mdqp »

m_from_space wrote: Wed Jun 01, 2022 5:35 amWell, you could easily just check for the length of the "array" (in this case actually called a list) or parts of its contents. And you could define a "new_array" and just keep the old default one.

Code: Select all

default array = [1, 2, 3]
default new_array = [1, 2, 3, 4, "newquest"]

label after_load:
    if len(array) == 3:
        $ array = new_array
    # or something like
    if "newquest" not in array:
        $ array = new_array
Oh, don't worry, I already have a solution pretty similar to the one you suggest. I don't like the idea of maintaining two copies of the same array (I still need to update the default value, and I define a copy to check against, now). It's hardly a big deal, and yes, I do check the length against the number of quests I have in the game (since that's a known quantity) and if there is a discrepancy I loop and add quests until everything is fine (I do this to avoid replacing the values in quests that are already in the game, since the player might have started those already).

I just wanted to know if I could access the default value, because it would have been "cleaner" to handle (I am always afraid to introduce some minor mistakes when I copy/paste something).

User avatar
zmook
Veteran
Posts: 421
Joined: Wed Aug 26, 2020 6:44 pm
Contact:

Re: Is it possible to access the default value of an array after it has changed?

#6 Post by zmook »

What is the array you have, and what changes do you want to make to it? There are a couple of possible answers:

1) If it's fixed content that doesn't change during play, just create it with 'define' instead of 'default'. Then it won't be written to the save file and when you update the code, you'll always have the up-to-date value, no "old versions" to worry about.
2) If you're just adding new content, you don't have to track what the old version was, just test if the new values are there, and if not, add them. This probably is easier if you have a dict rather than a list:

Code: Select all

label after_load:
    if not "new_quest_id" in all_quests.keys():
         all_quests["new_quest_id"] = new_quest_data()
You can always recover a list from a dict with

Code: Select all

quest_list = list(quest_dict.values())
colin r
➔ if you're an artist and need a bit of help coding your game, feel free to send me a PM

mdqp
Newbie
Posts: 24
Joined: Mon Dec 24, 2018 2:56 pm
Contact:

Re: Is it possible to access the default value of an array after it has changed?

#7 Post by mdqp »

zmook wrote: Wed Jun 01, 2022 12:39 pm What is the array you have, and what changes do you want to make to it? There are a couple of possible answers:

1) If it's fixed content that doesn't change during play, just create it with 'define' instead of 'default'. Then it won't be written to the save file and when you update the code, you'll always have the up-to-date value, no "old versions" to worry about.
2) If you're just adding new content, you don't have to track what the old version was, just test if the new values are there, and if not, add them. This probably is easier if you have a dict rather than a list:

Code: Select all

label after_load:
    if not "new_quest_id" in all_quests.keys():
         all_quests["new_quest_id"] = new_quest_data()
You can always recover a list from a dict with

Code: Select all

quest_list = list(quest_dict.values())
Really sorry for the late reply, I didn't check the forum in a while. The way I currently use the array, I also need to update some of the entries (for example, when an objective is visible, invisible, failed or completed), so I need to keep the data from old saves "as is" while adding new entries for new quests as I introduce them to the game (I make my money on Patreon, which means incremental updates each month).

To do this, I effectively have a second copy of the array I check under the after_load label.

Code: Select all

# fixing savefiles after loading
################################
label after_load:
    while len(questlog) < 2:
        $ questlog_fix = [Quest("Homecoming", "started",
                        "You are trying to learn how and when the brainwashing started to affect you. Even if ALICE is not a problem anymore,"
                        "you can't just ignore this situation. A visit to your home planet and your family might help you uncover what's going on.",
                        [[0, True, "Meet with your father and sister."], [0, False, "Ask them about unusual behaviour from you while you were still on Caldora."], [0, False, ""]]),
                        Quest("Friendly Visit", "hidden",
                        "A gang of small time criminals stole a family heirloom and the owner wants it back. Time to pay a visit to their hideout, and see what you can do.",
                        [[0, True, "Go to the location."], [0, True, "Find a way inside the hideout."], [0, True, "Find the item."], [0, True, "See if you can find other valuables. (optional)"]])
                        ]
        $ quest_pos = len(questlog)
        $ questlog.append(questlog_fix[quest_pos])
First I check the length of the questlog against the number of quests I currently have in the game (which is a known quantity). If there is a discrepancy, I append entries from "questlog_fix" (which is just a copy of the latest version of the "questlog" I have added to the game), until the questlog has the correct number of items. I am always wary of things which need manual updating with each change, so I was hoping there would be a way to know what's the default value in my latest version. It works this way, so the only improvement would be to make things neater. I'll think about using a dictionary, if that's better. What would you say is the best improvement for this use case between dictionary and list?

User avatar
m_from_space
Eileen-Class Veteran
Posts: 1057
Joined: Sun Feb 21, 2021 3:36 am
Contact:

Re: Is it possible to access the default value of an array after it has changed?

#8 Post by m_from_space »

You definitely should use a dictionary here. It's perfectly made for it. Use a simple internal word as the dictionary key (e.g. "homecoming") and it's very easy to check if this quest exists. Or updating data of this quest. Checking for the length of the array here is less manageable. My example just wanted to point you to using after_load. ;)

Using a dictionary is pretty simple, since you don't have to use "append()" or anything special. You also don't need the keys() function in Python3 as @zmook suggested.

Code: Select all

default quests = {}

if "homecoming" not in quests:
    quests["homecoming"] = [0, "hide", "text"...]

mdqp
Newbie
Posts: 24
Joined: Mon Dec 24, 2018 2:56 pm
Contact:

Re: Is it possible to access the default value of an array after it has changed?

#9 Post by mdqp »

m_from_space wrote: Sat Jul 23, 2022 1:05 pm You definitely should use a dictionary here. It's perfectly made for it. Use a simple internal word as the dictionary key (e.g. "homecoming") and it's very easy to check if this quest exists. Or updating data of this quest. Checking for the length of the array here is less manageable. My example just wanted to point you to using after_load. ;)

Using a dictionary is pretty simple, since you don't have to use "append()" or anything special. You also don't need the keys() function in Python3 as @zmook suggested.

Code: Select all

default quests = {}

if "homecoming" not in quests:
    quests["homecoming"] = [0, "hide", "text"...]
I see. Thanks a lot at you and @zmook for taking your time to reply. I am still using Ren'Py 7.3.5 which I think means no Python 3 for me (I am slowly working on this game's demo as I develop my "main" game at the time, and I didn't want to update mid-development, especially after an update did cause me some issues in the past).

I do have some qualms about switching to a dictionary, mainly because I already have a working questlog screen and all of that, but I'll give it a go and see if I can make things easier for myself. I'll leave the code here, in case anyone is interested.

Code: Select all

    class Quest(store.object):
        def __init__(self, name, status, desc, objectives):
            self.name = name
            self.desc = desc
            self.status = status
            self.objectives = objectives

    def reveal_quest(quest):
        if questlog[quest].status == "hidden":
            questlog[quest].status = "started"
    def hide_quest(quest):
        questlog[quest].status = "hidden"

    def fail_quest(quest):
        questlog[quest].status = "failed"

    def complete_quest(quest):
        questlog[quest].status = "complete"

    def reveal_objective(quest, *objv):
        for obj in objv:
            if questlog[quest].objectives[obj][1] == False:
                questlog[quest].objectives[obj][1] = True

    def hide_objective(quest, *objv):
        for obj in objv:
            if questlog[quest].objectives[obj][1] == True:
                questlog[quest].objectives[obj][1] = False

    def complete_objective(quest, *objv):
        for obj in objv:
            questlog[quest].objectives[obj][0] = 2

    def fail_objective(quest, *objv):
        for obj in objv:
            questlog[quest].objectives[obj][0] = 1

    def reset_objective(quest, *objv):
        for obj in objv:
            questlog[quest].objectives[obj][0] = 0

default    questlog = [Quest("Homecoming", "started",
                "You are trying to learn how and when the brainwashing started to affect you. Even if ALICE is not a problem anymore,"
                "you can't just ignore this situation. A visit to your home planet and your family might help you uncover what's going on.",
                [[0, True, "Meet with your father and sister."], [0, False, "Ask them about unusual behaviour from you while you were still on Caldora."], [0, False, ""]]),
                Quest("Friendly Visit", "hidden",
                "A gang of small time criminals stole a family heirloom and the owner wants it back. Time to pay a visit to their hideout, and see what you can do.",
                [[0, True, "Go to the location."], [0, True, "Find a way inside the hideout."], [0, True, "Find the item."], [0, True, "See if you can find other valuables. (optional)"]])
                ]


default questlog_text = 0

default questlog_page = "started"

screen questlog:
    key "mouseup_2" action NullAction()
    key "h" action NullAction()
    key "noshift_K_h" action NullAction()
    zorder 110
    add "gui/extranet_background.png"
    modal True

    frame:
        area (16,48,358,674)
        background Solid("#0000FF00")
        side ("c r"):
            viewport id "my_questlog_scroller": #REMEMBER YOUR VIEWPORT ID SO THE SCROLLBAR IS PLACED FOR IT
                draggable True mousewheel True
                vbox:
                    for quest in questlog:
                        if quest.status == questlog_page:
                            textbutton quest.name action SetVariable("questlog_text", questlog.index(quest))

            vbar value YScrollValue("my_questlog_scroller") #TAKES YOUR VIEWPORT ID AS THE ARG
    null height 20 #just a height set.

    vbox:
        style_prefix "pers"
        xpos 424
        ypos 64
        xmaximum 1056
        ymaximum 800
        spacing 30
        if questlog_text >= 0:
            if questlog[questlog_text].status == questlog_page:
                text questlog[questlog_text].desc

    vbox:
        style_prefix "pers"
        xpos 1568
        ypos 64
        xmaximum 320
        ymaximum 640
        spacing 30
        if questlog_text >= 0:
            if questlog[questlog_text].status == questlog_page:
                for obj in questlog[questlog_text].objectives:
                    if obj[1] == True:
                        if obj[0] == 0:
                            text "{=default}♦{/=default} " + obj[2]
                        elif obj[0] == 1:
                            text "{color=#e60000}{=default}{color=#e60000}♦{/color}{/=default} " + obj[2] + "{/color}"
                        else:
                            text "{color=00ff00}{=default}{color=00ff00}♦{/color}{/=default} " + obj[2] + "{/color}"

        else:
            text "error"

    add "gui/extranet_foreground.png"

    hbox:
        spacing 10
        xalign 0.5 yalign 0.85
        textbutton "Active" action SetVariable("questlog_page", "started") padding (0,0)
        textbutton "Complete" action SetVariable("questlog_page", "complete") padding (0,0)
        textbutton "Failed" action SetVariable("questlog_page", "failed") padding (0,0)

    hbox:
        xalign 0.5 yalign 0.95
        textbutton "Back" action [ Show('hologlasses_button'), Hide("questlog")]

Post Reply

Who is online

Users browsing this forum: Google [Bot]