Loading and Using Items/skills from a database.

Hey guys, I’m currently working on a little game where the player has 4 skills, in a menu you can choose from a large selection of skills, which 4 you want. My first issue is saving which skills are selected because that depends on how the skills will be executed… which is my next problem.
I have created a bunch of skills, but they all have their own function in the playerscript, which I don’t want.
I would like the player script to use skill IDs, which were supplied by the menu. To get the skill information from a skillDataBase. This is probably all very vague but I will try my best to clarify anything I havn’t explained well enough.

Effectively my pseudocode for this would be

MENU SCRIPT
{
     SaveInformation(Skill1ID = Slot1ID)
     SaveInformation(Skill2ID = Slot2ID)
     SaveInformation(Skill3ID = Slot3ID)
     SaveInformation(Skill4ID = Slot4ID)
}

PLAYER SCRIPT
{
     IF (Presskey(1)){
     skillDataBase(LoadInformation(Skill1ID))

     IF (Presskey(2)){
     skillDataBase(LoadInformation(Skill2ID))

     IF (Presskey(3)){
     skillDataBase(LoadInformation(Skill3ID))

     IF (Presskey(4)){
     skillDataBase(LoadInformation(Skill4ID))
}

SKILLDATABASE SCRIPT
{
   function ID1(){
   string name = "Fireball"
   int damage = 5
   int manacost = 3
   int castTime = 0.5f
   float castRange = 3
   instantiate (fireball, player.position, player.rotation)
   }

   function ID2(){
   string name = "Arcane Strike"
   int damage = 5
   int manacost = 3
   int cast time = 0.5f
   float castRange = 3
   instantiate (arcanestrike, player.position, player.rotation)    
   }

  //etc, 20 more skills

}

I’m working on a template system for creating any kind of item, weapon, equipment or ability.

The way I do it is designed around modability, but your game doesn’t have to be modable in order to support this system. All of the following code is directly from the system I have implemented in my project. It is meant to be an example of how you can implement such a system, and may not be exactly what you are looking for.

Note: Having a stable folder and organization system is important.

The following abstract class, AbilityTemplate, is a template class that has absolutely no functionality. Modders, and myself, inherit from this class in order to implement new abilities. Scroll down to see an example of an Ability that’s in my game.

public abstract class AbilityTemplate  {

	// Displayed name of the ability
	public abstract string AbilityName
	{
		get;
	}

	// Displayed RichText description of the ability
	public abstract string AbilityDescription
	{
		get;
	}

	// Whether or not AI can learn and use this ability
	public abstract bool UsedByAI
	{
		get;
	}

	// Can the player hold down a key to continuously use this ability?
	public abstract bool UsedContinuously
	{
		get;
	}

	// Does the ability have a charging period before it can be used?
	public abstract bool ChargedUsage
	{
		get;
	}

	// The ID of the image that will be used as an avatar for the ability
	public abstract string AvatarID
	{
		get;
	}
    
    internal int m_Level = 0;
    public int AbilityLevel
    {
        get
        {
            return m_Level;
        }
        protected set
        {
            m_Level = value;
        }
    }
	
	// Called the first frame that the player begins using the ability
	public virtual void OnAbilityUsedByPlayer(PlayerController player)
	{
		
	}

	// Called the first frame the AI begins using the ability
	public virtual void OnAbilityUsedByAI(Entity other, Entity target)
	{

	}

	// Called every frame while the player has learned and equipped this ability
	public virtual void OnAbilityPassivePlayerUpdate(PlayerController player)
	{

	}

	// Called every frame while the AI has learned and equipped this ability
	public virtual void OnAbilityPassiveAIUpdate(Entity other)
	{

	}

	// Called every frame while the player is using this ability
	public virtual void OnAbilityActivePlayerUpdate(PlayerController player)
	{

	}

	// Called every frame while the AI is using this ability
	public virtual void OnAbilityActiveAIUpdate(Entity other)
	{

	}

	// Determines whether or not an AI will use this ability on a target
	public virtual bool AICanUseOnTarget(Entity AI, Entity target)
	{
		return false;
	}

	// Called the first frame an AI/Player begins chargin this ability
	// Only called if ChargedUsage is true
	public virtual void OnBeginCharge()
	{

	}

	// Called every frame after OnBeginCharge is called until the player stops charging
	// the ability or until it returns true. If it returns true, then the ability is used.
	// Otherwise, the ability is not used.
	public virtual bool GetIsReady()
	{
		return false;
	}

	// Called whenever the player attempts to level up the ability
	public virtual bool TryLevelUp()
	{
		AbilityLevel++;
		return true;
	}
}

Here is an example ability that implements some very basic charging and damage functionality.

public class ExampleAbility : AbilityTemplate
{
	#region Overriden Properties

	public override string AbilityName
	{
		get
		{
			return "Example Ability";
		}
	}

	public override string AbilityDescription
	{
		get
		{
			return "This is the <color=#7F00FF>Example Ability</color>.

\r";
}
}

	public override bool UsedByAI
	{
		get
		{
			return true;
		}
	}

	public override bool ChargedUsage
	{
		get
		{
			return true;
		}
	}

	public override bool UsedContinuously
	{
		get
		{
			return false;
		}
	}

	public override string AvatarID
	{
		get
		{
			return "ExampleAbility";
		}
	}

	#endregion

	public int InitialDamage = 10;
	public int Damage = 10;

	public float UsageRange = 5f;

	public float TimeSinceChargeBegan = 0f;
	public float InitialCharginTime = 0.5f;
	public float ChargingTime = 0.5f;

	public override void OnAbilityUsedByPlayer(PlayerController player)
	{
		Entity target = new Entity();
		// Find target ...
		target.SendMessage("DoDamage", Damage);
	}

	public override void OnAbilityUsedByAI(Entity other, Entity target)
	{
		target.SendMessage("DoDamage", Damage);
	}

	public override bool GetIsReady()
	{
		TimeSinceChargeBegan += Time.deltaTime;
		return TimeSinceChargeBegan > ChargingTime;
	}

	public override bool AICanUseOnTarget(Entity AI, Entity target)
	{
		return Vector3.Distance(AI.Position, target.Position) < UsageRange;
	}

	// Every time the ability is leveled up, decrease charging time
	// and increase damage done.
	public override bool TryLevelUp()
	{
		AbilityLevel++;

		ChargingTime = InitialCharginTime * (AbilityLevel * 0.9f);
		Damage = InitialDamage + (1 * AbilityLevel);

		return true;
	}
}

Later, in an init function, I call some code that Registers the Type of my example ability class:

RegisterTemplate("ExampleAbility", typeof(ExampleAbility));

This function records the ExampleAbility Type in a Dictionary with the string ID “ExampleAbility” as the key.

Later i can invoke that type via

RegisteredAbilities["ExampleAbility"].Invoke()

and assign it to an Ability object which contains behavior for calling all of the functions defined in AbilityTemplate, as well as using the properties defined.


The entire process relies heavily on Reflection in my project, but they don’t have to in your’s. The only time you’d have to use reflection would have to be when you invoke the type and call the functions defined.


IMO this is a very effective method of creating a dynamic system of items or abilities. It doesn’t rely on static properties in order to implement behaviour outside of the few boolean flags that are defined.

In Summary:

Create a class you can inherit from that doesn’t immediately define behaviour. Define your behaviour in the respective ability’s class that extends the base class. Invoke the ability later through some registration and object system.

If you need help actually creating all the functionality for registration, invoking, and declaration, feel free to PM or email me.

If all the attacks have the same stat variables (Damage, castTime, etc…) then you could just load all of them into Attack objects (with the DB ID that is) and show all of that to the player and then store the selected IDs in a array somewhere or any other way you would like to store them.

And of course saving the IDs in a save file if you want to use them later on.

It’s always good to do a bit of searching before posting your question as most of the time somebody else already has asked it or at least part of the same question. Like for example: