Variables and math

Kaffekop

Member
Game Developer
Jul 23, 2017
442
3,155
Oh you great oracles of ren'py.

Why does working with ren'py always make me feel like going twelve rounds with Muhammad Ali. No matter how many times I try to get it to do something, nothing happens and when something finally begins making sense - I'm down for the count!

I'm just about ready to shoot myself, so I really hope that one of you oracles can help me with these (I'm sure are trivial to you) issues I'm having.

Question one:
I have two variables: Corruption & Focus.
I would like to display the "real" corruption (which is in fact derived from: Corruption - Focus) in a screen using the color red.

It took me the better part of four hours to figure this out:
Code:
text ('Corruption {}'.format(Corruption-Focus))
It does the trick, but the text is white and I can't for the life of me figure out where to put the color tags to get this to work in red - for example.

Question two:
How do I set up a "test" with the "real" corruption (Corruption - Focus) within the game? I'm currently doing something like this, with other variables to determine the flow of the story:
Code:
if PleasureZone >= 4:
         jump SomeWhere_1
I have a feeling that I'll be spending forever to figure this out on my own if I even can figure this out on my own.

And please understand that I'm not a coder by any stretch of your imagination. And I mean ... ANY STRETCH of your imagination, so an explanation in layman terms would be very much appreciated.
My mind doesn't bend the ren'py way and where others see order and logic, I see: ¤#"&"&#&¤#)(=

I hope you can help me, oh wise men (and women) of ren'py.

Cheers - Kaffekop
 
  • Like
Reactions: bas and Palanto

Rich

Old Fart
Modder
Donor
Respected User
Game Developer
Jun 25, 2017
2,566
7,382
Because you're dealing with manipulating variables, you're moving somewhat into Python syntax, as I'm sure you've discovered.

How about:
Code:
text ('Corruption {}'.format(Corruption-Focus)):
    color "#f00"
    any other tags to affect the text
