Alright, point one, please when you include code in your message, use the [code] and [/code] tags to format it. It will take in count the indentation and put the code inside a scrolling window to limit the size of the message. When it's Ren'py or Python code, this is mandatory, because a change in the indentation of the code imply a change in the code itself.
Secondly, hm, what do you mean by "the screen gets stuck". I tried it at home and I failed to make it fail ; or if you prefer it worked perfectly whatever I did, and when it didn't it was for the reason I through and not something that I would describe as a screen getting stuck.
Thirdly, it's natural that the
You must be registered to see the links
end the game. You can see this statement has having two behavior.
The first, and most used, one is to permit to return to the calling point. A label is
You must be registered to see the links
ed, which create a derivation of the original game flow. Then when you want to return to the said original game flow, you use the
return
statement.
Ren'py keep track of the calling point (and so where it need to return) by using a stack, and you can know the size of this stack with the
You must be registered to see the links
function.
But there's an implicit second behavior. Part of the core of Ren'py... is wrote by using the Ren'py script language. The game don't magically reach the
start label, but in fact call it. Therefore, when the size of the stack is null, a
return
statement end the game ; it make it return inside the part you where before hitting the "start" button.
Python:
label start:
# Get the size/depth of the calling stack
$ stack = renpy.call_stack_depth()
# "[variable]" make Ren'py display the content of this variable. It's
# a text interpolation.
# "[[" is used to escape the "[" to prevent the behavior explained
# above. And finally, the behavior of "]" depend if an interpolation
# have been started (in which case it end it) or not (in which case
# the character will be displayed).
# Therefore, "[[[stack]]" mean: display the value of the /stack/
# variable, between brackets.
"[[[stack]] Hey, how yo..."
call calledLabel
$ stack = renpy.call_stack_depth()
"[[[stack]] As I was saying, how you doing ?"
"END"
# The size of the stack is 0, so the game end.
return
label calledLabel:
$ stack = renpy.call_stack_depth()
"[[[stack]] What ? Don't go away like this !"
call anotherLabel
$ stack = renpy.call_stack_depth()
"[[[stack]] Don't be afraid, come closer."
# The size of the stack is NOT 0, so you return to the
# calling point.
return
label anotherLabel:
$ stack = renpy.call_stack_depth()
"[[[stack]] Come back please !"
return
Now, as for the questions that don't regard the problem you encountered, what to say ?
The code is really minimalist. It give a global idea about how you can do it, but nothing more.
The principle is simple :
- Init the values ;
- Display the combat user interface ;
- Ask the player for his action ;
- Compute the result of this action ;
- Update the values depending of this result ;
- Decide the action of the opponent ;
- Compute the result of this action :
- Update the values depending of this result ;
- Loop to 3 if both parties are still alive.
But as I said, in this case it's a minimalist version of this principle. The player is given only two choices, they are displayed by using a
menu
, and the opponent have only one possible action.
Something more evolved can be :
Note: WARNING, code wrote on the fly.
It should works, but I don't have the possibility to test it right now, so there's perhaps some typo or small errors.
Python:
label start:
"Get ready..."
"Fight !"
call combatInit
"The winner is [_return]"
"END"
return
label combatInit:
call MCInitCombat
# This let you have different opponents. Just call the
# right label depending of which one is in this combat.
call BadGuyInitCombat
# You can combinate /call/ and /jump/ without problem.
# A /call/ is ended only when a /return/ statement is
# proceeded, not necessarily at the end of a label.
jump combatMainLoop
label MCInitCombat:
$ MC_HP = 30
$ MC_armor = 1
$ MC_weapon = "sword"
$ MC_STRONG = 2
# [Here, init whatever other variables you have]
# The initialization is finished for the MC, return
# to /combatInit/ to now initialize the opponent.
return
label BadGuyInitCombat:
# Always use the save variables for the opponent,
# just change the values depend of which one it is.
$ OP_HP = 25
$ OP_armor = 0
$ OP_weapon = "dagger"
$ OP_STRONG = 0
# [Here, init whatever other variables you have]
# The initialization is finished for the opponent, return
# to /combatInit/ to now start the combat.
return
# Just as example of what I said above regarding the
# need to keep the same variables.
label BossInitCombat:
# It's a boss, he have more HP,
$ OP_HP = 45
# a better armor,
$ OP_armor = 3
# and a better weapon.
$ OP_weapon = "2 hands sword"
$ OP_STRONG = 1
# [Here, init whatever other variables you have]
return
label combatMainLoop:
# Display the combat interface, but do it by calling
# the screen. It mean that Ren'py will stop the processing
# of the game, until the player it a button on the screen.
call screen combatUI
# /_return/ is a special variable that store the value
# returned by the label or, in this case, the screen.
# Storing it in another variable is always a good idea,
# because the value of /_return/ is reset each time
# you return from something.
# Therefore, it let you call label or screen as part of
# the process.
$ result = _return
if result == "heal":
# The player choose to heal himself.
$ MC_HP += 10
elif result == "hit":
# The player choose a regular hit.
# Call the computing label, saying, through the
# parameter, that it's a regular hit, gave by the MC
# to the Opponent.
call isHit( False, "MC", "OP" )
elif result == "strong":
# The player choose a strong hit.
# Call the computing label, saying, through the
# parameter, that it's a strong hit, gave by the MC
# to the Opponent.
call isHit( True, "MC", "OP" )
$ MC_STRONG -= 1
# Decide what action will be done by the opponent
$ rdm = renpy.random.randint(0, 20 )
# 5 chance to have a strong hit. If there's a strong
# hit possible. Else it's a regular one.
if rdm > 15 and OP_STRONG > 0:
call isHit( True, "OP", "MC" )
$ OP_STRONG -= 1
else:
call isHit( False, "OP", "MC" )
# If both still have HP, next loop.
if MC_HP > 0 and OP_HP > 0:
jump combatMainLoop
# Else if the MC is still alive, he won.
elif MC_HP > 0:
return "MC"
# Else it's the opponent who won.
else:
return "Opponent"
# A called label can have parameters, which permit to
# have a single label that can handle more than a single
# case. The values will be stored in the order they are
# passed.
# Here, first parameter in /strong/, second in /hitBy/,
# third in /target/.
call isHIT( strong, hitBy, target )
# Get the weapon that hit.
$ weapon = getattr( store, hitBy + "_weapon" )
# Compute its damages
if weapon == "dagger":
$ damage = 2
elif weapon == "sword":
$ damage = 5
elif weapon == "2 hands sword":
$ damage = 8
else:
# It's a bug, do no damages.
$ damage = 0
# It's a strong attack, it double the damages
if strong is True:
$ damage *= 2
# Compute the new HP
$ HP = getattr( store, target + "_HP" )
if HP < 0:
$ HP = 0
# And assign them
$ setattr( store, target + "_HP", HP )
# Finished, return to the combat loop.
return
screen combatUI()
frame:
# MC HP in the top left corner.
text "MC: [MC_HP]":
xalign 0.0 yalign 0.0
# Opponent HP in the top right corner.
text "Opponent: [OP_HP]":
xalign 1.0 yalign 0.0
# MC possible actions in the middle
vbox:
xalign 0.5 yalign 0.5
textbutton "Take a potion":
# The action is to return from the screen,
# while returning the value "heal".
action Return( "heal" )
textbutton "Regular hit":
action Return( "hit" )
textbutton "Strong hit":
action Return( "strong" )
# The button will be sensitive (and so clickable)
# Only if the MC still have the possibility to do
# a strong hit.
sensitive MC_STRONG > 0
Featured in this code :
You must be registered to see the links
screen action, and also
setattr
and
getattr
Python instruction, for which you'll find explanations
here, with a complement two messages after it.