Programming C, C++, Java, PHP, Ruby, Turing, VB
Computer Science Canada 
Programming C, C++, Java, PHP, Ruby, Turing, VB  

Username:   Password: 
 RegisterRegister   
 [Tutorial]How to Make an RPG in Turing
Index -> Programming, Turing -> Turing Tutorials
Goto page 1, 2  Next
View previous topic Printable versionDownload TopicRate TopicSubscribe to this topicPrivate MessagesRefresh page View next topic
Author Message
azndragon




PostPosted: Sun Mar 30, 2003 4:32 pm   Post subject: [Tutorial]How to Make an RPG in Turing

How to make an RPG in Turing - Dated March 30th, 2003

This guide will help you through all the steps of creating an RPG. Be aware that in order to actually allow the user to "roleplay" their character, the better the experience, although this requires a lot more coding than a simple hack and slash game. Be warned, an RPG is very difficult to code, and will take many weeks, and months, or even years if you want it to be very well done.

Things to Know Before You Start

When making the RPG, make sure that you have knowledge of the following Turing concepts, and how to use them:

Displaying Text (Obviously)
Collecting Variables and using them
If statements (Very important)
Reading and Writing to/from a file (If you use saving)
Functions and Procedures (VERY useful for repetitive processes)
Processes (For music, or timers)
Arrays (For many types of 1 variable. i.e. items)
Loops (Very important in an RPG! Know conditional and counted loops)
Random Number

That should cover the basics. If you decide to make a more complex RPG, you may require other things, such as modules, etc. If you do not have sufficient knowledge of these concepts, it is not recommended that you make the RPG, until you have learned them, as this will make your life much harder.

A recommended idea is to play an RPG thoroughly, and explore the game, until you get the feel of how an RPG is made. The more you know about an RPG, the easier it will be to make your own.

About this Tutorial

This tutorial will cover many commands of Turing that you should know, but read them anyways, because their uses may help you when you want the RPG to do a specific task.

RPG Creating Concepts Covered
    The Overall RPG Experience
    Turing Concepts
    Displaying Text
    Collecting Variables and using them
    Naming Variables
    Reading/Writing from a file
    Functions and Procedures
    Processes
    Loops
    Arrays
    Random Number
    Properly Accepting User Input
    Elements of an RPG
    Readme File
    Collection of Data
    Damage Range
    Gender
    Races
    Classes
    Stats
    Battle System
    Attacking
    Magic
    Resistances/Weaknesses/Immunities/Absorption
    Abnormal Status
    Running Away
    Other Notes on Battle System
    Items
    Experience Chart
    Other Experience Charts
    Making your RPG better
    Testing
    Balancing
    Improving
    Final Notes


The Overall RPG Experience

Once you have decided that you want to code your RPG, you need to ask yourself a few questions:

Who is playing this game?

A very important aspect of creating an RPG is the audience. Do you intend the game to be played by new gamers, or hardcore RPG gamers?
If it is the former, you want to keep it simple, and easy for the user to understand. The RPG must be simple, and easier for them. Stick to the basic elements of an RPG, like stats, equipment, spells, items, etc. You do not need to include things like quests, puzzles in rooms, etc.

If it is the latter, you are in for a tough time. Although it is impossible to make an RPG in Turing that compares with famous games such as the Final Fantasy series, it is still possible to make one that is enjoyable to all, including the hardcore RPG gamer. You need to give the user something that will keep him/her playing, such as quests, a more complex character building system, and many elements that you can see in other RPG's. As recommended above, if you have played many RPG's, it should not be too difficult for you to look for new things to add.

Is this for a project, or just for fun?

Another important issue to address. The main issue discussed here is time. For a project, time is limited, and your main priority is to finish. If it is for fun, the finishing is likely not a possible aspect at all, because if it's for fun, you have as much time as you want to work on it, and improve it multiple times. For a project, you will likely have to stick to a simple RPG, that sets the user straight into action immediately, while an RPG made for fun can delve into the more complex aspects of an RPG.

How much control do I want to give the user?

This is closely related to the first question. You want to know how much control of their character growth you want to give. For a simple RPG, you should control their character growth, such as preset stats at certain levels for example. A more complex RPG should allow a user to customize their stats, choose their own classes, choose their own magic, and for a real challenge, emotional growth, which will allow the user to develop a character's personality that can affect the outcomes of certain events.

The above questions will help you set a guideline of how to make your RPG, and will set limits on how complex you want it to be.

Turing Concepts

Note: The following sections are not how to use them in Turing, but how to use them when coding your game. If you don't know how to use these commands, please look it up somewhere else.

Displaying Text

This is a very easy, and yet very important aspect of an RPG. You need to be able to have a way to communicate with a user, and have the user communicate to the program. Otherwise, there is no interaction, and that would make an RPG very boring. An example of how to display text is:

put "Welcome to my game!"

Simple, and yet effective. If you want, you may opt to use text effects also. See the other tutorial for text effects.

Collecting Variables And Using Them

Variables are the backbone of an RPG. Without them, the game is virtually impossible to make. You will need variables for storing stats, character details, spells, skills, items, monster data, just about anything the user does. You essentially need about 4 types of variables:

String (Deals with text variables, such as names, spells, items, etc)
Int (Stats, hit points, anything that needs a number)
Real (Decimal numbers, which are used in percentages, etc)
Boolean (Can be omitted, but will make certain comparisons easier)

String Variables

The string variable is very easy to use. It stores text for later use. You can use this in a variety of ways, such as comparing the input of a user to a set of strings that the game already has inside it. It can be used in character names, names of skills/magic/items/monsters, and a lot of other uses.

Int Variables

This variable can be used to store stats, item amounts, gold/money, or anything that requires a number.

Real Variables

This variable is a little harder to use. This variable is needed when you want to calculate percentages. Percentages also deal with random numbers, so make sure you know how to use them.

Boolean Variables

This is an optional variable, for values that you need to store when there are only 2 possibilities, yes/no, 0/1, or however you want to arrange it. You can use this variable in situations such as enabling/disabling music, whether or not a skill can be used, whether or not a level has been gained, etc.

