Hmm refreshing variables?

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
Melkoshi
Regular
Posts: 156
Joined: Tue Jun 02, 2009 8:56 pm
Projects: Jewels of Sytinane
Location: U.s.a.
Contact:

Hmm refreshing variables?

#1 Post by Melkoshi »

No clue if i'm doing this right. But i'm trying to work out the stats in my battle system.

I have a system of Lists such as.

Code: Select all

    # maxhp, str, agi, stm, int, armor, elefire, elewater, elewind, eleearth, eleholy, eleshadow
    # dodge = agi*.5
    # attackspeed = .25*agi+35
    
    

    $ equipweaponbuff = [ 6, 0, 0, 0,]
    
    $ korostr = korobasestats[1] + equipweaponbuff[0]
    $ korostats = [korostr, koroagi,]
    
I assumed if Korostr changed, then korostats would show the change without having to redefine it. I assumed wrong as my test game came back different. I had to redefine korostats in my script to get the change to show, even though i only altered equipweaponbuff's first variable. :s

anyway to refresh the variables? Or should i create a refresh label just to be safe that i'll call before using any of my stats?
--- My DeviantArt.
Game in Progress for demo-teaser:
story(script) = 45%
sprites = 100%
programming(interface) = 35%
CGs = 0%
Backgrounds = 5%
Music/sound = 0%

User avatar
PyTom
Ren'Py Creator
Posts: 16096
Joined: Mon Feb 02, 2004 10:58 am
Completed: Moonlight Walks
Projects: Ren'Py
IRC Nick: renpytom
Github: renpytom
itch: renpytom
Location: Kings Park, NY
Contact:

Re: Hmm refreshing variables?

#2 Post by PyTom »

You should have a label you call when the base variables are updated. An assignment occurs once - it doesn't define an invariant.
Supporting creators since 2004
(When was the last time you backed up your game?)
"Do good work." - Virgil Ivan "Gus" Grissom
Software > Drama • https://www.patreon.com/renpytom

Melkoshi
Regular
Posts: 156
Joined: Tue Jun 02, 2009 8:56 pm
Projects: Jewels of Sytinane
Location: U.s.a.
Contact:

Re: Hmm refreshing variables?

#3 Post by Melkoshi »

PyTom wrote:You should have a label you call when the base variables are updated. An assignment occurs once - it doesn't define an invariant.
Thats what i figured I'd have to do. but I figure i'd ask incase there was a function or something that did it anyways.

Thanks PyTom. :3
--- My DeviantArt.
Game in Progress for demo-teaser:
story(script) = 45%
sprites = 100%
programming(interface) = 35%
CGs = 0%
Backgrounds = 5%
Music/sound = 0%

Jake
Support Hero
Posts: 3826
Joined: Sat Jun 17, 2006 7:28 pm
Contact:

Re: Hmm refreshing variables?

#4 Post by Jake »

Melkoshi wrote: I figure i'd ask incase there was a function or something that did it anyways.
As it goes, the way this kind of thing is usually done is to define a class to store your stats and access particular modifications of them in. Classes are passed by reference rather than value (meaning that when you pass your class into a function and modify bits of it, the changes show up everywhere that class is used, as opposed to regular variables where the '5' you pass into a function is a completely different '5' to the variable you got the value from) and thus it's easier to keep consistent.

So if you're planning to do this kind of thing a lot, and you're feeling a little more confident with your programming, it's probably worth reading up on classes. They're not incredibly difficult - he's a quick example (from the Python interactive prompt, so please excuse the '>>>' and '...'s ;-) - and don't get daunted by the length of the code blocks, most of it's example usage. ;-):

Code: Select all

>>> class Fighter(object):
...   # This function gets called when you create a new Fighter
...   def __init__(self, strength, health):
...     # you can use 'self' to refer to the particular Fighter you're using
...     # from within any function on the class, but it has to be the first
...     # parameter to each function in the class.
...     self.Strength = strength
...     self.Health = health
...     self.MaxHealth = health
...     self.Alive = True
...   # This function can be called from the Fighter you've created in your code,
...   # and will affect that Fighter's Health using 'self':
...   def Damage(self, damage):
...     self.Health = self.Health - damage
...     if self.Health <= 0:
...       self.Alive = False
... 
>>> # This function takes a Fighter instance as a parameter and modifies a property of it,
... # but any other references to that Fighter elsewhere in your code will see the change.
... def Heal(fighter, health):
...   fighter.Health = fighter.Health + health
...   if (fighter.Health > fighter.MaxHealth):
...     fighter.Health = fighter.MaxHealth
... 
>>> def GiveStrengthBoost(fighter, boost):
...   fighter.Strength = fighter.Strength + boost
We create an instance of the class by calling it like a Function:

