MARS Experience System

From Multiverse

Jump to: navigation, search

Contents

Overview

The experience system enables player characters to increase their level of skills and abilities. The system has two main components:

  • Leveling player characters and the stats the player has
  • Raising rankings on skills and abilities.

Setting up skills and abilities is easier to understand, and a good introduction to the LevelingMap class and how it works.

NOTE: The experience system is dependent upon the profession system, so if you have not setup your professions, please review the article on the Profession System.

Players and leveling

Now on to how to get your profession to level. It is important to realize that the profession's leveling is actually the character's leveling. So the first order of business is to make sure that you have the following in your character_factory.py file in your world's configuration folder:

ot.put(CombatClient.NAMESPACE, "experience", MarsStat("experience", 0, 100))
ot.put(CombatClient.NAMESPACE, "level", MarsStat("level", 1, 100))

To use the MARS Experience System, the player character must have both the experience and level stats. The numbers after the stat names correspond to what the starting value is for that stat, in this case 0 for experience and 1 for the players level. Next to that number is the max amount for that stat. In this case experience needs to gain 100 points before it will level the player. On the flip side, the 100 for level means that there are only 100 levels that a player can reach. It is important to keep that distinction mind.

With the player now given the ability to gain experience, we need to provide a means for them to gain experience. To this end we need to look at the templates.py file in your world's config folder. Open it up in a text editor and change the wolf's template to look like this:

#
# Wolf Template
#
tmpl = Template("Wolf")
tmpl.put(WorldManagerClient.NAMESPACE, 
         WorldManagerClient.TEMPL_DISPLAY_CONTEXT, 
         DisplayContext("wolf.mesh", True))
tmpl.put(WorldManagerClient.NAMESPACE, WorldManagerClient.TEMPL_OBJECT_TYPE, ObjectTypes.mob)
tmpl.put(InventoryClient.NAMESPACE, InventoryClient.TEMPL_ITEMS, "Wolf Skin; Wolf Bones")
tmpl.put(CombatClient.NAMESPACE, "strength", MarsStat("strength", 20))
tmpl.put(CombatClient.NAMESPACE, "dexterity", MarsStat("dexterity", 20))
tmpl.put(CombatClient.NAMESPACE, "wisdom", MarsStat("wisdom", 20))
tmpl.put(CombatClient.NAMESPACE, "intelligence", MarsStat("intelligence", 20))
tmpl.put(CombatClient.NAMESPACE, "stamina", MarsStat("stamina", int(int(20)*1.5)))
tmpl.put(CombatClient.NAMESPACE, "stamina-max", MarsStat("stamina-max", int(int(20)*1.5)))
tmpl.put(CombatClient.NAMESPACE, "mana", MarsStat("mana", int(20)*2))
tmpl.put(CombatClient.NAMESPACE, "mana-max", MarsStat("mana-max", int(20)* 2))
tmpl.put(CombatClient.NAMESPACE, "health", MarsStat("health", int(20) * 2))
tmpl.put(CombatClient.NAMESPACE, "health-max", MarsStat("health-max", int(20)*2))
tmpl.put(CombatClient.NAMESPACE, "experience", MarsStat("experience", 0))
tmpl.put(CombatClient.NAMESPACE, "level", MarsStat("level", 1))
tmpl.put(CombatClient.NAMESPACE, CombatInfo.COMBAT_PROP_AUTOATTACK_ABILITY, "attack ability")
tmpl.put(CombatClient.NAMESPACE, CombatInfo.COMBAT_PROP_REGEN_EFFECT, "regen effect")
tmpl.put(CombatClient.NAMESPACE, "attackable", Boolean(True))
tmpl.put(CombatClient.NAMESPACE, "combat.mobflag", Boolean(True))
tmpl.put(CombatClient.NAMESPACE, "kill_exp", 10);
ObjectManagerClient.registerTemplate(tmpl)

The added "kill_exp" property is what is given to a player that attacks and kills this wolf. If only the player attacks the wolf, the experience is given 100% to that player. However the wolf keeps track of who attacked it, and if another player has attacked the wolf even once, it will split the experience between the two players. The split continues equally based on the number of players that attacked the wolf. You can modify the other entries in your templates.py file as you see fit for you needs. I used the wolf for this example because it is the one closest to where you spawn.