Naming Variables

Naming your variables is simple. Make sure you name all of your variables according to it's purpose, as this allows you to be able to differentiate the different variables a lot easier. It's also recommended that you use a commend (%) besides each variable that tells you what it does, in case you forget.

Good Variable Name: character_name
Bad Variable Name: cn

Reading/Writing From a File

If you wish to include a saving feature in your game, read this section, otherwise, skip it. But think about it, what good is an RPG, if you can't save? So it would probably be a good idea to include some sort of saving feature. First of all, you need to come up with a list of variables that are needed for future use, and those that are used for temporary purposes. For example, in the following list of variables,

Name of Character
Hit Points
Answer from user

You would save the first 2, as they are important to the operation of the game. The answer from the user is still important, but is not required when saving, because it is just used to temporarily store what the user enters. Let's say you want to save the name of a character, you would use:

code:
var stremout : int %Does not need to be set
var pathName : string := "save.sav" %The name of the file to be saved
var character_name : string := "Azndragon" %The variable to be saved

open : stremout, pathName, write
write : stremout, character_name
close : stremout

Using the write command instead of the put command allows you to partially secure your save file. If you use the put command, a user can open your save file in a text editor, such as notepad, edit the values, and save it. If you use the write command, and the person edits and saves it, Turing will not recognize the values, and will not work properly.

Loading a variable is similar to saving it:

code:
var stremin : int %Does not need to be set
var pathName : string := "save.sav" %The name of the file to be loaded

open : stremin, pathName, read
read : stremin, character_name
close : stremin


If you used write to save the file, you use read to load the file. If you used put to save the file, you use get to load the file.

By using the two above examples, while combining multiple variables in your save file, you can make a saving system, and therefore, allows the user to quit your RPG, and play it again later.

Functions and Procedures

If you are doing certain actions multiple times, Functions and Procedures may be the answer. Let's say you want to have a battle, and it's 500 lines long. If you want to have another battle somewhere else in the game, you would have to paste the same 500 lines somewhere else in the code, which is a waste of space. The alternate method is to use a procedure to load the battle. Start off with a "procedure battle", then paste your code, then put a "end battle" and every time you want to load a battle, just use the code "battle" and it will automatically execute the battle.

code:
procedure battle
[insert battle code here]
end battle

put "An imp attacks you!"
battle
[pointless events here]
put "A pack of wolves attack you!"
battle


Functions are a lot more complicated. Functions allow you to do certain operations with a parameter to be used within it. For example, if you want to collect gold, use:

code:
var total_gold : int := 500

function collect_gold (gold : int) : int
total_gold := total_gold + gold
put "You now have ",total_gold," gold."
end collect_gold

collect_gold (500)


This executes the collect_gold function, and the brackets are around the variable that is to be added to the gold amount. In this case, 500 gold is added, and the end result is 1000 gold.

Processes

Processes are mainly used for playing music. You make a process, insert the music file in it, and end it. Anytime you want to play the music, you use "fork [process name]", and the music will play in the background.

code:
process play_music
        Music.PlayFile (music file location)
end play_music

fork play_music


This will have the music play in the background.

Loops

Loops are very important parts of an RPG. They allow you to repeat many functions of the game. For example, you could use them to repeat battle processes until the monster or the player is left with 0 or less HP. They could also be used in combination with arrays for optimum efficiency, which is explained in the next section. There are 2 types of loops; counted, and conditional.

Conditional Loop

This loop just repeats itself over and over, until a condition is met, by using the command "exit when [variable] [operator: <, >, etc] [value]" inside the loop. For example:

code:
var gender : string

loop
        Put "What is your gender?"
        Exit when gender = "male" or gender = "female"
end loop
put "You are a ",gender,"."


Counted Loop

These types of loops repeat for a set number of times, whether it be twice, or 50 times. The power of these loops are used effectively in arrays, and can also be used when dealing with commands that have to executed more than once. Examples of counted loops are in the next section.

Arrays

Arrays are useful for when you want to have multiple variables with the same name. An example would be items. Using item1, item2, item3, item4..item100 is a very time consuming operation. Instead you would first declare the variable as:

code:
var item : array 1..100 as string


This will create 100 variables under the variable name of "item". You can now call on these variables using item (1), item (2), item (3), item (4) .. item(100). Let's say you want to set all items as potions. Instead of using item (1) := "Potion", you can combine the array with a for loop for maximum efficiency:

code:
var item : array 1..100 of string

for i : 1..100
        Item (i) := "Potion"
end for


With those simple lines of code, all 100 item variables are now potions.

Now look at this:

code:
for decreasing i : 120 .. 1
        if item (i) = "Potion" then
               item (i) := "None"
               exit
        end if
end for

The first thing that you may notice is that it has the word "decreasing" in it. This tells Turing that the numbers in the counted loop are going backwards instead of forwards. This is then used to search for an item called "Potion", and change it to "None". When this is done, it will automatically exit the for loop, therefore completing the process.

Random Number

Random numbers are very useful when calculating percentages, because percentages are based on probability. If something has a 35% chance of happening, you can simulate that with a Rand.Int (1, 100) command. So if you want to use this in your game, and you wanted to give the user a 35% chance of winning you would use:

code:
if Rand.Int (1,100) <= 35 then
        put "You win."
else
        put "You lose."
end if


The key element here is the >=. Why is that used, instead of <, >=, or >? Let's look into this in more detail. When something has a 35% chance of happening, and there are 100 numbers, the following numbers are winning numbers: 1,2,3,4,5,6..35. Any number from 36-100 is a loss. So if the random number is less than or equal to 35, the condition is met, as shown in the above code. With this system of code, you can simulate any combination of percentages as you please.

Now, for a more complex function of random numbers, consider this. What if you have a skill called Double Attack, that has a 5% chance of working for every skill level you have? How would you do it? Well, the answer is slightly more complex:

code:
var skill_level : int

if Rand.Int (1,100) <= skill_level * 5 then
        put "You use Double Attack!"
