# Random RPG Battle System in Lua

This is my battle system that I wrote in Lua. Bear with me on this one, this is my first real program that does something besides write hello world. If there is anything that I could have done differently, drop an answer down there and I will take your advice for my next program. Huge shoutout to Jakuje for helping me make this, he refined my code for me and told me how to do things correctly.

math.randomseed( os.time() )
math.random(); math.random(); math.random()
local function battle()
n = math.random(10) + 1 -- Everybody's HP, enemy HP randomly generated number from 10 to 100
enemyhp = 10*n
exp = enemyhp*0.5
g_herohp = 100
print("You have encountered an enemy!")
io.write(g_herohp)
io.write(" ")
io.flush()
io.write("Enemy HP: ")
io.write(enemyhp)
io.write(" ")
io.flush()
end
local function attack()  -- Attacking the enemy or running away
print("|Attack|Flee| ")
if input == "attack" then
attackdamage = math.random(51)
if attackdamage == 51 then
print("Critical Hit! 100 damage!")
enemyhp = enemyhp - 100
else
enemyhp = enemyhp - attackdamage
io.write("You dealt ")
io.write(attackdamage)
io.write(" damage!")
end
elseif input == "flee" then
escapechance = math.random(2)
if escapechance == 1 then
escape = true
end
end
end
local function enemyattack() -- Enemy attacks you with a random amount of damage
print(" Enemy is attacking!")
eattackdamage = math.random(40)
g_herohp = g_herohp - eattackdamage
io.write("Enemy dealt ")
io.write(eattackdamage)
io.write(" damage!")
end
local function battleinprogress() -- If I used battle then it would reset everyones health.
if g_herohp <= 0 then
print(" You have died!")
end
io.write(g_herohp)
io.write(" ")
io.flush()
io.write("Enemy HP: ")
io.write(enemyhp)
io.write(" ")
io.flush()
if enemyhp <= 0 then
print("You won!")
end
if escape == true then
print("You have run away!")
end
end
battle()
repeat
attack()
enemyattack()
battleinprogress()
until g_herohp <= 0 or enemyhp <= 0 or escape == true
end

• How are you actually running the game? – hjpotter92 Jun 29 '16 at 9:36
• @hjpotter92 I use an IDE to run it. I'll be releasing an adventure expansion too, and once it's done I'll compile it. – Dropdatderp Jun 29 '16 at 13:11
• No, what I meant was, where do you call these functions? How is the player object/table/variable defined? How many enemies can there be? etc. – hjpotter92 Jun 29 '16 at 13:43
• @hjpotter92 Did I forget to add that in with the post? Once I have access to my drive again I will edit this post. – Dropdatderp Jun 29 '16 at 13:45
• @hjpotter92 Although currently there is one enemy. I am implementing a level and item system so I will be updating this post a lot. – Dropdatderp Jun 29 '16 at 13:46

Since you are making calls to math.random a lot, keep a local copy in your code:

local random = math.random


Why are you switching between io.write and print statements? Use a string.format to format the data as you want:

print( ("You dealt %d damage!"):format(attackdamage) )


The above is merely a representation. It can be made a lot better (by putting templates as variables etc.)

n = math.random(10) + 1


The above will generate n in the range of 2 to 11. From the docs:

When called with two integers m and n, math.random returns a pseudo-random integer with uniform distribution in the range [m,n]. [...] The call math.random(n) is equivalent to math.random(1,n).

And, no need for keeping a temporary variable (here n):

enemyhp = 10 * random(10) -- better yet, use random(10, 100)


escapechance = math.random(2)
if escapechance == 1 then
escape = true
end


can simply become:

escape = random(2) == 1


Convert your input to lowercase first. Players might enter Attack or ATTACK too.

if input:lower() == "attack"


or

local input = io.read():lower()


# Most important

You should encapsulate your player, enemies etc. inside objects. Lua supports a rough implementation of OOP design using tables. Read the Lua PiL chapter #16

I understand that you're new to programming, and some of this might be a bit hard to understand, but I'm hoping it will be useful anyway.

# Formatting

It's a bit hard to visually get an overview of the code when it's so dense. You should add in some vertical space to make your code easier to read. For example, there should be one blank line between function definitions.

The indentation is a bit inconsistent. Try to always keep the "end" on the same level as the statement that starts the block (e.g. the "if"), and everything in between one level to the right.

# Structure/algorithm

You're using global variables to keep track of HP, which is generally not a good idea. For a small program like this it's OK, but consider how hard it would be to keep track of their values if the program had been thousands of lines spread across multiple files. It's a good idea to get into the habit of avoiding globals. Usually, this is accomplished by passing the relevant data as arguments to the functions, and either returning the updated data, or having the functions update the data in place.

Another thing that would be problematic in a larger program is that the output logic is mixed with the game logic. This can make it harder to change the code without breaking something unrelated to the thing you wanted to change. A central, important idea in programming is to separate different concepts as much as possible, so that the individual parts are simpler and have fewer reasons to change.

Here's how your main loop could look like with these concepts applied:

-- returns a table containing the player's data
local player = create_player()
repeat
local enemy = create_enemy()
local input = get_player_input()
-- implements the attack/flee logic and returns a table that represents the outcome, so that it can be printed later
local player_outcome = perform_player_action(player, enemy, input)
local enemy_outcome = perform_enemy_action(player, enemy)
print_turn(player_outcome, enemy_outcome) -- all the output happens here
until player.hp <= 0 or not enemy.hp <= 0 or player_outcome.escaped