Proof Of Concept - Breeding Game

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
Euter Space
Newbie
Posts: 9
Joined: Mon Apr 25, 2016 7:26 pm
Contact:

Proof Of Concept - Breeding Game

#1 Post by Euter Space » Thu Apr 28, 2016 9:23 am

2016-04-29
Asked admin to move thread to this forum, cut most stuff.


Oh, hey there everyone!
The title says it all, at the moment I'm trying my hand at something not usually well suited for a VN engine: A breeding game. And to make it even worse, I'm a complete newbie to any kind of coding or technicy stuff. Don't worry, though, I'll take it slow. Nonetheless, I'll need a little help along the way and that's what I want to use this thread for, asking you guys questions.
But also sharing code examples at later stages and answering questions of my own, if you have any.

I know, I see the red warning: "one question per thread". But there seems to be no better place to put this. I've considered the Cookbook and even posted this thread in the Ideas Subforum first, but there are neither any usable code examples yet nor is it the right kind of game for the WIP section.

Oh, and In case you're wondering what I'm talking about in some of the questions: The species the player takes care of and breeds is called "Ant-Fly".
So far that concludes the intro. Thanks for reading and have a nice day!


Questions
All help is greatly appreciated, thanks in advance!

No.1: Is there a way to display the leading zeros when randomly generating numbers through randint()?

Even though every Ant-Fly is special, it can be tedious to name all of them by hand. So whenever the player doesn't feel like doing it, the game uses a random number between 0000 and 9999 instead.

Code: Select all

$name = renpy.random.randint(0000, 9999)
Sadly, every number below 1000 looses their leading zeros. A 0023 turns into a simple 23, a 0144 into a 144. It's nothing game breaking, personally I think it's nicer to look at if every random number is the same length, though.

No.2: Is there a way to change or add to the name of a variable?

To store the genetics of the Ant-Flies, the game uses variables in the form of boxes. For example, box 1 consists of Box1Name, Box1Gender, Box1Pat, Box1Skin and Box1Eye. If the player buys or breeds a new Ant-Fly, he chooses one of the boxes to put it in. The game has to be prepared for every box to be chosen- so there are several lines of code about what variables to change in every case. At this stage there are only 10 boxes and 5 variables, but there will be a lot more in the future.
After finding out how to add to an equality check, I tried the same with the variable name. Moving the box number to the end of the name for easier access:

Code: Select all

label test:
    $nameN = "Name"
    menu:
        e "Where do you want to put the little fella?"
        "Box 1":
            $BoxNumber = 1
            
    $BoxName + BoxNumber = nameN 
    
    e "[nameN] was put in box [BoxNumber]."
This doesn't work, though. It only gives me a "can't assign to operator". I'm assuming RenPy tries to do math instead of just adding to the name of the variable. I've tried to put all kinds of brackets around both variables in several combinations to prevent this from happening, no luck yet.
Bonus Question: How to combine two variables (or plain text and a variable) into another variable and display it? I can't get that to work either, hence the workaround in the example above.

Code: Select all

label test:
    $BoxName1 = "Name"
    $BoxNumber = 1 

    
    e "[BoxName[BoxNumber]] was put in box [BoxNumber]."

label test:
    $BoxName1 = "Name"
    $BoxNumber = 1 
    $BoxName = "BoxName"

    
    e "[[BoxName][BoxNumber]] was put in box [BoxNumber]."
Both variants don't work. All I get is a "string indices must be integers, not unicode".

No.3: Is there an easy way to group things and check for dependencies between the grouped objects?

There are 7 genetic archetypes that have a certain bonus to be inherited corresponding to the pattern/color/eye combinations of the parents and the already inherited features of the offspring. Lucky for me, matching patterns and colours share the same name, so checking for a connection between the 2 is as easy as "if pattern == skin". If I want the game to check if the eye colour matches as well, it has to check every colour individually. A simplified example:

Code: Select all

    if eyecolour == "blue":
        if skin == "orange":
            #bonus happens
        elif skin != "orange":
            #no bonus happens
            
    elif eyecolour == "lilac":
        if skin == "yellow":
            #yay
        elif skin != "yellow":
            #nope
Blue and orange match, lilac and yellow as well. Blue and yellow do not match, just as lilac and orange do not. Is there a better way to do this? I was thinking about putting all skin pattern/colour choices in a list and all eye colours in another list, but with the matching combinations in the same spot respectively. Then have the game check for the same position or something. I'm not sure how to do that, though.


Thank you for taking the time to read through my questions. If anything I'm asking is unclear and needs more details or examples, please tell me.
Last edited by Euter Space on Fri Apr 29, 2016 5:17 am, edited 5 times in total.

User avatar
Euter Space
Newbie
Posts: 9
Joined: Mon Apr 25, 2016 7:26 pm
Contact:

