An Indie Oldschool Role-Playing Game

Developer Update #3

Developer Update #3

on Jul 22, 2013 | 4 comments

Some major progress has been made since the last update, and the game is slowly starting to shape up to something playable. Here’s what’s new for DarkDale this time:

 

Artificial Intelligence in DarkDale

Our first creature, a small bat, has been now fully rigged, animated and imported into the game! Beyond the relatively straightforward task of creating the animations for the different actions (move, turn, attack…), and coding in the creature component to contain and manage all those animations in the game world, this required setting up the entire structure managing artificial intelligence and pathfinding (dungeon navigation). Artificial intelligence had to be flexible, adaptive and, most importantly, easily scriptable. After reading multiple articles on AI, trying to see what would be the best option, I finally stumbled on this interesting one, and decided to go ahead with a strcuture of layered Finite State Machines.

If you do not know what an FSM is, it is a simple control structure for artificial intelligence that has been prevalent in game development for a long time. The basic idea is that an entity is in one state at a time, such as moving, sleeping or attacking. Obviously, “attacking” involves doing a lot of different things, such as evading blows, striking, blocking… so FSMs evolved into Hierarchical FSMs (HFSMs), where each state can have multiple sub-states. While generally fine for simple tasks, this structure was deemed too rigid in the last decade to fullfil the more dynamic behavior requirements of open-world / sandbox games such as The Elder Scrolls. Different more advanced solutions have been found, such as Behavior Trees or Hierarchical Task Networks, but most of these seemed a bit overkill for a dungeon crawler.

The solution of layering independent FSMs keeps the advantage of their simplicity but at the same time allows more flexible AI combinations. The creature AI in DarkDale is thus separated in three elements (or layers): the State layer, the Behavior layer and the Action layer:

  • States govern global modes. For example, a creature can be in the “Wandering” state until it sees a player, in which case it can switch to the “Attacking” state if it is hostile. Depending on what’s going on, the state will assign a behavior to the creature to execute.
  • Behaviors are complex actions composed of multiple elements. For example, the “Attacking” state of a creature which has only a melee attack will check if the creature is physically next to the party and ready to attack it. If not, it will assign the “MoveToMeleeAttackPosition” behavior. The behavior will calculate the path needed to reach the party (if possible) and assign the next action required to fulfill its goal. The “Wander” behavior navigates around obstacles. The “MeleeAttack” behavior attacks or waits for the creature cooldown to expire.
  • Actions are the building blocks of creature behaviors, such as “MoveForward”, “TurnLeft”, “MoveRight”, “MeleeAttack”…

This allows also a flexible modular design which keeps the code tidy, as multiple states could need to call the same behavior (defined once), and obviously multiple behaviors will require the same action. How state logic decides which behavior to assign is fully scriptable and can happen at multiple places:

  • In OnStateEnter or OnStateExit calls.
  • In the main creature AI loop, OnStateControl : this is called after every action the creature completes, or every frame if the creature is waiting.
  • By the means of various events, such as OnDetectParty.

You can also control the global AI directly from any script with functions such as creature:setState(state), creature:setBehavior(behavior), or even short-circuit the AI by setting it to an idle mode and “puppet” the creature directly from script with creature:moveForward(), creature:turnLeft()…

Exchanging blows with a bat.

Exchanging blows with a bat.

Here’s an example of a simple AI for a monster that wanders around until it sees the party, then attacks:


    aiStates = {
	{
            name = "Wandering",
            movementSpeed = {0.5, 2},
            onStateEnter = function(self) self:setBehavior("Wander") end,
            onDetectParty = function(self) 
                self:setState("Attacking")
                self:setTargetID("Party")	
            end,
        },
	{
            name = "Attacking",
            movementSpeed = {0.5, 1},
            attackSpeed = {2, 4},
            onStateControl = function(self) 
                if self:isInMeleeAttackPosition() then self:setBehavior("MeleeAttack")
                else self:setBehavior("MoveToMeleeAttackPosition") end
            end,
            onLoseParty = function(self) self:setState("Wandering") end,
	},
    },

A last neat little touch is that the delay between two attacks (the creature “cooldown”) is independent and the behavior can take it into account. A creature could for example attack the party, then retreat or strife left/right while its cooldown delay hasn’t expired, and when ready move again in position to attack the party. Basically, “two-step dance” combat fans will be served their own medicine!

By the way, creatures will also have health, stamina and mana stats, just like the player. A magic user will cast spells and try to hide away or resort to melee attacks if his mana reserves are depleted. A monster will not be able to use a “special attack” if it’s out of stamina. Cautious creatures will retreat when badly wounded. Creatures will also have area-of-effect abilities, for example an undead creature could scream, frightening player characters caught in the radius. All this will make for more interesting and complex tactics beyond your run-of-the mill hack & slash.

Oh, and did we mention friendly or summoned creatures & creature-vs-creature combat?

 

Bats Attack

The AI being set-up, next thing was to put in all the code related to managing combat – toHit rolls, damage rolls, the game console, the little floating damage numbers above the creatures, the blood splashes on the champion’s portraits, the stamina cost for attacks, experience points, the Dungeon Master “death smoke” effect on creature death, the “Ugh!”s and “Arhg!”s when hit… All sorts of little things that still need some tweaking, but are all coded in now. So here’s a first gameplay video, showing a combat with five bats in the sewers. Unfortunately, no funky AI behaviors implemented here yet: as a first combat scene, it’s quite straightforward and close to what you would expect in Eye of The Beholder or Legend of Grimrock, but more will come, don’t worry!

 

