Ren'Py patch question, different than normal patches

Seath Black

Well-Known Member
Jun 17, 2020
1,675
7,600
So what I want to do is create a patch that when removed from base game, it makes the game completely different... like a different game...
confusing I know, so let me explain in an example.

Normal game with patch:
it plays normal when played,

without patch:
its plays a totally different line of code in the renpy script. so if you hit start, it'll have a different beginning and end...
I know that is confusing but its the best I could describe... lol

Cant think of another way to explain...
with the patch the game plays like it was made...
without patch it plays like a separate game thats still in the script of said game... with a different story all round, but still in the same script file.... get it?
lol
thanks!
 
  • Thinking Face
Reactions: Twistty

79flavors

Well-Known Member
Respected User
Jun 14, 2018
1,557
2,170
In the base version of the game:

Python:
# --- script.rpy ---
init:

    define patched = False

label start:

    if patched:
        "This game has been patched."
        jump play_patched_version
    else:
        "This game has NOT been patched."
        jump play_base_version

    # blah, blah, more code...

Then have a patch file that has these two lines:

Python:
# --- patched.rpy ---
init 1:

    define patched = True

Anywhere you want your game to behave differently, just code a if patched: check and do one thing or another.

If the patched.rpy file exists the game will play one way, if it is missing it will play another.

This works because of the way init: works. init: without a number is the same as init 0:. When it start, RenPy runs each init block according to that number from low to high (think -999 to +999). So it runs init level 0 and sets the value to False, then if the patch file exists it runs init level 1 and replaces the value with True. If the patch file doesn't exist, then the replacement doesn't happen and the value stays False.
 

Seath Black

Well-Known Member
Jun 17, 2020
1,675
7,600
Wow. That was very well said, and explained very understandingly. You are awesome man. Thank you tons!
 
  • Like
Reactions: Twistty

Seath Black

Well-Known Member
Jun 17, 2020
1,675
7,600
In the base version of the game:

Python:
# --- script.rpy ---
init:

    define patched = False

label start:

    if patched:
        "This game has been patched."
        jump play_patched_version
    else:
        "This game has NOT been patched."
        jump play_base_version

    # blah, blah, more code...

Then have a patch file that has these two lines:

Python:
# --- patched.rpy ---
init 1:

    define patched = True

Anywhere you want your game to behave differently, just code a if patched: check and do one thing or another.

If the patched.rpy file exists the game will play one way, if it is missing it will play another.

This works because of the way init: works. init: without a number is the same as init 0:. When it start, RenPy runs each init block according to that number from low to high (think -999 to +999). So it runs init level 0 and sets the value to False, then if the patch file exists it runs init level 1 and replaces the value with True. If the patch file doesn't exist, then the replacement doesn't happen and the value stays False.
one question though. Do just put that in the beginning before the label start?
 

79flavors

Well-Known Member
Respected User
Jun 14, 2018
1,557
2,170
In theory, you can put init: blocks anywhere in the code. (RenPy is like that).

In practice, it makes sense for init: blocks to be at the top of the code, or as near the top as you feel like putting it... and yes, before the label start:. If only because every other programmer in the world will likely look there first.
 
  • Red Heart
Reactions: Seath Black

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Respected User
Donor
Jun 10, 2017
10,111
14,790
So what I want to do is create a patch that when removed from base game, it makes the game completely different... like a different game...
confusing I know, so let me explain in an example.
Confusing indeed. What difference did it make with a patch that, when present, "make the game completely different... like a different game..."

Writing code, and so making a game, is a question of logic. The simplest and most direct is your thoughts, the easier it will be to write the code. And when I see you write something like :
with the patch the game plays like it was made...
Sorry to say that, but I prefer to not see the code you'll write.

I'm not known for my respect of the conventions, or for following the path they traced, but there's a difference between my craziness and your confusion.
I get it that you want to make a game with content banned on Patreon, and so that the patch intent is to provide the game you've in mind. But it don't change the fact that a patch offer to play a game "differently to how it was made", and never to play a game "like it was made". And it's not just a question of semantic, it's all the logic behind the code that depend on this difference.
Look at the difficulty you had to write your question, this just because you took the problem from the wrong angle. A dozen of confused lines, that let you unsure that you'll be understood, when, if you took the problem from the right angle, a simple "How can I make a patch that will change the content of a game" would have been enough to express everything you're searching for. Before starting your game, you need to solve this problem of logic, because Ren'py will not be 79flavors or me, it will not read behind the lines to understand what you effectively want. And therefore your code will be either over complicated, or not working ; when not both.