Code: Select all

>>> boris = Fighter(10, 100)
We can look up properties by putting a dot then the property name after the name of our variable:

Code: Select all

>>> boris.Strength
10
>>> boris.Health
100
When we call functions that are defined on the class themselves, like 'Damage', we do it with a dot, similar to properties:

Code: Select all

>>> boris.Damage(15)
>>> boris.Health
85
>>> boris.Damage(34)
>>> boris.Health
51
When we call functions that take a class as a parameter, the same instance of the class is modified even if we never run any code to synch up the changes anywhere:

Code: Select all

>>> Heal(boris, 25)
>>> boris.Health
76
>>> Heal(boris, 25)
>>> boris.Health
100
>>> GiveStrengthBoost(boris, 5)
>>> boris.Strength
15
Most importantly, we can have two separate Fighters and use them completely separately, so it's much easier to keep track of all your data:

Code: Select all

>>> steve = Fighter(15, 80)
>>> steve.Health
80
>>> boris.Health
100
>>> steve.Damage(10)
>>> steve.Health
70
>>> boris.Health
100
>>> GiveStrengthBoost(steve, 10)
>>> steve.Strength
25
>>> boris.Strength
15
Server error: user 'Jake' not found

Melkoshi
Regular
Posts: 156
Joined: Tue Jun 02, 2009 8:56 pm
Projects: Jewels of Sytinane
Location: U.s.a.
Contact:

Re: Hmm refreshing variables?

#5 Post by Melkoshi »

Thats really cool Jake. I think I will look into that more. The whole automatic updating with a change is wonderful.

Though the last two examples confused me. Namly because I dont get how it figures to add or sub the numbers from health. But i'm going to asume thats what "heal" and "damage" is defined as.
--- My DeviantArt.
Game in Progress for demo-teaser:
story(script) = 45%
sprites = 100%
programming(interface) = 35%
CGs = 0%
Backgrounds = 5%
Music/sound = 0%

User avatar
Sumoslap
Regular
Posts: 59
Joined: Tue Oct 12, 2010 10:02 pm
Contact:

Re: Hmm refreshing variables?

#6 Post by Sumoslap »

I just want to chime in here and say thank you to Jake for scouring the forums and helping everyone with their problems. I am sure all of the individual posters you've helped are grateful, but I know I've learned a lot just lurking and reading your posts. So thanks from the silent majority as well. Support hero, indeed!

Jake
Support Hero
Posts: 3826
Joined: Sat Jun 17, 2006 7:28 pm
Contact:

Re: Hmm refreshing variables?

#7 Post by Jake »

Melkoshi wrote: Though the last two examples confused me. Namly because I dont get how it figures to add or sub the numbers from health. But i'm going to asume thats what "heal" and "damage" is defined as.
Yeah - in the Fighter class, there was this method defined:

Code: Select all

  def Damage(self, damage):
    self.Health = self.Health - damage
    if self.Health <= 0:
      self.Alive = False
- which takes the 'self' parameter so that it can modify the instance it was called from (boris or steve) and subtracts a value from the 'Health' attribute.
(You can tell it's a member of the class because it's definition was indented further than - or 'inside' - the class definition.)

The 'Heal' method was defined outside of the Fighter class, so it doesn't take the 'self' method, but basically does the same thing:

Code: Select all

def Heal(fighter, health):
  fighter.Health = fighter.Health + health
  if (fighter.Health > fighter.MaxHealth):
    fighter.Health = fighter.MaxHealth
- it's looking at and modifying the members of the class instance that gets passed in - so you pass in 'boris' to the function call, and it heals however much health to boris (at least, up to his 'MaxHealth').