else
        put "Nothing happens."
end if


Properly Accepting User Input

As many of you are aware, Turing is very picky when it comes to caps in input. This is easily seen when Turing will not properly read when a user types in YES, when the programmer wants the user to type in yes or Yes. The solution to this can be solved by using a simple function that converts a text string into pure caps, where it can then be easily accepted by Turing.

function caps (word : string) : string
word2 := ""
for i : 1 .. length (word)
if ord (word (i .. i)) > 96 then
if ord (word (i .. i)) < 123 then
word2 := word2 + chr (ord (word (i)) - 32)
else
word2 := word2 + chr (ord (word (i)) + 0)
end if
else
word2 := word2 + chr (ord (word (i)) + 0)
end if
end for
result word2
end caps

By using "caps(some word)", this function will convert it into "SOME WORD". Now say if you use an if statement after this, the pure caps allows the if statement to pick up on any variation of the string entered. Of course, it will not pick up bad spelling, so if you suck as spelling, too bad for you.

Now that you have the basic Turing concepts, it's time to deal with the elements of an RPG.

Elements of an RPG

Note: The following sections are optional, and you may choose to omit them when making your game.

Readme File

An important aspect of making an RPG is making sure that the user can use it properly. Sure, you know everything, but when someone else runs it, chances are that they will not see the code, and will most likely be clueless as what to do. Readme's do not have to be in-depth; just give the user enough information so that they can play the game correctly. Some things you might want to include in your readme file would be:

Controls
Processes of Game
Explanations of Various Elements of the game (spells, monsters, stats, etc)

Collection of Game Data

When making an RPG, especially the more complex ones, it would sometimes help to make a bunch of Word files, or something along the lines that stores all data in the game. In this case, the data should include things such as formulas, item names, item actions, monsters, storyline, everything about the game that could be used as a reference guide, because you never know when you forget what item does what. Obviously, you would not distribute it when you release the game, or else the other users will know basically everything about the game.

Damage Range

An important component of an RPG is damage. Damage is what kills the enemy and the player. There are generally 2 types of damage ranges:

D&D Style - Usually damage is about 40 or less for a strong character.
FF Style - Depending on the FF game, damage caps at 9999

Of course, you can make your own, but damage needs to be calculated according to stats, and enemy HP should not be too difficult in relationship to the max damage. For example, if a strong attack in your game is 50 damage, it would not be fair to the player if a boss has over 10000 HP, because the damage does not fit the HP value. 1000 HP would be a more realistic amount.

Gender

This is usually a preference setting for many games, but sometimes you may decide to give certain bonuses and penalties to certain genders. This should pretty much be self-explanatory, so I don't think I need to go into much detail here.

Races

Races can be used in the same manner as Gender.

Classes

Classes can be used in the same manner as Gender. Keep in mind that classes should have an obvious relationship with the stats that you will create.

Stats

For most games, stats are the backbone of a character's strength. If not, they are still a crucial element in battle. You should try to make stats that reflect the corresponding classes. For example, if you have a Fighter class, you need some sort of Strength or Power stats. Spell casters should have Intelligence or Wisdom. Be sure to balance the stats so that one stat is not too powerful over another. Some suggested stats to use are listed below. Remember, some stats may seem the same, but may have different effects based on the type of RPGs you have played in the past.

Strength
Agility
Vitality
Luck
Charisma
Intelligence
Wisdom

Note: The following sections of the battle system require extensive knowledge of commands such as arrays, functions, procedures, and being able to create multi-step formulas. The following sections should be skipped if your battle system is based on random numbers instead of stats. A complex battle system is probably one of the hardest components to make, so do not expect a good battle system in a few minutes. If you do not have the required knowledge, a simple battle system based on random numbers can and should be used.

Battle System

The most exciting part of an RPG is usually the battles. Battles are supposed to be fun for the user, and is usually required to become stronger or to advance the plot. A battle system will use the loop command extensively, and procedures and functions would really help. The basic form of a battle system should be

Ask user for command
Choose target
Command is done
Enemy may take damage
Enemy loses HP.
Enemy attacks, player may take damage
Player loses HP.

This process is repeated until either the monster or the player's go below zero.

Asking User for Command

This should be pretty easy. You give the user a list of commands, and store their answer as a variable. However, you may also want to display vital information such as HP, or something similar to it, and MP, or something related to that. Things like gold amount would not be useful to know in battle, unless you had some sort of skill/magic/etc that uses gold as part of a damage formula.

Choosing Target

If you want to have multiple monsters in battle, this should be used. If not, skip this section. When choosing targets, remember to give the user an accurate listing of the monsters in battle, and make sure that if a monster is killed, that it will not be shown as a target. You can do this by using a boolean variable, such as monster_dead. If that condition is true, the monster is dead, and will not be shown. If it's alive, the condition will be false, and it will be shown.

Command being Used

The different commands are explained below, and you should give the user plenty of choices to do, to give them more customizability in their battles.

Enemy taking damage

After commands such as attacking, and casting spells, you will need to display the damage, so the user knows what's going on.

Enemy losing HP

This action can simply be done with 1 line of code:

enemy_hp := enemy_hp - damage

Enemy Attacks

This is slightly more complex. There are 3 ways to code a monster.

Pure Attack
Pure Magic
Combination

The first 2 are not that hard. The coding is similar to the one of player attacking/casting magic, you just need to reverse some values. Instead of using player intelligence to calculate spell attack, it is now used as spell defence, since the player is on the recieving end of the spell.

The more complex method of enemy attacking is Combination. Combination enemy attack can also be divided into 2 methods:

Random Action
Artificial Intelligence

Random Action simply uses Random Integers to do random actions, such as a random integer to select attack/magic, etc. This can be a problem with magic casting, because casting random magic spells does not seem to be a good idea, due to the large sections of code needed, so melee monsters should just use random actions. The ideal method of magic monsters should be AI. You should code an AI that does certain actions according to certain actions in battle. For example, if the monster has Max MP, then they should not cast some sort of healing spell. If the monster "sees" that the player is absorbing a certain element, the monster should not cast that spell anymore. If the monster does not have enough MP for a spell, then they will not cast it. Setting up an AI takes up the most code, but the end result is a more realistic monster.

code:
if monster_hp / monster_maxhp * 100 < 100 then
        cast_spell := "Fireball"
else
        cast_spell := "Cure"
end if


This code states that if the monster is below 100% of HP, it will cast fireball. If not, then it will cast Cure. Of course, this is not fair to the player, because the monster will keep on healing itself, so it's up to you to balance the AI and make sure that the challenge does not become impossible.

In Summary:

Pure Attack - Simple code for melee monsters (will only attack, predictable)
Pure Magic - Simple code for magic casters (will only cast magic, predictable)
Combination - Random Action (random actions such as attacking, casting, etc)
- AI (attack/cast spell, depending on certain battle conditions)

Melee Classes - Pure Attack (basic code)
- Pure Magic (monster is almost useless)
- Random Action (attack, will cast occasionally)
- AI (attacks, will cast spells when necessary)

Magic Casters - Pure Attack (weak monster; magic casters should not attack)
- Pure Magic (casts all magic, can be easily beaten with Reflect Magic)
- Random Action (can do both at random, may cast useless spells once in a while)
- AI (ultimate option, gives mage a command based on battle status, will not cast useless spells)

Simply put, if you have the time, AI is the best option!

Player Loses HP

Back to the basics. Almost exactly the same as the enemy losing HP.

player_hp := player_hp - damage

Adding EXP

At the end of battle, experience should be added to the character's exp. The code should be something along the lines of:

code:
exp := exp + monster_exp


Be sure that you set the monster's EXP before battle. Make sure that the EXP corresponds to the enemy's difficulty.

Levelling Up

Let's say you have a level 1 character that needs 10 EXP to level up. At the end of battle, you would use something like:

code:
if character_level = 1 and exp >= 10 then
        character_level := 2
        exp_needed := 25 - exp
end if


This means that a level 1 character with over 10 EXP will move up a level, and the exp needed for the next level is 25 - minus his/her current EXP. Now, for a level 2 character that needs 25 exp to level up, you would use:

code:
if character_level = 2 and exp >= 25 then
        character_level := 3
        exp_needed := 40 - exp
end if


Gaining Gold/Items

Gaining gold is a simple line of code:

code:
gold := gold + enemy_gold


Gaining items is a lot more difficult. Make sure that the item addition is added only once, and if you are using a counted loop with an arary, make sure you use the exit command to leave the counted loop so you don't end up with duplicate items.

The following sections deal with formula calculations. Math skills are not really necessary, because formula calculations should be simple. Keep in mind that formulas are usually multistep, so make sure you can follow what your formula can do to help you test it. The formulas below are based solely on stats. Factors such as Elements, and Abnormal Status are not included, and will be covered later. Also, for simplicity of the code, declaring variables has been ignored. If you wish to test the code yourself, all variables are usually integer, with a few exceptions.

Attacking

There is virutally no way you could make an RPG work without the basic attack command. In most RPGs, this is your only choice, until you can be higher levelled to learn the spells, or for some classes, this is the ONLY way to fight. Damage should be based on the following factors:

Player Level
Player Strength or equivalent stat
Player Weapon
Enemy Level
Enemy Defence or equivalent stat
Enemy Armor (if applicable, such as human enemies)

However, you may also wish to have a separate formula just for calculating whether a hit is even successful or not. A check to see if the attack hits the opponent could be based on:

Player Level
Player Dexterity or equivalent stat
Player Weapon
Enemy Level
Enemy Agility or equivalent stat
Enemy Armor (if applicable)

A simple formula for accuracy check could be as follows:

code:
if (player_level + player_dexterity + player_weapon_chancetohit) >= (enemy_level + enemy_agility + enemy_armor_chancetododge) then
        [insert rest of damage code]
else
        put "You miss the enemy!"
end if


Of course, formulas may vary, but that's just a simple accuracy check. If the player misses, the battle goes onto the next step. Otherwise, the damage should be calculated. First step, you need to calculate the absolute maximum damage the player could do against an enemy with 0 defence. A simple formula could be

code:
damage := (player_level + player_strength) * weapon_power


A level 10 character with 50 Strength and has a weapon power of 85 could do a maximum damage of 5100. Of course, you do not want the damage to be 5100 ALL the time, as the damage gets predictable. A way to solve this is by using random numbers.

code:
damage := (player_level + player_strength) * weapon_power
damage := damage + Rand.Int (1, damage * 0.05 div 1)


This calculates damage, and adds up to any number from 1 to 5% of the initial damage as extra damage. If the base damage is 500, the extra damage could be anywhere from 1-25 extra damage. This will vary your damage, and will prevent it from becoming too predictable.

Once maximum damage is calculated, you need a method for damage reduction. You could add up all the enemy defence values and subtract it from maximum damage to get the final damage.

However, a problem arises with low levelled characters. An enemy with more than 0 defence could block a large portion of the characters damage, or if the character is a low-level magic caster, the damage could be completely blocked.

How can this be solved? A more advanced formula could be damage reduction by ratio. Lets say the base attack power (after calculations) is 10 above the base enemy defence (after calculations). Under the simple formula, this is a result of about 10 extra damage.

However, using ratios, this situation could a lot different. Note: The % difference is calculated using ( ( (bsattack / bsdefence) * 100) - 100)

Base Attack Power: 11
Base Defence Power: 1
% Difference: 1000%

Base Attack Power: 510
Base Defence Power: 500
% Difference: 2%

From a gamer's perspective, who do you think should recieve more bonus damage? The answer is obvious; player 1. The first player has obviously trained his character far above the enemy stats. The second character is also very strong, but has not surpassed the enemy as much as player 1, even though they both have 10 higher attack than the enemy defence.

What if the enemy has higher defence than the player's weapon power? Using the simple formula, the damage would be in the negatives, which would not be possible, and if the damage is 1, would make the battle almost impossible to win. Again, using ratios and % differences is the solution. Taking the previous values and reversing them gives a much different result. Note: % Difference is calculating using ( ( (base_attack / base_defence) * 100) - 100)

