Chapter 4
Magic

Anytime you talk about a fantasy-based RPG, you will eventually get around to talking about magic. A fantasy-based RPG wouldn’t be the same without the obligatory wizard or mage. An RPG world would probably be pretty boring without its magic. You wouldn’t have any of the magical creatures, and some of the races wouldn’t exist, such as elves, dwarves, or halflings (depending on how you explain their existence). All in all, it might not be much fun to run around in such a world. Luckily for you, this chapter will give you some ideas on how to integrate a basic magic system into your game.

There are many ways to implement a magic system. We’ll use a fairly standard mana system. Mana usually exists in one of two ways — entities have an inner reserve that allows magic users to cast spells, or the magic user is able to tap into an external source that permeates the world. When this reserve is empty or the character exhausts himself attempting to manipulate the external source, he must allow some time to pass before he can cast any more spells. All characters will have some mana, although it may be difficult for them to learn to use spells.

Some systems base a character’s ability to use magic on one of its stats, such as intelligence or wisdom. I feel this is fairly unrealistic, although probably easier for pen and paper RPGs. An intelligent character may be able to learn spells more easily, but I don’t believe this should have any bearing on how much mana he has. A less intelligent character may have an innate ability to use magic, but may not be smart enough to learn any spells. The system in this book will treat mana as another stat, although magic-using characters will recover mana quicker. We explain this by saying that magic-using classes have learned how magic works to some degree and how to train their bodies to be more in tune with the magic in the world. Classes that don’t use magic may be able to cast spells, but without this knowledge and training they won’t be able to recover mana as quickly as magic-using classes and won’t learn spells as easily. This recovery rate will be handled by the game, so all the player has to worry about is choosing a spell for the character to cast when he’s able.

First off, we’ll look at a class that will handle every aspect of an individual spell and a class that will manage the spells a magic-using character has available to him (think of this class as a spell book). We’ll also look at how a magic user learns his spells and how spells are used, both in and out of combat.

The Spell Class

Listing 4-1


public class Spell
{
private int _id;
private SpellType _type;
private string _name;
private string _description;
private Difficulty _difficulty;
private string _effectAmount;
private string _range;
private string _areaEffected;
private List<string> _classesAllowed;
private string _duration;
private byte _levelRequired;
private short _manaCost;
private AlignmentFlags _alignmentsAllowed;
private SpellCastRate _castRate;
private List<Bonus> _defBonuses;
private List<Bonus> _offBonuses;
private List<Bonus> _miscBonuses;

//graphic used in the spell book in game
[NonSerialized()]
private Texture2D _spellBookGraphic;
private string _spellBookGraphicFilename;
}

The _id member is the typical identifier for doing lookups into a list of spells from other code. The _name and _description members are also typical. The _type member tells us the type of spell. It’s an enumerated value that can be one of the following:

Listing 4-2


public enum SpellType
{
Offensive,
Defensive,
NonCombat
}

The spell type could be broken down into various subcategories that you see in many RPGs, but I opted for a simpler system. A full-blown RPG would probably expand on this.

The _difficulty member could be used to specify how difficult it would be to learn and/or cast this spell. Some RPG systems break spellcasting down into different types, sometimes combining them. Casting a spell could involve a verbal component, such as a word or phrase; a gesture or series of gestures using the hands or possibly the entire body; physical components (the old “eye of newt, wing of bat” kind of stuff); or something else. Doing one of these would be difficult enough in combat. Doing more than one would require great concentration and effort. Since we don’t really care about how the spell is cast, we can simply use a difficulty value as a substitute.

The _effectAmount member is a string that is used to determine how many points to apply to the target. The points can either be damaging or beneficial, depending on the type of spell. A healing spell will restore hit points to the target, while a fireball spell will damage as many entities as are in its area of effect, which the _areaEffected member is used to determine. Both members can have a format of “x-y.” In the case of _effectAmount, it’s the range of points that affect the target. In the case of _areaEffected, it’s the number of horizontal and vertical tiles that are affected. The _effectAmount member can also be a single number that is applied to the target after taking into account any resistances or weaknesses.

The _range member tells the maximum range of the spell. Normally the spell will travel this entire distance unless it’s blocked by something — an entity, a wall or other structure, a defensive spell, etc. If the spell is directed at an entity and the entity dodges the attack (if possible), the spell will continue until it reaches the _range value or it’s blocked. In some cases, the caster will be able to specify where the spell goes off. For example, a magical shield spell or one that creates a wall of ice, stone, or fire could be set to go off directly in front of the caster or some distance away, depending on the range of the spell.

The _classesAllowed member notes the classes that are capable of learning and using the spell. Depending on how you want to use this, the list can be empty to denote that all classes are allowed, or every class can be added to the list and the length of the list compared to the number of classes in your game. The latter case saves having to go through the entire list every time you need to make a check.

Duration can be formatted like _effectAmount, or it can be set up as “x*level of caster.” To make things easy, we’ll assume that the actual time value is going to be in seconds. In a larger scale game this could be something that might last hours, which the duration member of the bonus structure that we’re using is capable of handling. Since the checking of the duration is done automatically, we just set it up and forget it, no matter how long it lasts.

Certain spells can be very difficult to learn and may potentially have devastating effects if used or cast improperly. The _levelRequired member helps take care of a character attempting to learn a spell that he’s not ready for. It’s declared as a byte since we won’t have nearly as many levels as a byte is capable of handling.

Certain spells are also usually usable only by certain alignments. An evil character, for example, normally wouldn’t go around tossing off SmiteEvil spells, as that would probably be viewed as counterproductive. The _alignmentsAllowed member handles this. Notice that it’s an enum that allows multiple values to be assigned to it:

Listing 4-3


[Flags]
public enum AlignmentFlags
{
None = 0,
Good = 1,
Neutral = 2,
Evil = 4
}

Many spells will be usable by any alignment. In this case, the value assigned to the member would be 7, which is the sum of all the alignments.

In mana-based systems (as opposed to systems in which a caster has a set number of spells he can cast before having to take time to memorize his spells again), spells take energy to cast. The _manaCost member is used to tell us exactly how tiring that will be for a character. Expect to play with this value as you test your game to ensure that a magic-using character cannot cast enough spells to destroy an entire dungeon without a problem or does not run out of magic fighting a small rat and the next rat that comes along takes him out.

If a character has a virtual ton of mana, it’s probably not going to help the balance of your game if he can cast, say, a fireball every second. If you’ve ever played World of Warcraft, you’re probably familiar with the cooldown period required after casting a spell. After you cast a spell in WoW, the little toolbar icon is grayed out and slowly returns to normal in a clockwise fashion. You can click on that icon all you want, but until it’s completely back to normal nothing will happen. We’ll have the same kind of thing in our game. The _castRate member will be used to tell whether a spell is usable. It will be used with the _lastCast member of the EntitySpell class that we’ll look at a bit later. The values we currently have in the enum for the member are the following:

Listing 4-4


public enum SpellCastRate
{
None = -1, //No restrictions
Round, //Once per round of combat
Minute,
Hour,
Day,
Week,
Month
}

Notice that we have a value specifically for combat — Round. Since there’s no way to tell how long a round of combat will take, allowing a spell to be used this way can be a little easier than having a spell become available in the middle of a round when the character can’t use it or doesn’t know when it would be available, making it more difficult to plan what the character will do. It also provides a little more control over a spell than just making it None. All of the values are in game time, not real time, and don’t take into account pausing the game (which should be done automatically when the game loses focus). The latter is important since a player could simply pause the game after casting a spell and unpause it when the spell is ready again.

The three bonuses members should be familiar by now. The only thing worth noting is that the bonuses apply to the target, not the caster (unless he’s the target of course).

The _spellBookGraphic member is a texture that’s set using the _spellBookGraphicFilename member. It’s not stored in the entity’s file, but is loaded after the _spellBookGraphicFilename member is set.

Learning Spells

There are probably two typical but very different ways to have a character learn a spell:

Character gains a level — A fairly standard way to handle spells. When the character gains a level, it’s assumed he spends time training to merit the increases in whatever the system increases — stats, skills, and spells. This is the system we’ll use as we touched on last chapter when we learned about skills. When the character gains a level, he’ll get a number of skill points that can be spent on learning skills and/or spells. Magic-using characters will probably spend most of these points learning spells.

Anywhere and anytime — Given a chance to sit down and study, a character can attempt to learn a spell whenever the player wants. If this is allowed you usually won’t be using a level-based system for learning skills, but would instead use something more along the lines of the Dungeon Siege series’ skill-based system.