Sumoslap wrote:I just want to chime in here and say thank you to Jake
Aww - you're welcome! I've learned a lot over the years from people helping me out here and there, so it only seems fair. ;-)
Server error: user 'Jake' not found

Melkoshi
Regular
Posts: 156
Joined: Tue Jun 02, 2009 8:56 pm
Projects: Jewels of Sytinane
Location: U.s.a.
Contact:

Re: Hmm refreshing variables?

#8 Post by Melkoshi »

I think I get it. I'll have to play around with it to fully understand it. Thanks again Jake. :3
--- My DeviantArt.
Game in Progress for demo-teaser:
story(script) = 45%
sprites = 100%
programming(interface) = 35%
CGs = 0%
Backgrounds = 5%
Music/sound = 0%

Melkoshi
Regular
Posts: 156
Joined: Tue Jun 02, 2009 8:56 pm
Projects: Jewels of Sytinane
Location: U.s.a.
Contact:

Re: Hmm refreshing variables?

#9 Post by Melkoshi »

One more question..

I see in the first bit, there is no Maxhealth in the list.

Does classes add parts if one asigns them?

Like in the above. it only gives slots for name, health, strength

but then if later you say self.agility

agility will show up inside the class's list of items? is this correct?
--- My DeviantArt.
Game in Progress for demo-teaser:
story(script) = 45%
sprites = 100%
programming(interface) = 35%
CGs = 0%
Backgrounds = 5%
Music/sound = 0%

LordShiranai
Regular
Posts: 188
Joined: Wed Jul 07, 2010 5:49 pm
Completed: Mobile Food Madness, Super Otome Quest
Location: Pacific Northwest
Contact:

Re: Hmm refreshing variables?

#10 Post by LordShiranai »

Very good example by Jake of how to use objects to make things easier.
Melkoshi wrote:One more question..

I see in the first bit, there is no Maxhealth in the list.

Does classes add parts if one asigns them?

Like in the above. it only gives slots for name, health, strength

but then if later you say self.agility

agility will show up inside the class's list of items? is this correct?
In the constructor example, there are two arguments that can be passed two it (aside from the self), strength and health. Then within the constructor, the Maxhealth attribute gets assigned to be equal to the health argument.

If you wanted to add another stat, such as agility, it is probably best to simply modify the constructor to meet your needs.

Code: Select all

...   def __init__(self, strength, health, agility):
...     # you can use 'self' to refer to the particular Fighter you're using
...     # from within any function on the class, but it has to be the first
...     # parameter to each function in the class.
...     self.Strength = strength
...     self.Health = health
...     self.MaxHealth = health
...     self.Agility = agility    # New attribute for agility.
...     self.Alive = True
Naturally you also may wish to add functions that manipulate a Fighter's agility the same way there is a method to manipulate strength as in the rest of Jake's example.

I've noticed that in Python, unlike many other languages, you can create new data attributes on the fly upon an existing instance of a class. However, I feel this isn't really best practice and it is far better (and far less confusing) to declare attributes within the constructor so that the attributes of all existing instances of a class are well known at all times.
Don't Blame Me. I Voted for Vermin Supreme.

Melkoshi
Regular
Posts: 156
Joined: Tue Jun 02, 2009 8:56 pm
Projects: Jewels of Sytinane
Location: U.s.a.
Contact:

Re: Hmm refreshing variables?

#11 Post by Melkoshi »

Thats what I figured would be best in terms of new attributes. But the max health thing is whats confusing me

If classes update on the fly. wouldn't maxhp change because hp changes and we have self.maxhp = self.hp? Or does it not change because it's technically another attribute that we needed not in the orginal list?
--- My DeviantArt.
Game in Progress for demo-teaser:
story(script) = 45%
sprites = 100%
programming(interface) = 35%
CGs = 0%
Backgrounds = 5%
Music/sound = 0%

LordShiranai
Regular
Posts: 188
Joined: Wed Jul 07, 2010 5:49 pm
Completed: Mobile Food Madness, Super Otome Quest
Location: Pacific Northwest
Contact:

Re: Hmm refreshing variables?

#12 Post by LordShiranai »

Melkoshi wrote:Thats what I figured would be best in terms of new attributes. But the max health thing is whats confusing me