Base Attack Power: 1
Base Defence Power: 11
% Difference: -90.9%

Base Attack Power: 500
Base Defence Power: 510
% Difference: -1.9%

Player 1 is obviously far behind the enemy's stats, while player 2 is slightly behind, but not as much. Again, in both cases, the stats have a difference of 10.

With the % difference in place, the formula is simple:

code:
if base_attack >= base_defence
        bonus_damage := damage * ( ( (base_attack / base_defence) * 100) - 100)
        damage := damage + bonus_damage
else
        reduced_damage := damage * ( ( ( (base_attack / base_defence) * 100) - 100) * -1)
        damage := damage - reduced_damage
end if


In this case, player 1 suffers a 91% damage penalty, while player 2 only suffers a 2% penalty.

Next, you may wish to include critical hits, where damage is doubled. This is usually based on luck, and level. A simple method could be:

code:
critical_chance := character_luck + character_level


You should have this followed by a

code:
if Rand.Int (1,100) <= critical_chance then
        [critical hit]
else
        [normal damage]
end if


If the critical chance is 33, then the number has to be 1,2,3..33 to deal critical damage. If not, damage is normal.

And that's it! The damage calculating is done! An example of an attacking code could be:

code:
if (player_level + player_dexterity + player_weapon_chancetohit) >= (enemy_level + enemy_agility + enemy_armor_chancetododge) then
        damage := (player_level + player_strength) * weapon_power
        damage := damage + Rand.Int (1, damage * 0.05 div 1)
        base_defence := enemy_level + enemy_vitality + enemy_armor
        if base_attack >= base_defence
                bonus_damage := damage * ( ( (base_attack / base_defence) * 100) - 100)
                damage := damage + bonus_damage
        else
                reduced_damage := damage * ( ( ( (base_attack / base_defence) * 100) - 100) * -1)
                damage := damage - reduced_damage
        end if
        if Rand.Int (1,100) <= critical_chance then
                damage := damage * 2
                put "You land a critical hit, dealing ",damage," damage!"
        else
                put "You have dealt ",damage," damage!"
        end if
else
        put "You miss the enemy!"
end if


Remember, this is just a sample. Keep the damage limits, stat limits, weapon powers, armor powers, enemy defences, etc. into account when making your formula. You will most likely have to refine the code a little, so change some values or parts of the formula when something is not right.

Magic

If you plan to have magic in your RPG, this section is very important. Magic has the primary purpose to damage the enemy in battle. In order to calculate damage, it should be dependent on:

Your magic power
Your level
Enemy's magic defence
Enemy's level

You can also cover resistances/weaknesses, etc, but that will be covered in the next section. With all the values known, you should start with the calculation. The first thing you need to find out is the absolute maximum damage you could do to an enemy with 0 magic defence. One example could be

code:
magic_damage := character_intelligence * 20


A character with 50 intelligence could do a maximum of 1000 damage.

However, consider this. What if you have a basic fire spell, and another fire spell, but you want it to be stronger? You may want to have the intelligence multiplied by a variable that is dependent on the spell being casted. For example:

code:
put "What spell would you like to cast?"
get cast_spell

if cast_spell = "Fire" then
        spell_power = 10
elsif cast_spell = "Flame" then
        spell_power = 50
end if

damage := intelligence * spell_power


With this code, the damage is 1000 for Fire, and 5000 for Flame. After setting max damage, you may also want to add a bonus spell damage based on level. Maybe you would like to have a % damage bonus based on level, such as a level 53 character have a 53% bonus to damage. The code for this is pretty simple:

code:
damage := damage * ( (level / 100) + 1)


After calculating maximum damage, you will need to set damage reduction for magic defence. Similar to attacking, the formula should be based on ratios between the magic attack power vs. magic defence, or something similar to this.

code:
if base_magic_attack >= base_magic_defence
        bonus_damage := damage * ( ( (base_magic_attack / base_magic_defence) * 100) - 100)
        damage := damage + bonus_damage
else
        reduced_damage := damage * ( ( ( (base_magic_attack / base_magic_defence) * 100) - 100) * -1)
        damage := damage - reduced_damage
end if


Most likely, there will not be an accuracy check for magic casting, because most RPGs do not have spell failure. However, if you want to add spell failure, the formula is similar to the accuracy check when attacking. See that section for the code.

The final result of the code is:

code:
put "What spell would you like to cast?"
get cast_spell

if cast_spell = "Fire" then
        spell_power = 10
elsif cast_spell = "Flame" then
        spell_power = 50
end if

damage := intelligence * spell_power
damage := damage * ( (level / 100) + 1)

base_magic_defence := enemy_level + enemy_intelligence

if base_magic_attack >= base_magic_defence
        bonus_damage := damage * ( ( (base_magic_attack / base_magic_defence) * 100) - 100)
        damage := damage + bonus_damage
else
        reduced_damage := damage * ( ( ( (base_magic_attack / base_magic_defence) * 100) - 100) * -1)
        damage := damage - reduced_damage
end if


You may also want to set up your damage calculations as a function, using the spell_power as a parameter.

code:
function calculate_damage (spell_power : int) : int
        damage := intelligence * spell_power
        damage := damage * ( (level / 100) + 1)

        base_magic_defence := enemy_level + enemy_intelligence

        if base_magic_attack >= base_magic_defence
                bonus_damage := damage * ( ( (base_magic_attack / base_magic_defence) * 100) - 100)
                damage := damage + bonus_damage
        else
                reduced_damage := damage * ( ( ( (base_magic_attack / base_magic_defence) * 100) - 100) * -1)
                damage := damage - reduced_damage
        end if
end calculate_damage

put "What spell would you like to cast?"
get cast_spell

if cast_spell = "Fire" then
        calculate_damage (10)
elsif cast_spell = "Flame" then
        calculate_damage (50)
end if


This allows you to set the spell calculation into one set of code, and you can call upon it, with different spell_power values, depending on the spell that the player casts.

