New to Game Programming, Sub: Creating RPG Skills

Started by
10 comments, last by alnite 11 years, 11 months ago
This is my first post here so I'd like to give a bit of background first. Hey all.

Alright so first, I haven't made a 'proper' game yet. I just started programming a few months back and have a pretty solid understanding of the language (C++), but I haven't done anything graphical. The games I have made have been pretty complex console programs, plus I've made some really neat map generators (including semi-isometric ones, making minerals spawn in random but sensical places etc.).

Now you guys are thinking "why is this guy trying to make an RPG, sigh, all the newbies thinking they can jump in at the deep end". I see people talking about wanting to make their amazing new MMO idea and they clearly don't have a clue about what that actually entails, but the RPG I plan on making actually works right now. I have the battle system and a bunch of other stuff coded already. It's an original system which is unique as far as I know, with a bunch of great tactical options - especially for something that's based on Japanese battle systems. It really isn't as efficient as it could be, but that'll improve over time. Other stuff like collision etc. I'll have to learn from scratch though, I'm not that far ahead yet. Anyway!

Main topic:
I'm asking you guys for help, since I'm pretty ignorant of how games are actually built. Specifically, I'd like to know how you guys would go about coding the effects of skills without just plan coding them in a massive list. Right now, I have a bunch of .txt files with skill names, stats, levels etc stored in them, and I get that info via file i/o. The only way I can think of getting them to actually do something is to have a massive switch(case) or something, then basically writing the code for each individual skill in each case. This may be the typical way that you'd program it, but I don't know that. It's worth mentioning that I have a ton of skills, somewhere around 50-60, so that's why I'm even bothering to ask.

You're all welcome to give me advice about other things too, since again I'm completely new to actual game development. Also uh, I'll be learning/using SFML when making this.

Thanks in advance.
Advertisement
I'd like to know how you guys would go about coding the effects of skills without just plan coding them in a massive list. Right now, I have a bunch of .txt files with skill names, stats, levels etc stored in them, and I get that info via file i/o.


So I am assuming a skill is, more like an action or an ability. For example, Fly-kick (Melee) or Fireball (Projectile) but could also be passive, like Health Regeneration V.

This can get very, very complicated but if you want to keep the way you were doing it where skills are defined in some file: You can have a class for each type of skill, Projectile, Melee, Passive, AoE all of which inherit from a base Skill class with a bool update function. Now a Projectile would just move in a direction or at a target (set in the data) and do damage, damage type and whatnot and maybe even set off another skill etc.

e.g.


class Skill
{
virtual bool Update(deltaTime);
virtual void OnCollision(collisionData)
void ActivateSkill() // Put the skill into the skill manager or something...
Entity* user;
string Name;
string Description;
Skill* skillToUpgradeTo;

};

class Projectile : public Skill
{
bool usesTarget;
Image* image;
bool usesEntityDirection;
Entity* target;
unsigned int Speed;
Skill* skillToActivateAtEnd;
bool Update(deltaTime);
vector3 Direction;
};


Then the data could be for Fireball:


Type: Projectile
Name: Fireball
Description: Shoots a flaming ball of fire at your foes.
Target: 0
usesEntityDirection: 1
Image: "media\images\fireball.png"
speed: 3
skill to upgrade to: Super Fireball
skill to activate at end: Explosion
[/quote]

So, you would have some SkillLibrary class that would read the file for all the skills and give them all their data. You would need a switch on all the different types. (For example you would need to switch the type and if it was projectile you would create a projectile object and read the data from file as if it was a projectile object.

Now, the way I would actually do it is have an Action class that can be extended in scripts which could then create actions that do whatever the hell they want, although that system above could do almost anything it would be convoluted and weird.

Obviously this is highly dependant on your collision system and what actual abilities you want and all that kind of jazz, if you give more info on what game you are making and what you want to do with the skills that would make it easier to help you. (So I assume this is turn based? You could remove direction and uses entity direction in that case because you know they would always require a target)

Engineering Manager at Deloitte Australia

Thanks for the reply, I appreciate it.

You could think of this on a super basic level as a typical JRPG battle system, which basically means you choose a skill / target / execute. There are much deeper mechanics at work, but yeah they're just mechanics. As for collision, I'll probably only be using it for walking into walls or solid objects while outside of battles, so don't worry about that.

The skill types I'll be using are pretty much standard fare, for now at least. Healing, buffs (stat boosts, damage %+), debuffs, physical/magical damage.. Each skill also fits into a group too, so you could think of holy moves as being blue, defender moves are yellow kind of deal. Lastly, every skill has an element (I count 'no element' as one of them) so that when compared to the enemies resistances it'll change the damage output.

I'll go ahead and post some of my Battle code here.


void AssignDamage(Actor Attacker, Actor &Defender, Skill SK, Weapon TheWeapon)
{
/// Modifier:
// Weak 40%: 1.4
// None 00%: 1.0
// Resist 30%: 0.7
// Absorb 60%: -0.6

// Actors have a SetHP method which takes a negative integer value:
// Actor :: SetHP(int Change) { HP += Change; }

int Damage = 0;
double Attack = 0, Result = 0;
int ModType = SK.GetElement();
int PreDamageHP = Defender.GetHP();
bool CriticalHit = RollForCrit(((Attacker.GetSPD()*.12) * Attacker.GetLCK())); // Random Function 1-100, type double, returns bool
string TheChange;

Attacker.UseSkill(SK, Attacker, Defender); // don't really know what to do with this now

switch(SK.GetAttackType())
{
case PATK: Attack = Attacker.GetATK() + SK.GetPower() + TheWeapon.GetPower(); break;
case MATK: Attack = Attacker.GetMAG() + SK.GetPower(); break;
}

if(CriticalHit){
Attack *= 1.8; // ..or something.
}

Attack -= (Defender.GetDEF()/2);
Result = Attack - (Attack * Defender.GetMOD(ModType)); //eg. if defender is weak by 20%, this would be Attack * 1.2.
Damage = RoundNumber(Result);
Defender.SetHP(-Damage);

if(PreDamageHP < Defender.GetHP()){
TheChange = " absorbed ";
Attack = Defender.GetHP() - PreDamageHP;
} else {
TheChange = " took ";
Attack = PreDamageHP - Defender.GetHP();
}

cout << Defender.GetName() << TheChange << Attack << "DMG!";
}

// here is the function to round numbers up or down:
int RoundNumber(double NumToRound)
{
int WholeValue = NumToRound;

if((NumToRound - WholeValue) > .4)
WholeValue++;

return WholeValue;
}


Anyway, i'd like to hear more about your Action class, it sounds much better than how I'm currently trying to do things. I always get frustrated when I end up having to hard code so much.
In terms of storing skill data - you might want to consider using XML or an SQLite database, so you can maintain consistent structure across skills.

Each skill, if "generic" enough, can be created as a generic skill with specific parameters.

i.e. Fireball is a "Basic Attack" with type Fire, BasePower 10, and SplashDamage = true.

Most custom stuff you will want to code by hand; in some cases you will want to hard code it, as scripting can end up being just as difficult as simply coding it, not to mention the time you'll spend handwriting your own scripting language.

I'd also advise you to split up that function, that will grow in size and complexity - you may wish to split it into "ReceivesDamage" and "CausesDamage" for the receiving and the attacking unit; the attacking unit generally does not care who attacked it (unless you want to assign damage credit), but simply what type and how much damage it received.

This way, you can separate the attacking unit's damage calculating from the receiving unit's defensive calculations.

In terms of storing skill data - you might want to consider using XML or an SQLite database, so you can maintain consistent structure across skills.


Thanks for the tip, I'll look those up right away.

Each skill, if "generic" enough, can be created as a generic skill with specific parameters.

i.e. Fireball is a "Basic Attack" with type Fire, BasePower 10, and SplashDamage = true.[/quote]

Right now I have a Skill class which stores things like power, attack type, level, cost, name, info etc. That's pretty much the same thing as what you're talking about, right? I also tinkered around with having a basic Skill class, which just had generic things like the level, cost and so on, but not power kind of thing. Then I was going to have subclasses which would inherit from Skill called Buffs, PhysicalAttack etc. I don't know if it's necessary but yeah.

Also pardon my vagueness here, it's hard sometimes to point out what exactly I'm looking for. Here's an example:

Name: SmackYourBuns
Info: Lowers target's defence by 20%, 30 physical damage.
Name: Nutriants
Info: Heals party with power 50, type Earth.

So remember that UseSkill() call I have in my AssignDamage() function? That was to apply the actual effect of the skill. So like, I'd send in the Skill's ID# or something, then inside UseSkill I was going to have a big switch containing framework for different skill archetypes. So for example, this skill SmackYourBuns could use a case which had:

double StatChange = 0.2;
Defender.SetStat(Defence, StatChange);
AssignDamage(...);


.. kind of thing. FakeEDIT: I just realised that there are only really two types of skills, in essence. Or at least, two potential parts to a skill. Dealing damage (negative for healing) and changing stats (negative and positive, debuffs and buffs). Maybe I could work this into the main generic Skill class and just check to see if the required skill has both or just one of those things. Does that sound about right?

Most custom stuff you will want to code by hand; in some cases you will want to hard code it, as scripting can end up being just as difficult as simply coding it, not to mention the time you'll spend handwriting your own scripting language.[/quote]

Alright, sounds fine to me. If I've understood your suggestions for the class, I'm pretty sure that the majority of skills will be dealt with there anyway.

I'd also advise you to split up that function, that will grow in size and complexity - you may wish to split it into "ReceivesDamage" and "CausesDamage" for the receiving and the attacking unit; the attacking unit generally does not care who attacked it (unless you want to assign damage credit), but simply what type and how much damage it received.

This way, you can separate the attacking unit's damage calculating from the receiving unit's defensive calculations.[/quote]

This sounds true enough. Also yeah, I totally haven't even begun coding the enemy AI yet. Maybe I will have to send in the Actor if I end up using the aggro points priority system.

Thanks for the reply, I'm glad I'm getting so much help in my first thread here.
You don't want to have that AssignDamage method. As the number of skills grow, so is the size of that method.

Skill should be an interface, and it defines nothing (no attributes, damage, type, element, etc.). Here's an overview:


class ISkill {
public:
virtual void applySkill(Actor& actor) = 0;
virtual std::string getDescription() = 0;
};

class Fireball : public ISkill {
public:
virtual void applySkill(Actor& actor) {
// do fireball damage here to actor
}
};



By defining Skill as an interface without attributes, first, you are opening your skill libraries virtually limitless. You are not stuck to elemental skills, but also different types of skills, perhaps a specific swords slashes or pickpocket. Second, you won't have a large method body with different switch-case statements for different types of skills, as each skill is responsible in writing its own method to apply the effect to an actor. Third, you can use this interface as active skills (actor to actor), passive skills (actor to self), or status ailments (overtime buffs or debuffs).
I'm not entirely sure that I follow, sorry. It looks like your Fireball sub-class will only be able to execute a single ability, "Fireball". I understand that instead of having individual stats for each Skill, you could just use the specific numbers you need in each of those applySkill methods (which mean yeah, I don't need most of those stats), but this loops back to the problem I had in the first place - I don't necessarily want to hard code 60 skill classes this way.

The way I've been thinking of doing things is to have a couple of bool variables for each skill that's created - StatSkill, ForceSkill. This way, I only need two functions that almost all of my skills can use, passing in the skill itself for its stats. So if a skill heals and buffs, StatSkill = true; ForceSkill= true;. The skill is then passed into both funtions (one for stat changes, one for health changes) and it does its thing. If it's purely a damaging move, StatsSkill = false;. If need be, I could make EffectSkill (poison, weak, zombie) or SpecialSkill even (where I'd write individual functions for special skills, like for ones which let you control enemies or something).

From what I do understand though, your way of creating skills seems to be way more open, which sounds really great. I'm just not sure how you'd be able to keep that openness without making a different class for every single skill.

Again, sorry if I'm missing your point here. I'd appreciate it if you could clarify things for me.

I'm not entirely sure that I follow, sorry. It looks like your Fireball sub-class will only be able to execute a single ability, "Fireball". I understand that instead of having individual stats for each Skill, you could just use the specific numbers you need in each of those applySkill methods (which mean yeah, I don't need most of those stats),


Yes, each one of those method will execute a single ability.


but this loops back to the problem I had in the first place - I don't necessarily want to hard code 60 skill classes this way.
[/quote]

If you really want to make it that dynamic, then you need to implement a scripting system powerful enough to cover all types of skills, and that's probably several more months of development time. And TBH, you don't gain that much benefit unless you allow MODs to your game.

Each skill, eventually, is going to have to be unique and hardcoded to a certain extent. It's going to have its own graphics, its own projectiles, and its own behavior (summoning skills that create new units? skils that lasts over time? AoE effect? global effect? skills that spawn more skills? A couple of booleans and ints aren't going to be able to encapsulate all that, so you might as well code them all individually.

If you are smart in organizing your skill libraries, you don't have to code 60 skills separately. See below:


From what I do understand though, your way of creating skills seems to be way more open, which sounds really great. I'm just not sure how you'd be able to keep that openness without making a different class for every single skill.

Again, sorry if I'm missing your point here. I'd appreciate it if you could clarify things for me.
[/quote]

You don't have to, thanks to inheritance.

class FireBasedSkill : public ISkill {
public:
virtual void applySkill(Actor& actor) {
// apply fire-based damage to actor
}
};

class Fireball : public FireBasedSkill {
virtual void applySkill(Actor& actor) {
FireBasedSkill::applySkill(actor);
// apply fireball-specific code here
}
}

class UberFireball : public Fireball {
virtual void applySkill(Actor& actor) {
Fireball::applySkill(actor);
// more damage!!! burns the target for 100 seconds, etc. etc. etc.
}
}
I love what you did with the applySkill function calls here, it looks super efficient. It seems you could make good use of polymorphism with this approach too. I like how you can basically keep adding layers on top of each Skill object you make, giving tons of customisation, without the need to keep track of all of those variables in a single class. Am I correct in thinking that things like status effects etc. wouldn't need to be included in the main ISkill inheritence tree? You could just call applyEffect(Poison) within applySkill of any specific skill, right?

Anyway, thanks a lot for your help (and everyone else who helped in this thread). You've really clarified things and given me a bunch of options to play with - I feel a lot more confident now (:

Am I correct in thinking that things like status effects etc. wouldn't need to be included in the main ISkill inheritence tree?


You can. It's up to you how to design it. You can create a new class StatusEffect that implements ISkill, and this class will have common attributes for status effects like duration, damage +/-, and so on. Then if there's a special status effect that requires extra code, it can inherit from the main StatusEffect class, and add extra code as necessary.

I'd do it this way, so I can have an array of ISkill in the Actor class, and just iterates through it every frame calling applySkill(this);


You could just call applyEffect(Poison) within applySkill of any specific skill, right?
[/quote]

Yes, that's up to your implementation details.

This topic is closed to new replies.

Advertisement