(note the colon on the end, which then introduces the indented block.

Another approach would be to declare a temporary variable inside the screen:
Code:
screen displayStatsScreen:
    realCorruption = 'Corruption {}'.format(Corruption-Focus)

    text realCorruption color "#f00"
This declares a screen variable named "realCorruption" that contains the string version of your calculation, and then uses the value in the variable as the text that is displayed on the screen. (Note that in the text line, realCorruption is not inside quotes, which means that the variable's value is used instead of using the text "realCorruption")

As to your test, you can include the calculation in the "if" line:
Code:
    if Corruption - Focus > 53:
        jump SeriouslyCorrupted
 

Kaffekop

Member
Game Developer
Jul 23, 2017
442
3,155
@Rich

Thank you so much for taking the time. When I look at your solution it even looks ... logical (in lack of a better word) to me, which is fairly impressive.

I would never have guessed that the second question would have been that easy. Actually that solution I had thought of, but I dared not hope, that I had actually understood how that would work.

I went with option one, and once again, thank you so much for this. And I even understand what you're saying :)

Cheers - Kaffekop
 

Rich

Old Fart
Modder
Donor
Respected User
Game Developer
Jun 25, 2017
2,566
7,382
@Kaffekop - You're completely welcome. This kind of thing can be daunting for people that haven't programmed before. And it isn't helped by the fact that Ren'py actually has four different languages - Python, the script language, the screen language and ATL, each of which is somewhat different. But, after a while, the concepts begin to sink in, and the underlying logic begins to make itself known.
 
  • Like
Reactions: Papa Ernie

Rich

Old Fart
Modder
Donor
Respected User
Game Developer
Jun 25, 2017
2,566
7,382
@Kaffekop - Just dawned on me - you're working on "Sins of the Father," right? Just played it. Nice work so far...
 

Kaffekop

Member
Game Developer
Jul 23, 2017
442
3,155
@Rich - Four languages? What? Someone couldn't settle on just one? ;)
Thank you for playing and your kind words.
I better get back to putting v. 0.5 together.

Cheers - Kaffekop
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,969
16,222
It took me the better part of four hours to figure this out:
Code:
text ('Corruption {}'.format(Corruption-Focus))
It does the trick, but the text is white and I can't for the life of me figure out where to put the color tags to get this to work in red - for example.
That's why the official way to perform substitution in string is still the old "%" way (which will not works here) ; the "{}" used by format conflict with the in text Ren'py's tags.
One way to get rid of this a stupid ; but it works so it's not this stupid. format use index to know where to insert the values, it come handy here :
Code:
text "Corruption : {0}color=#FF0000{1} {2} {0}/color{1}".format( "{", "}", Corruption - Focus )
But I give you this solution only as a workaround if you encounter this kind of problem with something else. Because here the solution is way more simple than that.

A string can be constructed, and the text screen statement can deal with it ; which isn't the case of the (implicit or explicit) say statement.
So, the solution to your problem is :
Code:
text 'Corruption : {color=#FF0000} " + str( Corruption - Focus ) + "{/color}"
Python don't like type coercion, so you can't directly use the computer integer value, you must change it into a string (with str) first.
Note: The way Ren'py works, you can even forgot to close the color tag. But it's bad.



How do I set up a "test" with the "real" corruption (Corruption - Focus) within the game?
@Rich gave you the answer, but I have a some concern regarding all this. Not about the answer given, but about the whole process.

As far as I understand it, "Corruption - Focus" will be a recurrent thing in your game. And I assume that if you start with this, there will possibly be other "x - y" and perhaps some "x + y". Anyway, you'll have to write this construction many times in your game, and each time it will increase the risk of typo. It's not a big deal if you write "corruption - Focus", because Ren'py will complain, it become a problem if you write "Corruption + Focus" ; it's an error which happen even to the bests.

So, a better approach is to create a function to handle the computation for you :
Code:
init python:
    def realCorruption():
        return Corruption - Focus

screen blabla:
    [...]
    text "Corruption : {color=#FF0000} " + str( realCorruption() ) + "{/color}"
    [...]

label blibli:
    [...]
    if realCorruption() < 42:
        "You aren't corrupted enough to do this."
Now you are rid of the main problem and like there's less characters to write, it limit the risk of typo. But there's still the problem of the str which will not be obvious since you aren't a coder.
Therefore, a more typo free solution can be to use a C convention (prefixing the name by the type of the returned value) and a shortened name. Like this :
Code:
init python:
    #  You don't need the "real" after all. You know that if you need to use the
    # function it's because you want the computed value, so the real one.
    # iCorr for "real corruption as integer"
    def iCorr():
        return Corruption - Focus
    # sCorr for "real corruption as string"
    def sCorr():
        return str( Corruption - Focus )

screen blabla:
    [...]
    text "Corruption : {color=#FF0000} " + sCorr() + "{/color}"
    [...]

label blibli:
    [...]
    if iCorr() < 42:
        "You aren't corrupted enough to do this."
There's another solution, with a class and properties, but it's too advanced for what you want to do and it add nothing in the end, so I'll just say that it exist.
 
  • Like
Reactions: Kaffekop

Kaffekop

Member
Game Developer
Jul 23, 2017
442
3,155
@anne O'nymous - thank you for taking the time as well.
I read this, quite a few times really and at first my mind went: bleh! But eventually it began making sense (how weird is that?) - don't answer that ;)

That "function thingy" is a great solution to those pesky typo's. Thank you very much!

Some time ago I signed up for a Udemy class in Python, but after a few sessions I was so confused, that my head was spinning. I think I'll give it another go.

Cheers - Kaffekop
 
  • Like
Reactions: anne O'nymous

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,969
16,222
Some time ago I signed up for a Udemy class in Python, but after a few sessions I was so confused, that my head was spinning. I think I'll give it another go.
You have two way to go. First rely on professional teachers, and here what's probably the better option is , a founded and funded by the MIT and Harvard, and now joined by some of the most prestigious Universities around the world. By example you can try :




Or you rely on a more self taught way, and you can go with or . Personally I think that Python Spot is the best option for you, at least at first. It's split in real small parts, each one addressing a specific point, so you can just pass through what you don't care and focus on what matter for you right now.

All this said, start by reading (the rest of the site don't really worth it). It's part of a bigger tutorial, but it will give you some basis regarding coding. It's a really simple introduction and there's some chances that in fact you'll end with the feeling that you learned nothing. But it doesn't matter...
It's difficult to learn to code by yourself, or to start by learning a specific language, not because coding is difficult, but because it's a new way to think. Coding need more mind flexibility, while in the same time it need to be way more strict when you start to act. And it's the opposite of how the mind works initially ; we think strictly about what we need to do, then it doesn't matter if it's not this perfect. This while coding need that you find a solution to something that is abstract, then be perfect when you apply this solution.
And so, by reading the linked page, you'll see how a coder describe coding, which will help you understand this new way to think. Then you'll be more ready to learn.
 

Kaffekop

Member
Game Developer
Jul 23, 2017
442
3,155
@anne O'nymous - Thanks for trying to point me in the right direction with this. I'll give it a go next week, before I begin working on the next version of my project.

Cheers - Kaffekop
 

Kaffekop

Member
Game Developer
Jul 23, 2017
442
3,155
@anne O'nymous - hey there.
I've been testing that function thing, and it works.
I have a question more: How do I make sure, that sCorr and iCorr never go into a negative number?

Cheers - Kaffekop
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,969
16,222
I have a question more: How do I make sure, that sCorr and iCorr never go into a negative number?
By being more corrupted than you can focus ? :D

More seriously, I didn't thought about it, being too focused on your example, but I'll fix this right now :
Code:
init python:

   def iCorr():
       t = Corruption - Focus
       if t < 0: return 0
       #  No need for the "else" here. If it's negative you already quit the function
       # with the "return" above.
       return t

   def sCorr():
       #  You already have a function which do the computation and validation,
       # so you just need to turn its value into a string.
       return str( iCoor() )
In the end it's one more reason to use a function rather than a direct input.
You can take care of this case with the direct input, but it imply way more things to write, and so more risk of errors.
Just for the curious, the direct input looks like this :
Code:
    text "Corruption : " + ( 0 if Corruption - Focus < 0 else Corruption - Focus )
 
  • Like
Reactions: Kaffekop

Maid Lain

Well-Known Member
Modder
Game Developer
Apr 4, 2018
1,888
16,561
I don't like the idea of having two functions for the same thing. Also conditional operators always make you look cool even if it makes code harder to read. :cool::cool::cool:
Code:
def calc_corr(type):
    if type == 'int':
        return corruption - focus if corruption - focus >= 0 else 0
    elif type == 'str':
        return str(corruption - focus) if corruption - focus >= 0 else '0'
Code:
foo = 'Your real corruption is: ' + calc_corr('str')

if calc_corr('int') > 5:
    jump lewd_scene
 

Kaffekop

Member
Game Developer
Jul 23, 2017
442
3,155
@anne O'nymous
Thank you once more. I can even wrap my head around what it does now, when I look at it. It seems ... logical (even to me!)

@Maim Lain
Thank you for taking the time. I'm going with anne's because I can't understand what you're trying to say. Although i know that it probably works like a charm and in the same way, it looks like ... gibberish to me - no offense!

Cheers - Kaffekop
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,969
16,222
Also conditional operators always make you look cool even if it makes code harder to read. :cool::cool::cool:
Not bad, but too complex. Just make the parameter optional for the most used case :
Code:
init python:
    def realCorr( string=False ):
        v = 0 if Corruption - Focus < 0 else Corruption - Focus
        return v if string is False else str( v )

label blabla:
    #  No parameter given, so 'realCorr' will used the default value given
    # in the declaration above ; string will be False.
    if realCorr() < 42:
        [...]

screen blibli:
    #  You want it to be a string, so you overwrite the default value by
    # giving a parameter ; string will be True.
    text "Corruption : " + realCorr( True )
@Kaffekop it's a good demonstration of the mind flexibility I talked above.
As you can see, there's way more that a single solution for a given problem. Some are "classical", other more imaginative, but all will achieve the same result. There isn't one good answer here. Both my split functions, the one of @Maim Lain or my variation of it, are valid answer ; there's even few more in fact ;)
What matter is neither the number of lines, the cool effect, nor the classical aspect. No, what matter is the feeling you have regarding the code. The more at ease you are with it, the better it is. If you decide to learn coding, never be afraid of the examples you'll see. They are just here to teach you, once you'll understand more about the language, you'll also start to understand how to do it your way.
 

Maid Lain

Well-Known Member
Modder
Game Developer
Apr 4, 2018
1,888
16,561
@Kaffekop
No worries, I just wanted to write something that does the same as his two functions but as one function and in fewer lines. My function is definitely less intuitive and harder to read.


@anne O'nymous
I also thought about using a default parameter to make it shorter but while I didn't like the idea of using two functions for the same thing, I also didn't like the idea of having an optional parameter since I'd probably forget whether the int or str is the default. Having to type in 'int' or 'str' is pretty annoying as well though.

I think my preferred way to do it would be make one function that returns an int, and then whenever I need a string just use string interpolation, that way it autoconverts to a string. I'm pretty sure that way works in python.
 

Kaffekop

Member
Game Developer
Jul 23, 2017
442
3,155
By being more corrupted than you can focus ? :D

More seriously, I didn't thought about it, being too focused on your example, but I'll fix this right now :
Code:
init python:

   def iCorr():
       t = Corruption - Focus
       if t < 0: return 0
       #  No need for the "else" here. If it's negative you already quit the function
       # with the "return" above.
       return t

   def sCorr():
       #  You already have a function which do the computation and validation,
       # so you just need to turn its value into a string.
       return str( iCoor() )
In the end it's one more reason to use a function rather than a direct input.
You can take care of this case with the direct input, but it imply way more things to write, and so more risk of errors.
Just for the curious, the direct input looks like this :
Code:
    text "Corruption : " + ( 0 if Corruption - Focus < 0 else Corruption - Focus )
I'm sorry to ressurect this thread but it's easier than starting a new one with the same problem. I went belly up, so to speak, in September last year and have only recently begun delving into my project again. Much to my surprise I found out, that this doesn't work as intended. Or ... I don't know how to add those variables in sucha a way that it DOES work (much more likely in my opinion).

Here is what I do:
I set Corruption through the default statement (default Corruption = 0).
I do the same with Focus: default Focus = 0

I then add to the Corruption by doing so: $ Corruption += 1 (or any number really).
I do the same for Focus: $ Focus += 1 (or any number really).

It easily enough adds the various "Corruption" together, but it fails to subtract "Focus" at any time. Let me try to explain this better:
Focus is set to 1 (for example). What I expect is that every time I do a "$ Corruption += 2" it should subtract the two numbers (Corruption - Focus) in this instance (2 - 1) which is 1 and this result should then be added to the "Corruption score".

I cannot for the life of me understand why it doesn't nor am I able to do something about it.
can one of you oracles of Ren'py and Python help me out?

Cheers - Kaffekop
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,969
16,222
Focus is set to 1 (for example). What I expect is that every time I do a "$ Corruption += 2" it should subtract the two numbers (Corruption - Focus) in this instance (2 - 1) which is 1 and this result should then be added to the "Corruption score".
Something like this ?
Python:
init python:
    def addCorruption( step=1 ):
        step = step - Focus
        if step < 0: return
        store.Corruption += step

default Corruption = 0
default Focus = 0

label start:
    # If not set, the the value added will be 1
    $ addCorruption()
    "Corruption [Corruption] / Focus [Focus]"
    $ addCorruption( 2 )
    "Corruption [Corruption] / Focus [Focus]"
    $ Focus += 1
    $ addCorruption( 2 )
    "Corruption [Corruption] / Focus [Focus]"
    $Focus += 2
    $ addCorruption( 2 )
    "Corruption [Corruption] / Focus [Focus]"
    $ addCorruption( 4 )
    "Corruption [Corruption] / Focus [Focus]"
    "END"
Edit: Corrected a little "oops" thing in the code.
 
Last edited:

Kaffekop

Member
Game Developer
Jul 23, 2017
442
3,155
First off: Thank you for swinging by this thread again - greatly appreciated!
Second: Wut???

I'll give this a spin and see what happens.

Cheers - Kaffekop
 

79flavors

Well-Known Member
Respected User
Jun 14, 2018
1,608
2,256
It sounds like you want to use the current Focus value as a modifier to whatever you're trying to do with Corruption.

So (pseudo code):

Corruption = Corruption + ( Value - Focus )

So if you add 2 to Corruption, but Focus is 1.. then you want to add 1, not 2.
So if you add 2 to Corruption, but Focus is 2.. then you want to add 0, not 2?

Likewise..
So if you add 3 to Corruption, but Focus is 2.. then you want to add 1, not 3?

That sort of thing?

(Trying to get the question clear in my head, before Anne or Rich beats me to an answer :) )

Obvious flaw... what if Focus is higher then the value you're trying to apply?
... like what if you want do something like Corruption += 2, but Focus is 3? Does Corruption go down? Or does it just stay the same?