Re: Ant-Fly [ProofOfConcept/Breeding/Stat Raising/Management

#2 Post by Euter Space » Thu Apr 28, 2016 9:23 am

Reserved.
Last edited by Euter Space on Fri Apr 29, 2016 3:50 am, edited 1 time in total.

drKlauz
Regular
Posts: 168
Joined: Mon Oct 12, 2015 3:04 pm
Contact:

Re: Ant-Fly [ProofOfConcept/Breeding/StatRaising/Management]

#3 Post by drKlauz » Thu Apr 28, 2016 11:26 am

>Is there a way to display the leading zeros when randomly generating numbers through randint()?

Code: Select all

$name = '%04d'%renpy.random.randint(0000, 9999)
>Is there a way to change or add to the name of a variable?

Wrong:

Code: Select all

$BoxName + BoxNumber = nameN 
Less wrong:

Code: Select all

$nameN = BoxName + str(BoxNumber) 
Left side is where result should be, right side is what you want there.

You really should use more complex structures for such game, i believe.

Kinda ok:

Code: Select all

init python:
  class TAnt(renpy.store.object):
    def __init__(self,Name,Color):
      self.BoxNumber=None
      self.Name=Name if Name is not None else '%04d'%renpy.random.randint(0000, 9999)
      self.Color=Color
    def Place(self,BoxNumber=None):
      if self.BoxNumber is not None:
        Boxes[self.BoxNumber].remove(self)
      self.BoxNumber=BoxNumber
      if BoxNumber is not None:
        Boxes[BoxNumber].append(self)

  def ListAntsInBox(BoxNumber):
    rv=[]
    for Ant in Boxes[BoxNumber]:
      rv.append(Ant.Name)
    return ','.join(rv) if len(rv)>0 else 'noone'

label start:
  $Boxes=[[]]*11

label test:
  $AntNames=ListAntsInBox(2)
  "In box#2 lives [AntNames]"
  $Ant=TAnt('Bob','Lilac')
  $Ant.Place(2)
  "[Ant.Name] was put in box [Ant.BoxNumber]."
  $Ant=TAnt('Alice','Yellow')
  $Ant.Place(2)
  "[Ant.Name] was put in box [Ant.BoxNumber]."
  $AntNames=ListAntsInBox(2)
  "In box#2 lives [AntNames]"
  $Ant.Place(None)
  "[Ant.Name] was removed from box."
  $AntNames=ListAntsInBox(2)
  "In box#2 lives [AntNames]"

  "byebye"
return
>Is there an easy way to group things and check for dependencies between the grouped objects?

You can play with sets or dicts. Need to see whole picture (how many traits, how they defined, how they can be combined, etc) to properly suggest solution.
Or simply write huge if/elif/else mostrosity, heh.

User avatar
Euter Space
Newbie
Posts: 9
Joined: Mon Apr 25, 2016 7:26 pm
Contact:

Re: Ant-Fly [ProofOfConcept/Breeding/StatRaising/Management]

#4 Post by Euter Space » Fri Apr 29, 2016 4:39 am

drKlauz wrote:

Code: Select all

$name = '%04d'%renpy.random.randint(0000, 9999)
Works like a charm, thanks!
drKlauz wrote:Wrong:

Code: Select all

$BoxName + BoxNumber = nameN 
Less wrong:

Code: Select all

$nameN = BoxName + str(BoxNumber) 
Left side is where result should be, right side is what you want there.
Actually I want to define BoxName1, not nameN. I'm trying to put the names of two variables, BoxName and BoxNumber (that is "1", in this example), together to form BoxName1 and then define it (no idead if that even works). I somehow want to work around having to write an extra line of code for every single box. At the moment it looks like this:

Code: Select all

    if BoxNumber == 1:
        $BoxName1 = nameN
    elif Boxnumber == 2:
        $BoxName2 = nameN
    #etc.
And it's only the name in this example. In reality, there will be 20+ variables and 50+ boxes. x_x
drKlauz wrote:You really should use more complex structures for such game, i believe.

Kinda ok:

Code: Select all

init python:
  class TAnt(renpy.store.object):
    def __init__(self,Name,Color):
      self.BoxNumber=None
      self.Name=Name if Name is not None else '%04d'%renpy.random.randint(0000, 9999)
      self.Color=Color
    def Place(self,BoxNumber=None):
      if self.BoxNumber is not None:
        Boxes[self.BoxNumber].remove(self)
      self.BoxNumber=BoxNumber
      if BoxNumber is not None:
        Boxes[BoxNumber].append(self)

  def ListAntsInBox(BoxNumber):
    rv=[]
    for Ant in Boxes[BoxNumber]:
      rv.append(Ant.Name)
    return ','.join(rv) if len(rv)>0 else 'noone'

label start:
  $Boxes=[[]]*11

label test:
  $AntNames=ListAntsInBox(2)
  "In box#2 lives [AntNames]"
  $Ant=TAnt('Bob','Lilac')
  $Ant.Place(2)
  "[Ant.Name] was put in box [Ant.BoxNumber]."
  $Ant=TAnt('Alice','Yellow')
  $Ant.Place(2)
  "[Ant.Name] was put in box [Ant.BoxNumber]."
  $AntNames=ListAntsInBox(2)
  "In box#2 lives [AntNames]"
  $Ant.Place(None)
  "[Ant.Name] was removed from box."
  $AntNames=ListAntsInBox(2)
  "In box#2 lives [AntNames]"

  "byebye"
return
I've never heard of classes before, but you suggesting it made me do some research on what they are and how they work. Mostly so i could follow your example in the first place.^^ That's a very interesting system and seems to have great potential. Plus I can't stop imaginig little Bob and little Alice in their little box. I'm not exactly sure how this will interact with my other mechanics, though. I'll look into that more at the weekend, probably spawning more questions.
drKlauz wrote:You can play with sets or dicts. Need to see whole picture (how many traits, how they defined, how they can be combined, etc) to properly suggest solution.
Or simply write huge if/elif/else mostrosity, heh.
Not gonna lie, at this point the whole game is one big if/elif/else monstrosity...^^ I have an idea what to try about this, looking into that at the weekend as well. Will report any succusses and failings and put together a more detailed question then as well.

Thanks for the help, drKlauz!

drKlauz
Regular
Posts: 168
Joined: Mon Oct 12, 2015 3:04 pm
Contact:

Re: Proof Of Concept - Breeding Game

#5 Post by drKlauz » Fri Apr 29, 2016 6:19 am

Code: Select all

    if BoxNumber == 1:
        $BoxName1 = nameN
    elif Boxnumber == 2:
        $BoxName2 = nameN
    #etc.
List+Index is much better solution to this. This way you can change total boxnumbers, change how you name boxes. If you hardcode something, like box definition, you will suffer later, when you decide to add different box types for example.

>Mostly so i could follow your example in the first place.^^

If you decide to focus on game mechanics, i'm available for hire as programmer/consultant haha

Anyway, if you plan something complex, then it's good idea to make things as generic as possible. Don't hardcode any constants, don't copy paste code, don't write huge if/elif/else bedsheets.

>Is there an easy way to group things and check for dependencies between the grouped objects?
>Not gonna lie, at this point the whole game is one big if/elif/else monstrosity...^^

You can do something like this:

Code: Select all

init python:
  AntBaseValue=5
  ValueBonuses=[
    [{'Color':'Rainbow'}, 1000],
    [{'EyeColor':'Pink'}, 7],
    [{'Color':'Lilac','EyeColor':'Pink'},10],
    [{'Color':'White','EyeColor':'Red'}, 100],
    ]

  class TAnt(renpy.store.object):
    def __init__(self,Name,Color,EyeColor):
      self.BoxNumber=None
      self.Name=Name if Name is not None else '%04d'%renpy.random.randint(0000, 9999)
      self.Color=Color
      self.EyeColor=EyeColor
    def Place(self,BoxNumber=None):
      if self.BoxNumber is not None:
        Boxes[self.BoxNumber].remove(self)
      self.BoxNumber=BoxNumber
      if BoxNumber is not None:
        Boxes[BoxNumber].append(self)
    @property
    def Value(self):
      Value=AntBaseValue
      for BonusReq,Bonus in ValueBonuses:
        Match=True
        for Attr,Val in BonusReq.items():
          if getattr(self,Attr)!=Val:
            Match=False
            break
        if Match:
          Value+=Bonus
      return Value

label start:
  $Alice=TAnt('Alice','White','Red')
  $Bob=TAnt('Bob','White','Pink')
  $Charlie=TAnt('Charlie','Rainbow','Pink')
  "[Alice.Name] cost [Alice.Value], [Bob.Name] cost [Bob.Value], [Charlie.Name] cost [Charlie.Value]"

  "byebye"
return

User avatar
Euter Space
Newbie
Posts: 9
Joined: Mon Apr 25, 2016 7:26 pm
Contact:

Re: Proof Of Concept - Breeding Game

#6 Post by Euter Space » Mon May 02, 2016 1:21 pm

drKlauz wrote:List+Index is much better solution to this. This way you can change total boxnumbers, change how you name boxes. If you hardcode something, like box definition, you will suffer later, when you decide to add different box types for example.
I spend the better part of the weekend reading about lists and dicts. They open up a number of possibilities, but I haven’t settled on a definite concept yet. Every time I think of how to do something, I wonder if there's a better/shorter way to do it.
Especially since you posted that model code.
drKlauz wrote:You can do something like this:

Code: Select all

[...]
This is magic. I wasn’t even thinking about how to handle pricing, yet, since everything else was a mess already. Now I won’t have to worry about it. This is so neat.
Obviously, me playing around with the example you provided spawned some new questions and I've bumped into a few problems here and there.

Would it be possible to add a value bonus to everything, BUT a certain combination?
Checking for certain matches is mostly for inheritance (though certain merchants absolutely want matches for value), for pricing I want to encourage getting new color combinations.

Code: Select all

    AntBaseValue=5
    ValueBonuses=[
        #This is one of the seven archetypes: citrus-citrus-aqua
        [{'pat':'citrus','skin':'citrus','eye':'aqua'},10],
        #Archetypes are favoured when it comes to inheritance, so mixed colors are harder to get and should be given a value bonus (unless you try to sell them to the local ‘Archetype Breeding Association’, of course). 
        #The next few lines only have 2 matches. And while everyone who doesn't match gets the bonus, it doesn't exclude the correct match. So a citrus-citrus-aqua would still get the bonus.
        [{'pat':'citrus','skin':'citrus'},100]
        [{'pat':'citrus','eye':'aqua'},100],
        [{'skin':'citrus','eye':'aqua'},100],
        #This simply doesn't work. I didn't expect it to be this easy anyway and kinda just included this line because it demonstrates what I want to achieve in a very simple way.
        [{'pat':'citrus','skin':!='citrus','eye':'aqua'},100],
        #Since I don't know how to exclude certain attributes, I don't even know where to start to give another bonus to combinations with no match at all.
        ]
How to access the boxes?
I can add a box number to any Ant-Fly I want and they get stored in a list/dict (I guess?). But how would I restrict the boxes? Have box 1 only be able to hold 1 Ant-Fly and because females are bigger have them not fit into box 1 at all, but because box 2 is another box type it can hold up to two male Ant-Flies/ one female or something like that. I've yet to figure out how to even display the contents of a certain box.

Code: Select all

    "Box 1 is kinda cramped by now. Inside the box are: [Boxes[1]]."
    #Doesn't quite work. (KeyError:1L)  
I have some ideas how to handle the boxes, especially after I found out that this works:

Code: Select all

    $boxname = [0,"Empty","Empty","Empty"]
    $nameN = "Pretzel"
    $BoxNumber = 2
    "I have an Ant-Fly named [nameN]."
    "[nameN] will be put in box [BoxNumber]."
    $boxname[BoxNumber] = nameN
    "[boxname[2]] is now in box [BoxNumber]."
    #Sadly, this doesn't work:
    #"[boxname[BoxNumber]] is now in box [BoxNumber]."
Most of them include a lot of if/elif/else, though. Nevertheless it's a lot better than before.

How to add a new Ant-Fly to the Ant class?
All the Ant-Flies in the example were pre-defined. To do that, I have to know the name of the Ant-Fly. The names are player input/randomly generated, though. I could use "placeholder Ants", maybe call them Ant1, Ant2,... but that ends in the exact same spot as all the BoxName1, BoxName2 variables.
I read some examples for dynamically generated variables in loops, but everyone seems to agree that those are of the devil and dicts would do a much better job. How to use them with the class example you provided?
drKlauz wrote:If you decide to focus on game mechanics, i'm available for hire as programmer/consultant haha
Thank you for offering, but this is only an ambitious learning project. And while I'm willing to share with anyone who is interested (everybody should have an Ant-Fly), this is mostly a private game I want to make because I want to play it myself.^^
I'm very thankful for all the advice you've given me so far and I'll work hard to put it to good use. Thanks again, drKlauz!

Not much time over the course of the week. At the weekend I'll try to use everything I learned to rewrite the box system and implement a first money system (earlier than expected). I've also one eye on the stats and another half eye on energy/day cycles.
Last edited by Euter Space on Mon May 02, 2016 3:03 pm, edited 1 time in total.

drKlauz
Regular
Posts: 168
Joined: Mon Oct 12, 2015 3:04 pm
Contact:

Re: Proof Of Concept - Breeding Game

#7 Post by drKlauz » Mon May 02, 2016 2:51 pm

I wonder if there's a better/shorter way to do it.
Python is very expressive language, there is some bad sides too, but overall i pretty much love it. Once you learn it you can really do things incredible easy and quick.
Would it be possible to add a value bonus to everything, BUT a certain combination?
Set basic value to higher value and specific combination bonus to negative number.
You can actually use function as combination buff:

Code: Select all

  def ApplyRainbowGen(Child):
    Child.Color='Rainbow'

  InheritanceBonuses=[
    [{'Color':'Rainbow'}, ApplyRainbowGen],
    ]

  def ApplyInheritanceBonus(Child,Parent):
    for BonusReq,Bonus in ValueBonuses:
      Match=True
      for Attr,Val in BonusReq.items():
        if getattr(Parent,Attr)!=Val:
          Match=False
          break
      if Match and callable(Bonus):
        Bonus(Child)

  def MakeBaby(Male,Female):
    Child=TAnt(None,'Black','Black')
    ApplyInheritance(Child,Male)
    ApplyInheritance(Child,Female)
After re-reading, i think you can indeed use something like this

Code: Select all

  ValueBonuses=[
    # notice !Red
    [{'Color':'White','EyeColor':'!Red'}, 100],
    ]

    def Value(self):
      Value=AntBaseValue
      for BonusReq,Bonus in ValueBonuses:
        Match=True
        for Attr,Val in BonusReq.items():
          if Val[0]=='!':
            Val=Val[1:]
            Test=lambda a,b: a!=b
          else:
            Test=lambda a,b: a==b
          if not Test(getattr(self,Attr),Val):
            Match=False
            break
        if Match:
          Value+=Bonus
      return Value
How to access the boxes?
I would create class for Box, then maybe class AntFarm, which will contain and handle boxes.
During Ant.Place method, i would call Box.CanPlace(Ant) to check if ant will fit.
How to add a new Ant-Fly to the Ant class?
Ants probable shouldn't be predefined at all. During ant creation you should keep it in generic variable "Ant", once you created it fully, then place ant in box, so only box will handle it, and forget about Ant. Tho you should be careful if you interconnect box and ant, if you link box by number, everything ok, but if you keep box link in ant as direct reference, then you can get memory leak. It's kinda tricky sometimes.
Thank you for offering, but this is only an ambitious learning project.
It was half-joke, but still while i can answer simple question during teatime or when i want distraction from my main project, i can't answer all questions.

User avatar
Euter Space
Newbie
Posts: 9
Joined: Mon Apr 25, 2016 7:26 pm
Contact:

Re: Proof Of Concept - Breeding Game

#8 Post by Euter Space » Mon May 09, 2016 7:50 am

Finished rewriting the whole box part, added placeholder UI (figuring that out probably took most of the time...) and implemented the money system. Thanks to mainly the last part, this whole thing already feels a little bit like a game.
I'll probably only ask something once a week and depending on what I've been doing in between, difficulty and quantity of questions may vary (like this week, where there is only about 1 1/2 questions).
drKlauz wrote:After re-reading, i think you can indeed use something like this

Code: Select all

[...]
Works! I can now give bonuses to double-matches plus new colours. And even balance it so that new skin patterns and colours are worth more than just a new eye colour. Beautiful.
Zero-matches (combinations of traits from three different archetypes) still give me trouble, though. Takes a line of code for every possibility. But I have no idea how to change the value calculation to better incorporate this (not only in the technical sense), since it's not as easy as simply excluding something. Maybe it's okay as it is.
drKlauz wrote:Ants probable shouldn't be predefined at all. During ant creation you should keep it in generic variable "Ant", once you created it fully, then place ant in box, so only box will handle it, and forget about Ant. Tho you should be careful if you interconnect box and ant, if you link box by number, everything ok, but if you keep box link in ant as direct reference, then you can get memory leak. It's kinda tricky sometimes.
For the moment I use the ant class mainly for value calculation. The boxes themselves consist of several lists (boxname, boxgender, etc.), so I can make use of the list position to dynamically change and display the stats of a specific ant in a specific box. If a box is full, empty or locked is determined by name. This will get a little more interesting when I try to add boxes with multiple ants (box types) and ants with multiple traits of the same type (perks).
drKlauz wrote:I would create class for Box, then maybe class AntFarm, which will contain and handle boxes.
During Ant.Place method, i would call Box.CanPlace(Ant) to check if ant will fit.
^This will probably come into play then.

A more recent problem I've encountered while setting all this up is that text in the screens.rpy seems to behave differently than the script.rpy:

Code: Select all

"This is box [boxnumber]. Inside lives [boxname[boxnumber]]."
Works just fine as dialogue in the script.rpy, but adding the same variables to a label or just plain text either makes the label/text not appear or gives me an error. I wonder why that is?
drKlauz wrote:It was half-joke, but still while i can answer simple question during teatime or when i want distraction from my main project, i can't answer all questions.
Absolutely. Answer questions as long as you're having fun/ relax while doing it.
And as always, thanks again, drKlauz! (:

drKlauz
Regular
Posts: 168
Joined: Mon Oct 12, 2015 3:04 pm
Contact:

Re: Proof Of Concept - Breeding Game

#9 Post by drKlauz » Mon May 09, 2016 9:42 am

Zero-matches (combinations of traits from three different archetypes) still give me trouble, though.
Don't understand what exactly you want to get. It really helps if you provide not only description of problem, but also test cases. Something simple code like:

Code: Select all

#i have some ant
Ant=TAnt('Green','White')
#...

#...
#here i want to check if his eyes are white
WhiteEyes=...?
#...

#...
#here i use WhiteEyes
if WhiteEyes:
  '[Ant.Name] is blind :('
For complex combinations you can actually use classes(again):

Code: Select all

init python:
  AntBaseValue=5

  class TAnt(renpy.store.object):
    def __init__(self,Name,Color,EyeColor):
      self.BoxNumber=None
      self.Name=Name if Name is not None else '%04d'%renpy.random.randint(0000, 9999)
      self.Color=Color
      self.EyeColor=EyeColor
      self.CalculateValue()
    def Place(self,BoxNumber=None):
      if self.BoxNumber is not None:
        Boxes[self.BoxNumber].remove(self)
      self.BoxNumber=BoxNumber
      if BoxNumber is not None:
        Boxes[BoxNumber].append(self)
    def CalculateValue(self):
      self.Value=AntBaseValue
      for Bonus in Bonuses:
        if Bonus.DoCheck(self):
          Bonus.DoApply(self)
      return self.Value

  Bonuses=[]

  class BonusMeta(type):
    def __init__(cls,name,bases,dct):
      #this black magic allow Bonuses autoregistration
      #no need to manually add every bonus to list
      if name!='TBonusBase':
        Bonuses.append(cls)
      #this black magic allow to ignore boilerplate code, like @staticmethod
      cls.Check=staticmethod(cls.Check.__func__)
      cls.Apply=staticmethod(cls.Apply.__func__)

  #it can be anything, not just bonuses, genetic inheritance fit here quite nicely
  class BonusBase:
    __metaclass__=BonusMeta #part of black magic, mentioned above
    @classmethod
    def DoCheck(cls,Ant):
      for parent in cls.__mro__:
        if parent is BonusBase: break
        if not parent.Check(Ant): return False
      return True
    @classmethod
    def DoApply(cls,Ant):
      cls.Apply(Ant)
#     if you want cascade bonuses, then uncomment next 3 lines and comment previous
#      for parent in cls.__mro__:
#        if parent is BonusBase: break
#        parent.Apply(Ant)
    def Check(Ant):
      return True
    def Apply(Ant):
      pass

  #Add value if Ant color is Rainbow
  class BonusRainbowColor(BonusBase):
    def Check(Ant):
      return Ant.Color=='Rainbow'
    def Apply(Ant):
      Ant.Value+=100

  #Add value if Ant color is Rainbow AND Ant eye color in Rainbow
  class BonusRainbowColorAndEyeColor(BonusRainbowColor):
    def Check(Ant):
      return Ant.EyeColor=='Rainbow'
    def Apply(Ant):
      Ant.Value+=150
      #if you cascade bonuses then total bonus will be +100 for color, +100+150 for color+eyes
      #if you not cascade then total bonus will be +100 for color, +150 for color+eyes
      #Apply cascading allow some tricky, but make things more complicated
      #you probably should keep cascading of Checks, but not cascading of Apply

  #Add value if Ant color wasn't unlocked before
  #When player sell Ant for example, you add Ant color to UnlockedColors
  #Or you can change bonuses to grant bonus only to first Ant with such color
  class BonusNewColor(BonusBase):
    def Check(Ant):
      return Ant.Color not in UnlockedColors
    def Apply(Ant):
      Ant.Value+=10

label start:
  $UnlockedColors=['White']

  $Alice=TAnt('Alice','Red','Red') #+10 for Unlocked color, +5 default value
  $Bob=TAnt('Bob','White','Pink') #+5 default value
  $Charlie=TAnt('Charlie','Rainbow','Pink') #+100 for Color, +10 for Unlocked color, +5 default value
  $Diana=TAnt('Diana','Rainbow','Rainbow') #+150 for Color+Eye, +100 for Color, +10 for Unlocked color, +5 default value
  "[Alice.Name] cost [Alice.Value], [Bob.Name] cost [Bob.Value], [Charlie.Name] cost [Charlie.Value], [Diana.Name] cost [Diana.Value]"

  "byebye"
return
The boxes themselves consist of several lists (boxname, boxgender, etc.), so I can make use of the list position to dynamically change and display the stats of a specific ant in a specific box.
So instead of "Boxes[BoxNumber][AntNumber].Name" you use "boxname[BoxNumber][AntNumber]"? Not sure i can see any benefit in this tbh, but it's your choice heh.
Works just fine as dialogue in the script.rpy, but adding the same variables to a label or just plain text either makes the label/text not appear or gives me an error. I wonder why that is?
I can't see problem just from this line, what error, what code, etc?
Best option (if you don't mind sharing game) is put you game on http://github.com and share link, so if you have something not working, someone can simple download you game and see what is wrong there.
Answer questions as long as you're having fun
What can i say, i LOVE programming, especially tricky. Especially in python.

User avatar
Euter Space
Newbie
Posts: 9
Joined: Mon Apr 25, 2016 7:26 pm
Contact:

Re: Proof Of Concept - Breeding Game

#10 Post by Euter Space » Mon May 09, 2016 9:38 pm

drKlauz wrote:Don't understand what exactly you want to get. It really helps if you provide not only description of problem, but also test cases.
Sorry, of course. I kinda left it in the open because I wasn't sure if I'm asking too much if I want to add yet another mechanism to your formula.
So, what I'm trying to do is the following:

Code: Select all

    #This is my value list.
    #The visual trait matches/archetypes are: citrus(skin pattern)-citrus(skin color)-aqua(eye color), cream-cream-brown, king-king-red, mint-mint-lilac, pearl-pearl-grey, sky-sky-white and tiger-tiger-black.
    AntBaseValue=5
    ValueBonuses=[
        #The list starts with "citrus". (and I'll probably cut the code for the other colors for this example, since they look exactly the same, just with different names) 
        #Every single part gives a small value increase.
        [{'pat':'citrus'}, 5],
        [{'skin':'citrus'}, 5],
        [{'eye':'aqua'}, 5],
        #The whole set (archetype) gives an additional bonus. 
        [{'pat':'citrus','skin':'citrus','eye':'aqua'},10],
        #Breeding another pattern, skin oder eye color into the set, while leaving two traits from the original archetype in place, gives an even greater bonus. 
        [{'pat':'citrus','skin':'!citrus','eye':'aqua'},50],
        [{'pat':'!citrus','skin':'citrus','eye':'aqua'},50],
        #Only another eye color is worth slightly less. 
        [{'pat':'citrus','skin':'citrus','eye':'!aqua'},25],
        
        #What's missing now is the next step: An Ant-Fly that was bred with traits from three different archetypes.
        #For example "citrus-cream-lilac". 
        #The Ant-Fly possesses the pattern "citrus", usually part of the archetype "citrus-citrus-aqua", the skin color "cream", usually part of the archetype "cream-cream-brown" and the eye color "lilac", usually part of the archetype "mint-mint-lilac".
        #It can be anything, though, might as well be a "king-tiger-grey" or a "pearl-mint-white", as long as it consists of three different "natural" colors.
        #It's kinda difficult to breed this, so I want to reward it. But I cannot use this:
        
        [{'pat':'citrus','skin':'!citrus','eye':'!aqua'},100],
        
        #While it does give a bonus to any combination that contains the pattern "citrus" plus any skin that is not "citrus" and any eye color that is not "aqua", it doesn't prevent the two extra traits from matching on their own.
        #A "citrus-cream-brown" Ant-Fly would get the same bonus as a "citrus-cream-lilac" Ant-Fly, even though it consists of a two-match (cream + brown).
        #So the system would have to determine the pattern first.
        #In this example, it's "citrus", so the skin color can't be "citrus". In this example, the skin color is "cream" (could be anything except "citrus", though).
        #If the skin pattern is "citrus" and the skin color "cream", the eye color cannot be "aqua" or "brown". But that's okay, because in this example it's "lilac".
        #And only if all of this applies, the bonus is added to the value.
I hope this is a little better. If you need anything else, like the full list of code for all the colours (they really look all the same, though), just tell me and I'll provide it.
drKlauz wrote:So instead of "Boxes[BoxNumber][AntNumber].Name" you use "boxname[BoxNumber][AntNumber]"? Not sure i can see any benefit in this tbh, but it's your choice heh.
This is mostly because I didn't (and probably still don't) fully understand classes (but I'm working on it!), so it was kind of the "easy way out". Things get rewritten as I understand more and more and I go back to your earlier suggestions as well, considering them again, whenever I've acquired some more coding knowledge. Nothing is going to waste.
So there probably is no benefit to be seen, because there is none.^^
drKlauz wrote:I can't see problem just from this line, what error, what code, etc?
Yes, here:

Code: Select all

    #For example this is part of the game's script file:
    #The boxnumber is chosen beforehand and applying name, gender etc to the correct place on the list works.
    $boxname[boxnumber] = nameN
    $boxgender[boxnumber] = genderN
    $boxpat[boxnumber] = patN
    $boxskin[boxnumber] = skinN
    $boxeye[boxnumber] = eyeN
    #Also, if I want to display the information through the dialogue window, the correct traits are shown as well.
    "You named your new Ant-Fly [boxname[boxnumber]]. It is a [boxgender[boxnumber]] with [boxpat[boxnumber]] patterned skin in [boxskin[boxnumber]] color and with [boxeye[boxnumber]] eyes."
    
    #Now switching to the screens file.
screen boxes_single():
    frame:
        xalign 0.5
        xpos 500
        ypos 300
        has vbox
        #The first line will not display at first, but will appear after exiting and re-entering the screen.
        label _("{color=#ff84a2}This is box {b}[boxnumber]{/b}.{/color}")
        #The second and third line won't appear at all or crash the game with a "TypeError: list indices must be integers, not str"
        label _("{color=#ff84a2}Inside lives {b}[boxname[boxnumber]]{/b}.{/color}")
        label _("{color=#ff84a2}A {b}[boxgender[boxnumber]]{/b} with {b}[boxpat[boxnumber]]{/b} patterned skin in {b}[boxskin[boxnumber]]{/b} color and with {b}[boxeye[boxnumber]]{/b} eyes.{/color}")        
drKlauz wrote:For complex combinations you can actually use classes(again):

Code: Select all

[...]
Oh dear. That's massive. I'll have to go through that line after line. But I'm already loving the possibility to unlock traits. It's like you're predicting the future. I was just thinking about this and you've already made it. Just like with the value system before. Black magic indeed.^^
drKlauz wrote:Best option (if you don't mind sharing game) is put you game on http://github.com and share link, so if you have something not working, someone can simple download you game and see what is wrong there.
I've never used GitHub, I'll have a look at it.
Last edited by Euter Space on Tue May 10, 2016 5:48 am, edited 1 time in total.

drKlauz
Regular
Posts: 168
Joined: Mon Oct 12, 2015 3:04 pm
Contact:

Re: Proof Of Concept - Breeding Game

#11 Post by drKlauz » Tue May 10, 2016 5:45 am

So, what I'm trying to do is the following:

Code: Select all

...
I hope this is a little better.
NSFW link https://www.youtube.com/watch?v=7Dt5Nf7ct5c

Ooooookey... You see i'm not native english speaker (it's obvious i guess), also i know nothing about ant-flies, heck i know very little about regular ants. So you should excuse me for my ignorance.

I don't understand what you want to get, but i think Bonus class i showed in previous post can handle it. It provide generic way to check any conditions you want, and, if conditions met, generic way to alter ant or box or anything else you want. Once you understand how it works.

Let's try it from different angle.
This is mostly because I didn't (and probably still don't) fully understand classes (but I'm working on it!)
Pretty much everything in python (and renpy, more or less) is object.

You have book ("Big Fancy Dictionary 2nd ed.").
This dictionary book contain entries ("Squirel (noun) - little squiky pest").
"Squirel" is key, by which you find entry.
"Little squeaky pest" is value, bound to key.
"(noun)" is additional technical information about value.

Object is like dictionary book.
You have book (Ant).
It has keys (Name, Color, Value).
Some keys has additional info (Name and Color are simple Attributes, containing string or number or list, but CaclulateValue is code Attribute, so it's defined bit differently).
And each key has value (Name->"Alice", Color->"Lilac"). Some keys contain not string values, but code values, it's called methods.
You can consider simple Attributes(Name,Color) as Nouns, and Methods(CalculateValue) as Verbs.
There is things like "property", which behave like Noun, but Verb under cover.

Object created by Class. Class is template, blueprint for object. Like real dictionary book created by telling printer to print from PDF file, Object created by telling Python to create Instance from Class.

Classes can cascade using inheritance. It's like "Squirel - *see Big Book of Biology vol. III*", so you have base book which you can look if you not found entry in current book.

Class - blueprint of object.
Object - generic name for thing created from class.
Instance of Class X - specific object created from specific class X.
Attribute - dictionary entry, Key:Value
Method - Attribute with executable code Value.

Code: Select all

init python:
  #python and renpy ignore everything "#", it's called single-line comment
  #new class TAnt(with parent class, need in RenPy, but can be omited in real python for this case)
  class TAnt(renpy.store.object):
    #this special method __init__ used when you tell Python to create Instance of class TAnt
    #it's always must be called __init__, this how Python understand what to call
    #self, Name, Color is function arguments
    #self is special argument, it automatically added as first argument to every class method call
    #self is variable pointing on object itself
    #it can be called anyway you wish, but better keep it as "self"
    #Name and Color is your arguments used to initialize Ant
    def __init__(self,Name,Color):
      #we set values to keys of object
      self.Name=Name
      self.Color=Color
      #notice we didn't used CalculateValue(self), as self is auto added by python
      CalculateValue()
    #this is method, it calculate and set ant value
    def CalculateValue(self):
      #we set attribute Value of instance self
      self.Value=10
      #methods as function return things, we can skip this part, then function return None
      return self.Value

#world of python is ended, we entered renpy world
start:
  #lines in RenPy world started with $ are python code lines
  #we tell python to create instance of class TAnt, with arguments Name: "Alice" and Color: "Red"
  #now in variable Alice point to object, newly created instance of TAnt
  $Alice=TAnt('Alice','Red')

  #RenPy read from object Alice, value bound to key Name, which is string "Alice"
  "[Alice.Name] is lovely."
return
I'm very bad teacher, so here some better option:
https://www.codecademy.com/learn/python
https://www.quora.com/Which-online-Pyth ... s-the-best - some more

Some code i use is simple (Ant class). Some is harder (mix of methods, dictionaries and inheritance). Some hard code is optional, used in one place, to make other global codes simpler, like with metaclass thing.

If you don't understand some of my code, simple tell "i don't understand this line, please explain". It's ok to not know at start, it's not ok to hide ignorance until it's too late.

Or if you don't want to dive too deep in python, i can stop torturing you and leave you alone :lol:
After all you have some working ways you already understand. Noone really care if game code good looking, bad or ugly, if game itself is good. Not everything i do is good for everyone.
So if my code confuse you too much, simple tell "sorry, i don't understand your code and don't have time to learn", it's normal situation.
This situation is reason why gamedev teams consists of artists, game designers, coders, composers, writers, proofreaders and others. Each guy doing certain role he know.

User avatar
Euter Space
Newbie
Posts: 9
Joined: Mon Apr 25, 2016 7:26 pm
Contact:

Re: Proof Of Concept - Breeding Game

#12 Post by Euter Space » Tue May 10, 2016 7:25 am

Ah, I'm no native English speaker as well, so my descriptions could be better, too, I guess. The thing itself is actually pretty simple, but very difficult for me to express in mock-up code.

I clearly stated that this is a learning project, so don't worry, you're in no way torturing me. (:
I want to learn everything I need to know to make the best version of the game I'm imagining possible. Time is a factor, yes. I don't have a lot of it to spend on the project, but that doesn't mean I don't want to understand or just get done with it- that just means it will take a longer time.

Thank you for spending your time explaining and even encouraging more questions. I'll make sure to work through the bulk of new information you've given (thankfully, long weekend coming up) and make an effort to understand and improve. No easy ways out this time!

(some optional Ant-Fly information:)
Actually in the real world an Ant-Fly is a type of artificial bait used for fly fishing.^^
In the case of this game it's some kind of fantasy creature, mostly inspired (visually and behaviour-wise) by a mixture of ant and butterfly, but some other species as well. You can have a look at my two favourite males here, if you're interested. My second experiment ever in Sculptris (free little 3D sculpting program), so it still needs to be improved. Males have a very fleshy body, colourful and sweet-tasting, and are used to make all kinds of stuff. Tooth paste, gum, food colouring, sugar or even rubber. Females are not done yet, but they will look a lot more insect-like. Because of their hard bodies and bitter taste, they're mostly used for breeding, fighting and displaying, but their shell and razors still make nice cufflinks or jewellery bordering. Well, or bitter chocolate.^^

drKlauz
Regular
Posts: 168
Joined: Mon Oct 12, 2015 3:04 pm
Contact:

Re: Proof Of Concept - Breeding Game

#13 Post by drKlauz » Tue May 10, 2016 7:47 am

Sounds like a bit weird, but nice breeding game coming up sooner or later :D

User avatar
Euter Space
Newbie
Posts: 9
Joined: Mon Apr 25, 2016 7:26 pm
Contact:

Re: Proof Of Concept - Breeding Game

#14 Post by Euter Space » Mon May 23, 2016 9:03 am

Owie, no time at all at the moment.
Not even close to any complicated stuff, yet, though I still managed to get stuck when I made at least a very simple test yesterday. I feel really stupid, like I should know this already.
drKlauz wrote:So instead of "Boxes[BoxNumber][AntNumber].Name" you use "boxname[BoxNumber][AntNumber]"?
This is the first question I wanted to tackle.
Before continuing to the more complex structures I made this little test code using a variant of one of the earlier, less detailed functions.

Code: Select all

init python:
    class Ant(renpy.store.object):
        def __init__(self,name,gender,pat,skin,eye):
            self.BoxNumber=None
            self.name=name if name is not None else '%04d'%renpy.random.randint(0000, 9999)
            self.gender=gender
            self.pat=pat
            self.skin=skin
            self.eye=eye
     
        @property
        def value(self):
            value=AntBaseValue
            for BonusReq,Bonus in ValueBonuses:
                Match=True
                for Attr,Val in BonusReq.items():
                    if Val[0]=='!':
                        Val=Val[1:]
                        Test=lambda a,b: a!=b
                    else:
                        Test=lambda a,b: a==b
                    if not Test(getattr(self,Attr),Val):
                        Match=False
                        break
                if Match:
                    value+=Bonus
            return value 
           
                
    
    
label start:
    $Box1_1=Ant('Vani','male','citrus','citrus','aqua')
    $boxnumber = 1
    $antnumber = 1
    "This is box [boxnumber]. There is [antnumber] Ant-Fly inside."
    "The little fella's name is [Box1_1.name]."

    #Up until here, everything works fine, the next line, however, crashes with a KeyError: u'Box'

    "The little fella's name is [Box[boxnumber]_[antnumber].name]."

    #Lists made some problems when trying to display certain things as dialogue as well, so I used a little workaround for them. When trying the same with a class item, the game doesn't even start because of an invalid syntax.  

    $Antname = Box[boxnumber]_[antnumber].name    
    "The little fella's name is [Antname]."
Is this not how this is supposed to work?

drKlauz
Regular
Posts: 168
Joined: Mon Oct 12, 2015 3:04 pm
Contact:

Re: Proof Of Concept - Breeding Game

#15 Post by drKlauz » Mon May 23, 2016 12:16 pm

Point of using Farm->Box->Ant hierarchy is so Farm and Box doesn't care about what Ant is.
One of core points of using classes is incapsulation. Parent object (Box) don't know and don't care what stored inside it, as long as child behave. All Ant properties (name or color) must be incapsulated inside Ant itself. Only very limited functionality should be shared between Parent object and Child. In case of Box/Ant it's location of specific ant in specific box.

Code: Select all

Box[boxnumber]_[antnumber].name
You can't normally do such thing, most importantly you shouldn't do such thing. It void whole point of using independent boxes and ants. And if you void independence of elements you get big monolithic rigid mess. Once you decide to change something, whole monolith will resist.

Regarding why you can't simple do it. Python translate your written code into internal commands. One of such commands is "Load content stored in variable called X123, bound to memory cell at location 0x12345678". Well, kinda. Anyway, instead of giving name as "Box1_1", you give expression "Box[x]_[y]", and not just expression, but special expression which make sense only in limited area.

You can do this when necessary:

Code: Select all

varname='Box'+str(boxnumber)+'_'+str(antnumber)
ant=globals().get(varname)
ant.name='Bobb'
But it's usually means you doing things very wrong.

Code: Select all

$Boxes[boxnumber].Place(Ant)
By using this approach you decouple Boxes and Ants, and delegate job of moving ants to box class, if you decide to move ant then you simple tell box to do it. It's called delegation. Which is also very useful concept, not only in programming.

If you want simple solution:

Code: Select all

start:
  $boxes=[None]*11
  $boxnumber=2
  $boxes[boxnumber]=TAnt('vini',...colorsetc...)

  "Box [boxnumber] contain [boxes[boxnumber].name]"
It is as simple as possible without sacrificing too much flexibility. You can remove classes completely and use simple dictionaries if you want to manually manipulate properties.

Think how you will move ant. You have Box1_1 variable which contain "vani" fella. Then you decide to add "bobb" fella in box 1, guess you will put him into Box1_2 variable. How will you know it's Box1_2? What will happen when you decide to sell "vani"? Probably "bobb" should move from Box1_2 to Box1_1? How will you know which variables is empty, which must be moved, where they must be moved?
If you want to make building you get bricks and cement em together properly. If you try use sand, then sooner or later (actually sooner) your building will collapse.
Same with your code. Classes, functions, complex data structures are your bricks. You combine simple commands into more complex command. Then you don't write simple commands again, but you your new command. Then you combine such more complex commands. You make sure your bricks are good and use them, you don't reinvent brick every time you need one.

---

Learn basic programming concepts and basic python if you want to make game of any complexity above simple visual novel with couple of flags.

https://www.codecademy.com/learn/python

Programming is not simple knowing how to write code, it's understanding of concepts, paradigms, it's way of thinking, way of approaching problems, ability to recognize and apply patterns.

P.S.: *sacrifice virgin at crossroad* I summon you, Xela, from the darkest depths of the Warp to provide simple to understand solution to problem!.. please? :|
P.P.S.: i have feeling i have more chance to seduce cute jehovah witness door-to-door missionary into bdsm ls than help here, sorry

Post Reply

Who is online

Users browsing this forum: Google [Bot], oro121