Ren'Py Ren'py Battle System [Help] - like I'm 5 years old

MenmaYu

Broke as hell :3
Game Developer
Dec 28, 2017
179
137
Some time ago I made a random thread asking about a renpy game with a good grind here. Now I realized that that question is very vague and cover too much ground.

I'm looking for a game with a battle system that I can take apart and study. But better yet if someone can show me how they work because the battle systems from Lemmasoft is still too complex for my coding experience (close to none). I need someone to show me how it works like I'm a 5 year old kid.

As of now (September 22, 2020), there few updated tutorials that can help newbies like us with this problem. Now I know that asking Lemma is the prominent thing to do but I want F95 to also have a Dev Guide that newbies like me can access here on F95Zone.
 
  • Like
Reactions: Madmanator99

Madmanator99

Member
May 1, 2018
225
451
Hi, to be honest and with all due respect, it is still quite a vague question, because a battle system can be as simple as what some game events are, i.e you have an encounter with a bad guy and you can punch left, punch right, dodge, etc. Basicaly choice menus. Those can be done with labels, menus, and variables updates/checks that lead to label/menu jumps. The variables can be named HP/mana etc and displayed.
Then there are the more complicated ones where screens are used to input the choices, and finaly those that actualy modify renpy itself to add what is needed to make it work.

I'm not good with renpy, but I'm the type that starts with an idea and look for how/if it can be implemented.

If you are like me, then what I can say is that it helps to decide what you want your battle system to do, i.e play in your mind how you want a typical combat encounter to go (or write down in a text file, draw, use boxes with arrows, etc), break it down, see what each action can result in (hit, miss, or w/e), what choices come after what result (enemy turn, player turn, etc), what can end it (a variable named HP reaches 0, or a timer/turn counter variable, etc), what types of ends (win, lose, tie, etc), etc.
Once you break it down, it will be easier to implement it in renpy, as it breaks down a big problem into smaller/easier to solve problems.

This is where the combat simplicity/complexity plays a major roll, the more complicated your combat system, the harder it will be to implement.
 
  • Red Heart
Reactions: MenmaYu

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Respected User
Donor
Jun 10, 2017
10,110
14,782
I'm looking for a game with a battle system that I can take apart and study.
It goes from Planet Stronghold 2, to Sakura Dungeon, passing by Damsels and Dungeons, Super Powered or Heavy Five. All of them being totally different to the others.

There's too many "battle system" possibilities to effectively give you an answer. But basically it goes like that :
Python:
# Define the variables that will be used for the enemy.
default enemyHP = 0
default enemyAttack = 0
default enemyDamages = 0
# Define the variables that will be used for the MC.
default mcHP = 0
default mcAttack = 0
default mcDamages = 0

# The combat start here.
label combatStart:
    # Initialize the values for this combat.
    $ enemyHP = 20
    $ enemyAttack = 10
    $ enemyDamages = 5
    $ mcHP = 30
    $ mcAttack = 15
    $ mcDamages = 3

    #  The combat will continue until one of the opponent lost all
   # its health points.
    while enemyHP > 0 or enemyAttack > 0:
        # The MC try to hit
        call combatMcRound
        # Then the enemy will try, if its still alive.
        if enemyHP > 0:
            call combatEnemyRound

    # If the enemy is still alive, he win.
    if enemyHP > 0:
        jump mcLoose
    # Else it's the player.
    else:
        jump mcWin

# Round for the MC
label combatMcRound:
    # If a random value between 1 and 20 is lower than the attack
    # of the MC, he hit.
    if renpy.random.randint( 1, 20 ) < mcAttack:
        "You touch."
         # Therefore he remove his damages  from the enemy health points.
        $ enemyHP -= mcDamages
    # Else he missed and nothing happen.
    else:
        "You missed."
    return

# Round of the enemy, works as above.
label combatEnemyRound:
    if renpy.random.randint( 1, 20 ) < enemyAttack:
        "He touch."
        $ mcHP -= enemyDamages
    else:
        "He missed."
    return
 

MenmaYu

Broke as hell :3
Game Developer
Dec 28, 2017
179
137
Sorry for the late reply guys. Life after covid is really busy. :3

Sorry for the late reply and thanks Madmanator99.
"it is still quite a vague question"
Yeah, sorry if I couldn't make it any clearer as we are talking about battle engines. That said I'd quote you later, after I come up with my own idea on battle engine. :3

"but I'm the type that starts with an idea and look for how/if it can be implemented."
Fortunately, yes, we're the same type but sadly for me I lack understanding in programming. Things like how/when/where I'm allowed or not allowed to use variables, how far I can take statements and such. I do however understand the basics in Ren'py, but like I said,"close to zero" (sad). I even got myself a Python 3 tutorial to broaden my understanding and thanks to that I got a better gist on how it works. The problem with self study though is there is no one-on-one interaction and there's no one who can help when a problem arises.
It goes from Planet Stronghold 2, to Sakura Dungeon, passing by Damsels and Dungeons, Super Powered or Heavy Five. All of them being totally different to the others.
Thanks for the reply anne O'nymous. In increasing difficulty, which would be the easiest for a beginner like me can start with? I have seen the Sakura Dungeon, but I think that's still too advanced for me, the others I'll give a try later.

also...

"There's too many "battle system" possibilities to effectively give you an answer."
... Let's go with the code you sent me if you don't mind. I just like to the opportunity to see how other's make their own codes. That said, I tried to mess with it but something went wrong for some reason. I also tried tweaking with the values a bit but seems to loop even after whichever loses.
Python:
label start:

    menu:
        "Engage enemy.":
            jump combatStart
    if mcWin = True:
        "Oh, you won. Congratulations."
        "The game will now exit."
        return
    else :
        "Too bad you lost. Try again next time."
        "The game will now exit."
        return