Editor Revamped

The UI in the editor has also been redrawn in 1080p resolution with new icons and buttons. But the more interesting feature is that the “Wall Tool”, which served to paint walls or floors, has evolved into a more general “Tile Tool”. This will allow you to define particular tiles in the wallset .lua definition files, and simply paint them on the grid. As you see from the screenshot below, the sewers tileset currently uses “Wall”, “Floor” and “Canal” tiles, and the level shown is the one from the video above.

The new Tile Tool in the level editor.

The new Tile Tool in the level editor.

While still fun in dungeons, this feature will be particularly invaluable in towns or exteriors with separate Forest, Road, Grass, River, Bridge, Hill tiles to quickly paint, and these won’t get in the way of selecting and editing actual entities such as items or creatures. You can define up to approximately 200 different tiles per wallset, and each can have its own user-defined color, as well as its own, floor, ceiling, walls (called borders here), pillars…

 

What’s next?

The basic code for creatures, AI & combat being in, next thing we’ll focus on is the implementation of the magic system. The spells panel, the casting interface, the spells definitions, projectiles, colliders, particles, explosions… fun times ahead. The game progresses at a good pace, and I hope that most of the basic engine will be ready by the end of summer, and then it’s on the the actual content creation phase, and then testing. Expect DarkDale: Betrayal to ship somewhere mid 2014 if all goes well!

    4 Comments

  1. Good progress, good level of details. Are you planning the attacks to be instantaneous? It would be cool if the attack to a while. That makes sense as rogue can throw a knife much faster than large barbarian can swing a two-handed axe. That would lead to fun options. You could implement onAttackBegin and some creatures could attempt to dodge it. That in turn would lead to lots of new challenges – evasive creatures immune to slow weapons, creatures that you need to force into a dead end before you can kill it, etc.

    thomson

    July 23, 2013

    • I was thinking attacks to be instantaneous, and the “evasiveness” to be handled by the toHit rolls which are basically char accuracy vs creature evasion. Faster creatures will have higher evasion ratings. Slower weapons, such as large hammers, will have lower accuracy bonuses. A quick dagger will have a higher accuracy. Two handed weapons have accuracy penalties (slower) which get progressively removed as you level your skill. The delayed attack idea is interesting, but I’m not sure if it wouldn’t complicate things a bit too much (there’s cooldown already also which distinguishes fast from slow attacks). Also I’m not sure how to properly provide visual interaction as you don’t see the char’s weapons that the monsters can dodge…

      In your comment on grimrock.net, you also mention custom events: definitely, that’s a good idea. As with behaviors, I will provide some predefined ones, and allow custom ones as well.

      Because of the coding structure of the game, I cannot however put everything in lua, as the game is written in C# with lua accessible through a wrapper. For that reason, performance intensive calculations that need to be very optimized, such as pathFinding or line of sight algorithms (and the associated actions or events) have to be done in native code and provided as is.

      But I’ll think of how I could implement a generic event system accessible from lua scripts.

      Georges Dimitrov

      July 23, 2013

  2. Hi Georges,

    In my opinion the game seems very promising and indeed you have managed tremendous progress in the last month
    Some comments/questions from my side:
    1) I see that you choose to have a two level combat mechanic (first level being selecting the weapon to hit and second level slecting the type of hit, i.e., swing, etc). This resembles more the kind of fighting of Dungeon Master, rather than that of eye of the beholder. Personally, I preferred the latter, and I wonder wether this approach will make combat cumbersome and slow?
    2) Successfuly hitting an enemy results to a floating number indicating the damage you succeeded on it. Wouldn’t it be better to use the old EOB style approach, where damage is displayed on the weapon used to hit. Why? I think it gives the player a more accurate image of who/when hits and most importantly you do not have numbers floating all over your screen, which I think subtracts from the immersion to the game, making it less realistic?
    3) Will you support dual weapon wielders (for example two swords, or sword-dagger, axe-sword, etc), with the possibility to attack separately (I mean in different times with diferent cool down time for each weapon/hand). This is something, I remember from EOB2, which I liked a lot, but it didn’t seem to survive until now (Grimrock for example dind’t support it)?
    4) How to you plan to implement magic. Will you use an EOB like approach (i.e., using a spellbook requiring to memorize spells beforehand), or a Grimrock like (based on runes), which I personally, find it a little bit cumbersome, or perhaps a completely different aprroach? If possible give us some details on your plans?

    Thanks a lot

    greco

    July 24, 2013

    • Hi Greco,

      Some answers:

      1) From my first tests, I don’t think the combat will be that cumbersome with two clicks. If needed, the global pace of combat (cooldowns, etc) will be slowed to make sure things don’t get overwhelming.

      2) I’ll probably have numbers on the weapon indeed as well, just not implemented yet. Players will have options to turn feedback (console, floating numbers) on/off anyway.

      3) Dual wield support is definitely planned, as is two-handed weapons. Dual wielding will be a special trait available to certain skills at higher levels. Daggers are the main dual-wielding skill, but there may be other secret talents to find in game.

      4) Magic will be spellbook-based with mana to cast, quite close to how Might & Magic was. Rune magic is fun, but especially when you have to actually find the runes (Ultima Underworld comes to mind). It’s true it’s cumbersome, though.

      Georges Dimitrov

      July 26, 2013

Post a Reply

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