With both skills and spells, there are checks to be made to determine whether a character has learned what he’s selected. Spells are a bit more complicated than skills in this. There are several factors to take into consideration as we saw when looking at the Spell class:

The character’s class — When attempting to learn a new spell you probably will limit the player’s choice to only those the character is allowed to learn (although we’ll still do a check to verify this and the next two factors).

The character’s alignment — Usually this isn’t an issue with skills.

The character’s level — Again, usually the only way in which level usually has any effect on skills is the bonus the character gets for how many times it has bought that skill.

When a player has a character attempt to learn a spell, here’s what happens from a code standpoint:

Listing 4-5


public bool LearnSpell(int id, int skillPointsAllocated)
{
bool hasSpellcraftSkill = false;

foreach (int key in _skills.Keys)
{
if (GlobalData.Skills[key].Name == "Spellcraft")
{
hasSpellcraftSkill = true;
break;
}
}

if (!hasSpellcraftSkill)
return false;

EntitySpell spell = new EntitySpell();

spell.AllocatePoints(skillPointsAllocated);

_spells.Add(id, spell);

//get any bonuses for learning spells
//right now this is not used
int amount = 0;

return spell.Learn(amount);
}

An instance of the EntitySpell class is created and the points the player allocates to learning that spell are passed as a parameter to the class’s AllocatePoints method. The instance of the class is then added to the Entity object’s _spells member, even if the character fails to learn the spell. We do this because the skill points that are allocated to learning the spell remain, increasing the chance that the character learns the skill the next time he tries. There’s not much to the EntitySpell class, so let’s take a look at the whole thing:

Listing 4-6


public class EntitySpell
{
private bool _learned;
private bool _memorized;
private int _skillPointsAllocated;
private long _lastCast;
private Keys _hotKey;

public bool Learned
{
get { return _learned; }
set { _learned = value; }
}

public bool Memorized
{
get { return _memorized; }
set { _memorized = value; }
}

public int SkillPointsAllocated
{
get { return _skillPointsAllocated; }
set { _skillPointsAllocated = value; }
}

public long LastCast
{
get { return _lastCast; }
set { _lastCast = value; }
}

public Keys HotKey
{
get { return _hotKey; }
set { _hotKey = value; }
}

public void AllocatePoints(int amount)
{
_skillPointsAllocated += amount;
}

public void Memorize()
{
if (_learned)
_memorized = true;
}

public bool Learn(int bonus)
{
short roll = GlobalFunctions.GetRandomNumber(DieType.d100);

if (roll + bonus + (_skillPointsAllocated * 5) >= 100)
{
_learned = true;
_skillPointsAllocated = 0;
}

return _learned;
}
}

Since the spells an entity has learned are stored in a dictionary with the spell ID as the key, we don’t need the ID in the class. Whenever the entity uses the spell, we’ll get it from the key in the dictionary entry.

To learn a spell, the entity can allocate skill points to increase the chance of learning the spell. Each skill point currently increases the chance by 5%. This could be modified by some factors — the difficulty of the spell (remember that _difficulty member?), the amount of time the entity spends (we’re not tracking time for the game created in this book), or just about anything else you want. All the various bonuses the entity may have are passed into the Learn function and added to the random die roll. If the roll is 100 or greater, the character learns the spell and the _learned and _skillPointsAllocated members are set accordingly.

Depending on your system, you might require an entity to memorize a spell every time he wants to use it. If so, there’s the _memorized property you can use to check whether the entity has memorized the spell before allowing him to cast it. To memorize the spell, I added a function instead of using the property setter. This is just a personal preference. I usually try to have actions of an entity done via a function. The code in the function could just as easily be inside a property setter. If you feel this makes the code cleaner, just move it and get rid of the function.

Just about every RPG out there allows the player to create shortcuts for doing things — casting spells, attacking, etc. The _hotKey member will allow us to do this. Usually these keys are the number keys from 1 to 0, but they could be anything you want to allow the player to use. An interface will also have to be created to allow this, unless you allow a config file to be modified by the player. Of course, this won’t work on the Xbox 360 since the player doesn’t have access to any files.

Using Magic

So a character has a bunch of spells memorized, but he doesn’t have a way to use them yet. There are several ways in which the player could cast a spell, but it’s up to you to write the code to make these available to him:

