My point is that setting defaults in one section at the top of the code like you suggest is not always possible in a VN. Take the Ines variables I passed along as an example. It's reasonable to assume that the dev had not planned on making aspects of Ines' personality a path/choice for the player in the first release of Unbroken many moons ago, and they only decided to add that in recently. However, the story and game was already many versions deep by that point. So the only way to accommodate that late addition – given that the callback solution you noted wasn't in place – is to simply declare, initialize, and begin using those scores for Ines at the start of the code for the new chapter. It's functional, and it makes complete sense.
I think there might be a misunderstanding about the
You must be registered to see the links
as it works its way through the code.
It begins with engine startup (which is typically not edited by the developer). Next, "python early" blocks are run, though many developers don't use these. The first thing the developer typically influences is the "init phase", which occurs before anything is shown to the user (excluding an optional presplash). During the init phase, anything in an "init block" is set, such as defining Python classes and functions and
You must be registered to see the links
constants. At the end of the init phase (typically) is when
You must be registered to see the links
statements are run to set the value of variables. Once script execution begins,
You must be registered to see the links
. Next, Ren'Py begins calling the special labels
splashscreen
,
before_main_menu
, and
main_menu
. From the main menu, things typically transfer to either the
start
special label or the "load" function. The load function will overwrite any variables from default statements with their saved value (the current value of "defaulted" variables is always included when creating a save file).
So, the point is that a developer can continually add new variables to an existing project over time, so long as they do so using the "default" keyword. Importantly,
You must be registered to see the links
This means that if a variable is added with a simple Python command, as this game does with
$ inessubmission = 0
, it will not be saved if the user bypasses that line, such as when choosing a different route or loading an old saved game. This is especially bad when all other references to this variable are
$ inessubmission += 1
, meaning that they too will fail without the initial value.
As to the
config.after_load_callback
list and
after_load
label, these are built-in capabilities of Ren'Py that execute automatically prior to calling the "start" label and after the "load" function runs.
Some may argue that duplicate declarations should also be added at the top of the script when a new variable is required like this, mainly for documentation purposes. However, duel initialization can cause maintenance issues, where it's even allowed in the first place, so I can see why a dev would avoid it and only want a single entry in these cases.
As I think my above statement covers, declaring variables at init time actually occurs before any of the labels are processed, so it's before the script. Ren'Py will stop you from "defaulting" a variable more than once, so there's no way to have duel [sic] initialization. Putting them together "at the top of the script" isn't technically necessary, but it
is the standard practice, due to the headaches that can be avoided if the code is well organized. Many developers, myself included, will have an entire file specifically for constants and variables, so that they can always be located easily.
The core issue here I think is that writing an iterative novel with multiple releases is a very different beast than pure software development, and some practices simply may not translate well between the two disparate projects. I can relate to the desire for organized and well-formed coding though. It just may not always be possible given the limits imposed on this type of endeavour.
The release of software in an iterative manner is more of the norm, rather than the exception, at least in my professional and personal experience. While there are certainly some peculiarities to a visual novel, I don't find it to be different from other forms of software development in any meaningful way. Applying industry-wide good coding practices and having an adequate understanding of how the engine runs means that writing visual novel code is far easier. It's because Ren'Py is so forgiving that software can be released with "sub-optimal" code.
Finally, I appologize if my responses come across as condescending, but I sincerely hope that I can contribute to others writing better code.