The Ebonheim Chronicle

Development Blog for Chronicles IV: Ebonheim

For my hot girl summer I sat down bright and early to get some Chronicles work done. It has been a few weeks since I've been able to touch it (where before I was working on it nearly every night) and I also left it at a point where the next task is fairly large and daunting.


Because it's mostly a grid-based tactics RPG, I want to create a generic actions system that I can use to define all of the different types of abilities with the following constraints:

  • Be able to describe all targetable actions for player and enemy from basic movement to complex abilities
  • Be able to query an action for targeting constraints (pattern, line, range, etc)
  • Be able to query any action for the resulting turn state prior to execution
  • Be able to build all actions as an asset in an editor

In game development these days I typically shy away from ultra-generic constructs because they tend to grow into more of a hassle as you scale in complexity but a large component of this project is for all game content on release to be defined in-engine so that non-devs can easily generate custom content.

In a perfect world I would love for a full editor that allows me to create complex abilities like teleporting player behind an enemy and pushing them counter clockwise. Multi-stage actions with multiple dependent targeting constraints will empower a ton of complexity and variety in the game's combat and so I really want to get it right.

Unfortunately! What that means! Is that I'm extremely blocked by analysis paralysis on starting in on this system. It's very big and has to be correct enough to be able to be molded and scaled into the future. It will probably be several sessions of coding before I even have something to show for it and so the whole thing puts me into a mindless coma of inaction.

So my dev-day consisted entirely of making the above little tile highlighting animation. I mean I want to be able to highlight tiles for targeting so you definitely need that! I dreamed of getting my entire actions system working at the end of the day yesterday but instead I have a little animation and a blog post about game development being hard.

All in all still very happy to have broken my fast on this project and I'm going to keep crawling into the breach until I finally get past this hump!

#gamedev #chron4

| 🌐 | πŸ™‹β€ | @britown@blog.brianna.town

I love Dear ImGui. I use it every day and it's probably the most important contribution to independent development in the last decade. So when it came time to start thinking about making in-game UI, why not just create a similar immediate-mode system so that I can just make all my EGA RPG text and buttons and interactions work with literally the same API I use for my tools.


The code for the popup dialog there is

   egaui::setNextWindowPos({ 380, 32 });
   egaui::setNextWindowSize({ 300, 100 });
   if (egaui::begin("test 2!")) {

      egaui::text("Testing some UI");

      egaui::indent();

      egaui::beginGroup();
         egaui::alignTextToFramePadding();
         egaui::text("A button");
         egaui::alignTextToFramePadding();
         egaui::text("Another button");
      egaui::endGroup();

      egaui::sameLine();

      egaui::beginGroup();
         egaui::button("Btn 1");
         egaui::button("Btn 2");
      egaui::endGroup();
      
      egaui::unindent();

      egaui::setCursorPosX(egaui::getContentRegionMax().x - egaui::calcTextSize("Right Aligned").x);
      egaui::alignTextToFramePadding();
      egaui::text("Right Aligned");
   }
   egaui::end();

What's great about this, is this API is simple enough that later down the road when I start thinking of LUA/Scripting integration, creating bindings to enable scripts to define arbitrary UI becomes trivial. Custom menus and dialog trees and everything will be able to developed in the same asset system everything else uses.

Of course the real fun of all of this is that this API exists running inside a game instance that is being rendered to a full ImGui window:

edit: added a better looking window frame :3

#gamedev #chron4 #imgui

| 🌐 | πŸ™‹β€ | @britown@blog.brianna.town

I posted some gifs of my combat system mostly working which I'm proud of but I want to go ahead and do a little write-up on the mechanics as-designed and talk about plans for the future sooo hit the jump if you're into that.


Philosophy

I really want a combat system that focuses most of its complexity on strategic positioning rather than on numbers and calculations. It's one direction to take Nethack and focus on itemization and +10% bonuses and heavily numbers-driven character advancement but I wanted a deterministic rules-based system that is simple to pick up.

I was heavily inspired of course by Into the Breach with its chess-like puzzle boards but I also really appreciate a similar ethos from Slay the Spire where these games attempt to provide the player with as much information as possible about the outcome of their choices while still being challenging.

Rules of Combat

The sum-total set of rules that govern the above gif are as-follows:

  1. Actors have health (red pips) and stamina (green pips)
  2. When an actor receives damage, stamina is removed before health
  3. When an actor attacks, it also costs stamina
  4. If an actor loses all stamina before acting, their attack will be cancelled
  5. Stamina spent on attacking will recover on the actor's next turn (right before they act)
  6. Stamina lost from damage will recover 2 turns after it is lost (right before the actor acts)
  7. If an actor is being targeted by an attack and moves away before the attack executes, they will take an automatic 1 damage (β€œdodge cost”)
  8. Actors have speed which determine turn-execution-order (roman numerals)
  9. The player has turn-order priority within their speed category

In the above gif I slowed the execution way down to see all of the parts. White pips are stamina that will recover before the next action. The player dispatches a low-stamina enemy that is faster (moves first) and then suffers dodge cost to reposition around the enemies. They then uses player-advantage to cancel the enemy hits and take them out one at a time before they can act.

EGA UI

My tiles are 14x14 and the entire frame buffer shares a single 16-color palette from the 64-color EGA color space. I don't have arbitrary scaling or rotation. Everything has to fit under these restrictions including UI elements. This proves very challenging when you're making an RPG!

A large part of breaking this down and reducing complexity is to define meaning to specific palette slots. For instance Palette Index #0 is always β€œBlack” AKA the β€œBackground Element Color” and the β€œBorder Color” When creating art for map tiles, UI elements, actor sprites, I always use index 0 for this purpose. That way if I make a new palette, I can change #0 to a non-black and expect a fairly uniform distribution of effect on all of the art.

Next just comes down to the size of UI elements. Displaying health and stamina is shown on the tiles as pips which are, at minimum, 2x4 pixels. So literally I can't have more health and stamina in one row at the bottom of the tile than the tile can hold (7). I have a system to show multiple rows but a lot of these restrictions actually feed back into the simple design of the combat in the first place. I don't expect to have more than 30 combined health/stamina on a single actor just like I don't expect more than 16 actors to be in the turn order (because that's the largest roman numeral I can fit on a tile)

Other UI concepts that go into consideration are things like the pants color of a sprite happening to line up with the pips in such a way that it appears they have more stamina than they do. Another fun one was reducing black border pixels around elements to allow more of an actor sprite to bleed through from below.

Improving AI

My A* solves are fine enough for these gifs but you may notice a recurring concept in that enemies will often arbitrarily block each other trying to get adjacent to the player. This usually blocks their allies who have to go around, allowing the player to exploit the position and pick the enemies off one at a time. This sort of thing happens in Nethack and other dungeon crawlers where the common strategy is to always just back up to a hallway and force enemies into a bottleneck. I don't really want this strategy to always be universally viable.

A big part of the improvement is going to be mapping the possible decisions onto a weighted graph and solving with Dijkstra's. I want allied enemies to give multi-enemy-to-player-adjacency a higher weight. In the future I will also want enemies to block doorways and be smarter about getting into range of attack. The Player Advantage is a really big one because enemies can't react to player action on the turn that it happens. The counter-balance to me is better strategic positioning behavior.

The end-result I hope is a system where 2-on-1 fights are fairly unwinnable with basic combat. Overcoming difficult encounters will need to rely heavily on the upcoming abilities system.

Future Plans

Next up is more complicated attack patterns. I want to implement ranged attacks that don't require dodge-cost to avoid and play with that. My original spec also included a 3rd pip type, armor, which sits between health and stamina and is purely there to mitigate a new stun mechanic where certain attacks can cause action interrupt.

All of this is also building toward the really good stuff which are arbitrary cooldown abilities. I want abilities to make or break encounters because which abilities you have informs your character's build. Abilities will revolve around concepts such as pushing other actors around, repositioning, teleporting, redirecting enemy actions, sneaking / visibility, and bypassing the existing stamina rules.

Once you start thinking of things like side-pushing an enemy so they kill an adjacent enemy on your turn before that enemy attacks, the rest all starts to spill out, it's very exciting!

First Playable

I've reduced the full scope of the larger game project into just being a combat demo. This will be a standalone game that will be a set of a dozen or so pre-made encounters where the player will need to solve the encounter with their weapon and abilities and not die to continue onto the next. I hope with this project that I'll have a very well-fleshed-out combat system before I start moving onto the exploration and roguelike loop systems.

You Made it!

:eggbug: Good Job :eggbug:

:host-love: Thanks for reading :host-love:

#gamedev #chron4 #longpost

| 🌐 | πŸ™‹β€ | @britown@blog.brianna.town

A big part of the elevator pitch for Chronicles is Nethack with Into the Breach-inspired combat. As it turns out it can be really hard to message out to a player what is happening in combat when you have no pixels and no colors!!!

There's just 8 million tiny tweaks and details to make these gifs happen and I'm really happy with them.

#gamedev #chron4

| 🌐 | πŸ™‹β€ | @britown@blog.brianna.town

Feels like I hardly got to touch this over the weekend but did manage to squeeze in the basic system for actor turn-order as well as input-controller player character, camera following, and just the quickest dirtiest A* I've ever cobbled together.

Edit: Also wanted to show off some of the palettes I've been putting together as I try to wrangle standards for palette colors so that UI will still work.

#gamedev #chron4

| 🌐 | πŸ™‹β€ | @britown@blog.brianna.town

Feeling burned out on code this week so took a step back to use all the new tools and try to generate some assets. I get overwhelmed with pixel art but 14x14 tiles with 16 colors is comfortable enough that I can be happy with the aesthetic.

#gamedev #chron4 #pixelart

| 🌐 | πŸ™‹β€ | @britown@blog.brianna.town

I've always had this pipe dream of being able to live-edit all assets in a game project while the game is running and I'm feeling really strong about the progress of this newest project!


Most/all of my personal side-project revolve around C/C++ desktop apps with homespun engines. It's usually as much a journeyman effort for learning more CS as it is a desire to make a game. A big part of solving the issue of finishing a game has to do with having good architecture with a good assets pipeline.

In this example we have:

  • The assets data-catalog is on the top left
  • A running game instance in the top right (can have multiple running in windows independently in the same exe)
  • A tile schema editor for map tiles in the bottom left
  • A homemade pixel image editor in the bottom right.

Any pixel edits to the graphics in the editor live-update anywhere they are used (in this case both the running game and the schema editor) giving you redundancy to test your edits. It also has perfect referential integrity so you never have to worry about your game crashing when an assert comes up missing.

I will have to come up with some thoughtful posts digging into the how's and why's of all of this but the main concepts at play here are:

  • β€œC-Style” C++
  • Generated reflection code from struct definitions
  • Generic recursive file format
  • Live++
  • Dear ImGui

#gamedev #chron4 #cpp #imgui

| 🌐 | πŸ™‹β€ | @britown@blog.brianna.town