The Ebonheim Chronicle

Development Blog for Chronicles IV: Ebonheim

Something very hard about giving the player perfect information about how a turn will play out is that enemies can go before you in their turn order. This has caused a lot of confusion for testers because you might need to target an ability where an enemy is going to be rather than where they are.

My new idea for communicating this is that if your ability is going to affect an enemy at a position other than where they begin the turn, it shows a ghost sliding into where your ability will affect them.

#gamedev #chron4

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

Edit: The Combat Mechanics Milestone Demo is over, if you'd like to be considered for future playtests, you can email me at britown.cohost@gmail.com

If you'd like to try out the Chronicles IV Combat Demo currently brewing, I made a little form where you can submit your info and receive a copy.

This demo is designed as a smaller game than the full vision. It exists to narrow my scope and also start iterating on feedback from the Big Complicated Combat System.

Still not 100% sure when these will go out (very soon!) but I promised it would be this year and so it shall be!

https://forms.gle/x4Giibsu3WEgScLFA

#chron4

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

I wrote 3 months ago about how this is a particularly hard problem to solve.

For whatever reason I've been possessed to actually try implementing this over the last few days and I finally have something to show for it.

Here, the enemy has a teleport that has just enough range to cross the water and it has a long cooldown. Therefore the highest value path is to walk to the edge first, then teleport across to attack.

This is a dynamic use of the actor's abilities with no scripting!

Enemies are using abilities for the first time!

#gamedev #chron4

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

Sat down tonight to actually try and write a more complete song instead of little test loops using the Chronicles Audio Engine (tldr: 3 square wave channels and a noise generator)

I feel like it went very well! But I'm also completely new to this so any constructive feedback is welcome!!!

#gamedev #chron4 #tracker #chiptune

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

The final bit was getting my instrument editor working, including an interactive volume envelope editor. It works!!

#gamedev #chron4 #tracker

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

Haven't changed these tiles in a year.

Feedback welcome!

#gamedev #chron4 #pixelart

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

Just completed the second major refactor of the actions system[1]. This time the end goal is being able to query the final game state for a lot of complex result data that I've been needing to display in previews but it's been too much of a pain to aggregate.

  1. Here's talking about the first

Because action lists are arbitrarily complex it's actually very hard to answer some specific questions like β€œwhat actors did I damage?” Or β€œwho pushed me?” You want to record some events as you iterate but you don't want to write special event code for every action type which is what I was doing and it scaled horribly.

Anyway the new system feels elegant and just works for all cases including future complex cases in my imagination.

This is the endgame I think of this system, it feels really complete now which is good because it's the primary focus of my demo and I'm tired of hacking at it. I'm honestly really proud of myself for making something that is extremely complex and also straightforward to maintain and upgrade. My code tidiness has really saved me from a lot of headaches.

The main result of this is that turn highlighting telling you what your choices are going to do is finally comprehensive and complete.

The exciting future that this enables, however, is that enemy AI behavior can now know things like β€œWill using this ability here damage my target” so I can build a system where enemies have behavior goals and can use their abilities and check the results against their goals. If you want to read me ranting about enemy behavior in the complex actions system, you can do so here.

#gamedev #chron4

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

It's super easy now to do in-line coloring and icons across all user-facing text in the game πŸ˜€

#gamedev #chron4

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

I've talked a few times about how I'm replicating the design of Dear ImGui for my in-game UI

I now have the popup system working! Simple popups like context menus or dropdowns will dismiss if you click away from them, and then modal popups will disable everything under them until they are dismissed.

Also shown: Tooltips!

#gamedev #chron4

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

β€œWhat parts of EGA are you emulating? Only the color space and (more or less) resolution, or do you do something deeper?”

Great question! It's actually been long enough that I had forgotten a lot of the work I did on EGA emulation. The original project stored the frame buffer data in bit-planes the way it was done on the hardware. The code for this is on a public github repo:

#if defined(EGA_MODE_0Dh)
#define EGA_RES_WIDTH 320
#define EGA_RES_HEIGHT 200
#define EGA_TEXT_CHAR_WIDTH 8
#define EGA_TEXT_CHAR_HEIGHT 8
#define EGA_PIXEL_HEIGHT 1.2f
#define EGA_PIXEL_WIDTH 1.00f
#elif defined(EGA_MODE_10h)
#define EGA_RES_WIDTH 640
#define EGA_RES_HEIGHT 350
#define EGA_TEXT_CHAR_WIDTH 8
#define EGA_TEXT_CHAR_HEIGHT 14
#define EGA_PIXEL_HEIGHT 1.37f
#define EGA_PIXEL_WIDTH 1.00f
#else
#error segalib: You must define a video mode in config.h
#endif

#define EGA_COLORS 64
#define EGA_COLOR_UNDEFINED (EGA_COLORS)
#define EGA_COLOR_UNUSED (EGA_COLORS + 1)
#define EGA_PALETTE_COLORS 16
#define EGA_TEXT_RES_WIDTH (EGA_RES_WIDTH / EGA_TEXT_CHAR_WIDTH)
#define EGA_TEXT_RES_HEIGHT (EGA_RES_HEIGHT / EGA_TEXT_CHAR_HEIGHT)
#define EGA_PIXELS (EGA_RES_WIDTH * EGA_RES_HEIGHT)
#define EGA_BYTES (EGA_PIXELS / 8)
#define EGA_PLANES 4
#define EGA_IMAGE_PLANES (EGA_PLANES + 1)

#define MAX_IMAGE_WIDTH 1024
#define MAX_IMAGE_HEIGHT 768

I cringe a little looking back at some of this because I didn't know what I was doing and definitely wasn't doing a lot of hardware-specific memory layout work which is what I would do on an emulation project now. I didn't know about ImGui back then and still wanted my dream of in-engine dev tools so I actually made EGA-compliant developer tools you could switch into for editing the map and writing lua, it was a little wild!

Drawing a bitplaned asset onto an existing framebuffer was a giant pain because you had to shift the asset to align to the correct place. It was actually a performance problem on modern hardware and I ended up needing to do it much smarter than I originally thought. I remember digging up a lot of old posts and articles about techniques people used like this for storing animations inside the bitplanes.

I can't find it now but I remember an article from a developer talking about storing 8 copies of their assets each one shifted by one so you could always just render the aligned asset and never have to do the shifting logic!

When I resurrected the old EGA project into the new engine now powering Chronicles, I vastly simplified the back-end for convenience. Now the frame buffer is just 1 byte per pixel which only stores the palette index. In the end the only restrictions on the current generation of the game is the palette and color logic because even the resolution is apocryphal and text rendering is now completely arbitrary :host-joy:

In the end it's purely an aesthetic restriction now but I did once upon a time aim to have a pure backend implementation!

#gamedev #chron4

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