Hotkey — Assuming you’ve given the player a way to assign hotkeys, he should be able to press a particular hotkey any time the character is capable of casting the spell. When the character is capable depends on the spell and whether or not the player has selected a target. Some spells could be area-of-effect, meaning they don’t have a specific target. The player simply casts the spell and the game figures out what entities are in the affected area, which is usually a certain radius around the player or the point selected by the player in the case of a spell that has a range.

Mouse context menu — Using the right mouse button, the player could target an enemy and bring up a context menu with the things he can do to that enemy — attack, talk, or cast spells. Neverwinter Nights used this technique to great effect: Here the player, whose character is the woman in the top right picture, has clicked on an NPC, which brings up a radial menu of actions. She has selected to talk to the NPC. If this had been an enemy, however, a different set of menu items would have been shown and had the player been able to use magic, icons for the different spells that could be used would be available in submenus, shown by the arrows radiating out of some of the icons.

Figure 4-1

Mouse gestures — Not widely used, this technique gives the player more of a feeling of actually casting the spell by having him move the mouse in a specific pattern. One of the problems with this is that the code to capture the gesture would be fairly complex to write to ensure that there’s sufficient latitude in the accuracy expected in order to allow the player to cast the spell even if he’s slightly off with the pattern.

Spell book — Although an alternative, it’s probably not one you would implement. This would require the player to bring up the character’s spell book and select a spell from the book to use each time. If you don’t require the player to memorize spells, using a spell book is more realistic than just having the player press a key or select a menu item, but it would quickly become annoying. Think about it for a while and see if you as a player would be happy if you had to display a window that would probably cover most of the game world every time you wanted to cast a spell. The original EverQuest did something like this when the character was memorizing a spell, filling the entire window with a graphic of the spell book, and I hated it every time I had to do it. I mention this just to point out that more realistic is not always better.

No matter which way you choose to implement it, casting a spell is going to work the same for any of the above options:

The target property for the character is going to be set to the selected enemy.

The player picks the spell to be cast and tells the character to cast it.

The character object’s Cast method is called, passing the spell ID:

Listing 4-7