To explain the problem more clearly, imagine that you want to create a vehicle that can both fly and ride on the road.
With your approach of the problem, the question would be "how can I make a car intended to fly, be able to ride on the road when I remove the parts that permit it to fly". This would lead to a car to which some wings are added. It will ride perfectly, but fly like an iron, mostly because of its really bad aerodynamic. Therefore, you'll start to add more and more things on top of your car, in order to solve this flying problem. But the more you'll solve the flying problem, the more it will be difficult to drive the car, or the more things there will have to remove before driving it.
With the easiest and direct approach, the question would be "how can I make a plane ride on the road". And then it would lead to a plane that have four wheels, and wings that can be removed ; what is how all those vehicles are made. It would fly without problem, because originally designed for this, but be a little difficult to drive because a plane's wheel include the notion of depth. What will be solved relatively easily by adding the possibility to block the up/down movements of the wheel when in "road" position.
You'll still be trying to make your car fly more that few meters, while the guy who took the direct approach would have finished his third world tour.



This being said, and in top of what 79flavors said, that is the easiest and direct approach, but not the safest in regard of Patreon's ban, Ren'py offer a ton of callback and hooking features that let you tweak a game in such way that it can be totally different ; not only presenting a different story, but also different outcomes, a different behavior, and possibly different visual.
There's already many threads talking about that, so I'll not rewrite everything for the umpteenth time, just present some of the options :


  • That offer you the possibility to either totally replace a label by another or to insert yourself at top, or end, of a label.

  • That will be called each time an inline Python line, or a Python block, is proceeded ; right after it have been proceeded. This can, by example, be used to close the door with a girl by resetting her stats every time it change, or add some stats to a girl if you do it right.

  • That is called in between the init phase and the start of the game. It offer you the possibility to play with the variables declared by default and define, either replacing them or declaring some variables using them.

  • That is called right before displaying a dialog line, letting you change the content of this said line.
  • Screens can be overwrote, the last one created will be the one used
    This let you the possibility to radically change the UI, adding or removing option in it by example.
  • All the functions and methods can be changed
    The most frequent example (because Ren'py have a variable dedicated for this) is the rewrite of the menu one to shuffle the menu. But you can use it to intercept the arguments passed to each menu choice and play with them, to add a choice in this menu or to remove a choice from this menu.
    And the same can be done with any function/method, even when this isn't intended to be done. This offer you the possibility to totally change a behavior, or to hook yourself on top of a feature. And obviously the same can be done with all the Python code defined specifically for the game.

And this is just a small view of what is possible. Using you can track in what label you are, what help you having an optimized code in the callbacks/hooks. intent can be hijacked and let you change more precisely a part of the text. This while can take care of the "if patched" for you, having you, by example, write something like altSay "Normal sentence", "patched sentence" in place of the if [sentence] else [sentence] structure. And so on.
In regard of flexibility, Ren'py offer almost the same than more professional engines like Unity and Unreal, while offering a lot of possibilities to tweak a game without editing the original source.
 
  • Like
Reactions: Twistty

Twistty

The Happy Beaver
Respected User
Donor
Former Staff
Sep 9, 2016
4,138
37,740
I'm not known for my respect of the conventions, or for following the path they traced, but there's a difference between my craziness and your confusion.
LennyFace.jpg
I love that statement - and I'm going to steal it's a some point. Lol
In the base version of the game:

Python:
# --- script.rpy ---
init:

    define patched = False

label start:

    if patched:
        "This game has been patched."
        jump play_patched_version
    else:
        "This game has NOT been patched."
        jump play_base_version

    # blah, blah, more code...

Then have a patch file that has these two lines:

Python:
# --- patched.rpy ---
init 1:

    define patched = True

Anywhere you want your game to behave differently, just code a if patched: check and do one thing or another.

If the patched.rpy file exists the game will play one way, if it is missing it will play another.

This works because of the way init: works. init: without a number is the same as init 0:. When it start, RenPy runs each init block according to that number from low to high (think -999 to +999). So it runs init level 0 and sets the value to False, then if the patch file exists it runs init level 1 and replaces the value with True. If the patch file doesn't exist, then the replacement doesn't happen and the value stays False.
Thanks - worked perfectly for my personal game mod!
 
  • Hey there
Reactions: rKnight