If classes update on the fly. wouldn't maxhp change because hp changes and we have self.maxhp = self.hp? Or does it not change because it's technically another attribute that we needed not in the orginal list?
No, because MaxHealth and Health are both basic data types (in this case they are meant to be integers), they are not references to an object or list. So doing something such as fighter.Health = fighter.MaxHealth as in the example Heal function does not make these two persistently equal to each other. The current value of fighter.MaxHealth will be copied into fighter.Health that time only.
Don't Blame Me. I Voted for Vermin Supreme.

Melkoshi
Regular
Posts: 156
Joined: Tue Jun 02, 2009 8:56 pm
Projects: Jewels of Sytinane
Location: U.s.a.
Contact:

Re: Hmm refreshing variables?

#13 Post by Melkoshi »

Ah I gotcha. so it only does the link one time when it's first set in that case.

Therefore formulas inside wouldn't update would they? such as

self.dodge = self.agi * .5 * self.lv

It would only then take the link once. so if I had 5 as agi and 2 as lv. the dodge stat would equal to 5. But then at another point if I made the agi stat = 9. dodge would still equal 5 however.

right?
--- My DeviantArt.
Game in Progress for demo-teaser:
story(script) = 45%
sprites = 100%
programming(interface) = 35%
CGs = 0%
Backgrounds = 5%
Music/sound = 0%

LordShiranai
Regular
Posts: 188
Joined: Wed Jul 07, 2010 5:49 pm
Completed: Mobile Food Madness, Super Otome Quest
Location: Pacific Northwest
Contact:

Re: Hmm refreshing variables?

#14 Post by LordShiranai »

Melkoshi wrote:Ah I gotcha. so it only does the link one time when it's first set in that case.

Therefore formulas inside wouldn't update would they? such as

self.dodge = self.agi * .5 * self.lv

It would only then take the link once. so if I had 5 as agi and 2 as lv. the dodge stat would equal to 5. But then at another point if I made the agi stat = 9. dodge would still equal 5 however.

right?
Correct.

To alleviate this, you could create a function or method that recalculates the dodge value when agi is updated. An example that is line with Jake's previous examples.

Code: Select all

def set_agility(fighter, agility):
    fighter.Agility = agility
    fighter.Dodge = fighter.Agility * .5 * fighter.Level
So if you have a Fighter object named Bob and wanted to make its Agility 5, you'd call it like:
set_agility(Bob, 5)
This would make sure that the Dodge value is calculated correctly each time you set Agility.

I would personally favor creating method under the Fighter class itself that does the same thing, but it is a matter of personal preference IMO.

Code: Select all

class Fighter:

    # Everything else in previous such as constructor goes here...

    def set_agility(self, agility):
        self.Agility = agility
        self.Dodge = self.Agility * .5 * self.Level
Both are basically equivalent, but you'd call the second as:
Bob.set_agility(5)
Don't Blame Me. I Voted for Vermin Supreme.

Melkoshi
Regular
Posts: 156
Joined: Tue Jun 02, 2009 8:56 pm
Projects: Jewels of Sytinane
Location: U.s.a.
Contact:

Re: Hmm refreshing variables?

#15 Post by Melkoshi »

ah! I see now. I'd have to define it basiclly reguardless what I do then. But this way makes it alot less messy.


Now. this is what I am aiming for overall. Base stats(that will be updated each lv) + equipment stats = overall stats. I'm assuming I can then merge two class stats together, but i'm having trouble in visioning on how to point to the correct character to reference.

Example: my base stat is 5. This is set in the first character class as koro.agility = 5.

I then have a item class with stats, if it doesn't effect the stat it'd have 0. so sword1.agility = 5

is there a way to copy a full classes stats over? Like my equipment agility is currently = 0. but when i make the sword1 my equip. the equipment.agility reflects = sword1 agility


and then in the end. the final class would have everything counted as a final.

What I had before was the item stats as a list and having the final stats = [ (basestates[1]+equipstats[1]),]

can this
--- My DeviantArt.
Game in Progress for demo-teaser:
story(script) = 45%
sprites = 100%
programming(interface) = 35%
CGs = 0%
Backgrounds = 5%
Music/sound = 0%

Post Reply

Who is online

Users browsing this forum: Google [Bot], Lacha