[SOLVED] Strange variable behaviour

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.
Message
Author
User avatar
xela
Lemma-Class Veteran
Posts: 2481
Joined: Sun Sep 18, 2011 10:13 am
Contact:

Re: Strange variable behaviour

#16 Post by xela »

Milkymalk wrote:I'm fine with simplyfied explanations :-)
I wrote a longer one while you were typing that :)
Milkymalk wrote:But another question:

Why does this change the sp outside the function:

Code: Select all

    class Test:
        def cast_spell(self, sp):
            effectbuffer = sp.effects
            while len(effectbuffer) > 0:
                currenteffect = effectbuffer.pop()
            [...stuff...]
 
and this does not change amount outside the function?

Code: Select all

        def change_mana(self, target, change_to, amount, position):
            if position == 1:
                step = 1
            elif position == 2:
                step = -1
            deletemana = [ ]
            for i in range(15):
                deletemana.append(False)                    
            for i in range(15):
                if amount > 0 and (self.balls_color[7-(7-i)*step] == target or target == -1) and not self.ballselected[7-(7-i)*step]:
                    if change_to == -3:
                        deletemana[7-(7-i)*step] = True
                        amount -= 1

Code: Select all

effectbuffer = sp.effects
just adds a new reference pointing to sp.effects to local scope (still pointing to the effects attribute of sp object), reasonable thing here would be to call it "eb" to shorten the amount of code and maybe even the execution speed of your program.

In change_mana you're reassigning "amount" to a variable on change_mana scope, global (or whatever outer scope you're using) has no way of knowing that, so:

Code: Select all

amount -= 1
is actually the same as:

Code: Select all

amount = amount - 1
which in plain English says:

Reference variable "amount" on local scope to be whatever the supplied attribute "amount" referenced to on the outer scope and subtract one from it. In all consecutive loops, newly created local variable "amount" is used.

Behavior is exactly the same with lists (because .pop(), .append() do not reassign anything):

Code: Select all

def func(l):
    for i in xrange(10, 100):
        l = l + [i]
a = range(10)
func(a)
"a" on outer scope will remain the same

while:

Code: Select all

def func(l):
    for i in xrange(10, 100):
        l.append(i)
a = range(10)
func(a)
"a" on outer scope will become a list integers from 0 to 99.
Like what we're doing? Support us at:
Image

User avatar
Milkymalk
Miko-Class Veteran
Posts: 753
Joined: Wed Nov 23, 2011 5:30 pm
Completed: Don't Look (AGS game)
Projects: KANPEKI! ★Perfect Play★
Organization: Crappy White Wings
Location: Germany
Contact:

Re: Strange variable behaviour

#17 Post by Milkymalk »

That actually makes more sense!
I only use longer variable names in places where I don't need them often, so I remember what they mean in case I want to change something later. I know that documenting stuff is more practical, but I don't feel like documenting every dummy variable I ever use in every little function :roll:

Okay, I changed the structure of the code and now (almost) everything is processed via ui.interact() in a main loop. Works perfectly! Thank you for putting up with me :-)

I noticed this though:

This code works fine:

Code: Select all

        def directdamagespell(self, type, amount, caster, target):
            if target in (1, 3):                                              
                selectedtarget = self.gettarget(target)
                trueamount = (amount * (100 + caster.combatstats[type]))/100
                selectedtarget.takehit(type, trueamount)
                renpy.restart_interaction()
While this code stops executing directdamagespell after the label call (the label is exactly the same as the function):

Code: Select all

        def directdamagespell(self, type, amount, caster, target):
            if target in (1, 3):                                              
                selectedtarget = renpy.call('gettarget', target)
                trueamount = (amount * (100 + caster.combatstats[type]))/100
                selectedtarget.takehit(type, trueamount)
                renpy.restart_interaction()

label gettarget(type):
    $ playerselection = ('', '', '')
    if type == 0:
        while playerselection[0:2] != ('clicked_character', 'player'):
            $ playerselection = ui.interact()
    return playerselection[2]
The exactly same behaviour that I had before, so it has nothing to do with any interactions running while I do that. I don't need this to work, but it would be nice to understand this behaviour.
Crappy White Wings (currently quite inactive)
Working on: KANPEKI!
(On Hold: New Eden, Imperial Sea, Pure Light)

User avatar
xela
Lemma-Class Veteran
Posts: 2481
Joined: Sun Sep 18, 2011 10:13 am
Contact:

Re: Strange variable behaviour

#18 Post by xela »

Milkymalk wrote:The exactly same behaviour that I had before, so it has nothing to do with any interactions running while I do that. I don't need this to work, but it would be nice to understand this behaviour.
Not really a valid question if you read the documentation: Call.

Control is returned to RenPy statements so you cannot return to anywhere inside of a python block.
Like what we're doing? Support us at:
Image

User avatar
Milkymalk
Miko-Class Veteran
Posts: 753
Joined: Wed Nov 23, 2011 5:30 pm
Completed: Don't Look (AGS game)
Projects: KANPEKI! ★Perfect Play★
Organization: Crappy White Wings
Location: Germany
Contact:

Re: Strange variable behaviour

#19 Post by Milkymalk »

xela wrote:Not really a valid question if you read the documentation: Call.
I did:
allowing the return statement to return control to the statement following the call.
Following the call is the next line of the function. I'm not that much of a professional programmer to know the implicit difference between a statement and a line of code. Amateurs like me like to see something explicit like:

"If used as renpy.call() from within a function, all currently executing functions are exited and control is given back to the last position in the script."

Anyway, thank you for helping me with all this. My programming is a mess mainly because I still need to understand many of Python's and Ren'Py's possibilities and limitations. Your explanations are very appreciated!
Crappy White Wings (currently quite inactive)
Working on: KANPEKI!
(On Hold: New Eden, Imperial Sea, Pure Light)

User avatar
xela
Lemma-Class Veteran
Posts: 2481
Joined: Sun Sep 18, 2011 10:13 am
Contact:

Re: Strange variable behaviour

#20 Post by xela »

Milkymalk wrote:implicit difference between a statement and a line of code.
There isn't one (at least I can't think of one you should concern yourself with), the difference which is important here is between Ren'Py script statements and Python statements. Ren'Py statements are the once being stacked when call is invoked so:

Code: Select all

                trueamount = (amount * (100 + caster.combatstats[type]))/100
                selectedtarget.takehit(type, trueamount)
                renpy.restart_interaction()
are valid statements but they are Python statements and call cannot return you to them.

Example:

Code: Select all

label start:
    python: # First Ren'Py statement
        renpy.call("call_label")
        # 10 000 000 lines of python code here would still be considered a single Ren'Py statement that started with python
        # So nothing past call will be executed...
    call screen meow # <<--- Second Ren'Py statement (returning from called label will run this script)
Like what we're doing? Support us at:
Image

Post Reply

Who is online

Users browsing this forum: Google [Bot]