public bool CastSpell(int spellID)
{
if (_target != null)
{
Entity entity = this;
bool ret = false;

if (_target is Entity)
{
Entity target = (Entity)_target;
ret = GlobalData.Spells[spellID].Cast(ref target, ref entity);
_target = target;
}
else
ret = GlobalData.Spells[spellID].Cast(ref _target, ref entity);

return ret;
}

else
return false;

The entity finds the spell in the global spell list using the passed ID and calls the spell’s Cast method, passing the _target member and itself, in a roundabout way. Since the caster and target are passed by reference so resolution can be performed in the Spell class, it’s necessary to both create a new Entity object and set it to the player object and create a new Entity object for the target, since it won’t necessarily always be an entity. If the target is an entity and you try to cast it as part of the call to Cast, you’ll get a compile-time error.

Listing 4-8


public bool Cast(ref Entity target, ref Entity caster)
{
short mr = target.MagicResistance;
short roll = GlobalFunctions.GetRandomNumber(DieType.d100);

if (caster.CurMana >= GlobalData.Spells[_id].ManaCost)
caster.CurMana -= GlobalData.Spells[_id].ManaCost;
else
return false;

//Get caster's skill bonus
roll += (short)caster.GetCastingSkillBonus();

//resistance not applicable for any but offensive spells
if (_type == SpellType.Offensive)
roll -= mr;

if (roll >= 100)
{
int amount = 0;

switch (_type)
{
case SpellType.Defensive:
{
//normally you would just use the _defBonuses list
//but it can be done either way
if (_defBonuses != null)
{
foreach(Bonus bonus in _defBonuses)
((Entity)target).AddDefensiveBonus(bonus);
}
else
{
Bonus bonus = new Bonus();

bonus.Amount = Convert.ToInt16(amount);
bonus.Type = BonusType.Magic;
bonus.Duration = Convert.ToInt32(_duration);

((Entity)target).AddDefensiveBonus(bonus);
}
break;
}
case SpellType.NonCombat:
{
if (!((Entity)target).InCombat)
{
//go through bonuses and add to target
foreach (Bonus bonus in _defBonuses)
((Entity)target).AddDefensiveBonus(bonus);

foreach (Bonus bonus in _offBonuses)
((Entity)target).AddOffensiveBonus(bonus);

foreach (Bonus bonus in _miscBonuses)
((Entity)target).AddMiscBonus(bonus);

}

break;
}

case SpellType.Offensive:
{
target.Damage(amount, DamageType.Magical);

break;
}
}

return true;
}

return false;
}

A random number from 1 to 100 is generated, the caster’s skill bonus is added to it, any magical defensive bonus is subtracted if the spell is offensive (if it’s a defensive spell it would make sense for the target to try to resist it), and the result is checked to see if it’s over 100. If so, the target either takes damage, if it’s an offensive spell, or has whatever bonuses are part of the spell added to it.

It’s a fairly straightforward system that should work well for most basic RPGs. For anything else you’ll have to write a lot of specific code to get the spell system to do what you want. This could include using some kind of scripting (assuming you don’t want the game to run on the Xbox 360), which would offer a great deal of flexibility at the cost of increased development and testing. (Note that part of the reason the system is so easy is because we want to run it on the Xbox 360, and you can’t use scripting with the Xbox.) Testing any kind of scripting system is going to be difficult and take longer than regular testing, so be prepared to account for this in any development schedule you might have.

The Spell Book

A magic-using character has to have some place to write down all the spells he’s learned, unless he’s a cleric (it’s usually assumed that the character simply prays to his god each day and it grants the ability to cast the spells he’s given), so the player is going to need a way to keep track of what spells his character has. A spell book type of metaphor is usually used for this. Typically, they’ll look similar to the spell book interface from World of Warcraft.

Figure 4-2

Usually the spells a player uses the most are going to be associated with hotkeys or toolbar icons in the game’s interface, but at higher levels a character may have dozens of spells and there’s no way to keep them all available. A character may have spells that are only useful in certain circumstances and will swap out spells depending on the situation.

In order to allow the player to quickly and easily find the spells he’s looking for, some sort of organization is handy. For our purpose, organizing the spells by type comes to mind immediately. Obviously we’re not going to have World of Warcraft level art here, but it will be functional:

Figure 4-3

The spell book will have six spells per page. The name of the spell will be displayed next to the icon. Clicking on a tab to the left will change the spells displayed to those for that type. Clicking on the triangles at the bottom will turn the pages, with the page number displayed at the top.

As spells are learned, they’ll show up in the next available spot for the type of spell. The player will probably want to be able to move spells, so we’ll have to provide this functionality. This means we’ll need to know what spell is on what page. Luckily the ID of the spell will enable us to keep track. Our spell book is pretty simple because of this:

Listing 4-9


public class Spellbook
{
private List<SpellBookPage> _offSpells;
private List<SpellBookPage> _defSpells;
private List<SpellBookPage> _miscSpells;

public const int SpellsPerPage = 6;
}

If, for some reason, we ever had another spell type, we’d have to change the class, but that would be simple enough to do. If you decide to change the number of spells per page, at least you only have one place to change it, the SpellsPerPage constant.

Adding a spell to the book is fairly simple:

Listing 4-10


public void AddSpell(int id, SpellType type)
{
bool ret = false;

switch (type)
{
case SpellType.Offensive:
{
if (_offSpells == null)
_offSpells = new List<SpellBookPage>();

foreach (SpellBookPage page in _offSpells)
{
if ((ret = page.AddSpell(id)) == true)
break;
}

//all the current pages are full so start a new one
if (!ret)
{
SpellBookPage page = new SpellBookPage();
page.AddSpel l(id);
_offSpells.Add(page);
}

break;
}
case SpellType.Defensive:
{
if (_defSpells == null)
_defSpells = new List<SpellBookPage>();

foreach (SpellBookPage page in _defSpells)
{
if ((ret = page.AddSpell(id)) == true)
break;
}

//all the current pages are full so start a new one
if (!ret)
{
SpellBookPage page = new SpellBookPage();
page.AddSpell(id);
_defSpells.Add(page);
}

break;
}
case SpellType.NonCombat:
{
if (_miscSpells == null)
_miscSpells = new List<SpellBookPage>();

foreach (SpellBookPage page in _miscSpells)
{
if ((ret = page.AddSpell(id)) == true)
break;
}

//all the current pages are full so start a new one
if (!ret)
{
SpellBookPage page = new SpellBookPage();
page.AddSpell(id);
_miscSpells.Add(page);
}

break;
}
}
}

If there are no spells of that type in the spell book yet, the member holding those spells will be null, so we’ll have to create it. We then go through each page of that member, checking for an open spot by trying to add the spell to that page. If the AddSpell function returns false for every page, we know that all the pages are full, so we create a new one, add the spell to it, then add that page to the member holding the pages of that type.

Of course we need to allow the player to move a spell from one page to another:

Listing 4-11


public bool MoveSpell(int id, SpellType type,
int fromPage, int toPage)
{
bool ret = false;

switch (type)
{
case SpellType.Defensive:
{
//check to see if page exists
if (!(_defSpells.Count -1 < fromPage))
break;

//check to see if spell is actually on the fromPage
if (_defSpells[fromPage].HasSpell(id))
{
//return value tells us if toPage has room
//if not, it's up to the calling code to handle
ret = _defSpells[toPage].AddSpell(id);
if (ret)
_defSpells[fromPage].RemoveSpell(id);
}

break;
}
case SpellType.NonCombat:
{
//check to see if page exists
if (!(_miscSpells.Count-1<fromPage))
break;

//check to see if spell is actually on the fromPage
if (_miscSpells[fromPage].HasSpell(id))
{
//return value tells us if toPage has room
//if not, it's up to the calling code to handle
ret = _miscSpells[toPage].AddSpell(id);
if (ret)
_ miscSpells[fromPage].RemoveSpell(id);
}

break;
}
case SpellType.Offensive:
{
//check to see if page exists
if (!(_offSpells.Count-1<fromPage))
break;

//check to see if spell is actually on the fromPage
if (_offSpells[fromPage].HasSpell(id))
{
//return value tells us if toPage has room
//if not, it's up to the calling code to handle
ret = _offSpells[toPage].AddSpell(id);
if (ret)
_ offSpells[fromPage].RemoveSpell(id);
}

break;
}
}

return ret;
}

Several checks have to be made to ensure the function doesn’t throw an exception by assuming the parameters passed to it are valid when they’re not. You need to check that the page from which the spell is being moved exists, the page to which the spell is being moved exists and has room, and the spell exists in the page from which it’s being moved. If all these conditions are true, the spell is moved and the function returns true. If any of them are not valid, the function returns false and it’s up to the code calling the function to handle it in whatever way it wants. Normally the interface wouldn’t allow any of the parameters to be false so the function should always succeed, but it’s good practice to never assume anything.

The SpellBookPage class is just about as simple:

Listing 4-12


public class SpellBookPage
{
private int[] _spellIDs;

public int[] SpellIDs
{
get { return _spellIDs; }
set { _spellIDs = value; }
}

public SpellBookPage()
{
_spellIDs = new int[Spellbook.SpellsPerPage];
}

public bool AddSpell(int id)
{
bool ret = false;

for (int i = 0;i < Spellbook.SpellsPerPage; i++)
{
if (_spellIDs[i] == 0)
{
_spellIDs[i] = id;
ret = true;
break;
}
}

return ret;
}

public bool RemoveSpell(int id)
{
bool ret = false;

for(int i = 0; i < Spellbook.SpellsPerPage; i++)
{
if (_spellIDs[i] == id)
{
_spellIDs[i] = 0;
ret = true;
break;
}
}

return ret;
}

public bool HasSpell(int id)
{
bool ret = false;

for(int i = 0; i < Spellbook.SpellsPerPage; i++)
{
if (_spellIDs[i] == id)
{
ret = true;
break;
}
}

return ret;
}
}

When the page is created, the array containing the spell IDs is created to be the size of the SpellsPerPage constant. If you want to increase the number of spells per page, changing the constant means you won’t have to change any other code as everything is based on the constant.

The three functions in the class all work similarly — they take a spell ID as a parameter and iterate through the array to determine if what the function is supposed to do can be done. In the case of the RemoveSpell and HasSpell functions, the function returns true if the spell exists in the array. In the case of the AddSpell function, it returns true if the page is not full.

Summary

A character can now do just about whatever he wants and can defend himself either unarmed or with spells. He would look kind of silly just running around naked though. We’ll take care of that in the next chapter. We’ll add the capability of having all kinds of items in the world for the player to find and equip his character with. Those items will also have the ability to be magical since we now have spells that items can use.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.224.73.175