Resistances/Weaknesses/Immunities/Absorption

The formula for this is pretty simple. After damage calculations, you will use an if-statement to compare string values, and if a match is made, the spell damage is adjusted accordingly. For example:

code:
if monster_weakness = "Fire" then
        damage := damage * 2
elsif monster_resistance = "Fire" then
        damage := damage * 0.5
elsif monster_immunitiy = "Fire" then
        damage := damage * 0
elsif monster_absorb = "Fire" then
        damage :=  damage * -1
end if


As you can see, damage changes depending on the monster elemental attributes. If the monster is neutral to all elements, damage is not changed. What if you want to have multiple weaknesses/resistances/immunities/absorption? The answer is arrays. First, you will declare the variable as an array. For the next section, we will set up multiple weaknesses. Other elemental attributes must be added if you wish.

code:
var enemy_weakness : array 1 .. 8 of string


8 represents the number of elements in the game. The more elements you have, the higher the second number, because you need space if you want a monster that absorbs all elements, etc. After declaring the array, you would proceeed to the weakness setting. Let's make a monster have a weakness to Fire and Ice.

code:
enemy_weakness (1) := "Fire"
enemy_weakness (2) := "Ice"

for i : 3 .. 8
        enemy_weakness (i) := "None"
end for


This makes the monster have a weakness to Fire and Ice elements. Next, you insert your standard magic code.

code:
function calculate_damage (spell_power : int) : int
        damage := intelligence * spell_power
        damage := damage * ( (level / 100) + 1)

        base_magic_defence := enemy_level + enemy_intelligence

        if base_magic_attack >= base_magic_defence
                bonus_damage := damage * ( ( (base_magic_attack / base_magic_defence) * 100) - 100)
                damage := damage + bonus_damage
        else
                reduced_damage := damage * ( ( ( (base_magic_attack / base_magic_defence) * 100) - 100) * -1)
                damage := damage - reduced_damage
        end if
end calculate_damage

put "What spell would you like to cast?"
get cast_spell

if cast_spell = "Fire" then
        calculate_damage (10)
elsif cast_spell = "Flame" then
        calculate_damage (50)
elsif cast_spell = "Ice" then
        calculate_damage (10)
elsif cast_spell = "Blizzard" then
        calculate_damage (50)
end if


Now, the code that checks for elemental properties is slightly altered.

code:
procedure check_fire_elemental_properties
        for i : 1 .. 8
                elsif enemy_weakness (i)  = "Fire" then
                        damage := damage * 2
                elsif enemy_weakness (i)  = "Fire" then
                        damage := damage * 0.5
                elsif enemy_weakness (i)  = "Fire" then
                        damage := damage * 0
                elsif enemy_weakness (i)  = "Fire" then
                        damage :=  damage * -1
                end if
        end for
end check_fire_elemental_properties

procedure check_ice_elemental_properties
        for i : 1 .. 8
                elsif enemy_weakness (i)  = "Water" then
                        damage := damage * 2
                elsif enemy_weakness (i)  = "Water" then
                        damage := damage * 0.5
                elsif enemy_weakness (i)  = "Water" then
                        damage := damage * 0
                elsif enemy_weakness (i)  = "Water" then
                        damage :=  damage * -1
                end if
        end for
end check_ice_elemental_properties


The counted loop checks each of the various elemental properties. You can now call upon the procedures to check different elements, depending on the spell being casted. The final magic code would be:

code:
procedure check_fire_elemental_properties
        for i : 1 .. 8
                elsif enemy_weakness (i)  = "Fire" then
                        damage := damage * 2
                elsif enemy_weakness (i)  = "Fire" then
                        damage := damage * 0.5
                elsif enemy_weakness (i)  = "Fire" then
                        damage := damage * 0
                elsif enemy_weakness (i)  = "Fire" then
                        damage :=  damage * -1
                end if
        end for
end check_fire_elemental_properties

procedure check_ice_elemental_properties
        for i : 1 .. 8
                elsif enemy_weakness (i)  = "Water" then
                        damage := damage * 2
                elsif enemy_weakness (i)  = "Water" then
                        damage := damage * 0.5
                elsif enemy_weakness (i)  = "Water" then
                        damage := damage * 0
                elsif enemy_weakness (i)  = "Water" then
                        damage :=  damage * -1
                end if
        end for
end check_ice_elemental_properties

function calculate_damage (spell_power : int) : int
        damage := intelligence * spell_power
        damage := damage * ( (level / 100) + 1)

        base_magic_defence := enemy_level + enemy_intelligence

        if base_magic_attack >= base_magic_defence
                bonus_damage := damage * ( ( (base_magic_attack / base_magic_defence) * 100) - 100)
                damage := damage + bonus_damage
        else
                reduced_damage := damage * ( ( ( (base_magic_attack / base_magic_defence) * 100) - 100) * -1)
                damage := damage - reduced_damage
        end if
end calculate_damage

put "What spell would you like to cast?"
get cast_spell

if cast_spell = "Fire" then
        calculate_damage (10)
        check_fire_elemental_properties
elsif cast_spell = "Flame" then
        calculate_damage (50)
        check_fire_elemental_properties
elsif cast_spell = "Ice" then
        calculate_damage (10)
        check_ice_elemental_properties
elsif cast_spell = "Blizzard" then
        calculate_damage (50)
        check_ice_elemental_properties
end if


And that's it for elemental magic! For a more complex elemental formula, you may wish to have the user to have different % of elemental resistances/weaknesses/absorption. Immunity is automatically 0% damage, so that will not change. For example, you may want to set it so that if a player casts a spell that does 1000 damage, the enemy will absorb 50% of it instead, so instead of taking 1000, it heals 500! 300% weakness will make the monster take 3000 damage! And 75% resistance will cut the damage down to 250 damage.

Abnormal Status

Abnormal Status gives the battle a twist. It can do anything from making the battle just an obstacle, or can completely frustrate the player. If you have played a lot of RPGs, you will already know many of them. Some suggestions to use are:

