Skills

Terminology - "attributes" vs "skills"

In most roleplaying systems the concept of "attributes" like Strength, Dexterity, etc is seperate from the concept of "skills" like singing and fishing.  But think about it.

Strength, Lifting, Armwrestling, Dexterity, Agility, Movement, Jumping, Dancing, Singing, CastFireBallSpell, Cooking.

Which are attributes and which are skills?  Hard to tell, eh?  And even harder to motivate.

So I will merge the concepts.  They are all skills.

Issues that must be considered

Design suggestion

Needless to say, we need a very general approach.  This is my suggestion.

There are two central classes: Skill and SkillSet.  Skill is a simple root interface that looks something like this:

interface Skill {
  int getValue();
}

It's just a value holder in other words.  This already gives us an advantage - the actual value for some skills can be derived from other skills.  So the value of a movement skills might be 50% based on strength and agility of the same person.

SkillSet is a keyed collection of skills (like a Hashtable):

class SkillSet {
  void addSkill(Object key, Skill skill);
  void removeSkill(Skill skill);
  Enumeration getSkills();
  Enumeration getSkills(Class skillType);
}

Each Creature will have a SkillSet.  I'll talk more about SkillSets later in this document.

Combat example - using a sword

When I use my ShortSword in combat, an AttackResultEvent will try to figure out what the result is.  There will be some mathematical formula somewhere for determining the success of an attack.  Probably this will be based on different factors, such as what the defendant is doing, the fatigue of both combatants, etc.  I have no idea how this will be implemented (Julio will do this :o) but somehow the formula will involve the attacker's skill in fighting with short sword, and I'll give an example of how this may be figured out using this skills system.

Each weapon works differently so the AttackResultEvent will ask the shortSword to produce an attackSuccessIndex of some sort, given the attacker's SkillSet.  In this example shortSword determines that:

attackSuccessIndex = shortSwordSkill + (swordSkill * 3) + combatSkill

For a huge TwoHandedBattleSword it might look like this:

attackSuccessIndex = 2HBattleSwordSkill + (swordSkill * 2) + combatSkill + (Strength * 2)

Note these formulas are just examples!  But they illustrate how to include skill dependency.  Here we only include "upwards dependency", however, where your success at ShortSword depends on both the ShortSwordSkill and the SwordSkill.  But what about "downwards" dependency, where an improvement in DaggerSkill should give an indirect improvement in ShortSwordSkill?

Downwards dependency can be modelled directly in the Skill.  So when your DaggerSkill is improved, it will automatically improve your SwordSkill as well by some fraction.  And the SwordSkill will then automatically improve your CombatSkill by some fraction.  So an expert at swordfighting will also be reasonably good at combat in general, and thereby we able to use almost any weapon with reasonable confidence.  If a weapon is so weird and complex that you can't use it at all if you don't have any skill in it, it's attackSuccessIndex formula might look like this:

attackSuccessIndex = WeirdWeaponSkill * 5

Or something like that.  In this case the result is 0 if you don't have this specific skill at all.  But Julio will solve the specific mathematical relationships...

Using the SkillSet to find Skills

The SkillSet object will include lots of methods for finding skills.  The most direct one is getSkill(Object key).  This will be used for all commonly accessed skills such as Strength.  There will be constants in Creature like this for each skill that all creatures are expected to have:

 public static final String SKILL_STRENGTH = "strength";

We can also "encapsulate" parts of the skill system by adding methods like this to Creature:

public int getStrength() {
    Skill str = skills.getSkill(SKILL_STRENGTH);
    if (str == null)
        return 0;
    else
        return str.getValue();
}

This means we can hide the "super generical" nature of the skill system and provide a simple interface for some common attributes/skills.

To find all sword combat skills I can write: getSkills(orb.skills.SwordCombatSkill), or to find all combat related spells I can write: getSkills(orb.skills.CombatSkill), etc.  We can use all kinds of interfaces and class hierarchies in the orb.skills.* package to organize our different skills types, TeachableSkill for all skills that can be improved by teaching.

Note that we do not need one Skill class for each single weapon type, each single attribute, and so on.  We only need new classes for skills that work differently internally, or skills that we want to organize in categories using the class hierarchy.  So instead of ShortSwordCombatSkill, DaggerCombatSkill, etc we can use just SwordCombatSkill an include an instance variable for which Sword class the skill applies to.

We may also use global definition of skills, sort of like they have done with system properties.  Basically just a text file of skill names that we agree to use, such as "skill.combat", "skill.fishing", "skill.combat.sword". "skill.magic.detectMagic", etc.  Now if I want to find a skill I just write: skillSet.getSkill("skill.fishing").

After we have coded a few skills and skill-related activities we can decide on exactly which technique to use when finding skills.

Soul or body?

Now for the great philosphical question - who is good at singing, the body or the soul?  If someone turns me into a rabbit, am I still good at singing?

I propose putting all skills in the body, even if it may sound boring.  Why?  Well because the Soul is "merely" an Effect.  If the SingingSkill is stored in the Soul's skill set, then it won't be used if someone casts a curse on me that forces me to sing.  Another reason is that, even though Soul may initiate an action, it is the body that is registered as the "source" of the action.  That means the Action itself does not deal with the soul at all - it just knows that Fred (the body) wants to stab his sword at the orc.  So it's a lot cleaner if the action doesn't have to also worry about who actually made Fred attack the Orc, and can pick up the Skills directly from Fred's skill set.

Fun stuff - obscure skills

Being a disciple of the Arghahath priest order, I receive a special skill: ArghahathMeditation (or "skill.special.arghahathMeditation" if we use a global naming system).  If I am a loyal disciple (meditate often) then the great God Argha himself may protect me if things turn ugly.  What does this mean in game terms?

Well when I join the priest order, an ArghahathFilter is added to my collection.  If I ever get killed, this filter will be activitated and check my ArghahathMeditationSkill.  If it is high, I may be resurrected - i.e. healed up and teleported to the high temple of Argha.  Cool eh?  And all this without having to modify any core classes.  Just add new ones for that priest order.

If I manage to convert someone else, he may also be given the Arghahath filter and skill.  But he must keep up his meditation skill, it deteriorates quickly with time...

Learning and improving

The exact method of improving skills does not need to be specified in detail yet, but here is an example of how it may work for action-related skills:

Action related skills (perhaps tagged with the ActionSkill Interface?) can be improved when the action related to the skill is executed.  So all skills that implement the ActionSkill interface by adding this method:

  void skillUsed(GameEvent event);

CombatSkill is an action related skill and it's implementation works like this:  if the attack succeeded there is a % chance that the CombatSkill improves by a few points.  The higher the skills value is, the less the chance of improvement.  If the attack fails there is also a chance, but smaller.  If the attack critically fails (or something like that) the chance is very high that you improve.

We might also have an interface called TeachableSkill, with the following method:

  void lessonReceived(TeachSkillEvent lesson);

The lesson includes information about who the teacher is (or perhaps just his SkillSet), his skill at teaching, the duration of the lesson, and stuff like that.  The implementation of receiveLesson will vary for different skills depending on how easy there are to teach, but in most cases they will improve by a certain amount, modified by factors such as the intelligence of the student, the difference between the skill level of the student and the teacher, etc.

And then, of course, we probably want a PracticeableSkill interface that adds this method:

  void skillPracticed(PracticeSkill event);

You get the idea.

Temporary skills

Let's say I cast a spell that animates a Sword and makes a sword remember what it sees, and tell anybody who asks.  It adds a special SpyEffect to the sword that watches the events received by the sword and stores them in some kind of a memory.  Now Joe says "Sword, have you seen any orcs?".  The SpyEffect looks through it's memory and finds that, yes, 3 orcs passed by earlier this morning.  The SpyEffect now wants to make the sword tell this to Joe.  However to create a TalkEvent you must also specify which language you are speaking, as well as your skill at that language.

So the SpyEffect decides which language to use, creates a Skill object (or maintains one as an instance variable), and creates a TalkEvent where the source is the Sword.  So this is sort of a case where the Skill is stored in the soul.  Which means if someone else casts a SpySpell with less language skills, the two SpySpells will not interfere with each other's skill levels.

This is fun.  Let's say we have a spy sword with this effect that only speaks a really strange unknown language.  You really badly want to find out what the sword has seen, but you can't understand it's language so you have to find a translator :o)


Henrik Kniberg

Last updated: