Back to now talk about the code itself. I'll starts by addressing the generic issues, and talk about the "does this works for a sandbox" part after.
Python:
#No rollback
define config.hard_rollback_limit = 0
$ renpy.block_rollback()
Two issues here.
Firstly it's a really bad idea to disable the rollback, especially globally.
If you need to disable the rollback for your code to works, then your code is broken in a way or another. Disabling the rollback should be something exceptional, that you do only for the purpose of your game.
Also, remember that Ren'Py is really easy to mod, in order to set back the rollback by example.
Secondly, the
$ renpy.block_rollback()
line is outside of everything (label, screen, init block, Python code).
This mean that Ren'Py will probably not proceed it, and if it do, it will surely not be when you expect it.
Except few statements (
default
,
define
,
image
,
transform
,
style
, and from memory it's all) all your code must be either in an init block (
init:
or
init python:
), in a label, or in a screen.
Python:
# Background for my rooms
# Room 1
image morning ="images/background/morning.png"
image noon = "images/background/noon.png"
image afternoon = "images/background/afternoon.png"
image evening = "images/background/evening.png"
image night ="images/background/night.png"
# Room 2
image morning2 ="images/background/morning2.png"
image noon2 = "images/background/noon2.png"
image afternoon2 = "images/background/afternoon2.png"
image evening2 = "images/background/evening2.png"
image night2 ="images/background/night2.png"
# interaction image
image car = "images/interactions/car.png"
image car_h = "images/interactions/car_h.png"
image car_zoom = "images/interactions/car_zoom.png"
image returnb = "images/gui_game/return.png"
image returnb_h = "images/gui_game/return_h.png"
Those statements are useless.
You declare the image as pure images (see below) and you give them the same name than their file.
As the
You must be registered to see the links
, Ren'Py will automatically proceed to the declaration of any images located in the "images" directory and it's sub folders, creating an image having the same name than the file once stripped from its extension.
Said otherwise, Ren'Py already did exactly the same thing than all the
image
statement you used here.
Python:
# Room 1 Screen
screen station:
zorder 1
# Background of the room
if PoD == 0:
add "morning"
if PoD == 1:
add "noon"
if PoD == 2:
add "afternoon"
if PoD == 3:
add "evening"
if PoD == 4:
add "night"
Here, there's two "should be better to".
Firstly you shouldn't use a suite of
if
like you did.
By chance they aren't conflicting with each others, but it's not a reason to do it. You should instead use the
if
/
elif
[/
else
] structure:
Python:
if PoD == 0:
add "morning"
elif PoD == 1:
add "noon"
elif PoD == 2:
add "afternoon"
elif PoD == 3:
add "evening"
elif PoD == 4:
add "night"
Ren'Py/Python will automatically proceed each test until one match, then stop the series of test. This by opposition to your actual structure, where every test will always be proceeded.
If "PoD" value is equal to "0", with your code Ren'Py/Python will still test if "PoD" is equal to "1", then equal to "2", etc. This will my code if "PoD" is equal to "0", all the other tests will be skipped.
The second "should be better" come from an undocumented behavior of the
add
screen statement.
You can make it use an expression, and like you already have a list that make the correspondence between "PoD" and a string, this permit to replace all your
if
/
add
couple by a single line:
Python:
screen station:
zorder 1
# Background of the room
add ( sPoD[PoD].lower() )
Then:
Python:
screen station2:
zorder 1
# Background of the room
add ( sPoD[PoD].lower() + "2" )
And so on.
By itself using an
if
structure like you did isn't an issue. It can help to have a better view regarding what is happening "here". But in the same time it also drown you with information and this can lost you in the end.
Python:
label start:
"Hello, welcome."
show screen advanceTime
show screen gui_ingame
jump station
label station:
show screen advanceTime
show screen gui_ingame
call screen station
Here, one useless part, and a "should be better to" issue.
The useless part is that you show the screens every time.
A screen will be shown until you explicitly ask Ren'Py to hide it. Therefore, this part could be:
Python:
label start:
"Hello, welcome."
show screen advanceTime
show screen gui_ingame
jump station
label station:
call screen station
Both "advanceTime" and "gui_ingame" screens will still be displayed when you call the "station" screen, when the said screen is displayed, and after the screen have been displayed.
As for the "should be better to", it's related to the
You must be registered to see the links
screen statement.
This statement permit to include a screen inside another one. And like both "advanceTime" and "gui_ingame" are expected to be seen most of the time, you could have used:
Python:
screen station1:
zorder 1
use advanceTime
use gui_ingame
[...]
screen station2:
zorder 1
use advanceTime
use gui_ingame
[...]
This would then make the
show screen advanceTime
and
show screen gui_ingame
definitively useless.
Now that this is said, you rely was too much on screens, and not enough on labels.
Take "station1" by example. This part is both good and bad:
Python:
# interaction test, here only the Friday at evening first week
if PoD == 3 and DoW == 4 and WeeK == 0:
imagebutton:
focus_mask True
idle "car"
hover "car_h"
action ToggleScreen("car_zoom")
Good because yes, it's from the screen that you need to decide if the car is seen or not.
Bad because the car will not be seen just a one period, one day and one week. What mean that you'll have a lot of condition to define here, and it will soon be too much to effectively manage it. It would be better to rely on arguments past to the screen.
For my example, I changed the premise of the code, in order to have a better base for the demonstration.
I assumed that "station1" is an house garage. Therefore, the car is present outside of work hours, except for the Wednesday of the second week, because for some reason the car owner take his lunch at home. I also assumed that there's a bicycle, in order to have more than one item:
Python:
label station1:
# Is the car present ?
# The variable exist only in this label.
$ renpy.dynamic( "car" )
# If it's morning or night, or eithert Saturday or Sunday.
if PoD in [0, 4] and or DoW in [5, 6]:
$ car = True
# First exception, Wednesday of the second week, at lunch time.
elif Week == 2 and PoD == 1 and DoW == 2:
$ car = True
# Any other times, the car is not present.
else:
$ car = False
# Is the bicycle present ?
$ renpy.dynamic( "bicycle" )
# Yes, it's always present, it's your bicycle.
$ bicycle = True
# And now call the screen, telling it what it should display or not:
call screen station1( car, bicycle )
screen station1( car, bicycle ):
[...]
# If asked to display the car, display it.
if car:
imagebutton:
focus_mask True
idle "car"
hover "car_h"
action ToggleScreen("car_zoom")
# Same for the bicycle.
if bicycle:
imagebutton:
[...]
This shifts to the label the responsibility to know if something should be displayed or not.
It's important because:
- labels are a bit faster;
- screens are proceeded around 5 times by seconds (therefore the test would be performed 5 times by seconds);
- It keep the screens more readable;
- You can later simplify your labels to keep them readable.
Regarding
You must be registered to see the links
it's a function that the given variable will be relevant only in this label, and the labels called from it (but not the label jumped). This permit you to use a lot of variable to define what should be seen in your screen, without those variables being still present elsewhere in the game.
Regarding the point 4 of the list above, you can make your label more compact, while still being readable:
Python:
label station1:
# Is the car present ?
$ renpy.dynamic( "car" )
# An external label will take care of the computations.
call isCarPresent
# Get the value returned by the label, and store it
$ car = _return
# Is the bicycle present ?
$ renpy.dynamic( "bicycle" )
call isBicyclePresent
$ bicycle = _return
call screen station1( car, bicycle )
label isCarPresent:
# If it's morning or night, or eithert Saturday or Sunday.
if PoD in [0, 4] and or DoW in [5, 6]:
return True
# First exception, Wednesday of the second week, at lunch time.
elif Week == 2 and PoD == 1 and DoW == 2:
return True
# Any other times, the car is not present.
else:
return False
In fact, designed this way, your code will be more readable, even without the comments.
call isCarPresent
explicitly say what happen at this time. This while, if you need to make change in the conditions for the car to be present, you know that it will be in the label named "isCarPresent", and that this label will have nothing more than those conditions.
Relying on this approach instead of the "screen based" one you shown, it even more important that you intend to use this as part of an event system.
But, as you probably imagine, the example I gave is more suitable for recurring events than "one time" ones. So now that I explained how to shifts the computing to the label, and how to have simplified labels, I'll explain how to make all this works with none recurring events.
The trick is to not anymore rely on a flag (a boolean variable), but on a list that will contain the parts that have to be added in the screen:
Python:
label station1:
# By default, nothing will happen.
$ renpy.dynamic( "events" )
$ events = []
call isCarPresent
# If the returned value is /True/, then the car is present,
if _return:
# therefore, add it to the list of events.
$ events.append( "car" )
call isBicyclePresent
$ bicycle = _return
if _return:
$ events.append( "bicycle" )
call screen station1( events )
screen station1( events ):
[...]
# If "car" is parts of the events, display the button.
if "car" in events:
imagebutton:
focus_mask True
idle "car"
hover "car_h"
action ToggleScreen("car_zoom")
# If "bicycle" is parts of the events, display the button.
if "bicycle" in events:
imagebutton:
[...]
Now, everything rely on an unique variable, what permit to extend the events without real constraints nor limits.
Not much to say regarding the rest of the code, well except your save issue that I addressed previously.
Normally, the use of
renpy.restart_interaction
should be enough, but if it isn't I'll tell you how to solve it ; or someone else will do it if I can't at this time.