return


default enemyHP = 0
default enemyAttack = 0
default enemyDamages = 0

default mcHP = 0
default mcAttack = 0
default mcDamages = 0

label combatStart:
    $ enemyHP = 20
    $ enemyAttack = 10
    $ enemyDamages = 5
    $ mcHP = 50
    $ mcAttack = 15
    $ mcDamages = 3

    while enemyHP > 0 or enemyAttack > 0:
        call combatMcRound
        if enemyHP > 0:
            call combatEnemyRound

    if enemyHP > 0:
        $ mcLose = True
        jump mcLoose
    else:
        $ mcWin = False
        jump mcWin

label combatMcRound:
    if renpy.random.randint( 1, 20 ) < mcAttack:
        "You touch."
        $ enemyHP -= mcDamages

    else:
        "You missed."
    return

label combatEnemyRound:
    if renpy.random.randint( 1, 20 ) < enemyAttack:
        "He touch."
        $ mcHP -= enemyDamages
    else:
        "He missed."
    return
 

Madmanator99

Member
May 1, 2018
225
451
I see a couple of things in the combatStart label, but again, I'm not very good with renpy.

Python:
while enemyHP > 0 or enemyAttack > 0: (1)
        call combatMcRound
        if enemyHP > 0:
            call combatEnemyRound

    if enemyHP > 0:
        $ mcLose = True (2)
        jump mcLoose (3)
    else:
        $ mcWin = False (2)
        jump mcWin (3)
(1) : enemyAttack is never modified past this point, so the loop will keep going even when enemyHP is not > 0, try with mcHP instead of enemyAttack, that one does change as the mc gets hit and can reach 0, and instead of or, try and, since both the mc and the enemy must have HPs left for the combat to continue.

(2) : you can use a single variable, say mcWin, and set it to True when the mc wins, and False when the mc looses.

(3) : jump implies a label/menu with the specified name, ie. a label/menu named mcLoose and a label/menu named mcWin. And the same as for the mcWin and mcLoose variable, you can use a single label, and check the value of the mcWin variable to display the different combat results.

So first, try and replace the label combatStart with the one below.
Python:
label combatStart:
    $ enemyHP = 20
    $ enemyAttack = 10
    $ enemyDamages = 5
    $ mcHP = 50
    $ mcAttack = 15
    $ mcDamages = 3

    #as long as both are alive, keep fighting.
    while enemyHP > 0 and mcHP > 0: #you could use only mcHP here and it should still work, since the loop restarts after the enemy round ends.
        call combatMcRound
        if enemyHP > 0:
            call combatEnemyRound
    #sets the value for mcWin after the combat loop ends
    if enemyHP > 0:
        $ mcWin = False
    else:
        $ mcWin = True
    #jumps to the combatEnd label to display the result after mcWin is set.
    jump combatEnd
Then, add a new label at the very end named combatEnd, like below:
Python:
label combatEnd:
    if mcWin == True: #or mcWin != False, != stands for "Not Equal to".
        "Oh, you won. Congratulations."
        "The game will now exit."
    else :
        "Too bad you lost. Try again next time."
        "The game will now exit."
    return
Note the double equal signs, that is used to check a value instead of a single equal sign.

Next, you can remove that text from your label start since it's now moved to the label combatEnd, like below.
Python:
label start:
    menu:
        "Engage enemy.":
            jump combatStart
    return
Notice I removed the extra return, I don't believe it is needed.

And finally, I am not sure, but I think you need to initialise the variable mcWin, just like you did with the other ones, with a line like this:
Python:
default mcWin = False
 
Last edited:
  • Like
Reactions: anne O'nymous

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Respected User
Donor
Jun 10, 2017
10,110
14,782
[Please, do not answer inside the quote, it make it hard to read you, and even harder to answer you.

That said, I tried to mess with it but something went wrong for some reason. I also tried tweaking with the values a bit but seems to loop even after whichever loses.
It's possible. Unless it's a really big piece, I generally wrote the code on the fly when I answer, so there's sometimes typo.


Python:
while enemyHP > 0 or enemyAttack > 0: (1)
[...]
(1) : enemyAttack is never modified past this point, so the loop will keep going even when enemyHP is not > 0, try with mcHP instead of enemyAttack,
It was meant like that. Really don't know what crossed my mind when I wrote "enemyAttack" there :(


(2) : you can use a single variable, say mcWin, and set it to True when the mc wins, and False when the mc looses.
Again, yes. The jump where here to keep the gate opened for a different handling of the victory and loose, with a full scene behind. But if also can be handled that way.


Python:
    while enemyHP > 0 and mcHP > 0: #you could use only mcHP here and it should still work, since the loop restarts after the enemy round ends.
        call combatMcRound
        if enemyHP > 0:
            call combatEnemyRound
[/quote]

No, you can't just use [icode]mcHP[/icode], because there's no branching outside of the loop if [icode]enemyHP[icode] is lower than 0. The [icode]if enemyHP > 0:[/icode] is just here to prevent an error too often seen in combat system, where the enemy hit you a last time after you just killed him.
Therefore, if you remove the [icode]mcHP[/icode] you fall back to the opposite of the original endless loop error, where I fasly used [icode]enemyAttack[/icode] as condition ; if the MC win, he'll beat his enemy corps again and again until the end of times.