The last note about leveling the player is that the amount of experience required to level is defined in the combat.py file in your world's configuration directory. If you open this file in your favorite editor you will see this line in the LevelStat class definition:

expstat.max = stat.base * 100

As you can see the experience stat's maximum is set to the level stat's base (which is the current level) * 100. Which means each level will be gained by going 100 points each level. Experience doesn't reset like abilities and skills do, so it important to keep that in mind when you are creating your own calculations for leveling.

Leveling for skills and abilities

Before setting up skills and abilities, it is important to understand that abilities gaining experience also increases the skills experience. In both ability and skill, you can define how much each should increase when one is used successfully. Also any ability assigned to a skill that are used successfully will increment that skill. Keep that in mind as you set the experience earned for ability and skills.

For an initial introduction to this, consider the sword skill and pierce ability. The pierce ability will be used often since it is an attack type of ability, so we will allow it to gain one experience point per successful use. We will also say that to get to the first rank you will need to use it successfully ten times. We also have to decide what the max rank of this ability should be, and I think for that we will give three ranks. Here is what the code looks like for the pierce ability now:

 
# Adding Tutorial Abilities
ability = MeleeCombatAbility("Pierce")
ability.setTargetType(MarsAbility.TargetType.ENEMY)
ability.setMaxRange(5000)
ability.setActivationEffect(Mars.EffectManager.get("default weaponskill effect"))
ability.addCoordEffect(MarsAbility.ActivationState.COMPLETED, attackEffect)
ability.setActivationCost(5)
ability.setCostProperty("stamina")
ability.setCompleteSound("swordhit.wav")
ability.setActivationTime(1000)
ability.setRequiredSkill(Mars.SkillManager.get("Sword"), 1)
ability.setIcon("Interface\FantasyWorldIcons\WEAPON_dagger_A")
# put in the leveling information for this ability
ability.setExperiencePerUse(1)
ability.setBaseExpThreshold(10)
ability.setMaxRank(3)
Mars.AbilityManager.register(ability.getName(), ability)

Now, every time this ability is successfully used on a target, the ability will gain one experience point, and at ten its rank will go up to the next level, provided it isn't already at rank three. For simplicity, the other two abilities (fireball and heal) are defined to level the same way. Here is the code for them:

ability = EffectAbility("fireball")
ability.setActivationTime(3000)
ability.setActivationCost(10)
ability.setCostProperty("mana")
ability.setMaxRange(40000)
ability.setIcon("Interface\FantasyWorldIcons\SPELL_fireball_A")
ability.setTargetType(MarsAbility.TargetType.ENEMY)
ability.setActivationEffect(Mars.EffectManager.get("fireball effect"))
ability.addCooldown(Cooldown("GLOBAL", 1500))
ability.addCoordEffect(MarsAbility.ActivationState.ACTIVATING, fireballCastingEffect)
ability.addCoordEffect(MarsAbility.ActivationState.COMPLETED, fireballTargetEffect)
ability.setRequiredSkill(Mars.SkillManager.get("Magic"), 1)
# put in the leveling information for this ability
ability.setExperiencePerUse(1)
ability.setBaseExpThreshold(10)
ability.setMaxRank(3)
Mars.AbilityManager.register(ability.getName(), ability)

ability = EffectAbility("Heal")
ability.setTargetType(MarsAbility.TargetType.SELF)
ability.setMaxRange(1000)
ability.setActivationEffect(Mars.EffectManager.get("minor heal effect"))
ability.addCoordEffect(MarsAbility.ActivationState.COMPLETED, healCastingEffect)
ability.addCooldown(Cooldown("HEAL", 15000));
ability.setActivationCost(5)
ability.setCostProperty("stamina")
ability.setActivationTime(5000)
ability.setRequiredSkill(Mars.SkillManager.get("Heal"), 1)
ability.setIcon("Interface\FantasyWorldIcons\SPELL_heal_A")
# put in the leveling information for this ability
ability.setExperiencePerUse(1)
ability.setBaseExpThreshold(10)
ability.setMaxRank(3)
Mars.AbilityManager.register(ability.getName(), ability)

Now for the skills, you generally don't want them to gain rank as fast, since many different abilities can affect a particular skill. All the skills will increase at one experience point per successful ability used, but with a leveling point of 20 experience points. We will also cap the skills at three ranks. Here is what the skill_db.py file looks like now with our skills:

# Adding skills for the tutorial
skill = MarsCombatSkill("Sword")
skill.setDefaultAbility("Pierce")
# put in the leveling information for this ability
skill.setExperiencePerUse(1)
skill.setBaseExpThreshold(20)
skill.setMaxRank(3)
Mars.SkillManager.register(skill.getName(), skill)

skill = MarsCombatSkill("Magic")
skill.setDefaultAbility("Fireball")
# put in the leveling information for this ability
skill.setExperiencePerUse(1)
skill.setBaseExpThreshold(20)
skill.setMaxRank(3)
Mars.SkillManager.register(skill.getName(), skill)

skill = MarsCombatSkill("Heal")
skill.setDefaultAbility("Heal")
# put in the leveling information for this ability
skill.setExperiencePerUse(1)
skill.setBaseExpThreshold(20)
skill.setMaxRank(3)
Mars.SkillManager.register(skill.getName(), skill)

So basically by this setup alone, skills and abilities will level up as you would expect. Every tenth experience point, the abilities will gain a level, and and every twentieth point the skills will gain a level. The maximum rank for both ability and skill is three. Notice that the ability will reach max before the skill will, however it will still be able to gain its needed experience.

Professional leveling

Now that the player can not only have experience, we have provided a way to gain it, we need to turn to how we should manage the player leveling. Or to be more precise, leveling the profession a player has chosen. It should be noted that should a developer provide the means to do so a player can change their profession at anytime by changing the class property for the player.

Every player has certain base stats for their player. They are set at creation time via the character creation setup and used by the system to determine the stats that are built from them should be. An example of a base stat would be strength, which determines the values for health and stamina. A developer can freely create any stats they want to use as a base stats. Base stats are the ones that professions can modify and should only be used in this manner with the profession system, since it sets the stat's current, base and max at the same time.

Professions can be leveled two different ways, or you can combine them if you prefer. This section will not go into explaining the various ways to setup the LevelingMap, so please see the previous section if you have questions on how it can be setup. The first method is to modify all the stats associated with the profession by a specific amount or percentage. The second method is to setup a LevelingMap for each stat that you want affected for this profession. In continuation of our use of the examples from the Profession system we will modify the Tutorial Profession to have both methods.

For the the first method, I will have the profession level all base stats by a fixed amount of 5. With the base stats for this profession being strength and dexterity. Here is what the profession definition looks like in the profession_db.py file:

# create a profession object
profession = ProfessionObject("Tutorial Profession")
# add skills to the profession
profession.addSkill("Sword")
profession.addSkill("Magic")
profession.addSkill("Heal")
# add abilities to the profession
profession.addAbility("Pierce")
profession.addAbility("Fireball")
profession.addAbility("Heal")
# define the base stats for leveling
profession.addBaseStat("Strength")
profession.addBaseStat("Dexterity")
# define the base leveling map
tutlm = LevelingMap()
tutlm.setAllLevelFixedAmountModification(5)
profession.applyLevelingMap(tutlm)
# Now register that profession with the classabilityplugin
ClassAbilityPlugin.registerProfession(profession)

Now everytime this profession levels, it will increase the strength and dexterity for the player by 5 points, which in turn modifies the players health and stamina. For this profession though I think that I would like to have the Strength value further modified. I would like it to increase at level 2 and level 4 by about 10 points. So to set this up I modify the professions' definition as follows:

# create a profession object
profession = ProfessionObject("Tutorial Profession")
# add skills to the profession
profession.addSkill("Sword")
profession.addSkill("Magic")
profession.addSkill("Heal")
# add abilities to the profession
profession.addAbility("Pierce")
profession.addAbility("Fireball")
profession.addAbility("Heal")
# define the base stats for leveling
profession.addBaseStat("Strength")
profession.addBaseStat("Dexterity")
# define the base leveling map
tutlm = LevelingMap()
tutlm.setAllLevelFixedAmountModification(5)
profession.applyLevelingMap(tutlm)
# define a leveling map for strength
strlvlmap = LevelingMap()
strlvlmap.setLevelFixedAmountModification(2, 10)
strlvlmap.setLevelFixedAmountModification(4, 10)
profession.applyStatsLevelingMap("Strength", strlvlmap)
# Now register that profession with the classabilityplugin
ClassAbilityPlugin.registerProfession(profession)

Leveling maps and skills/abilties

The LevelingMap can also be used on skills and abilities. However, its purpose is a bit different. The LevelingMap only controls what the maximum point is for that level. This gives you the option of being more flexible in how they gain their levels. The main thing to keep in mind is that it does not effect the experience per use nor the max rank. It only controls the threshold that has to be reached for the next level.

So taking our example above, it makes more sense for each rank to increase the maximum needed to raise the rank again by 10. Thus creating a 10, 20, 30 progression through the ranks. To do this you must first create a leveling map and then assign it to the abilities.

Here is what the code looks like now:

 
# Adding Tutorial Abilities
ability = MeleeCombatAbility("Pierce")
ability.setTargetType(MarsAbility.TargetType.ENEMY)
ability.setMaxRange(5000)
ability.setActivationEffect(Mars.EffectManager.get("default weaponskill effect"))
ability.addCoordEffect(MarsAbility.ActivationState.COMPLETED, attackEffect)
ability.setActivationCost(5)
ability.setCostProperty("stamina")
ability.setCompleteSound("swordhit.wav")
ability.setActivationTime(1000)
ability.setRequiredSkill(Mars.SkillManager.get("Sword"), 1)
ability.setIcon("Interface\FantasyWorldIcons\WEAPON_dagger_A")
# put in the leveling information for this ability
ability.setExperiencePerUse(1)
ability.setBaseExpThreshold(10)
ability.setMaxRank(3)
# put in the leveling information for this ability
abilitylm = LevelingMap()
abilitylm.setAllLevelFixedAmountModification(10)
ability.setLevelingMap(abilitylm)
Mars.AbilityManager.register(ability.getName(), ability)

ability = EffectAbility("fireball")
ability.setActivationTime(3000)
ability.setActivationCost(10)
ability.setCostProperty("mana")
ability.setMaxRange(40000)
ability.setIcon("Interface\FantasyWorldIcons\SPELL_fireball_A")
ability.setTargetType(MarsAbility.TargetType.ENEMY)
ability.setActivationEffect(Mars.EffectManager.get("fireball effect"))
ability.addCooldown(Cooldown("GLOBAL", 1500))
ability.addCoordEffect(MarsAbility.ActivationState.ACTIVATING, fireballCastingEffect)
ability.addCoordEffect(MarsAbility.ActivationState.COMPLETED, fireballTargetEffect)
ability.setRequiredSkill(Mars.SkillManager.get("Magic"), 1)
# put in the leveling information for this ability
ability.setExperiencePerUse(1)
ability.setBaseExpThreshold(10)
ability.setMaxRank(3)
# put in the leveling information for this ability
abilitylm = LevelingMap()
abilitylm.setAllLevelFixedAmountModification(10)
ability.setLevelingMap(abilitylm)
Mars.AbilityManager.register(ability.getName(), ability)

ability = EffectAbility("Heal")
ability.setTargetType(MarsAbility.TargetType.SELF)
ability.setMaxRange(1000)
ability.setActivationEffect(Mars.EffectManager.get("minor heal effect"))
ability.addCoordEffect(MarsAbility.ActivationState.COMPLETED, healCastingEffect)
ability.addCooldown(Cooldown("HEAL", 15000));
ability.setActivationCost(5)
ability.setCostProperty("stamina")
ability.setActivationTime(5000)
ability.setRequiredSkill(Mars.SkillManager.get("Heal"), 1)
ability.setIcon("Interface\FantasyWorldIcons\SPELL_heal_A")
# put in the leveling information for this ability
ability.setExperiencePerUse(1)
ability.setBaseExpThreshold(10)
ability.setMaxRank(3)
# put in the leveling information for this ability
abilitylm = LevelingMap()
abilitylm.setAllLevelFixedAmountModification(10)
ability.setLevelingMap(abilitylm)
Mars.AbilityManager.register(ability.getName(), ability)

Please see the LevelingMap section at the beginning of this wiki to learn more ways that you can modify your abilities' leveling process. Now lets give the skills the same setup. Here is what the code look like in the skill_db.py:

# Adding skills for the tutorial
skill = MarsCombatSkill("Sword")
skill.setDefaultAbility("Pierce")
# put in the leveling information for this ability
skill.setExperiencePerUse(1)
skill.setBaseExpThreshold(20)
skill.setMaxRank(3)
# setup the levelingMap
skilllm = LevelingMap()
skilllm.setAllLevelFixedAmountModification(10)
skill.setLevelingMap(skilllm)
Mars.SkillManager.register(skill.getName(), skill)

skill = MarsCombatSkill("Magic")
skill.setDefaultAbility("Fireball")
# put in the leveling information for this ability
skill.setExperiencePerUse(1)
skill.setBaseExpThreshold(20)
skill.setMaxRank(3)
# setup the levelingMap
skilllm = LevelingMap()
skilllm.setAllLevelFixedAmountModification(10)
skill.setLevelingMap(skilllm)
Mars.SkillManager.register(skill.getName(), skill)

skill = MarsCombatSkill("Heal")
skill.setDefaultAbility("Heal")
# put in the leveling information for this ability
skill.setExperiencePerUse(1)
skill.setBaseExpThreshold(20)
skill.setMaxRank(3)
# setup the levelingMap
skilllm = LevelingMap()
skilllm.setAllLevelFixedAmountModification(10)
skill.setLevelingMap(skilllm)
Mars.SkillManager.register(skill.getName(), skill)

Now your skills and abilities will level at the amount indicated in the leveling map.

Now your profession, player, skills and abilities can all gain experience as you play the game.

The LevelingMap class

multiverse.mars.objects.LevelingMap is the main class used for defining leveling. It currently provides the ability to define either an overall change in something or a per level change. The LevelingMap only stores how things are modified, not what is modified: other classes deal with what.

For example, assume you want to level a player's strength strength stat. To have the stat increase at a fixed rate, say 5 points every level, then you use the setAllLevelFixedAmountModification() method. For example (in Python code):

test = LevelingMap()
test.setAllLevelFixedAmountModification(5)

Now every time that the player hits a level his strength will increase by five (5). You can also use this method to decrease a stat. For example, if you want a mage to lose three strength at each level, just use a negative argument, for example:

test = LevelingMap()
test.setAllLevelFixedAmountModification(-3)

Then every time the character levels, his strength drops by three points. LevelMap also provides a method, setAllLevelPercentageModification(), to modify a stat by a percentage. For example to increase the character's strength by five percent at each level:

test = LevelingMap()
test.setAllLevelPercentageModification(0.05)

This would work the same as the previous examples except that stat increases by the specified percentage, rather than a fixed value. The values for percents are 1 = 100%, 0.05 = 5%. It is important to keep this in mind when doing this form of leveling as if you put in just the 5, your stats would increase thusly: stat + stat * 5. Which would really make your stats grow.

You can combine a percentage and a fixed increase with a single method call. For example to make a character increase 1% as well as 5 points at each level:

test = LevelingMap()
test.setAllLevelModification(0.01, 5)

The stat would now increase at the rate of: stat + (stat * 0.01) + 5.

The examples so far have been increasing the same at all levels. But what if you wanted to increase it a specific amount at specific levels. The LevelingMap also provides the means to set this up. So let's say that you wanted everyone to increase at a 1% for every level they gain, but on every even level you want them to gain 5 points, and lets say you want that to stop after the 10th level. Here is what your LevelingMap would look like:

test = LevelingMap()
test.setAllLevelPercentageModification(0.01)
test.setLevelFixedAmount(2, 5)
test.setLevelFixedAmount(4, 5)
test.setLevelFixedAmount(6, 5)
test.setLevelFixedAmount(8, 5)
test.setLevelFixedAmount(10, 5)

As you can see for every level you will get a stat + (stat * 0.01) increase, and if your level is even you will be given an additional stat + 5. The all level modifications are handled first, then the result of that is used to calculate the level modification. So if you have 100 points in a stat, and you were using the above level map, the first run would give you 101, the second level would give you 102 after the all modification (101 + (101*0.01)), and 107 after the level modification (102 + 5).

Personal tools