Poison
Beserk
Confuse
Physical/Magical Damage Reduction
Rengeneration of HP/MP
Hit Rate Reduction/Improvement
Relection of Magic/Physical Attacks
Spell/Physical Damage Reduction/Improvement
Stats Increases/Penalties

Poison

This one is very simple. At the end of the round, you should add code that has the player take damage.

code:
if character_status = "Poison" then
        damage := character_maxhp * 0.1
        character_hp := character_hp - damage
end if


This has the player take 10% of Max HP damage per round.

Beserk

Beserk is also simple. At the stage where the user asks for the user's command, you skip it with an if-statement

code:
if character_status not= "Beserk" then
        put "What would you like to do?"
        get command
else
        command := "Attack"
end if


And thereafter, you would have it select a random monster using random integers.

Confuse

This one is a lot more tricky. For simplicity reasons, I suggest that commands used in the Confuse status be restricted to attacking only. When you allow it to use magic, you will have to have Turing select a random spell, check if they have enough MP or not, and then have it select a random target. For the case of Physical attacks only, the result is similar to beserk. Instead of having a random integer for every monster in the field, you have a random integer for every monster in battle, plus 1 for yourself, because when you are confused, hitting yourself is a valid command. The coding is very similar to that of Beserk.

Physical/Magical Damage Reduction/Increases

Under the damage calculation, before HP is taken away, you use an if statement to check the character status, and adjust the damage accordingly.

Rengeneration of HP/MP

The code is very similar to that of Poison, only instead of losing HP, you gain it.

Hit Rate Reduction/Improvement

In the hit rate calculations, you may wish to add/subtract from the hit rate, to give a bonus or penalty to the hit rate.

Reflection of Magic/Physical Attacks

After dealing damage, but not adjusting HP, you would set the damage to 0, and have an equal amount of damage be dealt to the opposite target.

code:
if character_status = "Reflect" then
        [damage calculation]
        reflected_damage := damage
        damage := 0
        character_hp := character_hp - reflected_damage 
else
        [damage calculation]
end if


Spell/Physical Damage Reduction/Improvement

This is almost the exact same as the elemental attributes, with certain strings in status that adjusts the damage from spells or physical attacks.

Stats Increases/Penalties

For this to work, you must first have 2 variables for each stat. One for the base stat, another for the stat after bonuses. The stat after bonus should be altered when the status is in place, and when it wears out, you need to re-set it as the base stat, added by the bonusus from weapons, armor, etc.

Running Away

You should first have a condition from which an enemy can run away. First of all, bosses should automatically deny the chance to run. Otherwise, it should be based on the character's luck, agility, or any stats you wish. When you are sucessful at running away, treat it as a victory by setting all enemy hp values at 0, but replace the victory screen with some sort of running away message.

Other Notes on Battle System

Even though the battle system seems simple enough, there are many loops that you have to add if you wish to have a smooth-flowing battle system. You should give room for user errors by giving them a 'back' option, incase they issue a command, and wish to change their mind without wasting a turn. Learn to love the F2 button, as this will automatically indent the entire program for you, making it a lot easier for you to understand your own code. You don't necessarily need a flashy battle system; a simple format should suffice.

Items

Items are an important addition to your RPG. Although you don't need them, having them allows a more diverse game. Items have a variety of purposes, from healing, restoring status, dealing damage, advancing the plot, and others. However, even using a simple Potion to heal your HP can be more complex than you think. For example, I use this:

code:
procedure use_potion
        if character_currenthp > character_maxhp - 100 then
                put "You drink the Potion, and regain ", character_maxhp - character_currenthp, " HP!"
                character_currenthp := character_maxhp
        elsif character_currenthp <= character_maxhp - 100 then
                put "You drink the Potion, and regain 30 HP!"
                character_currenthp := character_currenthp + 100
        end if
        put "You now have ", character_currenthp, " HP."
        put ""
        put "                Press any key to continue"
        getKey
        for decreasing i : 120 .. 1
                if item (i) = "Potion" then
                        item (i) := "None"
                        exit
                end if
        end for
end use_potion


As you can see, this procedure combines if statements, with counted loops and arrays. Notice the first section of the if statement. You want to make sure that you do not exceed certain limits. For healing items, make sure you don't exceed maximum HP. For items that deal damage, make sure you do not exceed the damage limit, unless you want it to. An item system in a menu system is still being developed by me, so for now, stick with battle items.

Experience Chart

An experience system is the most common form of character development. After reaching a certain EXP amount, the character levels up, and recieves bonuses to stats, more HP/MP, etc. This section explains what the certain EXP amount should be. Obviously, a character should not level up every battle, nor should they level up every 1000 battles, because this is not fair to the player. The key is to give them a limit that's challenging, and rewarding when they level up. A good ideal EXP amount to level up should be 15-20 times the amount of the EXP that a monster with a similar level gives. For example, if a level 20 monster gives out 1000 EXP, the EXP to level up from level 20 to level 21 should be approximately 15000 - 20000. Of course, you can choose your own ratio, but this is a suggestion.

Other Experience Charts

Some RPGs may also have a separate EXP chart. The FF series have used MP (Magic Points, not the ones inside battle), and AP (Ability Points). Instead of using points, however, you may decide to make it's own EXP chart. Usually, these other EXP charts accompany a class system. They should reflect the abilities of the class itself, while the standard EXP chart reflects the mastery of the abilities to fight. For the next example, JEXP will be used as the other EXP Chart (Job EXP)Compare the relationship between EXP and JEXP to a game of chess. EXP is knowing the rules, and how to play. JEXP is developing techniques and strategies to defeat the opponent. Obviously, learning techniques and strategies takes a lot more time than simply learning the rules. Likewise, JEXP should be more difficult to obtain than normal EXP. Of course, you can have it the other way around, but this way make more sense. Finding the number of JEXP needed to next level up is similar to that of normal EXP.

Making Your RPG Better

Testing

VERY important. Testing is what makes your game works. There are 2 things to test for in a RPG:

Bugs
Balance Issues

Balance Issues are covered in the next section. For bugs, make sure that you enable the button bar at the top of the screen. Even if it get's in your way, enable it! With that, you can pause your program, and see if anything is not doing what it's supposed to do. Another suggestion is to open the debugger menu, and trace the operation of the program. With that, you can also see other bugs when running the program. Another thing to do is to comment out any delay commands, because although they help the reader, they do not help the programmer! All it does is make your testing phase much slower, so enable it when you decide to release it.

Balancing

While testing, you will most likely be coming across some balance issues. These are not bugs by definition, but still need to be fixed. While some attacks seem really powerful and nice, it is not fair to the player to have a skill to have a really good skill, without some sort of setback. Likewise, some skills may be very weak, even though they were not supposed to be. The solution to this is repetitive testing; you may also want other users to test for you, because this way, you can get more situations to test. Remember, if the user is not challenged, or the game is too hard, they will not like it as much.

Improving

So your game's perfect huh? Don't stop there! Add more! Make the battle system more complex, add a new dungeon, make more monsters, add graphics, anything that makes it more fun! Remember, until you can make a game of commercial quality, there's always room for improvement. So you've done all that Turing can do? Move your game to another language! Making a high-quality game all by yourself is very satisfying, so don't quit when you get stuck, or you think you're done, because if you are completely done, you'd be working at Squaresoft or something.

Final Notes

This guide was only designed for text-RPG coders and coders-to-be, since that's all I know how to do. Graphics RPGs will need this guide, and more, since not only do you have to get the computer to calculate all values properly, you now need to make it appleasing to the user's eye.

Remember, this is only a guide. Only YOU can make the decisions, and it's up to you to decide which of my suggestions you want to follow. For those who are coding an RPG, take my advice into account when coding it. If you are reading this, make sure that you can handle all the coding of an RPG before you start, because it would be very disappointing if you started, and then got stuck, and couldn't finish your final project. For all users out there, you've now seen the sheer amounts of code required to make an RPG, and I hope you can now appreciate the effort and time required to make one. Good Luck to those who decide to make one of the most simple types of games, and at the same time, is one of the hardest. Check for updates later on, when I add more.

Azndragon

Copyright 2002 Andrew Chung

And so, that's my tutorial. It's not that bad writing it, but just imagine adding all the formatting to it! Hope you guys enjoy it.
Sponsor
Sponsor
Sponsor
sponsor
Tony




PostPosted: Sun Mar 30, 2003 5:18 pm   Post subject: (No subject)

wow... that is one big tutorial...

I'm gonna give you +20 bits now and more when I actually read it later on.

I've finally read your tutorial... wow... its long and VERY descriptive. I'm giving you a +80bits on top of that Very Happy
Latest from compsci.ca/blog: Tony's programming blog. DWITE - a programming contest.
nate




PostPosted: Tue Apr 08, 2003 6:37 pm   Post subject: WHoLLY CRAP

THATS ALMOST 9,000 words long!

Do you have nothing better to do then type a 9,000 word tutorial. Its good, but who is goining 2 read the whole thing.

-Nate
haujobb




PostPosted: Tue Apr 08, 2003 6:56 pm   Post subject: (No subject)

I did
Asok




PostPosted: Wed Apr 09, 2003 12:04 am   Post subject: (No subject)

I did ya lazy punk! Rolling Eyes

It's very good that azndragon decides to make the time to make a quality tutorial like this.

Besides, did it ever come to you that maybe he wanted to do the tutorial in the first place?
Eskimo




PostPosted: Wed Apr 09, 2003 10:36 am   Post subject: Woah

That...is LONG! Beautiful too! This helps a lot, man, thanks
Vicous




PostPosted: Wed Apr 09, 2003 12:05 pm   Post subject: (No subject)

wow, my brain hurts... this is long! but when you run away, you should not get as much experience and any items you may have gotten... consider an experience system based on how hard the fight was to win, no how strong the monster was... think about it
Vicous




PostPosted: Wed Apr 09, 2003 12:15 pm   Post subject: (No subject)

and few if any spelling mistakes! gets my seal of aproval! lol
Sponsor
Sponsor
Sponsor
sponsor
FwuffyTheBunny




PostPosted: Thu Apr 10, 2003 12:26 pm   Post subject: (No subject)

Great tutoral =)
Andy




PostPosted: Sat Jun 07, 2003 8:13 pm   Post subject: (No subject)

you should make this into a book, burn turing onto a cd, and sell it as a bundle "Make your own REAL RPG"
krishon




PostPosted: Sun Jun 15, 2003 3:42 pm   Post subject: (No subject)

ye, this is really nice, tho i did try to make an rpg earlier in the year b4 this wuz written. most of the stuff he put up there are essential in order to make it work. This is definitely one of the best tutorials on compsci. Good job Very Happy
PHP God




PostPosted: Mon Jun 16, 2003 10:54 am   Post subject: (No subject)

We should write a book. The turing manual sucks and doesn't explain things. Like in the first chapter it uses the randint function, but doesn't tell you what it does. It sucks so bad. Then agaian, a full turing manual would be really big.
krishon




PostPosted: Mon Jun 16, 2003 10:57 am   Post subject: (No subject)

lol, ye, we can split up and write a section on a fucntion and then make it into a book
Andy




PostPosted: Tue Jun 17, 2003 10:24 am   Post subject: (No subject)

ya then sell it to schools, so we dun have to use the crappy holt soft text book which is the exact same as the textfile -- lots of useless info 8)
Viper




PostPosted: Fri Nov 26, 2004 12:35 pm   Post subject: (No subject)

ok im makin a rpg that is kinda like diablo and i wanna make a large map but i dont know how to make something larger than the screen and be able to see it(or move to it)
Display posts from previous:   
   Index -> Programming, Turing -> Turing Tutorials
View previous topic Tell A FriendPrintable versionDownload TopicRate TopicSubscribe to this topicPrivate MessagesRefresh page View next topic

Page 1 of 2  [ 24 Posts ]
Goto page 1, 2  Next
Jump to:   


Style:  
Search: