An Indie Oldschool Role-Playing Game

With Fire and Axe

With Fire and Axe

on Aug 4, 2015 | 1 comment

As promised I’ll try to keep a more regular posting schedule, with a goal of at least once post a month, and maybe more  depending on progress. As I mentioned last time, the objective on the roadmap is currently to get all the different modules of the engine up and running.

In the past month, I started by taking care of the user interface for spells, which led to refactoring the spells system, and as spells cast had to look the part, it led to fixing the old particleSystem component I had, and then as a ball of flame which doesn’t illuminate the surroundings looks kind of awkward, I had to code in a light component.  Of course, casting spells in the void is boring, so I had to essentially get all the combat & AI engine up and running together with the rest of the engine to be able to set some enemies on fire. Finally, fighting without risk isn’t going to make a fun challenge, so I also put in the basic framework that handles conditions that can befall champions such as, you know, death.

The result of all this can be seen in this short gameplay video, and then you’re welcome to read on for a few additional details:

Let’s make some magic!

Aaaah, spellcasting. One of the backbones of any decent RPG. You can read more about the magic system in the old Magic in DarkDale (Part 1) and Magic in DarkDale (Part 2) posts, and although the UI has changed since, the basic game design principles are still the same. This month I focused on getting spells to function right, and it started with a UI redesign, which went through many iterations. Part of the problem is that spells are separated by magic schools and then by rank (Apprentice, Expert, Master…), which led me to initially design a kind of two-dimensional interface which had tabs for magic schools and tabs for ranks. But then spells could belong to more than one school simultaneously (what in-game lore calls “high” magic), which added a third dimension and things were getting out of control. So I backed down to a much more immediate and cleaner interface where there is only one scrolling panel, grouping spells per rank, no matter what school(s) they are from. Low vs. high magic spells are easily differentiated by color coding them (white vs. gold) and spells you cannot cast yet are greyed out.

Once you find the spell you are looking for in your spellbook, there are two actual ways to cast it. You can simply double-click on it directly in the spells panel, which is useful for utility spells you cast once in a while (Light, Repair Weapon…) or buffing spells (Shock Shield…), but not ideal in the middle of combat. This is why the game also features a quick spell casting system, which allows to cast spells directly from the champion portraits in the lower right, using the same interface as weapon attacks. Setting quick spells is just a matter of drag and drop, and you’re ready to throw fireballs around. How many quick spell slots you have depends on the champion intelligence:

  • 0-7: 1 spell slot
  • 8-12: 2 spell slots
  • 13-17: 3 spell slots
  • 18-22: 4 spell slots
  • 23-25: 5 spell slots

So, being able to “memorize” more spells without the need to open your spellbook and browse through the pages (which is the role-playing element this system tries to emulate) might be worth some consideration when rolling your character or wondering if that Amulet of Greater Intelligence is worth the astronomic price the wretched old merchant is asking for.

Actual spell effects are entirely scriptable through a series of event callbacks available, depending on the type of spell. For the Flame spell shown in the video above, the script is quite elementary:

onEntityHit = function(spell, entity)
    spell:dealDamageTo(entity);
end,

The function is called once for each entity in the area of effect of the spell – and yes that means even floors and walls, but as they don’t usually have a component which handles damage, dealing damage to them does nothing… until you want to make breakable structures of course and add the appropriate component.

Also, as you can see, some convenience functions will be provided for more common tasks, such as damaging or healing spells, but a complete API is there to access all defined properties of the spell beneath if you need to do any custom complex scripts. For example, the above code would be strictly equivalent to:

onEntityHit = function(spell, entity)
    local dmg = math.random(spell:getDamage());
    entity:dealDamage{
        damage = dmg,
        damageType = spell:getDamageType(),
        sourceEntity = spell:getCaster(),
        sourceSpell = spell,
    };
end,

 

A bat hit by a Flame spell in the middle of combat.

A bat hit by a Flame spell in the middle of combat.

Bats, bats all around

Apart spell casting above and under the hood, the other main element I worked on is combat. Combat was already sketched up to a working point, but many elements weren’t functioning correctly together or dated from the very beginning of the game development more than two years ago. I cleaned all that legacy code, so that now everything is smooth. Also, I had already made the transition to Unity’s more advanced Mecanim animation system for humanoid characters, but not for generic monsters such as those bats. This is now done both with on Unity’s animator controllers’ side and on the scripting backend : the framework is there to now easily import any monster in the game, whether I model and animate it myself, purchase it ready-made on the asset store or contract it.

While playing with all that, I realized that the monster AI was doing rather fine when one monster was around, but when there were a couple of them, such as in the video above, their collective movement was sometimes quite illogical. Some head-aching hours of messing with the pathfinding code later, I got rid of some very subtle and insidious bugs (better catch those now than later), enemy navigation is now more robust and behaves coherently enough in groups.

Along with the fighting came a cleanup of how combat information was displayed on the console, and how it was handled. For one, I separated the attack code, which happens on the champion side, from the damage handling code, which happens on the creature side. So “Gorath swings at a bat for 15 damage.” and “The bat is dead. (25 experience points.)” come from totally different parts of the engine now, which is like it should be, a modular approach which will make it easier to incorporate further elements I have down the to-do list. I fixed some color and grammar issues, and made the localization engine a bit more powerful to handle translations more easily, as the game will be released in English and French from the start. All the info that is output to the console will be configurable by the player in the game settings window, and you’ll be able to selectively turn on more details (such as to-hit percentages or armor/resistances calculations) or turn off combat messages altogether.

Finally, as said at the start of this post, I’ve implemented the conditions system, which you can see in action in the video above when our paladin falls unconscious then dies. But this is a subject that deserves its own post and I’ll discuss it in more detail next time. Meanwhile, thanks for the words of encouragement I’ve received since the last “Back on Track” post: having such support is great, so let’s get back at work!

 

    1 Comment

  1. Always very interesting to read you, I can’t wait to put my greasy modder’s hands on it 🙂
    Thank you for your commitment to this amazing project, and take some very good care.

    Cromcrom

    August 7, 2015

Post a Reply

Your email address will not be published. Required fields are marked *